diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..1cf867f786 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +# http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + + +[*.md] +max_line_length = 0 +trim_trailing_whitespace = false + +[*.jade] +max_line_length = 0 +trim_trailing_whitespace = false + +# Indentation override +#[lib/**.js] +#[{package.json,.travis.yml}] +#[**/**.js] diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..d1c2c2b349 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,30 @@ +module.exports = { + "globals": { + "describe": true, + "beforeEach": true, + "it": true, + "expect": true + }, + "env": { + "node": true + }, + "extends": "eslint:recommended", + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] + } +}; \ No newline at end of file diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 0000000000..77c09fb883 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,8 @@ +{ + "projects": { + "live": "angular-io", + "ngdocsdev": "ngdocsdev", + "kw-dev": "kw-angular-io", + "dev": "angular-io-dev" + } +} \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..fa749aa3fd --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,7 @@ +**Please do not add issues or pull requests to this repo.** +We are no longer making changes to documentation in this repository. +We will no longer process new issues or PRs and we will close them automatically. + +**Please post new [issues](https://github.com/angular/angular/issues) and [pull requests](https://github.com/angular/angular/pulls) to the content folder in [https://github.com/angular/angular/tree/master/aio/content](https://github.com/angular/angular/tree/master/aio/content)**. + +Be sure to prefix your issue/PR title with "**docs(aio):**" diff --git a/.github/PULL_REQUEST_TEMPLATE.MD b/.github/PULL_REQUEST_TEMPLATE.MD new file mode 100644 index 0000000000..c4e15a1d58 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.MD @@ -0,0 +1,7 @@ +**Please do not add issues or pull requests to this repo.** +We are no longer making changes to documentation in this repository. +We will no longer process new issues or PRs and we will close them automatically. + +**Please post new [issues](https://github.com/angular/angular/issues) and [pull requests](https://github.com/angular/angular/pulls) to the content folder in [https://github.com/angular/angular/tree/master/aio/content](https://github.com/angular/angular/tree/master/aio/content)**. + +Be sure to prefix your issue/PR title with "**docs(aio):**" diff --git a/.gitignore b/.gitignore index c69d33ad83..c327f2acf5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ node_modules _temp bower_components jspm_packages -typings **/packages build pubspec.lock @@ -12,21 +11,27 @@ pubspec.lock .DS_Store **/*.iml .idea +.vscode **/js/latest/api **/ts/latest/api +**/dart/latest/api **/docs/**/_fragments _.* **/resources/zips public/docs/xref-*.* _zip-output -www -/npm-debug.log -npm-debug.log.* +www* +npm-debug*.log* +**/debug.log *.plnkr.html plnkr.html +*.eplnkr.html +eplnkr.html *plnkr.no-link.html public/docs/*/latest/guide/cheatsheet.json protractor-results.txt - - - +link-checker-results.txt +/dist +/public/docs/dart +/public/docs/ts/_cache +/public/docs/_examples/*/dart diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..1e8b314962 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +6 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..edba3b37d8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,47 @@ +dist: trusty +sudo: required +language: node_js +node_js: + - "6" +os: + - linux +env: + global: + - DBUS_SESSION_BUS_ADDRESS=/dev/null + - DISPLAY=:99.0 + - CHROME_BIN=chromium-browser + - LATEST_RELEASE=4.0.0 + # Temporarily disabled until there is a new release branch for 4.0.0 + # - LATEST_RELEASE_BRANCH=2.4.x + - TASK_FLAGS="--dgeni-log=warn" + matrix: + # current angular release jobs + - TASK=lint + - TASK="run-e2e-tests --fast" SCRIPT=examples-install.sh + - TASK=build-compile SCRIPT=deploy-install.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v" + # current angular release branch jobs + # - TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh PREVIEW_BRANCH=$LATEST_RELEASE_BRANCH + # - TASK=build-compile SCRIPT=deploy-install-preview.sh PREVIEW_BRANCH=$LATEST_RELEASE_BRANCH WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v" + # angular master jobs + - TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh PREVIEW_BRANCH=master + - TASK=build-compile SCRIPT=deploy-install-preview.sh PREVIEW_BRANCH=master WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v" +matrix: + fast_finish: true + allow_failures: + # allow current angular release branch and master to fail + # these should be moved to a daily task instead of being ran on every PR + # - env: TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh PREVIEW_BRANCH=$LATEST_RELEASE_BRANCH + # - env: TASK=build-compile SCRIPT=deploy-install-preview.sh PREVIEW_BRANCH=$LATEST_RELEASE_BRANCH WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v" + - env: TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh PREVIEW_BRANCH=master + - env: TASK=build-compile SCRIPT=deploy-install-preview.sh PREVIEW_BRANCH=master WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v" +before_install: + - source ./scripts/env-set.sh + - ./scripts/before-install.sh +install: + - npm install --no-optional + - if [[ -n "$SCRIPT" ]]; then echo "EXTRA INSTALL $SCRIPT"; ./scripts/$SCRIPT; fi +before_script: + - sh -e /etc/init.d/xvfb start +script: + - $WAIT gulp $TASK $TASK_FLAGS + - if [[ -n "$POST_SCRIPT" ]]; then ./scripts/$POST_SCRIPT; fi diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index bede42df52..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - // Controls the rendering size of tabs in characters. Accepted values: "auto", 2, 4, 6, etc. If set to "auto", the value will be guessed when a file is opened. - "editor.tabSize": 2, - // Controls if the editor will insert spaces for tabs. Accepted values: "auto", true, false. If set to "auto", the value will be guessed when a file is opened. - "editor.insertSpaces": true, - // When enabled, will trim trailing whitespace when you save a file. - "files.trimTrailingWhitespace": false, - // Specifies the folder path containing the tsserver and lib*.d.ts files to use. - "typescript.tsdk": "public/docs/_examples/node_modules/typescript/lib" -} diff --git a/LICENSE b/LICENSE index 13a6fd789f..47bfda24ad 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2016 Google, Inc. +Copyright (c) 2017 Google, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 649724ec5d..5a68c5c1b7 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,157 @@ +# This angular.io documentation repository is closed and preserved just for archival purposes + +**Please post new [issues](https://github.com/angular/angular/issues) and [pull requests](https://github.com/angular/angular/pulls) to the content folder in [https://github.com/angular/angular/tree/master/aio/content](https://github.com/angular/angular/tree/master/aio/content)**. + +
+ # Angular.io -Angular.io is currently the preview site for Angular 2. This site also includes links to other helpful angular resources including Angular 1, Angular Material, and AngularFire. +---------- + +[![Build Status][travis-badge]][travis-badge-url] + +Angular.io is site for Angular **documentation** . + +This site also includes links to other helpful angular resources including +AngularJS, Angular Material, and AngularFire. + +## Issues + +Please file **Developer Guide, Cookbook, and code sample issues _only_** in this +[Angular.io](https://github.com/angular/angular.io/issues) github repo. + +**Angular API issues, cheatsheet corrections, feature requests, defect reports, and technical questions** concerning Angular itself +belong in the [**angular source code**](https://github.com/angular/angular/issues) github repo. +We can't handle those topics here and will ask you to re-post them on the angular repo. ## How you can help -- [File an issue on github](https://github.com/angular/angular.io/issues) -- [Contribute to Angular.io](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md) +Filing issues is helpful but **pull requests** that improve the docs are even better! + +Learn how to [contribute to Angular.io](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md). ## Development Setup -1. install [nvm](https://github.com/creationix/nvm) -2. clone this repo and [angular](https://github.com/angular/angular) on the same parent directory -3. cd into root directory `angular.io/` -4. make sure you are using the latest node and npm by running `nvm use 4`. -5. install local packages by running `npm install` +This site relies heavily on node and npm. + +1. Make sure you are using at least node v.5+ and latest npm; +if not install [nvm](https://github.com/creationix/nvm) to get node going on your machine. + +1. Install global npm packages by running `./scripts/before-install.sh` + +1. Clone + + - this repo + - [angular/angular source code repo](https://github.com/angular/angular) + + to the same parent directory. The **cloned repo directories must be siblings**, with the latter named **angular**. + +1. cd into root directory `angular.io/` + +1. Install local npm packages by running `./scripts/install.sh` + +1. See [below](#code-sample-development) for code sample development preparation. + +## Content Development +All documentation content is written in Jade which has [its own syntax](http://jade-lang.com/reference/). +Be aware of the strict demands imposed by this significant-whitespace language. +We strongly recommend running one of the gulp `serve-and-sync` commands [described below](#serve-and-sync) +while editing content so you can see the effect of your changes *as you type*. + +The documentation relies on specific styles and mixins. +Learn about those in the [documentation styleguide](https://angular.io/docs/ts/latest/styleguide.html). + +The jade documentation files are language-specific directories under either `public/docs/`. +For example, all of the TypeScript docs are in `public/docs/ts/latest`, e.g. +- `public/docs/ts/latest/quickstart.jade` +- `public/docs/ts/latest/guide/architecture.jade` +- `public/docs/ts/latest/cookbook/component-communication.jade` +- `public/docs/ts/latest/tutorial/toh-pt5.jade` -## Local server with watches and browser reload +### Local server with watches and browser reload 1. cd into root directory `angular.io/` - 2. run `gulp serve-and-sync` - 3. browser will launch on localhost:3000 and stay refreshed automatically. + 1. run `gulp serve-and-sync` + 1. browser will launch on localhost:3000 and stay refreshed automatically. -If you are only going to work on a specific part of the docs, such as the API or dev guide, then you can use one of the more specific gulp tasks to only watch those parts of the file system: + +If you are only going to work on a specific part of the docs, such as the dev guide, then you can use one of the more specific gulp tasks to only watch those parts of the file system: + +* `gulp serve-and-sync` : watch all the local Jade/Sass files, the API source and examples, and the dev guide files +* `gulp serve-and-sync-api` : watch only the API source and example files +* `gulp serve-and-sync-devguide` : watch only the dev guide files +* `gulp build-and-serve` : watch only the local Jade/Sass files + +## Code Sample Development + +All documentation is supported by sample code and plunkers. +Such code resides in the `public/docs/_examples` directory, under page-specific directories, further divided by language track. + +For example, the TypeScript QuickStart sample is in `public/docs/_examples/quickstart/ts`. + +All samples are in a consistent directory structure using the same styles and the same npm packages, including the latest release of Angular. +This consistency is possible in part thanks to gulp-driven tooling. +To run the samples locally and confirm that they work properly, +take the following extra steps to prepare the environment: + +1. cd to `public/docs/_examples` + +1. install the canonical node packages for all samples by running `npm install` + +1. cd back up to `angular.io` root: `cd ../../..` + +1. run `gulp add-example-boilerplate` (elevate to admin on Windows) +to copy canonical files to the sample directories and create symlinks there for node_modules. + +Now cd into any particular sample's language directory (e.g., `public/docs/_examples/quickstart/ts`) and try: +- `npm start` to simultaneously compile-with-watch and serve-in-browser-with-watch +- `npm run tsc` to compile only +- `npm run lite` to serve-and-watch in browser + +Look at the scripts in `package.json` for other options. +Also, open any `plunkr.no-link.html` to see the code execute in plunker +(you may have to run `gulp build-plunkers` first to create/update). + +You must check that your example is free of lint errors. +- `gulp lint` + +### Sample end-to-end tests + +All samples should be covered to some degree by end-to-end tests: +- `gulp run-e2e-tests` to run all TypeScript and JavaScript tests +- `gulp run-e2e-tests --lang=all` to run TypeScript and JavaScript tests +- `gulp run-e2e-tests --filter=quickstart` to filter the examples to run, by name +- `gulp run-e2e-tests --fast` to ignore npm install, webdriver update and boilerplate copy + +Any combination of options is possible. + +### Resetting the project +This project generates a lot of untracked files, if you wish to reset it to a mint state, you can run: + +- `git clean -xdf` + +Also, there is a script available for Linux, OSX and Windows Gitbash users that will setup the project using the steps shown in this section: + +- `./scripts/install.sh` + +### Run with current build instead of release packages +Can switch the `@angular` packages in `~/public/docs/_examples/node_modules` to the current build packages with +``` +gulp install-example-angular --build +``` +Restore to RELEASE packages with +``` +gulp install-example-angular +``` +>These commands will fail if something is locking any of the packages ... as an IDE often does. +> +>The symptom typically is an error trying to `rm -rf node_modules/@angular`. +> +>_Solution_: unlock the hold on the package(s). In VS Code, re-load the window (`cmd-P` then enter `>relow`). -* `serve-and-sync` : watch all the local Jade/Sass files, the API source and examples, and the dev guide files -* `serve-and-sync-api-docs` : watch only the API source and example files -* `serve-and-sync-devguide` : watch only the dev guide files -* `build-and-serve` : watch only the local Jade/Sass files ## Technology Used -- Angular 1.x: The production ready version of Angular +- Angular: Current Angular +- AngularJS: A v.1.x version of Angular - Angular Material: An implementation of Material Design in Angular.js +- Gulp: node-based tooling - Harp: The static web server with built-in preprocessing. - Sass: A professional grade CSS extension language - Normalize: A modern, HTML5-ready alternative to CSS resets @@ -37,4 +161,7 @@ If you are only going to work on a specific part of the docs, such as the API or ## License -Powered by Google ©2010-2016. Code licensed under an [MIT-style License](https://github.com/angular/angular.io/blob/master/LICENSE). Documentation licensed under [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/). +Powered by Google ©2010-2017. Code licensed under an [MIT-style License](https://github.com/angular.io/blob/master/LICENSE). Documentation licensed under [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/). + +[travis-badge]: https://travis-ci.org/angular/angular.io.svg?branch=master +[travis-badge-url]: https://travis-ci.org/angular/angular.io diff --git a/firebase.json b/firebase.json index 7a3251612b..4f6e69080f 100644 --- a/firebase.json +++ b/firebase.json @@ -1,59 +1,121 @@ { - "firebase": "angular-io", - "public": "www", - "rewrites": [ - { - "source": "/docs/dart/latest/testing", - "destination": "/docs/dart/latest/index.html" - }, - { - "source": "/docs/dart/latest/tutorial", - "destination": "/docs/dart/latest/index.html" - }, - { - "source": "/docs/js/latest/testing", - "destination": "/docs/js/latest/index.html" - }, - { - "source": "/docs/js/latest/tutorial", - "destination": "/docs/js/latest/index.html" - }, - { - "source": "/docs/ts/latest/guide/setup.html", - "destination": "/docs/ts/latest/index.html" - }, - { - "source": "/cheatsheet", - "destination": "/docs/ts/latest/guide/cheatsheet.html" - }, - { - "source": "/cheatsheet.json", - "destination": "/docs/ts/latest/guide/cheatsheet.json" - }, - { - "source": "/AngularCheatSheet_Letter.pdf", - "destination": "/docs/ts/latest/guide/AngularCheatSheet_Letter.pdf" - }, - { - "source": "/AngularCheatSheet_Poster.pdf", - "destination": "/docs/ts/latest/guide/AngularCheatSheet_Poster.pdf" - }, - { - "source": "/cardboard", - "destination": "/cardboard/index.html" - }, - { - "source": "/license", - "destination": "/license.txt" - }, - { - "source": "/events", - "destination": "/events.html" - } - ], - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ] + "hosting": { + "public": "www", + "redirects": [ + { + "source": "/docs/dart/latest/quickstart.html", + "destination": "https://webdev.dartlang.org/angular/quickstart?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs/dart/latest/tutorial/toh-pt5.html", + "destination": "https://webdev.dartlang.org/angular/tutorial/toh-pt5?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs/dart/latest/tutorial", + "destination": "https://webdev.dartlang.org/angular/tutorial?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs/dart/latest/tutorial/**", + "destination": "https://webdev.dartlang.org/angular/tutorial?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs/dart/latest/api", + "destination": "https://webdev.dartlang.org/angular/api?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs/dart/latest/api/**", + "destination": "https://webdev.dartlang.org/angular/api?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs/dart/latest/guide/**", + "destination": "https://webdev.dartlang.org/angular/guide?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/**/dart", + "destination": "https://webdev.dartlang.org/angular?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/**/dart/**", + "destination": "https://webdev.dartlang.org/angular?utm_campaign=dart_migration&utm_medium=redirect&utm_source=angular.io", + "type": 301 + }, + { + "source": "/docs", + "destination": "https://angular.io/docs/ts/latest/", + "type": 301 + } + ], + "rewrites": [ + { + "source": "/docs/js/latest/testing", + "destination": "/docs/js/latest/guide/testing.html" + }, + { + "source": "/docs/js/latest/tutorial", + "destination": "/docs/js/latest/index.html" + }, + { + "source": "/docs/ts/latest/cookbook/a1-a2-quick-reference.html", + "destination": "/docs/ts/latest/cookbook/ajs-quick-reference.html" + }, + { + "source": "/docs/ts/latest/guide/setup.html", + "destination": "/docs/ts/latest/index.html" + }, + { + "source": "/docs/ts/latest/testing", + "destination": "/docs/ts/latest/guide/testing.html" + }, + { + "source": "/cheatsheet", + "destination": "/docs/ts/latest/guide/cheatsheet.html" + }, + { + "source": "/cheatsheet.json", + "destination": "/docs/ts/latest/guide/cheatsheet.json" + }, + { + "source": "/AngularCheatSheet_Letter.pdf", + "destination": "/docs/ts/latest/guide/AngularCheatSheet_Letter.pdf" + }, + { + "source": "/AngularCheatSheet_Poster.pdf", + "destination": "/docs/ts/latest/guide/AngularCheatSheet_Poster.pdf" + }, + { + "source": "/cardboard", + "destination": "/cardboard/index.html" + }, + { + "source": "/license", + "destination": "/license.txt" + }, + { + "source": "/events", + "destination": "/events.html" + }, + { + "source": "/survey", + "destination": "/survey.html" + }, + { + "source": "/styleguide", + "destination": "/docs/ts/latest/guide/style-guide.html" + } + ], + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**", + "docs/dart/**" + ] + } } diff --git a/gulpfile.js b/gulpfile.js index 82162b7610..b6a3900b24 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -7,8 +7,6 @@ var _ = require('lodash'); var argv = require('yargs').argv; var env = require('gulp-env'); var Q = require("q"); -// delPromise is a 'promise' version of del -var delPromise = Q.denodeify(del); var Minimatch = require("minimatch").Minimatch; var Dgeni = require('dgeni'); var Package = require('dgeni').Package; @@ -16,6 +14,7 @@ var fsExtra = require('fs-extra'); var fs = fsExtra; var exec = require('child_process').exec; var execPromise = Q.denodeify(exec); +var execSync = require('child_process').execSync; // cross platform version of spawn that also works on windows. var xSpawn = require('cross-spawn'); var prompt = require('prompt'); @@ -23,126 +22,240 @@ var globby = require("globby"); // Ugh... replacement needed to kill processes on any OS // - because childProcess.kill does not work properly on windows var treeKill = require("tree-kill"); +var blc = require("broken-link-checker"); +var less = require('gulp-less'); +var tslint = require('gulp-tslint'); // TODO: // 1. Think about using runSequence // 2. Think about using spawn instead of exec in case of long error messages. var TOOLS_PATH = './tools'; +var ANGULAR_IO_PROJECT_PATH = path.resolve('.'); var ANGULAR_PROJECT_PATH = '../angular'; var PUBLIC_PATH = './public'; var TEMP_PATH = './_temp'; var DOCS_PATH = path.join(PUBLIC_PATH, 'docs'); var EXAMPLES_PATH = path.join(DOCS_PATH, '_examples'); -var NOT_API_DOCS_GLOB = path.join(PUBLIC_PATH, './{docs/*/latest/!(api),!(docs)}/**/*'); +var BOILERPLATE_PATH = path.join(EXAMPLES_PATH, '_boilerplate'); +var EXAMPLES_TESTING_PATH = path.join(EXAMPLES_PATH, 'testing/ts'); +var NOT_API_DOCS_GLOB = path.join(PUBLIC_PATH, './{docs/*/latest/!(api),!(docs)}/**/*.*'); var RESOURCES_PATH = path.join(PUBLIC_PATH, 'resources'); var LIVE_EXAMPLES_PATH = path.join(RESOURCES_PATH, 'live-examples'); +var STYLES_SOURCE_PATH = path.join(TOOLS_PATH, 'styles-builder/less'); var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder')); -var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper')); -var plunkerBuilder = require(path.resolve(TOOLS_PATH, 'plunker-builder/plunkerBuilder')); +var ExampleZipper = require(path.resolve(TOOLS_PATH, 'example-zipper/exampleZipper')); +var regularPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/regularPlunker')); +var embeddedPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/embeddedPlunker')); var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils')); +const WWW = argv.page ? 'www-pages' : 'www' + +const isSilent = !!argv.silent; +if (isSilent) gutil.log = gutil.noop; +const _dgeniLogLevel = argv.dgeniLog || (isSilent ? 'error' : 'info'); + var _devguideShredOptions = { examplesDir: path.join(DOCS_PATH, '_examples'), fragmentsDir: path.join(DOCS_PATH, '_fragments'), - zipDir: path.join(RESOURCES_PATH, 'zips') + zipDir: path.join(RESOURCES_PATH, 'zips'), + logLevel: _dgeniLogLevel }; var _devguideShredJadeOptions = { - jadeDir: DOCS_PATH - + jadeDir: DOCS_PATH, + logLevel: _dgeniLogLevel }; var _apiShredOptions = { - examplesDir: path.join(ANGULAR_PROJECT_PATH, 'modules/angular2/examples'), + lang: 'ts', + examplesDir: path.join(ANGULAR_PROJECT_PATH, 'packages/examples'), fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'), - zipDir: path.join(RESOURCES_PATH, 'zips/api') + zipDir: path.join(RESOURCES_PATH, 'zips/api'), + logLevel: _dgeniLogLevel }; -var _excludePatterns = ['**/node_modules/**', '**/typings/**', '**/packages/**']; +var _excludePatterns = ['**/node_modules/**']; var _excludeMatchers = _excludePatterns.map(function(excludePattern){ return new Minimatch(excludePattern) }); var _exampleBoilerplateFiles = [ - 'karma.conf.js', - 'karma-test-shim.js', - 'package.json', - 'styles.css', - 'tsconfig.json', - 'typings.json' - ]; - -var _exampleDartWebBoilerPlateFiles = ['styles.css']; - -// --filter may be passed in to filter/select _example app subdir names -// i.e. gulp run-e2e-tests --filter=foo ; would select all example apps with -// 'foo' in their folder names. -gulp.task('run-e2e-tests', function() { - var spawnInfo = spawnExt('npm', ['install'], { cwd: EXAMPLES_PATH}); - return spawnInfo.promise.then(function() { - copyExampleBoilerplate(); - var exePath = path.join(process.cwd(), "./node_modules/.bin/"); - spawnInfo = spawnExt('webdriver-manager', ['update'], {cwd: exePath}); - return spawnInfo.promise; - }).then(function() { - return findAndRunE2eTests(argv.filter); + 'src/styles.css', + 'src/systemjs.config.js', + 'src/systemjs-angular-loader.js', + 'src/tsconfig.json', + 'bs-config.json', + 'bs-config.e2e.json', + 'package.json', + 'tslint.json' +]; + +var _exampleUnitTestingBoilerplateFiles = [ + 'src/browser-test-shim.js', + 'karma-test-shim.js', + 'karma.conf.js' +]; + +var _exampleConfigFilename = 'example-config.json'; + +// Gulp flags: +// +// --lang=[all | ts | js | dart | 'ts|js' | 'ts|js|dart' | ...] +// +// This affects which language API docs and E2E tests are run. Can be 'all', +// or a regex pattern to match any one of 'ts', 'js', or 'dart'. +// Default: 'ts|js' except for the "full site build" tasks (see below), +// for which it is 'all'. + +// langs and skipLangs partition ['ts', 'js', 'dart']. +var lang, langs, skipLangs, buildDartApiDocs = false; +function configLangs(langOption) { + const fullSiteBuildTasks = ['build-compile', 'check-deploy', 'harp-compile']; + const buildAllDocs = argv['_'] && + fullSiteBuildTasks.some((task) => argv['_'].indexOf(task) >= 0); + const langDefault = /*buildAllDocs ? 'all' :*/ 'ts|js'; + if (langOption === '') { + lang = ''; + langs = []; + } else { + lang = (langOption || langDefault).toLowerCase(); + if (lang === 'all') lang = 'ts|js|dart'; + langs = lang.match(/\w+/g); // the languages in `lang` as an array + } + gutil.log(`Building docs for: [${langs}]`); + if (langs.indexOf('dart') >= 0) { + buildDartApiDocs = true; + // For Dart, be proactive about checking for the repo + checkAngularProjectPath(ngPathFor('dart')); + } else { + argv.pub = false; + } + skipLangs = []; + ['ts', 'js', 'dart'].forEach(lang => { + if (langs.indexOf(lang) < 0) skipLangs.push(lang); + }); + gutil.log(`Skipped languages: [${skipLangs}]`); +} +configLangs(argv.lang); + +function isDartPath(path) { + // Testing via indexOf() for now. If we need to match only paths with folders + // named 'dart' vs 'dart*' then try: path.match('/dart(/|$)') != null; + return path.indexOf('/dart') > -1; +} + +function excludeDartPaths(paths) { + return paths.filter(function (p) { return !isDartPath(p); }); +} + +/** + * Run Protractor End-to-End Specs for Doc Samples + * Alias for 'run-e2e-tests' + */ +gulp.task('e2e', runE2e); + +gulp.task('run-e2e-tests', runE2e); + +/** + * Run Protractor End-to-End Tests for Doc Samples + * + * Flags + * --filter to filter/select _example app subdir names + * e.g. gulp e2e --filter=foo // all example apps with 'foo' in their folder names. + * + * --fast by-passes the npm install and webdriver update + * Use it for repeated test runs (but not the FIRST run) + * e.g. gulp e2e --fast + * + * --lang to filter by code language (see above for details) + * e.g. gulp e2e --lang=ts // only TypeScript apps + */ +function runE2e() { + var promise; + if (argv.fast) { + // fast; skip all setup + promise = Promise.resolve(true); + } else { + // Not 'fast'; do full setup + gutil.log('runE2e: install _examples stuff'); + var spawnInfo = spawnExt('npm', ['install'], { cwd: EXAMPLES_PATH}); + promise = spawnInfo.promise + .then(copyExampleBoilerplate) + .then(function() { + gutil.log('runE2e: update webdriver'); + spawnInfo = spawnExt('npm', ['run', 'webdriver:update'], {cwd: EXAMPLES_PATH}); + return spawnInfo.promise; + }); + }; + + var outputFile = path.join(process.cwd(), 'protractor-results.txt'); + + promise.then(function() { + return findAndRunE2eTests(argv.filter, outputFile); }).then(function(status) { - reportStatus(status); - }).fail(function(e) { - return e; + reportStatus(status, outputFile); + if (status.failed.length > 0){ + return Promise.reject('Some test suites failed'); + } + }).catch(function(e) { + gutil.log(e); + process.exitCode = 1; }); -}); + return promise; +} // finds all of the *e2e-spec.tests under the _examples folder along // with the corresponding apps that they should run under. Then run // each app/spec collection sequentially. -function findAndRunE2eTests(filter) { - var startTime = new Date().getTime(); +function findAndRunE2eTests(filter, outputFile) { // create an output file with header. - var outputFile = path.join(process.cwd(), 'protractor-results.txt'); - var header = "Protractor example results for: " + (new Date()).toLocaleString() + "\n\n"; - if (filter) { - header += ' Filter: ' + filter.toString() + '\n\n'; - } + var startTime = new Date().getTime(); + var header = `Doc Sample Protractor Results for ${lang} on ${new Date().toLocaleString()}\n`; + header += argv.fast ? + ' Fast Mode (--fast): no npm install, webdriver update, or boilerplate copy\n' : + ' Slow Mode: npm install, webdriver update, and boilerplate copy\n'; + header += ` Filter: ${filter ? filter : 'All tests'}\n\n`; fs.writeFileSync(outputFile, header); // create an array of combos where each - // combo consists of { examplePath: ... , protractorConfigFilename: ... } - var exeConfigs = []; + // combo consists of { examplePath: ... } + var examplePaths = []; var e2eSpecPaths = getE2eSpecPaths(EXAMPLES_PATH); - var srcConfig = path.join(EXAMPLES_PATH, 'protractor.config.js'); - e2eSpecPaths.forEach(function(specPath) { - var destConfig = path.join(specPath, 'protractor.config.js'); - fsExtra.copySync(srcConfig, destConfig); + e2eSpecPaths.forEach(function(specPath) { // get all of the examples under each dir where a pcFilename is found - examplePaths = getExamplePaths(specPath, true); + localExamplePaths = getExamplePaths(specPath, true); + // Filter by example name if (filter) { - examplePaths = examplePaths.filter(function (fn) { + localExamplePaths = localExamplePaths.filter(function (fn) { return fn.match(filter) != null; }) } - examplePaths.forEach(function(exPath) { - exeConfigs.push( { examplePath: exPath, protractorConfigFilename: destConfig }); + // Filter by language, also supports variations like js-es6 + localExamplePaths = localExamplePaths.filter(function (fn) { + return fn.match('/'+lang+'(?:-[^/]*)?$') != null; + }); + localExamplePaths.forEach(function(examplePath) { + examplePaths.push(examplePath); }) }); // run the tests sequentially var status = { passed: [], failed: [] }; - return exeConfigs.reduce(function (promise, combo) { + return examplePaths.reduce(function (promise, examplePath) { return promise.then(function () { - return runE2eTests(combo.examplePath, combo.protractorConfigFilename, outputFile).then(function(ok) { + var runTests = isDartPath(examplePath) ? runE2eDartTests : runE2eTsTests; + return runTests(examplePath, outputFile).then(function(ok) { var arr = ok ? status.passed : status.failed; - arr.push(combo.examplePath); + arr.push(examplePath); }) }); }, Q.resolve()).then(function() { var stopTime = new Date().getTime(); status.elapsedTime = (stopTime - startTime)/1000; - fs.appendFileSync(outputFile, '\nElaped Time: ' + status.elapsedTime + ' seconds'); return status; }); } @@ -150,44 +263,132 @@ function findAndRunE2eTests(filter) { // start the example in appDir; then run protractor with the specified // fileName; then shut down the example. All protractor output is appended // to the outputFile. -function runE2eTests(appDir, protractorConfigFilename, outputFile ) { - // start the app - var appRunSpawnInfo = spawnExt('npm',['run','http-server', '--', '-s' ], { cwd: appDir }); - - // start protractor - var pcFilename = path.resolve(protractorConfigFilename); // need to resolve because we are going to be running from a different dir - var exePath = path.join(process.cwd(), "./node_modules/.bin/"); - var spawnInfo = spawnExt('protractor', - [ pcFilename, '--params.appDir=' + appDir, '--params.outputFile=' + outputFile], { cwd: exePath }); - return spawnInfo.promise.then(function(data) { - // kill the app now that protractor has completed. - // Ugh... proc.kill does not work properly on windows with child processes. - // appRun.proc.kill(); - treeKill(appRunSpawnInfo.proc.pid); - return true; - }).fail(function(err) { - // Ugh... proc.kill does not work properly on windows with child processes. - // appRun.proc.kill(); - treeKill(appRunSpawnInfo.proc.pid); +function runE2eTsTests(appDir, outputFile) { + // Grab protractor configuration or defaults to systemjs config. + try { + var exampleConfig = fs.readJsonSync(`${appDir}/${_exampleConfigFilename}`); + } catch (e) { + exampleConfig = {}; + } + + var config = { + build: exampleConfig.build || 'build', + run: exampleConfig.run || 'serve:e2e' + }; + + var appBuildSpawnInfo = spawnExt('npm', ['run', config.build], { cwd: appDir }); + var appRunSpawnInfo = spawnExt('npm', ['run', config.run, '--', '-s'], { cwd: appDir }); + + var run = runProtractor(appBuildSpawnInfo.promise, appDir, appRunSpawnInfo, outputFile); + + if (fs.existsSync(appDir + '/aot/index.html')) { + run = run.then(() => runProtractorAoT(appDir, outputFile)); + } + return run; +} + +function runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile) { + var specFilename = path.resolve(`${appDir}/../e2e-spec.ts`); + return prepPromise + .catch(function(){ + var emsg = `Application at ${appDir} failed to transpile.\n\n`; + gutil.log(emsg); + fs.appendFileSync(outputFile, emsg); + return Promise.reject(emsg); + }) + .then(function (data) { + var transpileError = false; + + // start protractor + + var spawnInfo = spawnExt('npm', [ 'run', 'protractor', '--', 'protractor.config.js', + `--specs=${specFilename}`, '--params.appDir=' + appDir, '--params.outputFile=' + outputFile], { cwd: EXAMPLES_PATH }); + + spawnInfo.proc.stderr.on('data', function (data) { + transpileError = transpileError || /npm ERR! Exit status 100/.test(data.toString()); + }); + return spawnInfo.promise.catch(function(err) { + if (transpileError) { + var emsg = `${specFilename} failed to transpile.\n\n`; + gutil.log(emsg); + fs.appendFileSync(outputFile, emsg); + } + return Promise.reject(emsg); + }); + }) + .then( + function() { return finish(true);}, + function() { return finish(false);} + ) + + function finish(ok){ + // Ugh... proc.kill does not work properly on windows with child processes. + // appRun.proc.kill(); + treeKill(appRunSpawnInfo.proc.pid); + return ok; + } +} + +function runProtractorAoT(appDir, outputFile) { + fs.appendFileSync(outputFile, '++ AoT version ++\n'); + var aotBuildSpawnInfo = spawnExt('npm', ['run', 'build:aot'], { cwd: appDir }); + var promise = aotBuildSpawnInfo.promise; + + var copyFileCmd = 'copy-dist-files.js'; + if (fs.existsSync(appDir + '/' + copyFileCmd)) { + promise = promise.then(() => + spawnExt('node', [copyFileCmd], { cwd: appDir }).promise ); + } + var aotRunSpawnInfo = spawnExt('npm', ['run', 'serve:aot'], { cwd: appDir }); + return runProtractor(promise, appDir, aotRunSpawnInfo, outputFile); +} + +// start the server in appDir/build/web; then run protractor with the specified +// fileName; then shut down the example. All protractor output is appended +// to the outputFile. +function runE2eDartTests(appDir, outputFile) { + // Launch http server out of ts directory because all the config files are there. + var httpLaunchDir = path.resolve(appDir, '../ts'); + var deployDir = path.resolve(appDir, 'build/web'); + gutil.log('AppDir for Dart e2e: ' + appDir); + gutil.log('Deploying from: ' + deployDir); + + var appRunSpawnInfo = spawnExt('npm', ['run', 'serve:e2e', '--', deployDir, '-s'], { cwd: httpLaunchDir }); + if (!appRunSpawnInfo.proc.pid) { + gutil.log('http-server failed to launch over ' + deployDir); return false; - }); + } + if (argv.pub === false) { + var prepPromise = Promise.resolve(true); + gutil.log('Skipping pub upgrade and pub build (--no-pub flag present)'); + } else { + var pubUpgradeSpawnInfo = spawnExt('pub', ['upgrade'], { cwd: appDir }); + var prepPromise = pubUpgradeSpawnInfo.promise.then(function (data) { + return spawnExt('pub', ['build'], { cwd: appDir }).promise; + }); + } + return runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile); } -function reportStatus(status) { - gutil.log('Suites passed:'); +function reportStatus(status, outputFile) { + var log = ['']; + log.push('Suites passed:'); status.passed.forEach(function(val) { - gutil.log(' ' + val); - }); - - gutil.log('Suites failed:'); - status.failed.forEach(function(val) { - gutil.log(' ' + val); + log.push(' ' + val); }); if (status.failed.length == 0) { - gutil.log('All tests passed'); + log.push('All tests passed'); + } else { + log.push('Suites failed:'); + status.failed.forEach(function (val) { + log.push(' ' + val); + }); } - gutil.log('Elapsed time: ' + status.elapsedTime + ' seconds'); + log.push('\nElapsed time: ' + status.elapsedTime + ' seconds'); + var log = log.join('\n'); + gutil.log(log); + fs.appendFileSync(outputFile, log); } // returns both a promise and the spawned process so that it can be killed if needed. @@ -209,9 +410,11 @@ function spawnExt(command, args, options) { proc.stderr.on('data', function (data) { gutil.log(data.toString()); }); - proc.on('close', function (data) { + proc.on('close', function (returnCode) { gutil.log('completed: ' + descr); - deferred.resolve(data); + // Many tasks (e.g., tsc) complete but are actually errors; + // Confirm return code is zero. + returnCode === 0 ? deferred.resolve(0) : deferred.reject(returnCode); }); proc.on('error', function (data) { gutil.log('completed with error:' + descr); @@ -233,51 +436,45 @@ gulp.task('help', taskListing.withFilters(function(taskName) { return shouldRemove; })); -// requires admin access +// requires admin access because it adds symlinks gulp.task('add-example-boilerplate', function() { var realPath = path.join(EXAMPLES_PATH, '/node_modules'); - var nodeModulesPaths = getNodeModulesPaths(EXAMPLES_PATH); + var nodeModulesPaths = excludeDartPaths(getNodeModulesPaths(EXAMPLES_PATH)); nodeModulesPaths.forEach(function(linkPath) { gutil.log("symlinking " + linkPath + ' -> ' + realPath) fsUtils.addSymlink(realPath, linkPath); }); - - realPath = path.join(EXAMPLES_PATH, '/typings'); - var typingsPaths = getTypingsPaths(EXAMPLES_PATH); - typingsPaths.forEach(function(linkPath) { - gutil.log("symlinking " + linkPath + ' -> ' + realPath) - fsUtils.addSymlink(realPath, linkPath); - }); - + return copyExampleBoilerplate(); }); + +// copies boilerplate files to locations +// where an example app is found +gulp.task('_copy-example-boilerplate', function (done) { + return argv.fast ? done() : copyExampleBoilerplate(); +}); + // copies boilerplate files to locations // where an example app is found // also copies certain web files (e.g., styles.css) to ~/_examples/**/dart/**/web -// also copies protractor.config.js file function copyExampleBoilerplate() { - var sourceFiles = _exampleBoilerplateFiles.map(function(fn) { - return path.join(EXAMPLES_PATH, fn); - }); - var examplePaths = getExamplePaths(EXAMPLES_PATH); - - var dartWebSourceFiles = _exampleDartWebBoilerPlateFiles.map(function(fn){ - return path.join(EXAMPLES_PATH, fn); - }); - var dartExampleWebPaths = getDartExampleWebPaths(EXAMPLES_PATH); + gutil.log('Copying example boilerplate files'); + var examplePaths = excludeDartPaths(getExamplePaths(EXAMPLES_PATH)); - return copyFiles(sourceFiles, examplePaths) + // Make boilerplate files read-only to avoid that they be edited by mistake. + var destFileMode = '444'; + return copyFiles(_exampleBoilerplateFiles, BOILERPLATE_PATH, examplePaths, destFileMode) + // copy the unit test boilerplate .then(function() { - return copyFiles(dartWebSourceFiles, dartExampleWebPaths); + var unittestPaths = getUnitTestingPaths(EXAMPLES_PATH); + return copyFiles(_exampleUnitTestingBoilerplateFiles, + EXAMPLES_TESTING_PATH, unittestPaths, destFileMode); }) - // copy protractor.config.js from _examples dir to each subdir that - // contains a e2e-spec file. - .then(function() { - var sourceFiles = [ path.join(EXAMPLES_PATH, 'protractor.config.js') ]; - var e2eSpecPaths = getE2eSpecPaths(EXAMPLES_PATH); - return copyFiles(sourceFiles, e2eSpecPaths); + .catch(function(err) { + gutil.log(err); + throw err; }); } @@ -286,24 +483,77 @@ gulp.task('remove-example-boilerplate', function() { nodeModulesPaths.forEach(function(linkPath) { fsUtils.removeSymlink(linkPath); }); - - var typingsPaths = getTypingsPaths(EXAMPLES_PATH); - typingsPaths.forEach(function(linkPath) { - fsUtils.removeSymlink(linkPath); - }); - + + deleteExampleBoilerPlate(); +}); + +// Npm install Angular libraries into examples/node_modules, +// either release or current build packages +// Examples: +// gulp install-example-angular --build // use current build packages +// gulp install-example-angular --build=2.0.0-b43f954 // use tagged packages +// gulp install-example-angular // restore release packages +// +// Find the tags here: https://github.com/angular/core-builds/releases +gulp.task('install-example-angular', installExampleAngular); + +function installExampleAngular() { + var sources; + var template; + var libs = [ + 'core', 'common', 'compiler', 'compiler-cli', + 'platform-browser', 'platform-browser-dynamic', 'platform-server', + 'forms', 'http', 'router', 'upgrade']; + + var build = argv.build; + if (build) { + if (typeof build === 'string') { + build = (build[0]==='#' ? '' : '#') + build; + } else { + build = ''; + } + } else{ + build = 'npm'; + } + // Like: "angular/core-builds" or "@angular/core" + sources = libs.map( lib => { + return build === 'npm' + ? `@angular/${lib}` + : `git+https://github.com/angular/${lib}-builds${build}`; + }); + + if (argv.build) { + sources.push('@angular/tsc-wrapped'); // tsc-wrapped needed for builds + sources.push('typescript@2.2.1'); // recent builds need recent TypeScript + } + + sources.push('@angular/router-deprecated'); + + gutil.log(`Installing Angular packages from ${build === 'npm' ? 'NPM' : 'BUILD ' + build}`); + + var spawnInfo = spawnExt('node', ['node_modules/rimraf/bin.js', 'node_modules/@angular'], { cwd: EXAMPLES_PATH}); + return spawnInfo.promise + .then(() => { + spawnInfo = spawnExt('npm', ['install', ...sources], {cwd: EXAMPLES_PATH}); + return spawnInfo.promise + }); +} + +// deletes boilerplate files that were added by copyExampleBoilerplate +// from locations where an example app is found +gulp.task('_delete-example-boilerplate', deleteExampleBoilerPlate); + +function deleteExampleBoilerPlate() { + gutil.log('Deleting example boilerplate files'); var examplePaths = getExamplePaths(EXAMPLES_PATH); var dartExampleWebPaths = getDartExampleWebPaths(EXAMPLES_PATH); - + var unittestPaths = getUnitTestingPaths(EXAMPLES_PATH); + return deleteFiles(_exampleBoilerplateFiles, examplePaths) .then(function() { - return deleteFiles(_exampleDartWebBoilerPlateFiles, dartExampleWebPaths); - }) - .then(function() { - var e2eSpecPaths = getE2eSpecPaths(EXAMPLES_PATH); - return deleteFiles(['protractor.config.js'], e2eSpecPaths); - }) -}); + return deleteFiles(_exampleUnitTestingBoilerplateFiles, unittestPaths); + }); +} gulp.task('serve-and-sync', ['build-docs'], function (cb) { // watchAndSync({devGuide: true, apiDocs: true, apiExamples: true, localFiles: true}, cb); @@ -326,11 +576,9 @@ gulp.task('build-and-serve', ['build-docs'], function (cb) { watchAndSync({localFiles: true}, cb); }); -gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers']); -// Stop zipping examples Feb 28, 2016 -//gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']); +gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']); -gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs', 'build-dart-cheatsheet']); +gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs']); gulp.task('build-devguide-docs', ['_shred-devguide-examples', '_shred-devguide-shared-jade'], function() { return buildShredMaps(true); @@ -344,15 +592,10 @@ gulp.task('build-js-api-docs', ['_shred-api-examples'], function() { return buildApiDocs('js'); }); -gulp.task('build-plunkers', function() { - return copyExampleBoilerplate() - .then(function() { - return plunkerBuilder.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log }); - }); -}); - -gulp.task('build-dart-cheatsheet', [], function() { - return buildApiDocs('dart'); +// Using the --build flag will use systemjs.config.web.build.js (for preview builds) +gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() { + regularPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build }); + return embeddedPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build, targetSelf: argv.targetSelf }); }); gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){ @@ -401,10 +644,33 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){ }); }); -gulp.task('check-deploy', ['build-docs'], function() { +gulp.task('harp-compile', () => { + return harpCompile() +}); + +gulp.task('harp-serve', () => { + // Harp will watch and serve workspace files. + const cmd = 'npm run harp -- server .'; + gutil.log('Launching harp server (over project files)'); + gutil.log(` > ${cmd}`); + gutil.log('Note: issuing this command directly from the command line will show harp comiple warnings.'); + return execPromise(cmd); +}); + +gulp.task('serve-www', () => { + // Serve generated site. + return execPromise(`npm run live-server ${WWW}`); +}); + +gulp.task('build-compile', ['build-docs'], function() { + return harpCompile(); +}); + +gulp.task('check-deploy', ['firebase-use-proj-check', 'build-docs'], () => { return harpCompile().then(function() { - gutil.log('compile ok - running live server ...'); - execPromise('npm run live-server ./www'); + gutil.log('compile ok'); + gutil.log('running live server ...'); + execPromise(`npm run live-server ${WWW}`); return askDeploy(); }).then(function(shouldDeploy) { if (shouldDeploy) { @@ -420,10 +686,41 @@ gulp.task('check-deploy', ['build-docs'], function() { }); }); +gulp.task('firebase-use-proj-check', cb => { + try { + execSync('firebase use'); + } catch (e) { + // Rerun command so user gets project + alias info + execSync('firebase use', {stdio:[0,1,2]}); + throw `\nAborting: no firebase project selected. Run:\n\n firebase use \n\n`; + } + return cb(); +}); + gulp.task('test-api-builder', function (cb) { execCommands(['npm run test-api-builder'], {}, cb); }); +// Usage: +// angular.io: gulp link-checker +// local site: gulp link-checker --url=http://localhost:3000 +gulp.task('link-checker', function(done) { + var method = 'get'; // the default 'head' fails for some sites + var exclude = [ + // Dart API docs aren't working yet; ignore them + '*/dart/latest/api/*', + // Somehow the link checker sees ng1 {{...}} in the resource page; ignore it + 'resources/%7B%7Bresource.url%7D%7D', + // API docs have links directly into GitHub repo sources; these can + // quickly become invalid, so ignore them for now: + '*/angular/tree/*', + // harp.json "bios" for "Ryan Schmukler", URL isn't valid: + 'http://slingingcode.com' + ]; + var blcOptions = { requestMethod: method, excludedKeywords: exclude}; + return linkChecker({ blcOptions: blcOptions }); +}); + // Internal tasks gulp.task('set-prod-env', function () { @@ -444,12 +741,19 @@ gulp.task('_harp-compile', function() { }); }); -gulp.task('_shred-devguide-examples', ['_shred-clean-devguide'], function() { - return docShredder.shred( _devguideShredOptions); +gulp.task('_shred-devguide-examples', ['_shred-clean-devguide', '_copy-example-boilerplate'], function() { + // Split big shredding task into partials 2016-06-14 + const exPath = path.join(EXAMPLES_PATH, (argv.filter || '') + '*'); + var examplePaths = globby.sync(exPath, {ignore: ['**/node_modules', '**/_boilerplate']}); + var promise = Promise.resolve(true); + examplePaths.forEach(function (examplePath) { + promise = promise.then(() => docShredder.shredSingleExampleDir(_devguideShredOptions, examplePath)); + }); + return promise; }); -gulp.task('_shred-devguide-shared-jade', ['_shred-clean-devguide-shared-jade'], function() { - return docShredder.shred( _devguideShredJadeOptions); +gulp.task('_shred-devguide-shared-jade', ['_shred-clean-devguide-shared-jade', '_copy-example-boilerplate'], function() { + return docShredder.shred(_devguideShredJadeOptions); }); gulp.task('_shred-clean-devguide-shared-jade', function(cb) { @@ -458,29 +762,57 @@ gulp.task('_shred-clean-devguide-shared-jade', function(cb) { // jade fragments now all go into _fragments subdirs under their source. var newCleanPath = path.join(DOCS_PATH, '**/_fragments/*.jade'); // Much slower 8-9x then using globby first ... ??? - // return delPromise([ newCleanPath, oldCleanPath]); + // return del([ newCleanPath, oldCleanPath]); var files = globby.sync( [newCleanPath, oldCleanPath]); - return delPromise(files); + return del(files); }); gulp.task('_shred-clean-devguide', function(cb) { - var cleanPath = path.join(_devguideShredOptions.fragmentsDir, '**/*.*') - return delPromise([ cleanPath, '!**/*.ovr.*', '!**/_api/**']); + var cleanPath = path.join(_devguideShredOptions.fragmentsDir, (argv.filter || '*') + '*/*.*') + return del([ cleanPath, '!**/*.ovr.*', '!**/_api/**']); }); gulp.task('_shred-api-examples', ['_shred-clean-api'], function() { - checkAngularProjectPath(); - return docShredder.shred( _apiShredOptions); + const promises = []; + gutil.log('Shredding API examples for languages: ' + langs.join(', ')); + langs.forEach(lang => { + if (lang === 'js') return; // JS is handled via TS. + checkAngularProjectPath(ngPathFor(lang)); + promises.push(docShredder.shred(_apiShredOptions)); + }); + return Q.all(promises); }); gulp.task('_shred-clean-api', function(cb) { var cleanPath = path.join(_apiShredOptions.fragmentsDir, '**/*.*') - return delPromise([ cleanPath, '!**/*.ovr.*' ]); + return del([ cleanPath, '!**/*.ovr.*' ]); }); gulp.task('_zip-examples', function() { - exampleZipper.zipExamples(_devguideShredOptions.examplesDir, _devguideShredOptions.zipDir); - exampleZipper.zipExamples(_apiShredOptions.examplesDir, _apiShredOptions.zipDir); + new ExampleZipper(_devguideShredOptions.examplesDir, _devguideShredOptions.zipDir); + // exampleZipper.zipExamples(_apiShredOptions.examplesDir, _apiShredOptions.zipDir); +}); + + +// Linting + +gulp.task('lint', function() { + return gulp.src([ + './public/docs/_examples/**/*.ts', + '!./public/docs/_examples/**/ts-snippets/*.ts', + '!./public/docs/_examples/style-guide/ts/**/*.avoid.ts', + '!./public/docs/_examples/**/node_modules/**/*', + '!./public/docs/_examples/**/build/**/*', + // temporary until codelyzer is fixed mgechev/codelyzer#60 + '!./public/docs/_examples/animations/ts/app/hero.service.ts' + ]) + .pipe(tslint({ + rulesDirectory: ['node_modules/codelyzer'], + configuration: require('./tslint.json') + })) + .pipe(tslint.report('prose', { + summarizeFailureOutput: true + })); }); @@ -489,31 +821,123 @@ gulp.task('_zip-examples', function() { function harpCompile() { // Supposedly running in production makes harp faster // and less likely to drown in node_modules. - env({ - vars: { NODE_ENV: "production" } - }); + env({ vars: { NODE_ENV: "production" } }); gutil.log("NODE_ENV: " + process.env.NODE_ENV); - + + if(argv.page) harpJsonSetJade2NgTo(true); + + if(skipLangs && fs.existsSync(WWW) && backupApiHtmlFilesExist(WWW)) { + gutil.log(`Harp site recompile: skipping recompilation of API docs for [${skipLangs}]`); + gutil.log(`API docs will be copied from existing ${WWW} folder (if they exist).`) + del.sync(`${WWW}-backup`); // remove existing backup if it exists + renameIfExistsSync(WWW, `${WWW}-backup`); + } else { + gutil.log(`Harp full site compile, including API docs for all languages.`); + if (skipLangs) + gutil.log(`Ignoring API docs skip set (${skipLangs}) because full ` + + `site has not been built yet or some API HTML files are missing.`); + } + var deferred = Q.defer(); gutil.log('running harp compile...'); showHideExampleNodeModules('hide'); - var spawnInfo = spawnExt('npm',['run','harp', '--', 'compile', '.', './www' ]); + showHideApiDir('hide'); + var spawnInfo = spawnExt('npm',['run','harp', '--', 'compile', '.', WWW ]); spawnInfo.promise.then(function(x) { gutil.log("NODE_ENV: " + process.env.NODE_ENV); showHideExampleNodeModules('show'); + showHideApiDir('show'); + harpJsonSetJade2NgTo(false); if (x !== 0) { deferred.reject(x) } else { + restoreApiHtml(); deferred.resolve(x); } }).catch(function(e) { gutil.log("NODE_ENV: " + process.env.NODE_ENV); showHideExampleNodeModules('show'); + showHideApiDir('show'); + harpJsonSetJade2NgTo(false); deferred.reject(e); }); return deferred.promise; } +function linkChecker(options) { + var deferred = Q.defer(); + var options = options || {}; + + var blcOptions = options.blcOptions || {}; + var customData = options.customData || {}; + + // don't bother reporting bad links matching this RegExp + var excludeBad = argv.excludeBad ? new RegExp(argv.excludeBad) : (options.excludeBad || ''); + + var previousPage; + var siteUrl = argv.url || options.url || 'https://angular.io/'; + + // See https://github.com/stevenvachon/broken-link-checker#blcsitecheckeroptions-handlers + var handlers = { + robots: function(robots, customData){}, + html: function(tree, robots, response, pageUrl, customData){ + // gutil.log('Scanning ' + pageUrl); + }, + junk: function(result, customData){}, + + // Analyze links + link: function(result, customData){ + if (!result.broken) { return; } + if (excludeBad && excludeBad.test(result.url.resolved)) { return; } + + var currentPage = result.base.resolved + if (previousPage !== currentPage) { + previousPage = currentPage; + fs.appendFileSync(outputFile, '\n' + currentPage); + gutil.log('broken: ' + currentPage); + } + var msg = '\n [' + result.html.location.line + ', ' + result.brokenReason + '] ' + result.url.resolved; + fs.appendFileSync(outputFile, msg); + // gutil.log(msg); + // gutil.log(result); + }, + + page: function(error, pageUrl, customData){}, + site: function(error, siteUrl, customData){}, + + end: function(){ + var stopTime = new Date().getTime(); + var elapsed = 'Elapsed link-checking time: ' + ((stopTime - startTime)/1000) + ' seconds'; + gutil.log(elapsed); + fs.appendFileSync(outputFile, '\n'+elapsed); + gutil.log('Output in file: ' + outputFile); + deferred.resolve(true); + } + }; + + // create an output file with header. + var outputFile = path.join(process.cwd(), 'link-checker-results.txt'); + var header = 'Link checker results for: ' + siteUrl + + '\nStarted: ' + (new Date()).toLocaleString() + + '\nExcluded links (blc file globs): ' + blcOptions.excludedKeywords + + '\nExcluded links (custom --exclude-bad regex): ' + excludeBad.toString() + '\n\n'; + gutil.log(header); + fs.writeFileSync(outputFile, header); + + var siteChecker = new blc.SiteChecker(blcOptions, handlers); + var startTime = new Date().getTime(); + + try { + gutil.log('link checker started'); + siteChecker.enqueue(siteUrl, customData); + } catch (err) { + gutil.log('link checker died'); + console.error('link checker died', err); + deferred.reject(err); + } + return deferred.promise; +} + // harp has issues with node_modules under the public dir // but we need them there for example testing and development // this method allows the node modules folder under '_examples' @@ -533,16 +957,79 @@ function showHideExampleNodeModules(showOrHide) { } } +// Show/hide the API docs harp source folder for every lang in skipLangs. +function showHideApiDir(showOrHide) { + skipLangs.forEach(lang => { + _showHideApiDir(lang, showOrHide); + }); +} + +// Rename the API docs harp source folder for lang to/from 'api' to '_api-tmp-foo'. +function _showHideApiDir(lang, showOrHide) { + const vers = 'latest'; + const basePath = path.join(DOCS_PATH, lang, vers); + const apiDirPath = path.join(basePath, 'api'); + const disabledApiDirPath = path.join(basePath, '_api-tmp-hide-from-jade'); + const args = showOrHide == 'hide' + ? [apiDirPath, disabledApiDirPath] + : [disabledApiDirPath, apiDirPath]; + renameIfExistsSync(...args); +} + +// For each lang in skipLangs, copy the API dir from ${WWW}-backup to WWW. +function restoreApiHtml() { + const vers = 'latest'; + skipLangs.forEach(lang => { + const relApiDir = path.join('docs', lang, vers, 'api'); + const apiSubdir = path.join(WWW, relApiDir); + const backupApiSubdir = path.join(`${WWW}-backup`, relApiDir); + if (fs.existsSync(backupApiSubdir)) { + gutil.log(`cp ${backupApiSubdir} ${apiSubdir}`) + fs.copySync(backupApiSubdir, apiSubdir); + } + }); +} + +// For each lang in skipLangs, ensure API dir exists in folderName +function backupApiHtmlFilesExist(folderName) { + const vers = 'latest'; + var result = 1; + skipLangs.forEach(lang => { + if (lang === 'dart') return true; + const relApiDir = path.join('docs', lang, vers, 'api'); + const backupApiSubdir = path.join(folderName, relApiDir); + if (!fs.existsSync(backupApiSubdir)) { + gutil.log(`WARNING: API docs HTML folder doesn't exist: ${backupApiSubdir}`); + result = 0; + } + }); + return result; +} + +function harpJsonSetJade2NgTo(v) { + const harpJsonPath = path.join(ANGULAR_IO_PROJECT_PATH, 'harp.json'); + execSync(`perl -pi -e 's/("jade2ng": *)\\w+/$1${v}/' ${harpJsonPath}`); + const harpJson = require(harpJsonPath); + gutil.log(`jade2ng: ${harpJson.globals.jade2ng}`); +} +// Copies fileNames into destPaths, setting the mode of the +// files at the destination as optional_destFileMode if given. // returns a promise -function copyFiles(fileNames, destPaths) { +function copyFiles(fileNames, originPath, destPaths, optional_destFileMode) { var copy = Q.denodeify(fsExtra.copy); + var chmod = Q.denodeify(fsExtra.chmod); var copyPromises = []; destPaths.forEach(function(destPath) { fileNames.forEach(function(fileName) { - var baseName = path.basename(fileName); - var destName = path.join(destPath, baseName); - var p = copy(fileName, destName, { clobber: true}); + var originName = path.join(originPath, fileName); + var destName = path.join(destPath, fileName); + var p = copy(originName, destName, { clobber: true}); + if(optional_destFileMode !== undefined) { + p = p.then(function () { + return chmod(destName, optional_destFileMode); + }); + } copyPromises.push(p); }); }); @@ -565,7 +1052,7 @@ function deleteFiles(baseFileNames, destPaths) { // TODO: filter out all paths that are subdirs of another // path in the result. function getE2eSpecPaths(basePath) { - var paths = getPaths(basePath, '*e2e-spec.js', true); + var paths = getPaths(basePath, '*e2e-spec.+(js|ts)', true); return _.uniq(paths); } @@ -576,16 +1063,9 @@ function getNodeModulesPaths(basePath) { return paths; } -function getTypingsPaths(basePath) { - var paths = getExamplePaths(basePath).map(function(examplePath) { - return path.join(examplePath, "/typings"); - }); - return paths; -} - function getExamplePaths(basePath, includeBase) { // includeBase defaults to false - return getPaths(basePath, "example-config.json", includeBase) + return getPaths(basePath, _exampleConfigFilename, includeBase); } function getDartExampleWebPaths(basePath) { @@ -593,6 +1073,14 @@ function getDartExampleWebPaths(basePath) { return paths; } +function getUnitTestingPaths(basePath) { + var examples = getPaths(basePath, _exampleConfigFilename, true); + return examples.filter((example) => { + var exampleConfig = fs.readJsonSync(`${example}/${_exampleConfigFilename}`, {throws: false}); + return exampleConfig && !!exampleConfig.unittesting; + }); +} + function getPaths(basePath, filename, includeBase) { var filenames = getFilenames(basePath, filename, includeBase); var paths = filenames.map(function(fileName) { @@ -608,6 +1096,8 @@ function getFilenames(basePath, filename, includeBase) { // ignore (skip) the top level version. includePatterns.push("!" + path.join(basePath, "/" + filename)); } + // ignore (skip) the files in BOILERPLATE_PATH. + includePatterns.push("!" + path.join(BOILERPLATE_PATH, "/" + filename)); var nmPattern = path.join(basePath, "**/node_modules/**"); var filenames = globby.sync(includePatterns, {ignore: [nmPattern]}); return filenames; @@ -619,17 +1109,22 @@ function watchAndSync(options, cb) { env({ vars: { NODE_ENV: "production" } }); - + execCommands(['npm run harp -- server .'], {}, cb); var browserSync = require('browser-sync').create(); browserSync.init({proxy: 'localhost:9000'}); + // When using the --focus=name flag, only **/name/**/*.* example files and + // **/name.jade files are watched. This is useful for performance reasons. + // Example: gulp serve-and-sync --focus=architecture + var focus = argv.focus; + if (options.devGuide) { - devGuideExamplesWatch(_devguideShredOptions, browserSync.reload); + devGuideExamplesWatch(_devguideShredOptions, browserSync.reload, focus); } if (options.devGuideJade) { - devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload); + devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload, focus); } if (options.apiDocs) { apiSourceWatch(browserSync.reload); @@ -644,11 +1139,12 @@ function watchAndSync(options, cb) { // returns a promise; function askDeploy() { - + // Show user what the currently active firebase project is: + execSync('firebase use', {stdio:[0,1,2]}); prompt.start(); var schema = { name: 'shouldDeploy', - description: 'Deploy to Firebase? (y/n): ', + description: `Deploy ${WWW} to firebase? (y/n)`, type: 'string', pattern: /Y|N|y|n/, message: "Respond with either a 'y' or 'n'", @@ -670,7 +1166,7 @@ function filterOutExcludedPatterns(fileNames, excludeMatchers) { } function apiSourceWatch(postBuildAction) { - var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/angular2/src/**/*.*')]; + var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/**/*.*')]; gulp.watch(srcPattern, {readDelay: 500}, function (event, done) { gutil.log('API source changed'); gutil.log('Event type: ' + event.event); // added, changed, or deleted @@ -681,7 +1177,7 @@ function apiSourceWatch(postBuildAction) { } function apiExamplesWatch(postShredAction) { - var examplesPath = path.join(ANGULAR_PROJECT_PATH, 'modules/angular2/examples/**'); + var examplesPath = path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/examples/**'); var includePattern = path.join(examplesPath, '**/*.*'); var excludePattern = '!' + path.join(examplesPath, '**/node_modules/**/*.*'); var cleanPath = [path.join(_apiShredOptions.fragmentsDir, '**/*.*'), '!**/*.ovr.*']; @@ -691,18 +1187,22 @@ function apiExamplesWatch(postShredAction) { gutil.log('Event type: ' + event.type); // added, changed, or deleted gutil.log('Event path: ' + event.path); // The path of the modified file - return delPromise(cleanPath).then(function() { + return del(cleanPath).then(function() { return docShredder.shred(_apiShredOptions); }).then(postShredAction); }); } -function devGuideExamplesWatch(shredOptions, postShredAction) { - var includePattern = path.join(shredOptions.examplesDir, '**/*.*'); - // removed this version because gulp.watch has the same glob issue that dgeni has. +function devGuideExamplesWatch(shredOptions, postShredAction, focus) { + var watchPattern = focus ? '{' + focus + ',cb-' + focus+ '}/**/*.*' : '**/*.*'; + var includePattern = path.join(shredOptions.examplesDir, watchPattern); + // removed this version because gulp.watch has the same glob issue that dgeni has. // var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*'); // gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) { - var files = globby.sync( [includePattern], { ignore: [ '**/node_modules/**', '**/_fragments/**']}); + var ignoreThese = [ '**/node_modules/**', '**/_fragments/**', '**/dist/**', + '**/dart/.pub/**', '**/dart/build/**']; + ignoreThese = ignoreThese.concat(_exampleBoilerplateFiles.map((file) => `public/docs/_examples/*/*/${file}`)); + var files = globby.sync( [includePattern], { ignore: ignoreThese }); gulp.watch([files], {readDelay: 500}, function (event, done) { gutil.log('Dev Guide example changed') gutil.log('Event type: ' + event.type); // added, changed, or deleted @@ -711,12 +1211,14 @@ function devGuideExamplesWatch(shredOptions, postShredAction) { }); } -function devGuideSharedJadeWatch(shredOptions, postShredAction) { - var includePattern = path.join(DOCS_PATH, '**/*.jade'); +function devGuideSharedJadeWatch(shredOptions, postShredAction, focus) { + var watchPattern = focus ? '**/' + focus + '.jade' : '**/*.jade'; + var includePattern = path.join(DOCS_PATH, watchPattern); // removed this version because gulp.watch has the same glob issue that dgeni has. // var excludePattern = '!' + path.join(shredOptions.jadeDir, '**/node_modules/**/*.*'); // gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) { - var files = globby.sync( [includePattern], { ignore: [ '**/node_modules/**', '**/_fragments/**']}); + var ignoreThese = [ '**/node_modules/**', '**/_examples/**', '**/_fragments/**', '**/latest/api/**' ]; + var files = globby.sync( [includePattern], { ignore: ignoreThese}); gulp.watch([files], {readDelay: 500}, function (event, done) { gutil.log('Dev Guide jade file changed') gutil.log('Event type: ' + event.type); // added, changed, or deleted @@ -734,7 +1236,8 @@ function buildApiDocs(targetLanguage) { try { // Build a specialized package to generate different versions of the API docs var package = new Package('apiDocs', [require(path.resolve(TOOLS_PATH, 'api-builder/angular.io-package'))]); - package.config(function(targetEnvironments, writeFilesProcessor, readTypeScriptModules) { + package.config(function(log, targetEnvironments, writeFilesProcessor, readTypeScriptModules, linkDocsInlineTagDef) { + log.level = _dgeniLogLevel; ALLOWED_LANGUAGES.forEach(function(target) { targetEnvironments.addAllowed(target); }); if (targetLanguage) { targetEnvironments.activate(targetLanguage); @@ -743,23 +1246,19 @@ function buildApiDocs(targetLanguage) { // Don't read TypeScript modules if we are not generating API docs - Dart I am looking at you! readTypeScriptModules.$enabled = false; } - writeFilesProcessor.outputFolder = targetLanguage + '/latest/api'; + linkDocsInlineTagDef.lang = targetLanguage; + linkDocsInlineTagDef.vers = 'latest'; + writeFilesProcessor.outputFolder = path.join(targetLanguage, linkDocsInlineTagDef.vers, 'api'); } }); var dgeni = new Dgeni([package]); return dgeni.generate(); } catch(err) { - gutil.log(err); - gutil.log(err.stack); + console.error(err); + console.error(err.stack); throw err; } - - function copyApiDocsToJsFolder() { - // Make a copy of the JS API docs to the TS folder - return gulp.src([path.join(DOCS_PATH, 'ts/latest/api/**/*.*'), '!' + path.join(DOCS_PATH, 'ts/latest/api/index.jade')]) - .pipe(gulp.dest('./public/docs/js/latest/api')); - } } function buildShredMaps(shouldWrite) { @@ -769,7 +1268,8 @@ function buildShredMaps(shouldWrite) { fragmentsDir: _devguideShredOptions.fragmentsDir, jadeDir: './public/docs', outputDir: './public/docs', - writeFilesEnabled: shouldWrite + writeFilesEnabled: shouldWrite, + logLevel: _dgeniLogLevel }; return docShredder.buildShredMap(options).then(function(docs) { return docs; @@ -831,7 +1331,7 @@ function getChangedExamplesForCommit(commit, relativePath) { return commit.getDiff().then(function(diffList) { var filePaths = []; diffList.forEach(function (diff) { - diff.patches().forEach(function (patch) { + diff.patches().then(function (patch) { if (patch.isAdded() || patch.isModified) { var filePath = path.normalize(patch.newFile().path()); var isExample = filePath.indexOf(relativePath) >= 0; @@ -907,7 +1407,7 @@ function execCommands(cmds, options, cb) { if (!cmds || cmds.length == 0) cb(null, null, null); var exec = require('child_process').exec; // just to make it more portable. gutil.log("NODE_ENV: " + process.env.NODE_ENV); - + exec(cmds[0], options, function(err, stdout, stderr) { if (err == null) { if (options.shouldLog) { @@ -932,9 +1432,21 @@ function execCommands(cmds, options, cb) { }); } -function checkAngularProjectPath() { - if (!fs.existsSync(ANGULAR_PROJECT_PATH)) { - throw new Error('API related tasks require the angular2 repo to be at ' + path.resolve(ANGULAR_PROJECT_PATH)); - } +function ngPathFor(lang) { + return ANGULAR_PROJECT_PATH + (lang === 'dart' ? '-dart' : ''); } +function checkAngularProjectPath(_ngPath) { + var ngPath = path.resolve(_ngPath || ngPathFor('ts')); + if (fs.existsSync(ngPath)) return; + throw new Error('API related tasks require the angular2 repo to be at ' + ngPath); +} + +function renameIfExistsSync(oldPath, newPath) { + if (fs.existsSync(oldPath)) { + gutil.log(`Rename: mv ${oldPath} ${newPath}`); + fs.renameSync(oldPath, newPath); + } else { + gutil.log(`renameIfExistsSync cannot rename, path not found: ${oldPath}`); + } +} diff --git a/harp.json b/harp.json index 6d8f1f1aa1..82e5ca762f 100644 --- a/harp.json +++ b/harp.json @@ -4,9 +4,7 @@ "description": "Angular is a development platform for building mobile and desktop web applications", "keywords": "Angular, AngularJS, AngularDart, Javscript, Dart, Framework, JavaScript MVC, Google", "siteURL": "http://angular.io", - "jsLatest": "2.0.0-beta.02", - "dartLatest": "2.0.0-beta.02", - + "jade2ng": false, "bios": { "misko": { "name": "Miško Hevery", @@ -31,7 +29,7 @@ "picture": "/resources/images/bios/naomi.jpg", "twitter": "naomitraveller", "website": "http://google.com/+NaomiBlack", - "bio": "Naomi is Angular's TPM generalist and jack-of-all-trades. She leads Angular Material and AngularDart, and acts as webmaster for angular.io. She's been at Google since 2006, as a technical program manager on projects ranging from Accessibility to Google Transit. She fights daleks in her spare time.", + "bio": "Naomi is Angular's TPM generalist and jack-of-all-trades. She supports Angular's internal Google users and solves hard-to-define problems. She's been at Google since 2006, as a technical program manager on projects ranging from Accessibility to Google Transit. She fights daleks in her spare time.", "type": "Lead" }, @@ -40,14 +38,25 @@ "picture": "/resources/images/bios/brad-green.jpg", "twitter": "bradlygreen", "website": "https://plus.google.com/+BradGreen", - "bio": "Brad Green works at Google as an engineering director. Brad manages the Google Sales Platform suite of projects as well as the AngularJS framework. Prior to Google, Brad worked on the early mobile web at AvantGo, founded and sold startups, and spent a few hard years toiling as a caterer. Brad's first job out of school was as lackey to Steve Jobs at NeXT Computer writing demo software and designing his slide presentations. Brad lives in Mountain View, CA with his wife and two children.", + "bio": "Brad Green works at Google as an engineering director. Brad manages the Google Sales Platform suite of projects as well as the AngularJS framework. Prior to Google, Brad worked on the early mobile web at AvantGo, founded and sold startups, and spent a few hard years toiling as a caterer. Brad's first job out of school was as lackey to Steve Jobs at NeXT Computer writing demo software and designing his slide presentations. Brad enjoys throwing dinner parties with his wife Heather and putting on plays with his children.", "type": "Lead" }, "juleskremer": { "name": "Jules Kremer", "picture": "/resources/images/bios/juleskremer.jpg", - "bio": "Jules is a TPM on the Angular team. When not working with developers, Jules is often bending into pretzel-like shapes, climbing mountains or drinking really awesome beer.", + "twitter": "jules_kremer", + "website": "https://plus.google.com/+JulesKremer", + "bio": "Jules is Head of Angular Developer Relations at Google. When not working with developers, Jules is often bending into pretzel-like shapes, climbing mountains or drinking really awesome beer.", + "type": "Lead" + }, + + "jelbourn": { + "name": "Jeremy Elbourn", + "picture": "/resources/images/bios/jelbourn.jpg", + "twitter": "jelbourn", + "website": "https://plus.google.com/+JeremyElbourn/", + "bio": "Angular Material Team Lead. FE Engineer @ Google specializing in AngularJS, component design, and the cleanest of code.", "type": "Lead" }, @@ -56,7 +65,7 @@ "picture": "/resources/images/bios/pete.jpg", "twitter": "petebd", "website": "http://www.bacondarwin.com", - "bio": "Angular 1 for JS Team Lead. Pete has been working on the core team since 2012 and became the team lead for the Angular 1 for JS branch in November 2014. He has co-authored a book on AngularJS and regularly talks about and teaches Angular.", + "bio": "AngularJS for JS Team Lead. Pete has been working on the core team since 2012 and became the team lead for the AngularJS for JS branch in November 2014. He has co-authored a book on AngularJS and regularly talks about and teaches Angular.", "type": "Lead" }, @@ -65,32 +74,39 @@ "picture": "/resources/images/bios/thomas.jpg", "twitter": "ThomasBurleson", "website": "http://www.solutionOptimist.com", - "bio": "Thomas is a software architect for commercial & open-source web solutions. With over 15 years working on thin-client RUX [using Flex and Angular], Thomas is passionate about software excellence, and distributed team-development. Thomas is the Team Lead for Google's Angular Material OSS. His mission is to work with a fantastic team and help deliver a framework of UX components for the AngularJS frameworks (v1.x and v2). He previously worked at SiriusXM as a UX and Principal Architect for their Internet Radio applications.", + "bio": "AngularJS Material and @angular/flex-layout Team Lead. Thomas joined the core team in 2014. He leads a team of developers working on UX components for AngularJS.", "type": "Lead" }, - - "victorsavkin": { - "name": "Victor Savkin", - "picture": "/resources/images/bios/victor.jpg", - "twitter": "victorsavkin", - "bio": "Victor works on Angular at Google. He is interested in functional programming and client-side applications. Being a language nerd he spends a lot of his time playing with TypeScript, Dart, Elm, Haskell, and Clojure.", + "stephenfluin": { + "name": "Stephen Fluin", + "picture": "/resources/images/bios/stephenfluin.jpg", + "twitter": "stephenfluin", + "website": "https://plus.google.com/+stephenfluin", + "bio": "Stephen is a Developer Advocate working on the Angular team. Before joining Google, he was a Google Expert. Stephen loves to help enterprises use technology more effectively.", + "type": "Google" + }, + "robwormald": { + "name": "Rob Wormald", + "picture": "/resources/images/bios/rob-wormald.jpg", + "twitter": "robwormald", + "website": "http://github.com/robwormald", + "bio": "Rob is a Developer Advocate on the Angular team at Google. He's the Angular team's resident reactive programming geek and founded the Reactive Extensions for Angular project, ngrx.", + "type": "Google" + }, + "aaronzhang": { + "name": "Aaron Zhang (章小飞)", + "picture": "/resources/images/bios/xiaofei.jpg", + "twitter": "", + "website": "http://github.com/damoqiongqiu", + "bio": "Aaron is Angular's developer PM in China. He is the lead for angular.cn and social channels in China, and helps developers in China's enterprise and open source communities to be successful with Angular. One of the earliest Angular developers in China since Angular 2012, he translated the first books on Angular into Chinese. Aaron joined the Google team in 2016.", "type": "Google" }, - "tobias": { "name": "Tobias Bosch", "picture": "/resources/images/bios/tobias.jpg", "twitter": "tbosch1009", "website": "https://plus.google.com/+TobiasBosch", - "bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular 2.", - "type": "Google" - }, - - "brianford": { - "name": "Brian Ford", - "picture": "/resources/images/bios/brian-ford.jpg", - "twitter": "briantford", - "bio": "Brian works on the AngularJS core team at Google where he tries his very best to make computers do the right thing.", + "bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular.", "type": "Google" }, @@ -107,19 +123,10 @@ "name": "David East", "picture": "/resources/images/bios/david-east.jpg", "twitter": "_davideast", + "website":"https://github.com/davideast", "bio": "David East is a Developer Programs Engineer at Google. He works full-time on the Firebase team and part-time on the Angular core team.", "type": "Google" }, - - "jeffcross": { - "name": "Jeff Cross", - "picture": "/resources/images/bios/jeff-cross.jpg", - "twitter": "jeffbcross", - "website": "https://twitter.com/jeffbcross", - "bio": "Jeff is a member of the Angular core team at Google, focusing on data access and application performance. Jeff has an extensive background in open source software, marketing, and user experience design. When not in front of a computer, he spends his time doing whatever his kids tell him to do, which usually involves playing music or making gadgets.", - "type": "Google" - }, - "alexeagle": { "name": "Alex Eagle", "picture": "/resources/images/bios/alex-eagle.jpg", @@ -138,14 +145,6 @@ "type": "Google" }, - "yegor": { - "name": "Yegor Jbanov", - "picture": "/resources/images/bios/yegor.jpg", - "website": "http://google.com/+YegorJbanov", - "bio": "I'm Yegor and I work on Angular 2 for Dart and performance.", - "type": "Google" - }, - "julieralph": { "name": "Julie Ralph", "picture": "/resources/images/bios/julie-ralph.jpg", @@ -160,25 +159,7 @@ "picture": "/resources/images/bios/alex-rickabaugh.jpg", "twitter": "synalx", "website": "https://plus.google.com/+AlexRickabaugh/about", - "bio": "I am a new member of the Angular team, solving challenges of data access and RPC for applications of any scale.", - "type": "Google" - }, - - "jelbourn": { - "name": "Jeremy Elbourn", - "picture": "/resources/images/bios/jelbourn.jpg", - "twitter": "jelbourn", - "website": "https://plus.google.com/+JeremyElbourn/", - "bio": "FE Engineer @ Google specializing in AngularJS, component design, and the cleanest of code.", - "type": "Google" - }, - - "alexwolfe": { - "name": "Alex Wolfe", - "picture": "/resources/images/bios/alex-wolfe.jpg", - "twitter": "alexwolfe", - "website": "https://github.com/alexwolfe", - "bio": "Alex is the Head of UX for Firebase at Google and leads the design and development for the website, dashboard, and docs. Alex helps lead the design and development for the Angular.io website. He has been designing and building products for over 15 years and has helped grow over 10 startups in the valley. Prior to joining Firebase, he was the Head of UX/UI for AdRoll. Alex is an avid tennis player and a former Street Fighter 2 World Champion.", + "bio": "Core team member working to optimize the Angular platform for the next generation of applications, including mobile. Before joining the Angular team, Alex worked in the Google sales organization where he helped build the first large Angular application within Google.", "type": "Google" }, @@ -200,12 +181,46 @@ "type": "Google" }, + "hansl": { + "name": "Hans Larsen", + "picture": "/resources/images/bios/hansl.jpg", + "twitter": "hanslatwork", + "website": "http://www.codingatwork.com/", + "bio": "Hans is a software engineer at Google on the Angular team and was previously at Slack. He works everyday to help make it easier for everyone to create beautiful, consistent web applications using Angular, using Material Design components and the CLI tool.", + "type": "Google" + }, + + "victorsavkin": { + "name": "Victor Savkin", + "picture": "/resources/images/bios/victor.jpg", + "twitter": "victorsavkin", + "website": "http://victorsavkin.com/", + "bio": "Victor has been on the Angular team since the inception of Angular. While at Google, Victor developed dependency injection, change detection, forms, and the router. Today he is a co-founder at nrwl.io.", + "type": "Community" + }, + "jeffcross": { + "name": "Jeff Cross", + "picture": "/resources/images/bios/jeff-cross.jpg", + "twitter": "jeffbcross", + "website": "https://twitter.com/jeffbcross", + "bio": "Jeff was one of the earliest core team members on AngularJS. He developed the Angular http and AngularFire modules, contributed to RxJS 5, and was most recently the Tech Lead of the Angular Mobile team at Google. Jeff is a former Googler and co-founder at nrwl.io.", + "type": "Community" + }, + "alexwolfe": { + "name": "Alex Wolfe", + "picture": "/resources/images/bios/alex-wolfe.jpg", + "twitter": "alexwolfe", + "website": "https://github.com/alexwolfe", + "bio": "Alex built and designed the original angular.io website, and the reboot of the Angular logo. An X-Googler, Alex has been designing and building products for over 15 years and helped grow over 10 startups in the valley. Alex is an avid tennis player and a former Street Fighter 2 World Champion.", + "type": "Community" + }, + "marcy": { "name": "Marcy Sutton", "picture": "/resources/images/bios/marcy.jpg", "twitter": "marcysutton", "website": "http://marcysutton.com", - "bio": "Marcy Sutton is a developer at Adobe in Seattle working on Angular accessibility and Material Design. She is a primary contributor to ngAria, the accessibility module, as well as the author of a new accessibility plug-in for Protractor. She's also in love with riding bicycles.", + "bio": "Marcy Sutton is a senior front-end engineer at Deque Systems, where she works on the axe-core team focusing on accessibility test integrations. Marcy is passionate about making the web accessible for everyone. She is a core team member to Angular Material, where she regularly brings her accessibility expertise to the table–she is also a primary contributor to the ngAria module as well as an accessibility plugin for Protractor. She's in love with riding bicycles and snowboards and can often be found outside.", "type": "Community" }, @@ -222,36 +237,11 @@ "name": "Lucas Mirelmann", "picture": "/resources/images/bios/lucas.jpg", "twitter": "lgalfaso", + "website": "https://github.com/lgalfaso", "bio": "Lucas works as a Software Engineer at Google and is a core Angular contributor.", "type": "Google" }, - "tonyc": { - "name": "Tony Childs", - "picture": "/resources/images/bios/tonyc.jpg", - "twitter": "javatricks", - "website": "http://www.stupidjavatricks.com", - "bio": "Tony Childs is a consultant working for Google. He is a contributor to the Angular Material project and is responsible for the md-icon component.", - "type": "Google" - }, - - "ryan": { - "name": "Ryan Schmukler", - "picture": "/resources/images/bios/ryan.jpg", - "twitter": "rschmukler", - "website": "http://slingingcode.com", - "bio": "Developer on ngMaterial. Full-stack JavaScript hacker. Open-source contributor with libraries totaling over 225K downloads.", - "type": "Community" - }, - - "rmesserle": { - "name": "Robert Messerle", - "picture": "/resources/images/bios/rmesserle.jpg", - "twitter": "Bobbo_O", - "bio": "Robert is a software engineer on the Angular team at Google, working primarily on the Angular Material project.", - "type": "Google" - }, - "kathy": { "name": "Kathy Walrath", "picture": "/resources/images/bios/kathy.jpg", @@ -260,17 +250,12 @@ "bio": "Kathy writes and edits docs about Dart and related technologies. Before Google, she worked at Sun, NeXT, and HP. Long ago, Kathy co-created and maintained The Java Tutorial.", "type": "Google" }, - "scott": { - "name": "Scott Hyndman", - "picture": "/resources/images/bios/scott.jpg", - "bio": "Scott works for Google on the Material Design team, where he brings designers' dreams to life on the web.", - "type": "Google" - }, "kara": { "name": "Kara Erickson", "picture": "/resources/images/bios/kara-erickson.jpg", "twitter": "karaforthewin", + "website": "https://github.com/kara", "bio": "Kara is a software engineer on the Angular team at Google and a co-organizer of the Angular-SF Meetup. Prior to Google, she helped build UI components in Angular for guest management systems at OpenTable. She enjoys snacking indiscriminately and probably other things too.", "type": "Google" }, @@ -283,6 +268,27 @@ "bio": "Chuck is a Software Engineer on the Angular team at Google. He is a programming language geek, UI framework and component library veteran, and has a passion for simplifying the task of programming. Before Google, he worked at Microsoft and Borland.", "type": "Google" }, + "vikram": { + "name": "Vikram Subramanian", + "picture": "/resources/images/bios/vikram.jpg", + "twitter": "vikerman", + "bio": "Vikram is a Software Engineer on the Angular team focused on Engineering Productivity. That means he makes sure people on the team can move fast and not break things. Vikram enjoys doing Yoga and going on walks with his daughter.", + "type": "Google" + }, + "maxsills": { + "name": "Max Sills", + "picture": "/resources/images/bios/max-sills.jpg", + "twitter": "angularjs", + "website": "http://google-opensource.blogspot.com/", + "bio": "Max Sills is Angular's Open Source lawyer.", + "type": "Google" + }, + "shannon": { + "name": "Shannon Ayres", + "picture": "/resources/images/bios/shannon.jpg", + "bio": "Shannon is a technical editor in Developer Relations at Google. She loves movies, especially Sunset Boulevard, and her favorite TV show is The Walking Dead. Her mission: Righting wrong writing!", + "type": "Google" + }, "pawel": { "name": "Pawel Kozlowski", @@ -297,7 +303,7 @@ "picture": "/resources/images/bios/michal.jpg", "twitter": "m_gol", "website": "https://plus.google.com/u/0/103101124310040612163/", - "bio": "Front-end developer at Laboratorium EE, core contributor to Angular & jQuery. Makes sure Angular 1 & jQuery work fine together. Interested in new JavaScript standards.", + "bio": "Front-end developer at Laboratorium EE, core contributor to Angular & jQuery. Makes sure AngularJS & jQuery work fine together. Interested in new JavaScript standards.", "type": "Community" }, @@ -311,9 +317,9 @@ "elad": { "name": "Elad Bezalel", "picture": "/resources/images/bios/eladbezalel.jpg", - "website": "https://github.com/EladBezalel", - "bio": "Elad is a fullstack developer with a very storng love for design. Since 8 years old, he's been designing in Photoshop and later on fell in love with programing. This strong bond between design and computer programming gave birth to a new kind of love. And he is currently doing the combination of both, as a core member of the ngMaterial project.", - "type": "Community" + "website": "https://github.com/EladBezalel", + "bio": "Elad is a fullstack developer with a very strong love for design. Since 8 years old, he's been designing in Photoshop and later on fell in love with programing. This strong bond between design and computer programming gave birth to a new kind of love. And he is currently doing the combination of both, as a core member of the ngMaterial project.", + "type": "Community" }, "marclaval": { @@ -321,7 +327,7 @@ "picture": "/resources/images/bios/marclaval.jpg", "twitter": "marclaval", "website": "https://github.com/mlaval", - "bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular 2.", + "bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular.", "type": "Community" }, @@ -339,15 +345,7 @@ "picture": "/resources/images/bios/patrick-stapleton.jpg", "twitter": "gdi2290", "website": "https://angularclass.com", - "bio": "Also know as PatrickJS where JS stands for his middle and last names. Patrick is very active in Open-Source with over 4,300+ contributions in the last year alone on projects such as Angular2, AngularJS, FalcorJS, Docker, Bootstrap, gulp, and redis to name a few. He is also working on the development of Angular 2 server-side rendering as Universal Angular 2 and teaching Modern Web Development at AngularClass. He was previously the CTO of Keychain Logistics, a HackReactor Instructor and Alum.", - "type": "Community" - }, - - "cburgdorf": { - "name": "Christoph Burgdorf", - "picture": "/resources/images/bios/cburgdorf.jpg", - "website": "https://github.com/cburgdorf", - "bio": "Christoph began with programming at the age of 10 with BASIC but has since moved on to become proficient in various different programming languages and technologies. Christoph has contributed to many projects, including AngularJS, jquery-ui, TodoMVC and the banshee media player and is also the creator of the nickel.rs framework. When he's not evangelizing Git, he likes to travel the world with his bicycle.", + "bio": "Also know as PatrickJS where JS stands for his middle and last names. Patrick is very active in Open-Source with over 4,300+ contributions in the last year alone on projects such as Angular, AngularJS, FalcorJS, Docker, Bootstrap, gulp, and redis to name a few. He is also working on the development of Angular server-side rendering as Universal Angular and teaching Modern Web Development at AngularClass. He was previously the CTO of Keychain Logistics, a HackReactor Instructor and Alum.", "type": "Community" }, @@ -363,9 +361,11 @@ "name": "Ward Bell", "picture": "/resources/images/bios/wardbell.jpg", "website": "https://github.com/wardbell", + "twitter": "wardbell", "bio": "Ward is an all-around developer with JavaScript, node, and .net chops. He's a frequent conference speaker and podcaster, trainer, Google Developer Expert for Angular, Microsoft MVP, and PluralSight author. He is also president of IdeaBlade, an enterprise software consulting firm and the makers of breeze.js. He would like to get more sleep and spend more time in the mountains.", "type": "Community" }, + "johnpapa": { "name": "John Papa", "picture": "/resources/images/bios/john-papa.jpg", @@ -374,13 +374,15 @@ "bio": "John is a Google Developer Expert, Microsoft Regional Director and MVP, frequent author of courses for Pluralsight, a former technology Evangelist for Microsoft front end teams, and author of the popular Angular Style Guide. He can often be found speaking around the world at keynotes and sessions for many conferences. You can always find John at johnpapa.net or on twitter at @john_papa.", "type": "Community" }, + "martinstaffa": { "name": "Martin Staffa", "picture": "/resources/images/bios/martinstaffa.jpg", "twitter": "Narretz", - "bio": "Martin is an English major turned web developer who loves frontend stuff. He's been part of the Angular 1 team since 2014. If you can't find him roaming the Github issue queues, he's probably out with his camera somewhere.", + "bio": "Martin is an English major turned web developer who loves frontend stuff. He's been part of the AngularJS team since 2014. If you can't find him roaming the Github issue queues, he's probably out with his camera somewhere.", "type": "Community" }, + "topherfangio": { "name": "Topher Fangio", "picture": "/resources/images/bios/topherfangio.jpg", @@ -388,6 +390,152 @@ "website": "http://github.com/topherfangio", "bio": "Topher loves the web and how it empowers new forms of creativity, connection and business. He is currently a core contributor on the Angular Material project and sometimes blogs about random things.", "type": "Community" + }, + + "filipesilva": { + "name": "Filipe Silva", + "picture": "/resources/images/bios/filipe-silva.jpg", + "twitter": "filipematossilv", + "website": "http://github.com/filipesilva", + "bio": "Filipe is a passion-driven developer that always strives for the most elegant solution for each problem. He is currently an author for Angular.io, a core contributor for Angular-CLI and senior front end engineer at KonnectAgain. When not busy going through PRs, you can find him scouring reddit for new dinner recipes to cook or enjoying a craft beer in Dublin.", + "type": "Community" + }, + + "teropa": { + "name": "Tero Parviainen", + "picture": "/resources/images/bios/teropa.jpg", + "twitter": "teropa", + "website": "http://teropa.info/", + "bio": "Tero is an independent software developer and writer. He's been building web applications for his whole professional career, and has almost figured out how to do vertical centering in CSS.", + "type": "Community" + }, + + "deborah": { + "name": "Deborah Kurata", + "picture": "/resources/images/bios/deborah.jpg", + "twitter": "deborahkurata", + "website": "http://blogs.msmvps.com/deborahk/", + "bio": "Deborah is an independent software developer and author. She is author of several Pluralsight courses including: 'Angular 2: Getting Started'", + "type": "Community" + }, + + "jesusrodriguez": { + "name": "Jesús Rodríguez", + "picture": "/resources/images/bios/jesus-rodriguez.jpg", + "twitter": "foxandxss", + "website": "http://angular-tips.com", + "bio": "Jesus is an open source lover, a book author and editor, and AngularUI lead developer. He is currently a core contributor to the UI Bootstrap project.", + "type": "Community" + }, + + "torgeirhelgevold": { + "name": "Torgeir Helgevold", + "picture": "/resources/images/bios/torgeirhelgevold.jpg", + "twitter": "helgevold", + "website": "http://www.syntaxsuccess.com", + "bio": "Torgeir (Tor) is a front-end architect with a passion for JavaScript development. He is also an author for angular.io and an active tech blogger.", + "type": "Community" + }, + + "fatimaremtullah": { + "name": "Fatima Remtullah", + "picture": "/resources/images/bios/fatima.jpg", + "twitter": "amitafr", + "website": "http://www.amitafremtullah.com", + "bio": "Fatima is a Product Designer and Front-End Developer. When she is not nerding out she is probably eating an abundance of cookies.", + "type": "Community" + }, + + "eric": { + "name": "Eric Jimenez", + "picture": "/resources/images/bios/eric.jpg", + "twitter": "_ericjim", + "website": "http://eric.to/", + "bio": "Eric is a gamer, writer, and programmer.", + "type": "Community" + }, + + "mikeryan": { + "name": "Mike Ryan", + "picture": "/resources/images/bios/mikeryan.jpg", + "twitter": "mikeryan52", + "website": "https://medium.com/@MikeRyan52", + "bio": "Mike Ryan is a Software Engineer at Synapse Wireless, working on solving challenging problems in the internet-of-things space. He is an advocate of reactive programming and a core contributor to the ngrx project.", + "type": "Community" + }, + + "rex": { + "name": "Rex Ye", + "picture": "/resources/images/bios/rex.jpg", + "twitter": "rexebin", + "bio": "Rex is a full-stack developer. He maintains the Angular.cn website with his old pal Ralph Wang and he plays a key role in bridging between the Chinese Angular community and the world-wide community. He loves playing with flashy new technologies and enjoys the challenge of mastering new skills. His biggest challenge to date is figuring out how to sooth a crying 4-month-old baby.", + "type": "Community" + }, + + "ralph": { + "name": "Ralph Wang", + "picture": "/resources/images/bios/ralph.jpg", + "twitter": "ralph_wang_gde", + "bio": "Ralph(Zhicheng Wang) is a senior consultant at ThoughWorks and also a GDE. He is a technology enthusiast and he is a passionate advocate of “Simplicity, Professionalism and Sharing”. In his eighteen years of R&D career, he worked as tester, R&D engineer, project manager, product manager and CTO. He is looking forward to the birth of his baby.", + "type": "Community" + }, + + "brandonroberts": { + "name": "Brandon Roberts", + "picture": "/resources/images/bios/brandonroberts.jpg", + "twitter": "brandontroberts", + "website": "https://github.com/brandonroberts", + "bio": "Brandon is a front-end developer for a game studio developing web applications for STEM-based learning games. He is also a natural born troubleshooter who helps solve Angular issues on Github and Gitter support channels, particularly dealing with routing. He is also a member of the Angular docs team.", + "type": "Community" + }, + + "crisbeto": { + "name": "Kristiyan Kostadinov", + "picture": "/resources/images/bios/crisbeto.jpg", + "website": "http://crisbeto.com/", + "bio": "Kristiyan is a front-end developer, passionate open-source contributor and a core team member on Angular Material.", + "type": "Community" + }, + + "gkalpak": { + "name": "Georgios Kalpakas", + "picture": "/resources/images/bios/gkalpak.jpg", + "twitter": "gkalpakas", + "website": "https://github.com/gkalpak", + "bio": "George is a Software Engineer with a passion for chess, robotics and automating stuff. He has a strong need to know how things work (so if you already know, he'd love to have a talk with you). He has been a member of the AngularJS team since 2014. When not doing geeky stuff, he is probably trying to convince his wife and kids to apply programming principles in real life. (Or is it the other way around?)", + "type": "Community" + }, + + "kapunahelewong": { + "name": "Kapunahele Wong", + "picture": "/resources/images/bios/kapunahelewong.jpg", + "website": " https://github.com/kapunahelewong", + "twitter": "kapunahele", + "bio": "Kapunahele is a front-end developer and contributor to angular.io. She loves just about anything to do with JavaScript, Angular and electronics. She enjoys mapping Hawaiian star names and constellations to Western ones and loves dancing native Hawaiian hula.", + "type": "Community" + }, + + "devversion": { + "name": "Paul Gschwendtner", + "picture": "/resources/images/bios/devversion.jpg", + "website": "http://github.com/DevVersion/", + "twitter": "DevVersion", + "bio": "Paul is a 16-year-old developer living in Germany. While he attends school, Paul works as a core team member on Angular Material. Paul focuses on tooling and building components for Angular.", + "type": "Community" + }, + + "mmalerba": { + "name": "Miles Malerba", + "picture": "/resources/images/bios/mmalerba.jpg", + "bio": "Miles is a software engineer on the Angular Material team at Google. In addition to Javascripting he enjoys eating food and ogling cute puppies.", + "type": "Google" + }, + + "jasonaden": { + "name": "Jason Aden", + "picture": "/resources/images/bios/jasonaden.jpg", + "bio": "Jason is a software engineer at Google on the Angular Core team. He is enthusiastic about Angular and application development in the modern age. In his free time Jason enjoys spending time with his wife and four children and doing outdoor activities (hiking, fishing, snowboarding, etc.).", + "type": "Google" } } } diff --git a/package.json b/package.json index 2fd87fa130..2879b1483d 100644 --- a/package.json +++ b/package.json @@ -2,73 +2,75 @@ "name": "angular.io", "version": "0.0.0", "private": true, - "description": "Angular 2 documentation", + "description": "Angular documentation", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "harp": "harp", "live-server": "live-server", "test-api-builder": "jasmine-node tools/api-builder", - "protractor": "protractor" }, "repository": { "type": "git", "url": "https://github.com/angular/angular.io.git" }, - "licenses": [ - { - "type": "Apache", - "url": "http://www.apache.org/licenses/LICENSE-2.0.html" - } - ], + "license": "MIT", "bugs": { "url": "" }, "devDependencies": { - "archiver": "^0.16.0", - "assert-plus": "^0.1.5", + "archiver": "^1.0.0", + "assert-plus": "^1.0.0", + "bootstrap": "3.3.6", + "broken-link-checker": "0.7.1", "browser-sync": "^2.9.3", "canonical-path": "0.0.2", - "cross-spawn": "^2.1.0", - "del": "^1.2.0", + "cheerio": "^0.20.0", + "codelyzer": "0.0.26", + "cross-spawn": "^4.0.0", + "del": "^2.2.0", "dgeni": "^0.4.0", - "dgeni-packages": "^0.11.1", + "dgeni-packages": "^0.16.0", "diff": "^2.1.3", - "fs-extra": "^0.24.0", - "glob": "^5.0.14", + "fs-extra": "^0.30.0", "globby": "^4.0.0", "gulp": "^3.5.6", "gulp-env": "0.4.0", + "gulp-less": "^3.1.0", + "gulp-sass": "^2.3.2", "gulp-task-listing": "^1.0.1", + "gulp-tslint": "^5.0.0", "gulp-util": "^3.0.6", "gulp-watch": "^4.3.4", - "harp": "^0.19.0", + "harp": "^0.21.0", "html2jade": "^0.8.4", "indent-string": "^2.1.0", "jasmine-core": "^2.3.4", "jasmine-node": "^1.14.5", - "jsdom": "^7.0.2", + "jsdom": "^9.2.1", "jsonfile": "^2.2.2", "karma": "^0.13.10", - "karma-chrome-launcher": "^0.2.0", - "karma-jasmine": "^0.3.6", - "live-server": "^0.8.1", - "lodash": "^3.10.1", + "karma-chrome-launcher": "^1.0.1", + "karma-jasmine": "^1.0.2", + "live-server": "^1.0.0", + "lodash": "^4.13.1", "marked": "^0.3.5", - "minimatch": "^2.0.10", + "minimatch": "^3.0.0", "mkdirp": "^0.5.1", "node-html-encoder": "0.0.2", - "nodegit": "0.5.0", - "path": "^0.11.14", - "prompt": "^0.2.14", + "nodegit": "0.13.0", + "path": "^0.12.7", + "prompt": "^1.0.0", "protractor": "^3.0.0", "q": "^1.4.1", "tree-kill": "^1.0.0", - "typescript": "1.7.3", - "yargs": "^3.23.0" + "tslint": "^3.15.1", + "typescript": "~2.0.10", + "yargs": "^4.7.1" }, "dependencies": { "jstransformer-marked": "^1.0.1" - } + }, + "homepage": "http://angular.io/" } diff --git a/public/_data.json b/public/_data.json index e3df10773e..3b224f69eb 100644 --- a/public/_data.json +++ b/public/_data.json @@ -2,12 +2,11 @@ "index": { "hero": "home", "title": "One framework.", - "subtitle": "Mobile and desktop." + "subtitle": "Mobile & desktop." }, "features": { - "title": "Features & Benefits", - "subtitle": "Powerful Features for Developing Apps" + "title": "Features & Benefits" }, "contribute": { @@ -16,11 +15,6 @@ "autoformat": "true" }, - "news": { - "title": "News", - "subtitle": "Check out what we are up to" - }, - "events": { "title": "Events", "subtitle": "Where we'll be presenting" @@ -29,5 +23,9 @@ "support": { "title": "Support", "subtitle": "Get help from the Angular Community" + }, + + "presskit": { + "title": "Press Kit" } } diff --git a/public/_includes/_footer.jade b/public/_includes/_footer.jade index 394072d8ed..421c208aa1 100644 --- a/public/_includes/_footer.jade +++ b/public/_includes/_footer.jade @@ -7,51 +7,51 @@ if version && language else - var styleguide = "/docs/ts/latest/styleguide.html" -.main-footer - nav.background-silver.grid-fluid +div(class="main-footer" data-swiftype-index="false") + nav.background-midnight.grid-fluid .c3.main-footer-branding .logo-inverse-large .c2 - h3.text-headline LIBRARIES + h3.text-headline RESOURCES ul.text-body - li Angular 2.0 - li Angular 1 for JS - li Angular 1 for Dart - li Angular Material - li AngularFire - - .c2 - h3.text-headline LEARN - - ul.text-body - li 5 Min Quickstart - li Step by Step Guide - li Full API - li Resources - li Design Docs & Notes + // TODO: (ericjim) make a libraries page to showcase all angular libraries + //li Libraries + li About + li Books & Training + li Tools & Libraries + li Community + li Press Kit .c2 h3.text-headline HELP ul.text-body + li Stack Overflow + li Gitter li Google Group - li Chat Room - li Report an Issue + li Report Issues + li Site Feedback - .c3 + .c2 h3.text-headline COMMUNITY ul.text-body - li Blog - li Google+ - li Twitter + li Events + li Meetups + li Twitter li GitHub + li Contribute + + .c2 + h3.text-headline LANGUAGES + ul.text-body + li 中文版 - footer(class="background-steel") - small.text-caption Powered by Google ©2010-2016. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0. - a(aria-label="View Style Guide" href=styleguide title="Style Guide" class="styleguide-trigger text-snow" md-button) - span.icon-favorite \ No newline at end of file + footer(class="background-midnight") + small.text-caption Powered by Google ©2010-2017. Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0. + a(aria-label="View Style Guide" href=styleguide title="Style Guide" class="styleguide-trigger") + span.icon-favorite diff --git a/public/_includes/_head-include.jade b/public/_includes/_head-include.jade index 2e46febe96..489ba51bd2 100644 --- a/public/_includes/_head-include.jade +++ b/public/_includes/_head-include.jade @@ -1,18 +1,25 @@ - var language = current.path[1] - var version = '' +- var section = '' if current.path[2] - var version = current.path[2].replace(/\_+/gm, ".") +if current.path[3] + - var section = current.path[3].toUpperCase() + + if language == 'js' if language == 'dart' if title == "Angular" title #{title} +else if section + title #{title} - #{language} - #{section} else if language title #{title} - #{language} else - title #{title} - Angular 2 + title #{title} - Angular meta(charset="utf-8") meta(http-equiv="X-UA-Compatible" content="IE=edge") @@ -22,14 +29,14 @@ meta(name="robots" content="all") meta(name="referrer" content="origin") meta(name="viewport" id="viewport" content="width=device-width, initial-scale=1") -meta(property="og:title" content="Angular 2") +meta(property="og:title" content="Angular") meta(property="og:image" content="/resources/images/logos/standard/shield-large.png") meta(property="og:image:type" content="image/png") meta(property="og:image:width" content="184") meta(property="og:image:height" content="200") meta(property="og:description" content="#{description}") -meta(itemprop="name" content="Angular 2") +meta(itemprop="name" content="Angular") meta(itemprop="description" content="#{description}") meta(itemprop="image" content="https://angular.io/resources/images/logos/standard/shield-large.png") @@ -57,4 +64,4 @@ link(rel="stylesheet" href="/https/github.com/resources/css/main.css") - \ No newline at end of file + diff --git a/public/_includes/_hero-home.jade b/public/_includes/_hero-home.jade index 314f1ec67f..b413803e3b 100644 --- a/public/_includes/_hero-home.jade +++ b/public/_includes/_hero-home.jade @@ -1,12 +1,13 @@ -header(class="background-sky") - .hero.background-superhero-paper.is-large - h1.text-headline.hero-logo #{title}
#{subtitle} +header(class="background-sky l-relative") - .hero-cta - a(href="/https/github.com/docs/ts/latest/quickstart.html" class="md-raised button button-large button-plain" - md-button) Get Started - -.banner.is-centered - .banner-ng-annoucement - h4 Announcing Angular Attack — a 48 hour online hackathon on May 14 - 15th, 2016.  - a(href="https://www.angularattack.com/" target="_blank") Register Today \ No newline at end of file + .hero.background-superhero-paper.is-large + img(class="hero-logo" src='/https/github.com/resources/images/logos/angular/angular.svg') + h1.text-headline #{title}
#{subtitle} + a(href="/https/github.com/docs/ts/latest/quickstart.html" class="hero-cta md-raised button button-large button-plain" md-button) Get Started + + announcement-bar + .announcement-bar-slide.clearfix + img(src="/resources/images/logos/angular/angular-banner-logo-grey.png" width="64") + p Angular v4.0 is out! Smaller, faster, no biggie... + a(href="http://angularjs.blogspot.com/2017/03/angular-400-now-available.html" target="_blank" class="button md-button") Learn more + diff --git a/public/_includes/_hero.jade b/public/_includes/_hero.jade index e7ebf89745..bf346a6a3a 100644 --- a/public/_includes/_hero.jade +++ b/public/_includes/_hero.jade @@ -1,14 +1,41 @@ -- var textFormat = '' +//- template: public/_includes/_hero +//- Refer to jade.template.html and addJadeDataDocsProcessor to figure out where the context of this jade file originates +- var textFormat = ''; - var headerTitle = title + (typeof varType !== 'undefined' ? (': ' + varType) : ''); +- var capitalize = function capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } +- var useBadges = docType || stability; +//- renamer :: String -> String +//- Renames `Let` and `Var` into `Const` +- var renamer = function renamer(docType) { +- return (docType === 'Let' || docType === 'Var') ? 'Const' : docType +- } if current.path[4] && current.path[3] == 'api' - var textFormat = 'is-standard-case' -header(class="hero background-sky") - h1(class="hero-title text-display-1 #{textFormat}") #{headerTitle} +if current.path.indexOf('cheatsheet') > 0 || current.path[current.path.length-2] === 'api' + - var base = current.path[4] ? '../guide' : './guide'; + - var ngVersion = '(v4.X.Y)'; + +header.hero.background-sky + h1(class="hero-title #{textFormat}") #{headerTitle} !{ngVersion} + + if useBadges + if stability + span(class="badge is-#{stability}"). + #{capitalize(stability)} + if security + span(class="badge is-deprecated"). + Security Risk + + //- CLEAR FLOAT ELEMENTS + .clear if subtitle - h2.hero-subtitle.text-subhead #{subtitle} + h2.hero-subtitle #{subtitle} + else if docType + h2.hero-subtitle #{renamer(capitalize(docType))} + + if current.path[3] == 'api' && current.path[1] == 'dart' + block breadcrumbs - else if current.path[0] == "docs" - != partial("_version-dropdown") \ No newline at end of file diff --git a/public/_includes/_main-nav.jade b/public/_includes/_main-nav.jade index 4cbe5e397e..5ecfcd7108 100644 --- a/public/_includes/_main-nav.jade +++ b/public/_includes/_main-nav.jade @@ -1,15 +1,13 @@ -md-toolbar(class="main-nav background-regal l-pinned-top l-layer-5",scroll-y-offset-element) - nav - h1 Angular by Google +- var language = current.path[1] || 'ts' +- if (language !== 'ts' || language !== 'js' || language !== 'dart') { language = 'ts'; } - button(class="main-nav-button main-nav-mobile-trigger l-right" aria-label="View Menu" ng-click="appCtrl.toggleMainMenu($event)" md-button) Site Menu +nav(data-swiftype-index="false" class="main-nav l-pinned-top l-layer-5", scroll-y-offset-element) + h1 Angular by Google - ul(ng-class="appCtrl.showMainNav ? 'is-visible' : ''") - li.l-left Features - li.l-left Docs - li.l-left About - li.l-left Contribute - li.l-left Support - li.l-left News - li.l-left Events - li.l-right.feedback-button feedback + button(class="main-nav-button main-nav-mobile-trigger l-right" aria-label="View Menu" ng-click="appCtrl.toggleMainMenu($event)" md-button) Site Menu + + ul(ng-class="appCtrl.showMainNav ? 'is-visible' : ''") + li.l-left Features + li.l-left Docs + li.l-left Events + li.l-right Get Started diff --git a/public/_includes/_next-item.jade b/public/_includes/_next-item.jade index c4626a453f..df379265ae 100644 --- a/public/_includes/_next-item.jade +++ b/public/_includes/_next-item.jade @@ -1,19 +1,24 @@ - var currentPage = false - var nextPage = false +- var hideNextPage = false; + - var data = public.docs[current.path[1]][current.path[2]][current.path[3]]._data for page, slug in data // CHECK IF CURRENT PAGE IS SET, THEN SET NEXT PAGE if currentPage - if !nextPage && page.nextable - .l-sub-section - h3 Next Step - a(href="/https/github.com/docs/#{current.path[1]}/#{current.path[2]}/#{current.path[3]}/#{slug}.html") #{page.title} + if !nextPage && page.nextable && !page.hide + if !hideNextPage + .l-sub-section + h3 Next Step + a(href="/https/github.com/docs/#{current.path[1]}/#{current.path[2]}/#{current.path[3]}/#{slug}.html") #{page.title} //NEXT PAGE HAS NOW BEEN SET - var nextPage = true + - hideNextPage = page.hideNextPage + // SET CURRENT PAGE FLAG WHEN YOU PASS IT if current.path[4] == slug - - var currentPage = true \ No newline at end of file + - var currentPage = true diff --git a/public/_includes/_scripts-include.jade b/public/_includes/_scripts-include.jade index c7fa5c3527..aee83952ab 100644 --- a/public/_includes/_scripts-include.jade +++ b/public/_includes/_scripts-include.jade @@ -7,51 +7,33 @@ script(src="/resources/js/vendor/clipboard.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js") -script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular-animate.min.js") +script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular-aria.min.js") script(src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.js") + + + + + script(src="/resources/js/site.js") +script(src="/resources/js/util.js") script(src="/resources/js/controllers/app-controller.js") +script(src="/resources/js/controllers/resources-controller.js") script(src="/resources/js/directives/cheatsheet.js") script(src="/resources/js/directives/api-list.js") script(src="/resources/js/directives/bio.js") script(src="/resources/js/directives/bold.js") +script(src="/resources/js/directives/announcement-bar.js") script(src="/resources/js/directives/code.js") script(src="/resources/js/directives/copy.js") script(src="/resources/js/directives/code-tabs.js") script(src="/resources/js/directives/code-pane.js") script(src="/resources/js/directives/code-example.js") +script(src="/resources/js/directives/if-docs.js") +script(src="/resources/js/directives/live-example.js") script(src="/resources/js/directives/scroll-y-offset-element.js") - - -script. - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-8594346-15', 'auto'); - ga('send', 'pageview') - - -if current.path[0] == "docs" - - script. - (function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){ - (w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t); - e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e); - })(window,document,'script','//s.swiftypecdn.com/install/v1/st.js','_st'); - - _st('install','VsuU7kH5Hnnj9tfyNvfK'); - - -script(src="//www.gstatic.com/feedback/api.js" type="text/javascript") - - -script. - (function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}})(document,"script","twitter-wjs"); \ No newline at end of file diff --git a/public/_includes/_scripts-minimum.jade b/public/_includes/_scripts-minimum.jade new file mode 100644 index 0000000000..a568f88d15 --- /dev/null +++ b/public/_includes/_scripts-minimum.jade @@ -0,0 +1,27 @@ + +script. + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-8594346-15', 'auto'); + ga('send', 'pageview') + + +if current.path[0] == "docs" || current.path[0] == "search" +script. + (function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){ + (w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t); + e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e); + })(window,document,'script','//s.swiftypecdn.com/install/v2/st.js','_st'); + + _st('install','VsuU7kH5Hnnj9tfyNvfK','2.0.0'); + + + +script(src="//www.gstatic.com/feedback/api.js" type="text/javascript") + + +script. + (function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}})(document,"script","twitter-wjs"); diff --git a/public/_includes/_util-fns.jade b/public/_includes/_util-fns.jade index d5274d903e..7a755027c8 100644 --- a/public/_includes/_util-fns.jade +++ b/public/_includes/_util-fns.jade @@ -1,23 +1,134 @@ //- Mixins and associated functions +//- _docsFor: used to identify the language this version of the docs if for; +//- Should be one of: 'ts', 'dart' or 'js'. Set in lang specific _util-fns file. +- var _docsFor = ''; + +//- Should match `_docsFor`, but in this case provides the full capitalized +//- name of the language. +- var _Lang = 'TypeScript'; + +//- Simple "macros" used via interpolation in text: +//- e.g., the #{_priv}el variable has an `@Input` #{_decorator}. + +//- Use #{_decorator} whereever the word "decorator" is expected, provided it is not +//- preceded by the article "a". (E.g., will be "annotation" for Dart) +- var _decorator = 'decorator'; + +//- Articles (which toggle between 'a' and 'an'). Used for, e.g., +//- array vs. list; decorator vs. annotation. +- var _a = 'a'; +- var _an = 'an'; + +//- TS arrays vs. Dart lists +- var _Array = 'Array'; +- var _array = 'array'; + +//- Promise vs. Future, etc +- var _Promise = 'Promise'; +- var _PromiseUrl = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'; +- var _PromiseLinked = '' + _Promise + ''; +- var _Observable = 'Observable'; + +//- Directories & folders +- var _appDir = 'app'; +- var _indexHtmlDir = 'project root'; +- var _mainDir = _appDir; + +//- Location of sample code +- var _liveLink = 'live link'; +- var _ngRepoURL = 'https://github.com/angular/angular'; +- var _ngDocRepoURL = 'https://github.com/angular/angular.io'; +- var _qsRepo = 'https://github.com/angular/quickstart'; +- var _qsRepoZip = _qsRepo + '/archive/master.zip'; + +- var _npm = 'npm'; + +//- NgModule related +- var _AppModuleVsAppComp = 'AppModule' +- var _appModuleTsVsAppCompTs = 'src/app/app.module.ts' +- var _appModuleTsVsMainTs = 'src/app/app.module.ts' +- var _bootstrapModule = 'bootstrapModule' +- var _declsVsDirectives = 'declarations' +- var _moduleVsComp = 'module' +- var _moduleVsRootComp = 'module' +- var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic' + +//- Other +- var _truthy = 'truthy'; +- var _falsy = 'falsy'; + +//- Used to prefix identifiers that are private. In Dart this will be '_'. +- var _priv = ''; + +//- Use to conditionally include the block that follows +ifDocsFor(...). +//- Generally favor use of Jade named blocks instead. ifDocsFor is convenient +//- for prose that should appear only in one language version. +mixin ifDocsFor(langPattern) + if _docsFor.toLowerCase().match(langPattern.toLowerCase()) + block + +//- Use to map inlined (prose) TS paths into, say, Dart paths via the +//- adjustTsExamplePathForDart transformer function. +mixin adjExPath(path) + if adjustTsExamplePathForDart + | #{adjustTsExamplePathForDart(path)} + else + | #{path} + mixin includeShared(filePath, region) - var newPath = translatePath(filePath, region); !=partial(newPath) -mixin makeExample(filePath, region, title, stylePatterns) +mixin makeExample(_filePath, region, _title, stylePatterns) + - var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title}); + - var filePath = adjustments.filePath; + - var title = adjustments.title; - var language = attributes.language || getExtn(filePath); - var frag = getFrag(filePath, region); - var defaultFormat = frag.split('\n').length > 2 ? "linenums" : ""; - var format = attributes.format || defaultFormat; - if (title) - .example-title #{title} - code-example(language="#{language}" format="#{format}") - != styleString(frag, stylePatterns) + - if (attributes.format === '.') format = ''; + - var avoid = !!attributes.avoid; + - var avoidClass = avoid ? 'is-anti-pattern' : ''; + + div(class="code-example #{avoidClass}") + if (title) + header + h4 #{title} + code-example(language="#{language}" format="#{format}") + != styleString(frag, stylePatterns) + +//- Like makeExample, but: (1) doesn't show line numbers. (2) If region +//- is omitted and title is 'foo (r)' then region is taken as 'r'. +//- (3) Title will always end with a phrase in parentheses; if no such +//- ending is given or is just (), then the title will be suffixed with +//- either "(excerpt)", or "(#{_region})" when _region is defined. +mixin makeExcerpt(_filePath, _region, _title, stylePatterns) + - var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/); + - var parenText; + - if (matches) { _filePath = matches[1]; parenText = matches[2]; } + - var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title}); + - var filePath = adjustments.filePath; + - var title = adjustments.title; + - var region = _region || (_region === '' ? '' : parenText); + - var excerpt = parenText || region || 'excerpt'; + - if (title) title = title + ' (' + excerpt + ')'; + +makeExample(filePath, region, title, stylePatterns)(format='.') + +//- Get the doc example name either from `_example` if set, or +//- extract the example name from `current`. +- var getExampleName = function() { +- var dir = current.path[current.path.length - 1]; +- return _example ? _example : dir == 'latest' ? current.source : dir; +- }; mixin makeTabs(filePaths, regions, tabNames, stylePatterns) - filePaths = strSplit(filePaths); + - if (adjustTsExamplePathForDart) filePaths = filePaths.map(adjustTsExamplePathForDart); - regions = strSplit(regions, filePaths.length); - tabNames = strSplit(tabNames, filePaths.length); + - if (adjustTsExampleTitleForDart) tabNames = tabNames.map(adjustTsExampleTitleForDart); code-tabs each filePath,index in filePaths @@ -37,74 +148,117 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns) - var frag = getFrag(filePath, ''); - var json = unescapeHtml(frag); - var jsonExtract = extractJson(json, jsonConfig); + - var avoid = !!attributes.avoid; + - var avoidClass = avoid ? 'is-anti-pattern' : ''; + + div(class="code-example #{avoidClass}") + if (title) + header + h4 #{title} + code-example(language="#{language}" format="#{format}") + if (jsonExtract == 'ERROR') + err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}" + else + != styleString(jsonExtract, stylePatterns) + +if !jade2ng + //- Open (and close) an explanation
. See QuickStart + script. + function why(id, backTo) { + var id = "#"+id; + var el = document.querySelector(id); + el.hidden=el.hidden=!el.hidden; - if (title) - .example-title #{title} - code-example(language="#{language}" format="#{format}") - if (jsonExtract == 'ERROR') - err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}" - else - != styleString(jsonExtract, stylePatterns) - -- // Open (and close) an explanation
. See QuickStart -script. - function why(id, backTo) { - var id = "#"+id; - var el = document.querySelector(id); - el.hidden=el.hidden=!el.hidden; - - if (el.hidden && backTo){ - // the next line is required to work around a bug in WebKit (Chrome / Safari) - location.href = "#"; - location.href = "#" + backTo; + if (el.hidden && backTo){ + // the next line is required to work around a bug in WebKit (Chrome / Safari) + location.href = "#"; + location.href = "#" + backTo; + } + } + script. + function verbose(isVerbose) { + isVerbose = !! isVerbose; + var el = document.querySelector('button.verbose.off'); + el.style.display = isVerbose ? 'block' : 'none'; + var el = document.querySelector('button.verbose.on'); + el.style.display = isVerbose ? 'none' : 'block'; + + CCSStylesheetRuleStyle('main','.l-verbose-section', 'display', + isVerbose ? 'block' : 'none'); } - } -script. - function verbose(isVerbose) { - isVerbose = !! isVerbose; - var el = document.querySelector('button.verbose.off'); - el.style.display = isVerbose ? 'block' : 'none'; - var el = document.querySelector('button.verbose.on'); - el.style.display = isVerbose ? 'none' : 'block'; - - CCSStylesheetRuleStyle('main','.l-verbose-section', 'display', - isVerbose ? 'block' : 'none'); - } - -script. - function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){ - /* returns the value of the element style of the rule in the stylesheet - * If no value is given, reads the value - * If value is given, the value is changed and returned - * If '' (empty string) is given, erases the value. - * The browser will apply the default one - * - * string stylesheet: part of the .css name to be recognized, e.g. 'default' - * string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td' - * string style: camelCase element style, e.g. 'fontSize' - * string value optional : the new value - */ - var CCSstyle = undefined, rules, sheet; - for(var m in document.styleSheets){ - sheet = document.styleSheets[m]; - if(sheet.href && sheet.href.indexOf(stylesheet) != -1){ - rules = sheet[document.all ? 'rules' : 'cssRules']; - for(var n in rules){ - console.log(rules[n].selectorText); - if(rules[n].selectorText == selectorText){ - CCSstyle = rules[n].style; - break; + + script. + function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){ + /* returns the value of the element style of the rule in the stylesheet + * If no value is given, reads the value + * If value is given, the value is changed and returned + * If '' (empty string) is given, erases the value. + * The browser will apply the default one + * + * string stylesheet: part of the .css name to be recognized, e.g. 'default' + * string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td' + * string style: camelCase element style, e.g. 'fontSize' + * string value optional : the new value + */ + var CCSstyle = undefined, rules, sheet; + for(var m in document.styleSheets){ + sheet = document.styleSheets[m]; + if(sheet.href && sheet.href.indexOf(stylesheet) != -1){ + rules = sheet[document.all ? 'rules' : 'cssRules']; + for(var n in rules){ + console.log(rules[n].selectorText); + if(rules[n].selectorText == selectorText){ + CCSstyle = rules[n].style; + break; + } + } + break; } } - break; - } + if(value == undefined) + return CCSstyle[style] + else + return CCSstyle[style] = value } - if(value == undefined) - return CCSstyle[style] - else - return CCSstyle[style] = value - } + //--------------------------------------------------------------------------------------------------------- +//- Converts the given project-relative path (like 'app/main.ts') +//- to a doc folder relative path (like 'quickstart/ts/app/main.ts') +//- by prefixing it with '/ts/'. If title is not given, +//- then the project-relative path is used, adjusted to remove numeric +//- file version qualifiers; e.g. 'styles.1.css' becomes 'styles.css'. +- var adjExampleProjPathAndTitle = function(ex/*:{filePath,title}*/) { +- // E.g. of a project relative path is 'app/main.ts' +- if (ex.title === null || ex.title === undefined) { +- // Title is not given so take it to be ex.filePath. +- // Title like styles.1.css or foo_1.dart? Then drop the '.1' or '_1' qualifier: +- var matches = ex.filePath.match(/^(.*)[\._]\d(\.\w+)$/); +- ex.title = matches ? matches[1] + matches[2] : ex.filePath; +- } +- ex.filePath = getExampleName() + '/' + _docsFor + '/' + ex.filePath; +- return ex; +- }; + +//- If the given path is project relative, then first convert it using +//- adjExampleProjPathAndTitle(ex). Then the path is adjusted to match +//- the documentation language. +- var adjustExamplePathAndTitle = function(ex/*:{filePath,title}*/) { +- // Not a doc folder relative path? Assume that it is app project relative. +- if(isProjRelDir(ex.filePath)) adjExampleProjPathAndTitle(ex); +- // Adjust doc folder relative paths if adjustment functions exist. +- if(adjustTsExamplePathForDart) ex.filePath = adjustTsExamplePathForDart(ex.filePath); +- if(adjustTsExampleTitleForDart) ex.title = adjustTsExampleTitleForDart(ex.title); +- return ex; +- }; + +//- Returns truthy iff path is example project relative. +- var isProjRelDir = function(path) { +- return !path.match(/\/(js|ts|dart)(-snippets)?\//) && !path.endsWith('e2e-spec.ts'); +- // Last conjunct handles case for shared project e2e test file like +- // cb-component-communication/e2e-spec.js (is shared between ts & dart) +- // TODO: generalize: compare start with getExampleName(); which needs to be fixed. +- }; + - var translatePath = function(filePath, region) { - filePath = filePath.trim(); - var regionPad = (region && region.length) ? '-' + region.toString() : ''; @@ -303,4 +457,4 @@ script. - } - } - } -- } \ No newline at end of file +- } diff --git a/public/_includes/_version-dropdown.jade b/public/_includes/_version-dropdown.jade index 38e167a1fd..d9ebe2b368 100644 --- a/public/_includes/_version-dropdown.jade +++ b/public/_includes/_version-dropdown.jade @@ -5,11 +5,23 @@ - var version = '' - var page = '' - +//- Replace _ underscores with . dots if current.path[2] - var version = current.path[2].replace(/\_+/gm, ".") -if current.path[4] +if current.path[6] + if public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]][current.path[5]][current.path[6]] + - var page = current.path[3] + '/' + current.path[4] + '/' + current.path[5] + '/' + current.path[6] + '/' + else + - var page = current.path[3] + '/' + current.path[4] + '/' + current.path[5] + '/' + current.path[6] + '.html' + +else if current.path[5] + if public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]][current.path[5]] + - var page = current.path[3] + '/' + current.path[4] + '/' + current.path[5] + '/' + else + - var page = current.path[3] + '/' + current.path[4] + '/' + current.path[5] + '.html' + +else if current.path[4] if public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]] - var page = current.path[3] + '/' + current.path[4] + '/' else @@ -21,43 +33,45 @@ else if current.path[3] else - var page = current.path[3] + '.html' - +//- VERSION TREE CREATOR MIXIN mixin tree(directory, urlPrefix, name, latest) - ul - for val, semvar in directory - if semvar !== '.git' && semvar !== '_data' - - var libVersion = (semvar == "latest") ? latest : semvar.replace(/\_+/gm, ".") - li #{name} #{libVersion} + for val, semvar in directory + if semvar !== '.git' && semvar !== '_data' + - var libVersion = (semvar == "latest") ? latest : semvar.replace(/\_+/gm, ".") + li #{name} #{libVersion} - +//- BUTTON TITLE GENERATION if language == 'ts' if version == "latest" - - var title = 'Angular 2 for TypeScript' + - var title = 'Angular for TypeScript' else - var title = 'Angular ' + version + ' for TypeScript' if language == 'js' if version == "latest" - - var title = 'Angular 2 for JavaScript' + - var title = 'Angular for JavaScript' else - var title = 'Angular ' + version + ' for JavaScript' if language == 'dart' if version == "latest" - - var title = 'Angular 2 for Dart' + - var title = 'Angular for Dart' else - var title = 'Angular ' + version + ' for Dart' +if current.path[4] !== 'change-log' + //- DROPDOWN BUTTON + nav.dropdown + button(aria-label="Select a version of Angular" md-button class="dropdown-button" ng-click="appCtrl.toggleVersionMenu($event)") #{title} + div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu") - -nav.hero-subtitle.text-subhead.dropdown - button(aria-label="Select a version of Angular" md-button class="dropdown-button" ng-click="appCtrl.toggleVersionMenu($event)") #{title} - div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu") - - - div(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''") - mixin tree(public.docs.ts, "/docs/ts", "Angular 2 for TypeScript") - mixin tree(public.docs.js, "/docs/js", "Angular 2 for JavaScript") - mixin tree(public.docs.dart, "/docs/dart", "Angular 2 for Dart") + //- DROPDOWN MENU + ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''") + mixin tree(public.docs.ts, "/docs/ts", "Angular for TypeScript") + mixin tree(public.docs.js, "/docs/js", "Angular for JavaScript") + //- Disable cross-language link for API entry pages (but keep for top API search page): + - var isApiEntryPage = current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]] + if public.docs.dart && !isApiEntryPage + mixin tree(public.docs.dart, "/docs/dart", "Angular for Dart") diff --git a/public/_layout.jade b/public/_layout.jade index aef7728caa..6f01183b22 100644 --- a/public/_layout.jade +++ b/public/_layout.jade @@ -1,22 +1,33 @@ -doctype html public -html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework") - head - != partial("/_includes/_head-include") +if jade2ng + if hero == 'home' + != partial("/_includes/_hero-home") + else + != partial("/_includes/_hero") + != partial("../_includes/_banner") + - var format = autoformat ? 'docs-content' : '' + article(class="l-content #{format}") + != yield +else + doctype html public + html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework") + head + != partial("/_includes/_head-include") - body.ng-cloak.l-offset-nav(ng-controller="AppCtrl as appCtrl") - != partial("/_includes/_main-nav") + body.ng-cloak.l-offset-nav(ng-controller="AppCtrl as appCtrl") + != partial("/_includes/_main-nav") - - if hero == 'home' - != partial("/_includes/_hero-home") - else - != partial("/_includes/_hero") + + if hero == 'home' + != partial("/_includes/_hero-home") + else + != partial("/_includes/_hero") - - var format = autoformat ? 'docs-content' : '' + - var format = autoformat ? 'docs-content' : '' - article(class="l-content #{format}") - != yield + article(class="l-content #{format}") + != yield - != partial("/_includes/_footer") - != partial("/_includes/_scripts-include") \ No newline at end of file + != partial("/_includes/_footer") + != partial("/_includes/_scripts-include") + != partial("/_includes/_scripts-minimum") diff --git a/public/about/index.jade b/public/about/index.jade index b6b429b178..1150e51a56 100644 --- a/public/about/index.jade +++ b/public/about/index.jade @@ -22,7 +22,7 @@ for person, name in bios if person.type == type .c3 - md-card(biocard class="bio-card" website="#{person.website}" twitter="#{person.twitter}" pic="#{person.picture}" bio="#{person.bio}" name="#{person.name}") + md-card(biocard class="bio-card" website=person.website twitter=person.twitter pic=person.picture bio=person.bio name=person.name) header image(src="#{person.picture}" alt="#person.name") diff --git a/public/cardboard/index.jade b/public/cardboard/index.jade index 57a8b0bbb6..a0a76d0e80 100644 --- a/public/cardboard/index.jade +++ b/public/cardboard/index.jade @@ -30,7 +30,7 @@ style(rel='stylesheet'). li. Best Technology Demonstration
- Huge hint: Angular 2 scores points + Huge hint: Angular scores points p Don’t have Cardboard and want one? Check out: p.text-center diff --git a/public/contribute.jade b/public/contribute.jade index c15dda4470..994d46a36d 100644 --- a/public/contribute.jade +++ b/public/contribute.jade @@ -3,11 +3,11 @@ p We'd love for you to contribute to our source code and to make Angular projects even better. .l-sub-section - h3 Angular 2 + h3 Angular - p Angular 2, now in beta, is a next generation mobile and desktop application development platform. + p Angular is a next generation mobile and desktop application development platform. - a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) Contribute to Angular 2 + a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) Contribute to Angular .l-sub-section h3 Angular for JavaScript or Dart @@ -23,7 +23,7 @@ p Our goal is to deliver a lean, lightweight set of Angular-based UI elements that implement the material design specification for use in Angular single-page applications (SPAs). - a(href="https://github.com/angular/material/blob/master/docs/guides/CONTRIBUTING.md" class="button" md-button) Contribute to Angular Material + a(href="https://github.com/angular/material/blob/master/.github/CONTRIBUTING.md" class="button" md-button) Contribute to Angular Material .l-sub-section h3 AngularFire diff --git a/public/docs/ImageGuide.pdf b/public/docs/ImageGuide.pdf new file mode 100644 index 0000000000..21280dce88 Binary files /dev/null and b/public/docs/ImageGuide.pdf differ diff --git a/public/docs/README.md b/public/docs/README.md deleted file mode 100644 index 95d331b115..0000000000 --- a/public/docs/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Why the _fragments dir is checked in - -Within this repo files generated as a result of shredding the `_examples` dir ( the contents of the `_fragments` dir) are checked in so that we can avoid running the -shredder over the entire `_examples` dir each time someone refreshes the repo ( the `shred-full` gulp task). -The gulp `serve-and-watch` shredder is only a �partial� shredder. It only shred�s files in directories changed during -the current session. diff --git a/public/docs/_data.json b/public/docs/_data.json index daade7e3ea..121e4db32f 100644 --- a/public/docs/_data.json +++ b/public/docs/_data.json @@ -3,17 +3,5 @@ "title": "Angular Docs", "subtitle": "Choose a language for Angular", "layout": "../_layout" - }, - - "search": { - "title": "Docs Search Results", - "layout": "../_layout" - }, - - "styleguide": { - "title": "Docs Style Guide", - "subtitle": "Design & Layout Patterns For Documentation", - "layout": "../_layout", - "autoformat": "true" } } diff --git a/public/docs/_examples/.gitignore b/public/docs/_examples/.gitignore index 7a15251d4f..3fb5ae8562 100644 --- a/public/docs/_examples/.gitignore +++ b/public/docs/_examples/.gitignore @@ -1,10 +1,18 @@ -styles.css -typings -typings.json -*.js.map -package.json -karma.conf.js -karma-test-shim.js -tsconfig.json -npm-debug*. -**/protractor.config.js +# _boilerplate files +!_boilerplate/* +*/*/src/styles.css +*/*/src/systemjs-angular-loader.js +*/*/src/systemjs.config.js +*/*/src/tsconfig.json +*/*/bs-config.e2e.json +*/*/bs-config.json +*/*/package.json +*/*/tslint.json + +# example files +_test-output +protractor-helpers.js +*/e2e-spec.js +**/ts/**/*.js +**/js-es6*/**/*.js +**/ts-snippets/**/*.js diff --git a/public/docs/_examples/_boilerplate/bs-config.e2e.json b/public/docs/_examples/_boilerplate/bs-config.e2e.json new file mode 100644 index 0000000000..24570dbcc9 --- /dev/null +++ b/public/docs/_examples/_boilerplate/bs-config.e2e.json @@ -0,0 +1,14 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "src", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": { + "0": null + } + } +} diff --git a/public/docs/_examples/_boilerplate/bs-config.json b/public/docs/_examples/_boilerplate/bs-config.json new file mode 100644 index 0000000000..4e58595267 --- /dev/null +++ b/public/docs/_examples/_boilerplate/bs-config.json @@ -0,0 +1,8 @@ +{ + "server": { + "baseDir": "src", + "routes": { + "/node_modules": "node_modules" + } + } +} diff --git a/public/docs/_examples/_boilerplate/example-config.json b/public/docs/_examples/_boilerplate/example-config.json new file mode 100644 index 0000000000..ff5403e6ca --- /dev/null +++ b/public/docs/_examples/_boilerplate/example-config.json @@ -0,0 +1,4 @@ +{ + "build": "build", + "run": "serve" +} diff --git a/public/docs/_examples/_boilerplate/package.json b/public/docs/_examples/_boilerplate/package.json new file mode 100644 index 0000000000..2e4bc19f91 --- /dev/null +++ b/public/docs/_examples/_boilerplate/package.json @@ -0,0 +1,44 @@ +{ + "name": "angular-examples", + "version": "1.0.0", + "private": true, + "description": "Example package.json, only contains needed scripts for examples. See _examples/package.json for master package.json.", + "scripts": { + "build": "tsc -p src/", + "build:watch": "tsc -p src/ -w", + "build:e2e": "tsc -p e2e/", + "serve": "lite-server -c=bs-config.json", + "serve:e2e": "lite-server -c=bs-config.e2e.json", + "prestart": "npm run build", + "start": "concurrently \"npm run build:watch\" \"npm run serve\"", + "pree2e": "webdriver-manager update && npm run build:e2e", + "e2e": "concurrently \"npm run serve:e2e\" \"npm run protractor\" --kill-others --success first", + "protractor": "protractor protractor.config.js", + "pretest": "npm run build", + "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"", + "pretest:once": "npm run build", + "test:once": "karma start karma.conf.js --single-run", + "lint": "tslint ./src/**/*.ts -t verbose", + + "build:upgrade": "tsc", + "serve:upgrade": "http-server", + "build:cli": "ng build --no-progress", + "serve:cli": "http-server dist/", + "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js", + "serve:aot": "lite-server -c bs-config.aot.json", + "start:webpack": "webpack-dev-server --inline --progress --port 8080", + "test:webpack": "karma start karma.webpack.conf.js", + "build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --bail", + "build:babel": "babel src -d src --extensions \".es6\" --source-maps", + "copy-dist-files": "node ./copy-dist-files.js", + "i18n": "ng-xi18n" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": {}, + "devDependencies": { + "angular-cli": "^1.0.0-rc.0" + }, + "repository": {} +} diff --git a/public/docs/_examples/_boilerplate/plnkr.json b/public/docs/_examples/_boilerplate/plnkr.json new file mode 100644 index 0000000000..5fb55b50ad --- /dev/null +++ b/public/docs/_examples/_boilerplate/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "QuickStart", + "basePath": "src/", + "files": [ + "app/app.component.ts", + "index.html" + ], + "open": "app/app.component.ts", + "tags": ["quickstart"] +} diff --git a/public/docs/_examples/_boilerplate/src/styles.css b/public/docs/_examples/_boilerplate/src/styles.css new file mode 100644 index 0000000000..d81835d0cd --- /dev/null +++ b/public/docs/_examples/_boilerplate/src/styles.css @@ -0,0 +1,116 @@ +/* #docregion , quickstart, toh */ +/* Master Styles */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +h2, h3 { + color: #444; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +/* #enddocregion quickstart */ +body, input[text], button { + color: #888; + font-family: Cambria, Georgia; +} +/* #enddocregion toh */ +a { + cursor: pointer; + cursor: hand; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} + +/* Navigation link styles */ +nav a { + padding: 5px 10px; + text-decoration: none; + margin-right: 10px; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} + +/* items class */ +.items { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 24em; +} +.items li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.items li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.items li.selected { + background-color: #CFD8DC; + color: white; +} +.items li.selected:hover { + background-color: #BBD8DC; +} +.items .text { + position: relative; + top: -3px; +} +.items .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +/* #docregion toh */ +/* everywhere else */ +* { + font-family: Arial, Helvetica, sans-serif; +} diff --git a/public/docs/_examples/_boilerplate/src/systemjs-angular-loader.js b/public/docs/_examples/_boilerplate/src/systemjs-angular-loader.js new file mode 100644 index 0000000000..8b1005444e --- /dev/null +++ b/public/docs/_examples/_boilerplate/src/systemjs-angular-loader.js @@ -0,0 +1,49 @@ +var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm; +var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; +var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; + +module.exports.translate = function(load){ + if (load.source.indexOf('moduleId') != -1) return load; + + var url = document.createElement('a'); + url.href = load.address; + + var basePathParts = url.pathname.split('/'); + + basePathParts.pop(); + var basePath = basePathParts.join('/'); + + var baseHref = document.createElement('a'); + baseHref.href = this.baseURL; + baseHref = baseHref.pathname; + + if (!baseHref.startsWith('/base/')) { // it is not karma + basePath = basePath.replace(baseHref, ''); + } + + load.source = load.source + .replace(templateUrlRegex, function(match, quote, url){ + var resolvedUrl = url; + + if (url.startsWith('.')) { + resolvedUrl = basePath + url.substr(1); + } + + return 'templateUrl: "' + resolvedUrl + '"'; + }) + .replace(stylesRegex, function(match, relativeUrls) { + var urls = []; + + while ((match = stringRegex.exec(relativeUrls)) !== null) { + if (match[2].startsWith('.')) { + urls.push('"' + basePath + match[2].substr(1) + '"'); + } else { + urls.push('"' + match[2] + '"'); + } + } + + return "styleUrls: [" + urls.join(', ') + "]"; + }); + + return load; +}; diff --git a/public/docs/_examples/_boilerplate/src/systemjs.config.js b/public/docs/_examples/_boilerplate/src/systemjs.config.js new file mode 100644 index 0000000000..ea7a3879ac --- /dev/null +++ b/public/docs/_examples/_boilerplate/src/systemjs.config.js @@ -0,0 +1,52 @@ +/** + * System configuration for Angular samples + * Adjust as necessary for your application needs. + */ +(function (global) { + System.config({ + paths: { + // paths serve as alias + 'npm:': 'node_modules/' + }, + // map tells the System loader where to look for things + map: { + // our app is within the app folder + 'app': 'app', + + // angular bundles + '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js', + '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js', + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', + + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + app: { + main: './main.js', + defaultExtension: 'js', + meta: { + './*.js': { + loader: 'systemjs-angular-loader.js' + } + } + }, + rxjs: { + defaultExtension: 'js' + } + } + }); +})(this); diff --git a/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js b/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js new file mode 100644 index 0000000000..5774fd8187 --- /dev/null +++ b/public/docs/_examples/_boilerplate/src/systemjs.config.web.build.js @@ -0,0 +1,96 @@ +/** + * WEB VERSION FOR CURRENT ANGULAR BUILD + * (based on systemjs.config.js in angular.io) + * System configuration for Angular samples + * Adjust as necessary for your application needs. + * + * UNTESTED ! + */ +(function (global) { + System.config({ + // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER + transpiler: 'ts', + typescriptOptions: { + // Copy of compiler options in standard tsconfig.json + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + }, + meta: { + 'typescript': { + "exports": "ts" + } + }, + paths: { + // paths serve as alias + 'npm:': 'https://unpkg.com/', + 'ng:': 'https://cdn.rawgit.com/angular/' + }, + // map tells the System loader where to look for things + map: { + // our app is within the app folder + 'app': 'app', + + // angular bundles + '@angular/animations': 'ng:animations-builds/master/bundles/animations.umd.js', + '@angular/animations/browser': 'ng:animations-builds/master/bundles/animations-browser.umd.js', + '@angular/core': 'ng:core-builds/master/bundles/core.umd.js', + '@angular/common': 'ng:common-builds/master/bundles/common.umd.js', + '@angular/compiler': 'ng:compiler-builds/master/bundles/compiler.umd.js', + '@angular/platform-browser': 'ng:platform-browser-builds/master/bundles/platform-browser.umd.js', + '@angular/platform-browser/animations': 'ng:animations-builds/master/bundles/platform-browser-animations.umd.js', + '@angular/platform-browser-dynamic': 'ng:platform-browser-dynamic-builds/master/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'ng:http-builds/master/bundles/http.umd.js', + '@angular/router': 'ng:router-builds/master/bundles/router.umd.js', + '@angular/router/upgrade': 'ng:router-builds/master/bundles/router-upgrade.umd.js', + '@angular/forms': 'ng:forms-builds/master/bundles/forms.umd.js', + '@angular/upgrade': 'ng:upgrade-builds/master/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'ng:upgrade-builds/master/bundles/upgrade-static.umd.js', + + // angular testing umd bundles (overwrite the shim mappings) + '@angular/core/testing': 'ng:core-builds/master/bundles/core-testing.umd.js', + '@angular/common/testing': 'ng:common-builds/master/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'ng:compiler-builds/master/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'ng:platform-browser-builds/master/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'ng:platform-browser-dynamic-builds/master/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'ng:http-builds/master/bundles/http-testing.umd.js', + '@angular/router/testing': 'ng:router-builds/master/bundles/router-testing.umd.js', + '@angular/forms/testing': 'ng:forms-builds/master/bundles/forms-testing.umd.js', + + // other libraries + 'rxjs': 'npm:rxjs@5.0.1', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js', + 'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js', + 'typescript': 'npm:typescript@2.2.1/lib/typescript.js', + + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + app: { + main: './main.ts', + defaultExtension: 'ts', + meta: { + './*.ts': { + loader: 'systemjs-angular-loader.js' + } + } + }, + rxjs: { + defaultExtension: 'js' + } + } + }); + +})(this); + +/* +Copyright 2016 Google Inc. All Rights Reserved. +Use of this source code is governed by an MIT-style license that +can be found in the LICENSE file at http://angular.io/license +*/ diff --git a/public/docs/_examples/_boilerplate/src/systemjs.config.web.js b/public/docs/_examples/_boilerplate/src/systemjs.config.web.js new file mode 100644 index 0000000000..376fcdde8a --- /dev/null +++ b/public/docs/_examples/_boilerplate/src/systemjs.config.web.js @@ -0,0 +1,83 @@ +/** + * WEB ANGULAR VERSION + * (based on systemjs.config.js in angular.io) + * System configuration for Angular samples + * Adjust as necessary for your application needs. + */ +(function (global) { + System.config({ + // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER + transpiler: 'ts', + typescriptOptions: { + // Copy of compiler options in standard tsconfig.json + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + }, + meta: { + 'typescript': { + "exports": "ts" + } + }, + paths: { + // paths serve as alias + 'npm:': 'https://unpkg.com/' + }, + // map tells the System loader where to look for things + map: { + // our app is within the app folder + 'app': 'app', + + // angular bundles + '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js', + '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js', + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', + + // other libraries + 'rxjs': 'npm:rxjs@5.0.1', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js', + 'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js', + 'typescript': 'npm:typescript@2.2.1/lib/typescript.js', + + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + app: { + main: './main.ts', + defaultExtension: 'ts', + meta: { + './*.ts': { + loader: 'systemjs-angular-loader.js' + } + } + }, + rxjs: { + defaultExtension: 'js' + } + } + }); + +})(this); + +/* +Copyright 2016 Google Inc. All Rights Reserved. +Use of this source code is governed by an MIT-style license that +can be found in the LICENSE file at http://angular.io/license +*/ diff --git a/public/docs/_examples/_boilerplate/src/tsconfig.json b/public/docs/_examples/_boilerplate/src/tsconfig.json new file mode 100644 index 0000000000..05839ec2ff --- /dev/null +++ b/public/docs/_examples/_boilerplate/src/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*", + "**/*-aot.ts" + ] +} diff --git a/public/docs/_examples/_boilerplate/tslint.json b/public/docs/_examples/_boilerplate/tslint.json new file mode 100644 index 0000000000..276453f4f5 --- /dev/null +++ b/public/docs/_examples/_boilerplate/tslint.json @@ -0,0 +1,93 @@ +{ + "rules": { + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "eofline": true, + "forin": true, + "indent": [ + true, + "spaces" + ], + "label-position": true, + "label-undefined": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + "static-before-instance", + "variables-before-functions" + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-key": true, + "no-duplicate-variable": true, + "no-empty": false, + "no-eval": true, + "no-inferrable-types": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unused-expression": true, + "no-unused-variable": true, + "no-unreachable": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ] + } +} diff --git a/public/docs/_examples/animations/e2e-spec.ts b/public/docs/_examples/animations/e2e-spec.ts new file mode 100644 index 0000000000..4fba7ec475 --- /dev/null +++ b/public/docs/_examples/animations/e2e-spec.ts @@ -0,0 +1,351 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { logging, promise } from 'selenium-webdriver'; + +/** + * The tests here basically just checking that the end styles + * of each animation are in effect. + * + * Relies on the Angular testability only becoming stable once + * animation(s) have finished. + * + * Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations + * but they're not supported in Chrome at the moment. The upcoming nganimate polyfill + * may also add some introspection support. + */ +describe('Animation Tests', () => { + + const INACTIVE_COLOR = 'rgba(238, 238, 238, 1)'; + const ACTIVE_COLOR = 'rgba(207, 216, 220, 1)'; + const NO_TRANSFORM_MATRIX_REGEX = /matrix\(1,\s*0,\s*0,\s*1,\s*0,\s*0\)/; + + beforeEach(() => { + browser.get(''); + }); + + describe('basic states', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-basic')); + }); + + it('animates between active and inactive', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('styles inline in transitions', () => { + + let host: ElementFinder; + + beforeEach(function() { + host = element(by.css('hero-list-inline-styles')); + }); + + it('are not kept after animation', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('combined transition syntax', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-combined-transitions')); + }); + + it('animates between active and inactive', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('two-way transition syntax', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-twoway')); + }); + + it('animates between active and inactive', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('enter & leave', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-enter-leave')); + }); + + it('adds and removes element', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('enter & leave & states', () => { + + let host: ElementFinder; + + beforeEach(function() { + host = element(by.css('hero-list-enter-leave-states')); + }); + + it('adds and removes and animates between active and inactive', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.1); + + li.click(); + browser.driver.sleep(300); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('auto style calc', () => { + + let host: ElementFinder; + + beforeEach(function() { + host = element(by.css('hero-list-auto')); + }); + + it('adds and removes element', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('height')).toBe('50px'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('different timings', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-timings')); + }); + + it('adds and removes element', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + expect(li.getCssValue('opacity')).toMatch('1'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('multiple keyframes', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-multistep')); + }); + + it('adds and removes element', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + expect(li.getCssValue('opacity')).toMatch('1'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('parallel groups', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-groups')); + }); + + it('adds and removes element', () => { + addInactiveHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + expect(li.getCssValue('opacity')).toMatch('1'); + + removeHero(700); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('adding active heroes', () => { + + let host: ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-basic')); + }); + + it('animates between active and inactive', () => { + addActiveHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + browser.driver.sleep(300); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + }); + }); + + describe('callbacks', () => { + it('fires a callback on start and done', () => { + addActiveHero(); + browser.manage().logs().get(logging.Type.BROWSER) + .then((logs: logging.Entry[]) => { + const animationMessages = logs.filter((log) => { + return log.message.indexOf('Animation') !== -1 ? true : false; + }); + + expect(animationMessages.length).toBeGreaterThan(0); + }); + }); + }); + + function addActiveHero(sleep?: number) { + sleep = sleep || 500; + element(by.buttonText('Add active hero')).click(); + browser.driver.sleep(sleep); + } + + function addInactiveHero(sleep?: number) { + sleep = sleep || 500; + element(by.buttonText('Add inactive hero')).click(); + browser.driver.sleep(sleep); + } + + function removeHero(sleep?: number) { + sleep = sleep || 500; + element(by.buttonText('Remove hero')).click(); + browser.driver.sleep(sleep); + } + + function getScaleX(el: ElementFinder) { + return Promise.all([ + getBoundingClientWidth(el), + getOffsetWidth(el) + ]).then(function(promiseResolutions) { + let clientWidth = promiseResolutions[0]; + let offsetWidth = promiseResolutions[1]; + return clientWidth / offsetWidth; + }); + } + + function getBoundingClientWidth(el: ElementFinder): promise.Promise { + return browser.executeScript( + 'return arguments[0].getBoundingClientRect().width', + el.getWebElement() + ); + } + + function getOffsetWidth(el: ElementFinder): promise.Promise { + return browser.executeScript( + 'return arguments[0].offsetWidth', + el.getWebElement() + ); + } +}); diff --git a/public/docs/_examples/architecture/ts/.gitignore b/public/docs/_examples/animations/ts/.gitignore similarity index 100% rename from public/docs/_examples/architecture/ts/.gitignore rename to public/docs/_examples/animations/ts/.gitignore diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/example-config.json b/public/docs/_examples/animations/ts/example-config.json similarity index 100% rename from public/docs/_examples/cb-a1-a2-quick-reference/ts/example-config.json rename to public/docs/_examples/animations/ts/example-config.json diff --git a/public/docs/_examples/animations/ts/plnkr.json b/public/docs/_examples/animations/ts/plnkr.json new file mode 100644 index 0000000000..f047395e7f --- /dev/null +++ b/public/docs/_examples/animations/ts/plnkr.json @@ -0,0 +1,8 @@ +{ + "description": "Angular Animations", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ] +} diff --git a/public/docs/_examples/animations/ts/src/app/app.module.ts b/public/docs/_examples/animations/ts/src/app/app.module.ts new file mode 100644 index 0000000000..0773357c58 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/app.module.ts @@ -0,0 +1,38 @@ +// #docregion animations-module +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +// #enddocregion animations-module + +import { HeroTeamBuilderComponent } from './hero-team-builder.component'; +import { HeroListBasicComponent } from './hero-list-basic.component'; +import { HeroListInlineStylesComponent } from './hero-list-inline-styles.component'; +import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component'; +import { HeroListEnterLeaveStatesComponent } from './hero-list-enter-leave-states.component'; +import { HeroListCombinedTransitionsComponent } from './hero-list-combined-transitions.component'; +import { HeroListTwowayComponent } from './hero-list-twoway.component'; +import { HeroListAutoComponent } from './hero-list-auto.component'; +import { HeroListGroupsComponent } from './hero-list-groups.component'; +import { HeroListMultistepComponent } from './hero-list-multistep.component'; +import { HeroListTimingsComponent } from './hero-list-timings.component'; + +// #docregion animation-module +@NgModule({ + imports: [ BrowserModule, BrowserAnimationsModule ], + // #enddocregion animation-module + declarations: [ + HeroTeamBuilderComponent, + HeroListBasicComponent, + HeroListInlineStylesComponent, + HeroListCombinedTransitionsComponent, + HeroListTwowayComponent, + HeroListEnterLeaveComponent, + HeroListEnterLeaveStatesComponent, + HeroListAutoComponent, + HeroListTimingsComponent, + HeroListMultistepComponent, + HeroListGroupsComponent + ], + bootstrap: [ HeroTeamBuilderComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-auto.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-auto.component.ts new file mode 100644 index 0000000000..84b25c05de --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-auto.component.ts @@ -0,0 +1,47 @@ +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-auto', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + + /* When the element leaves (transition "in => void" occurs), + * get the element's current computed height and animate + * it down to 0. + */ + // #docregion animationdef + animations: [ + trigger('shrinkOut', [ + state('in', style({height: '*'})), + transition('* => void', [ + style({height: '*'}), + animate(250, style({height: 0})) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListAutoComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-basic.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-basic.component.ts new file mode 100644 index 0000000000..76d5ba686c --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-basic.component.ts @@ -0,0 +1,70 @@ +// #docplaster +// #docregion +// #docregion imports +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; +// #enddocregion imports + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-basic', + // #enddocregion + /* The click event calls hero.toggleState(), which + * causes the state of that hero to switch from + * active to inactive or vice versa. + */ + // #docregion + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + // #enddocregion + /** + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define animations for transitioning between the states, + * one in each direction + */ + // #docregion + // #docregion animationdef + animations: [ + trigger('heroState', [ + // #docregion states + state('inactive', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })), + state('active', style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.1)' + })), + // #enddocregion states + // #docregion transitions + transition('inactive => active', animate('100ms ease-in')), + transition('active => inactive', animate('100ms ease-out')) + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListBasicComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-combined-transitions.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-combined-transitions.component.ts new file mode 100644 index 0000000000..fc654cbcb5 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-combined-transitions.component.ts @@ -0,0 +1,59 @@ +// #docregion +// #docregion imports +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; +// #enddocregion imports + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-combined-transitions', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + /* + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define an animated transition between these two + * states, in *both* directions. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })), + state('active', style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.1)' + })), + // #docregion transitions + transition('inactive => active, active => inactive', + animate('100ms ease-out')) + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListCombinedTransitionsComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-enter-leave-states.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-enter-leave-states.component.ts new file mode 100644 index 0000000000..c01e182e8b --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-enter-leave-states.component.ts @@ -0,0 +1,63 @@ +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-enter-leave-states', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + /* The elements here have two possible states based + * on the hero state, "active", or "inactive". We animate + * six transitions: Between the two states in both directions, + * and between each state and void. With this we can animate + * the enter and leave of elements differently based on which + * state they are in when they are added and removed. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style({transform: 'translateX(0) scale(1)'})), + state('active', style({transform: 'translateX(0) scale(1.1)'})), + transition('inactive => active', animate('100ms ease-in')), + transition('active => inactive', animate('100ms ease-out')), + transition('void => inactive', [ + style({transform: 'translateX(-100%) scale(1)'}), + animate(100) + ]), + transition('inactive => void', [ + animate(100, style({transform: 'translateX(100%) scale(1)'})) + ]), + transition('void => active', [ + style({transform: 'translateX(0) scale(0)'}), + animate(200) + ]), + transition('active => void', [ + animate(200, style({transform: 'translateX(0) scale(0)'})) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListEnterLeaveStatesComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-enter-leave.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-enter-leave.component.ts new file mode 100644 index 0000000000..f27b5f10e1 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-enter-leave.component.ts @@ -0,0 +1,51 @@ +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-enter-leave', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. The element enters from + * the left and leaves to the right using translateX. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({transform: 'translateX(0)'})), + transition('void => *', [ + style({transform: 'translateX(-100%)'}), + animate(100) + ]), + transition('* => void', [ + animate(100, style({transform: 'translateX(100%)'})) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListEnterLeaveComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-groups.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-groups.component.ts new file mode 100644 index 0000000000..12a57292f7 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-groups.component.ts @@ -0,0 +1,80 @@ +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition, + group +} from '@angular/animations'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-groups', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['./hero-list.component.css'], + styles: [` + li { + padding: 0 !important; + text-align: center; + } + `], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. + * + * The transitions have *parallel group* that allow + * animating several properties at the same time but + * with different timing configurations. On enter + * (void => *) we start the opacity animation 0.1s + * earlier than the translation/width animation. + * On leave (* => void) we do the opposite - + * the translation/width animation begins immediately + * and the opacity animation 0.1s later. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({width: 120, transform: 'translateX(0)', opacity: 1})), + transition('void => *', [ + style({width: 10, transform: 'translateX(50px)', opacity: 0}), + group([ + animate('0.3s 0.1s ease', style({ + transform: 'translateX(0)', + width: 120 + })), + animate('0.3s ease', style({ + opacity: 1 + })) + ]) + ]), + transition('* => void', [ + group([ + animate('0.3s ease', style({ + transform: 'translateX(50px)', + width: 10 + })), + animate('0.3s 0.2s ease', style({ + opacity: 0 + })) + ]) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListGroupsComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-inline-styles.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-inline-styles.component.ts new file mode 100644 index 0000000000..ed1bdb7646 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-inline-styles.component.ts @@ -0,0 +1,60 @@ +// #docregion +// #docregion imports +import { + Component, + Input, +} from '@angular/core'; +import { + trigger, + style, + animate, + transition +} from '@angular/animations'; +// #enddocregion imports + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-inline-styles', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + /** + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define an animation for the inactive => active transition. + * This animation has no end styles, but only styles that are + * defined inline inside the transition and thus are only kept + * as long as the animation is running. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + // #docregion transitions + transition('inactive => active', [ + style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.3)' + }), + animate('80ms ease-in', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })) + ]), + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListInlineStylesComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-multistep.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-multistep.component.ts new file mode 100644 index 0000000000..4e57896de5 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-multistep.component.ts @@ -0,0 +1,71 @@ +import { + Component, + Input, +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition, + keyframes, + AnimationEvent +} from '@angular/animations'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-multistep', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. Each transition is + * defined in terms of multiple keyframes, to give it + * a bounce effect. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({transform: 'translateX(0)'})), + transition('void => *', [ + animate(300, keyframes([ + style({opacity: 0, transform: 'translateX(-100%)', offset: 0}), + style({opacity: 1, transform: 'translateX(15px)', offset: 0.3}), + style({opacity: 1, transform: 'translateX(0)', offset: 1.0}) + ])) + ]), + transition('* => void', [ + animate(300, keyframes([ + style({opacity: 1, transform: 'translateX(0)', offset: 0}), + style({opacity: 1, transform: 'translateX(-15px)', offset: 0.7}), + style({opacity: 0, transform: 'translateX(100%)', offset: 1.0}) + ])) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListMultistepComponent { + @Input() heroes: Heroes; + + animationStarted(event: AnimationEvent) { + console.warn('Animation started: ', event); + } + + animationDone(event: AnimationEvent) { + console.warn('Animation done: ', event); + } +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-timings.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-timings.component.ts new file mode 100644 index 0000000000..3218609b4a --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-timings.component.ts @@ -0,0 +1,58 @@ +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-timings', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['./hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. The element enters from + * the left and leaves to the right using translateX, + * and fades in/out using opacity. We use different easings + * for enter and leave. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({opacity: 1, transform: 'translateX(0)'})), + transition('void => *', [ + style({ + opacity: 0, + transform: 'translateX(-100%)' + }), + animate('0.2s ease-in') + ]), + transition('* => void', [ + animate('0.2s 10 ease-out', style({ + opacity: 0, + transform: 'translateX(100%)' + })) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListTimingsComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list-twoway.component.ts b/public/docs/_examples/animations/ts/src/app/hero-list-twoway.component.ts new file mode 100644 index 0000000000..46d0c64a68 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list-twoway.component.ts @@ -0,0 +1,58 @@ +// #docregion +// #docregion imports +import { + Component, + Input +} from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; +// #enddocregion imports + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-list-twoway', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['./hero-list.component.css'], + /* + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define an animated transition between these two + * states, in *both* directions. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })), + state('active', style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.1)' + })), + // #docregion transitions + transition('inactive <=> active', animate('100ms ease-out')) + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListTwowayComponent { + @Input() heroes: Heroes; +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-list.component.css b/public/docs/_examples/animations/ts/src/app/hero-list.component.css new file mode 100644 index 0000000000..b256521e49 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-list.component.css @@ -0,0 +1,27 @@ +ul { + list-style-type: none; + padding: 0; +} + +li { + display: block; + width: 120px; + line-height: 50px; + padding: 0 10px; + box-sizing: border-box; + background-color: #eee; + border-radius: 4px; + margin: 10px; + cursor: pointer; + overflow: hidden; + white-space: nowrap; +} + +.active { + background-color: #cfd8dc; + transform: scale(1.1); +} +.inactive { + background-color: #eee; + transform: scale(1); +} diff --git a/public/docs/_examples/animations/ts/src/app/hero-team-builder.component.ts b/public/docs/_examples/animations/ts/src/app/hero-team-builder.component.ts new file mode 100644 index 0000000000..e5413be50e --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero-team-builder.component.ts @@ -0,0 +1,94 @@ +import { Component } from '@angular/core'; + +import { Heroes } from './hero.service'; + +@Component({ + selector: 'hero-team-builder', + template: ` +
+ + + +
+
+
+

Basic State

+

Switch between active/inactive on click.

+ +
+
+

Styles inline in transitions

+

Animated effect on click, no persistend end styles.

+ +
+
+

Combined transition syntax

+

Switch between active/inactive on click. Define just one transition used in both directions.

+ +
+
+

Two-way transition syntax

+

Switch between active/inactive on click. Define just one transition used in both directions using the <=> syntax.

+ +
+
+

Enter & Leave

+

Enter and leave animations using the void state.

+ +
+
+
+
+

Enter & Leave & States

+

+ Enter and leave animations combined with active/inactive state animations. + Different enter and leave transitions depending on state. +

+ +
+
+

Auto Style Calc

+

Leave animation from the current computed height using the auto-style value *.

+ +
+
+

Different Timings

+

Enter and leave animations with different easings, ease-in for enter, ease-out for leave.

+ +
+
+

Multiple Keyframes

+

Enter and leave animations with three keyframes in each, to give the transition some bounce.

+ +
+
+

Parallel Groups

+

Enter and leave animations with multiple properties animated in parallel with different timings.

+ +
+
+ `, + styles: [` + .buttons { + text-align: center; + } + button { + padding: 1.5em 3em; + } + .columns { + display: flex; + flex-direction: row; + } + .column { + flex: 1; + padding: 10px; + } + .column p { + min-height: 6em; + } + `], + providers: [Heroes] +}) +export class HeroTeamBuilderComponent { + constructor(private heroes: Heroes) { } +} diff --git a/public/docs/_examples/animations/ts/src/app/hero.service.ts b/public/docs/_examples/animations/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..6bdeb5a512 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/app/hero.service.ts @@ -0,0 +1,60 @@ +import { Injectable } from '@angular/core'; + +class Hero { + constructor(public name: string, + public state = 'inactive') { + } + + toggleState() { + this.state = (this.state === 'active' ? 'inactive' : 'active'); + } +} + +let ALL_HEROES = [ + 'Windstorm', + 'RubberMan', + 'Bombasto', + 'Magneta', + 'Dynama', + 'Narco', + 'Celeritas', + 'Dr IQ', + 'Magma', + 'Tornado', + 'Mr. Nice' +].map(name => new Hero(name)); + +@Injectable() +export class Heroes implements Iterable { + + currentHeroes: Hero[] = []; + + [Symbol.iterator]() { + return this.currentHeroes.values(); + } + + canAdd() { + return this.currentHeroes.length < ALL_HEROES.length; + } + + canRemove() { + return this.currentHeroes.length > 0; + } + + addActive() { + let hero = ALL_HEROES[this.currentHeroes.length]; + hero.state = 'active'; + this.currentHeroes.push(hero); + } + + addInactive() { + let hero = ALL_HEROES[this.currentHeroes.length]; + hero.state = 'inactive'; + this.currentHeroes.push(hero); + } + + remove() { + this.currentHeroes.splice(this.currentHeroes.length - 1, 1); + } + +} diff --git a/public/docs/_examples/animations/ts/src/index.html b/public/docs/_examples/animations/ts/src/index.html new file mode 100644 index 0000000000..6c4a13adb2 --- /dev/null +++ b/public/docs/_examples/animations/ts/src/index.html @@ -0,0 +1,34 @@ + + + + + Animations + + + + + + + + + + + + + + + + + + +

External H1 Title for E2E test

+ + +
    +
  • External list for E2E test
  • +
+ + + diff --git a/public/docs/_examples/animations/ts/src/main.ts b/public/docs/_examples/animations/ts/src/main.ts new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/animations/ts/src/main.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/architecture/dart/lib/backend_service.dart b/public/docs/_examples/architecture/dart/lib/backend_service.dart deleted file mode 100644 index ed425dfc82..0000000000 --- a/public/docs/_examples/architecture/dart/lib/backend_service.dart +++ /dev/null @@ -1,24 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; -import 'logger_service.dart'; - -@Injectable() -class BackendService { - final Logger _logger; - List getAll(type) { - // TODO get from the database and return as a promise - if (type == Hero) { - return [ - new Hero('Windstorm', power: 'Weather mastery'), - new Hero('Mr. Nice', power: 'Killing them with kindness'), - new Hero('Magneta', power: 'Manipulates metalic objects') - ]; - } - _logger.error('Cannot get object of this type'); - throw new ArgumentError("TODO: put log content here"); - } - - BackendService(Logger this._logger); -} diff --git a/public/docs/_examples/architecture/dart/lib/hero.dart b/public/docs/_examples/architecture/dart/lib/hero.dart deleted file mode 100644 index 1aa20e0ee8..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero.dart +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -class Hero { - static int _nextId = 1; - int id; - String name; - String power; - - Hero(this.name, {this.power}) { - id = _nextId++; - } -} diff --git a/public/docs/_examples/architecture/dart/lib/hero_detail_component.dart b/public/docs/_examples/architecture/dart/lib/hero_detail_component.dart deleted file mode 100644 index d89b4e44a8..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero_detail_component.dart +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; - -@Component(selector: 'hero-detail', templateUrl: 'hero_detail_component.html') -class HeroDetailComponent { - @Input() Hero hero; -} diff --git a/public/docs/_examples/architecture/dart/lib/hero_detail_component.html b/public/docs/_examples/architecture/dart/lib/hero_detail_component.html deleted file mode 100644 index 7dde3107e4..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero_detail_component.html +++ /dev/null @@ -1,9 +0,0 @@ -
-

{{hero.name}} Detail

-
Id: {{hero.id}}
-
Name: - -
- -
Power: -
diff --git a/public/docs/_examples/architecture/dart/lib/hero_list_component.dart b/public/docs/_examples/architecture/dart/lib/hero_list_component.dart deleted file mode 100644 index 7027a01bd8..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero_list_component.dart +++ /dev/null @@ -1,37 +0,0 @@ -// #docplaster -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; -import 'hero_detail_component.dart'; -import 'hero_service.dart'; - -// #docregion metadata -// #docregion providers -@Component( -// #enddocregion providers - selector: 'hero-list', - templateUrl: 'hero_list_component.html', - directives: const [HeroDetailComponent], -// #docregion providers - providers: const [HeroService]) -// #enddocregion providers -// #enddocregion metadata -/* -// #docregion metadata, providers -class HeroListComponent { ... } -// #enddocregion metadata, providers -*/ -// #docregion class -class HeroListComponent { - List heroes; - Hero selectedHero; -// #docregion ctor - HeroListComponent(HeroService heroService) { - heroes = heroService.getHeroes(); - } -// #enddocregion ctor - selectHero(Hero hero) { - selectedHero = hero; - } -} -// #enddocregion class diff --git a/public/docs/_examples/architecture/dart/lib/hero_list_component.html b/public/docs/_examples/architecture/dart/lib/hero_list_component.html deleted file mode 100644 index 539ef5fdd5..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero_list_component.html +++ /dev/null @@ -1,8 +0,0 @@ - -

Hero List

- -
- {{hero.name}} -
- - diff --git a/public/docs/_examples/architecture/dart/lib/hero_list_component_1.html b/public/docs/_examples/architecture/dart/lib/hero_list_component_1.html deleted file mode 100644 index 8673962169..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero_list_component_1.html +++ /dev/null @@ -1,10 +0,0 @@ - -
{{hero.name}}
- -
...
- - - -
...
- - diff --git a/public/docs/_examples/architecture/dart/lib/hero_service.dart b/public/docs/_examples/architecture/dart/lib/hero_service.dart deleted file mode 100644 index e15db5f1cd..0000000000 --- a/public/docs/_examples/architecture/dart/lib/hero_service.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:angular2/angular2.dart'; - -import 'backend_service.dart'; -import 'hero.dart'; -import 'logger_service.dart'; - -// #docregion class -@Injectable() -class HeroService { - final BackendService _backendService; - final Logger _logger; - HeroService(Logger this._logger, BackendService this._backendService); - List getHeroes() { - List heroes = _backendService.getAll(Hero); - _logger.log('Got ${heroes.length} heroes from the server.'); - return heroes; - } -} -// #enddocregion class diff --git a/public/docs/_examples/architecture/dart/lib/logger_service.dart b/public/docs/_examples/architecture/dart/lib/logger_service.dart deleted file mode 100644 index e1815da9a8..0000000000 --- a/public/docs/_examples/architecture/dart/lib/logger_service.dart +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import 'dart:html'; - -import 'package:angular2/angular2.dart'; - -/// A service for logging messages of various types. -/// -/// We could switch this implementation to use package:logging. -@Injectable() -class Logger { - void log(Object msg) => window.console.log(msg); - - void error(Object msg) => window.console.error(msg); - - void warn(Object msg) => window.console.warn(msg); -} diff --git a/public/docs/_examples/architecture/dart/pubspec.yaml b/public/docs/_examples/architecture/dart/pubspec.yaml deleted file mode 100644 index 1afbfed0d4..0000000000 --- a/public/docs/_examples/architecture/dart/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# #docregion -name: developer_guide_intro -description: Developer Guide Intro -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/architecture/dart/web/index.html b/public/docs/_examples/architecture/dart/web/index.html deleted file mode 100644 index 17a00ffbed..0000000000 --- a/public/docs/_examples/architecture/dart/web/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - Intro to Angular 2 - - - - - - Loading... - - diff --git a/public/docs/_examples/architecture/dart/web/main.dart b/public/docs/_examples/architecture/dart/web/main.dart deleted file mode 100644 index c96db07bb8..0000000000 --- a/public/docs/_examples/architecture/dart/web/main.dart +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:developer_guide_intro/backend_service.dart'; -import 'package:developer_guide_intro/hero_list_component.dart'; -import 'package:developer_guide_intro/hero_service.dart'; -import 'package:developer_guide_intro/logger_service.dart'; - -main() { - // #docregion bootstrap - bootstrap(HeroListComponent, [BackendService, HeroService, Logger]); - // #enddocregion bootstrap -} diff --git a/public/docs/_examples/architecture/e2e-spec.js b/public/docs/_examples/architecture/e2e-spec.js deleted file mode 100644 index a8818ad019..0000000000 --- a/public/docs/_examples/architecture/e2e-spec.js +++ /dev/null @@ -1,61 +0,0 @@ -describe('Architecture', function () { - - var _title = "Hero List"; - - beforeAll(function () { - browser.get(''); - }); - - function itReset(name, func) { - it(name, function() { - browser.get('').then(func); - }); - } - - it('should display correct title: ' + _title, function () { - expect(element(by.css('h2')).getText()).toEqual(_title); - }); - - it('should display correct detail after selection', function() { - var detailView = element(by.css('hero-detail')); - expect(detailView.isPresent()).toBe(false); - // select the 2nd element - var selectEle = element.all(by.css('hero-list > div')).get(1); - selectEle.click().then(function() { - return selectEle.getText(); - }).then(function(selectedHeroName) { - // works but too specific if we change the app - // expect(selectedHeroName).toEqual('Mr. Nice'); - expect(detailView.isDisplayed()).toBe(true); - var detailTitleEle = element(by.css('hero-detail > h4')); - expect(detailTitleEle.getText()).toContain(selectedHeroName); - }); - }) - - itReset('should display correct detail after modification', function() { - var detailView = element(by.css('hero-detail')); - expect(detailView.isPresent()).toBe(false); - // select the 2nd element - var selectEle = element.all(by.css('hero-list > div')).get(1); - selectEle.click().then(function () { - return selectEle.getText(); - }).then(function (selectedHeroName) { - var detailTitleEle = element(by.css('hero-detail > h4')); - expect(detailTitleEle.getText()).toContain(selectedHeroName); - var heroNameEle = element.all(by.css('hero-detail input')).get(0); - - // check that both the initial selected item and the detail title reflect changes - // made to the input box. - // heroNameEle.sendKeys('foo'); - sendKeys(heroNameEle, 'foo'); - expect(detailTitleEle.getText()).toContain('foo'); - expect(selectEle.getText()).toContain('foo'); - - // getText on an input element always returns null - // http://stackoverflow.com/questions/20310442/how-to-gettext-on-an-input-in-protractor - // expect(heroNameEle.getText()).toEqual(selectedHeroName); - expect(heroNameEle.getAttribute('value')).toEqual(selectedHeroName + 'foo'); - }); - }) - -}); diff --git a/public/docs/_examples/architecture/e2e-spec.ts b/public/docs/_examples/architecture/e2e-spec.ts new file mode 100644 index 0000000000..e967804483 --- /dev/null +++ b/public/docs/_examples/architecture/e2e-spec.ts @@ -0,0 +1,100 @@ +'use strict'; // necessary for es6 output in node + +import { protractor, browser, element, by, ElementFinder } from 'protractor'; + +const nameSuffix = 'X'; + +class Hero { + id: number; + name: string; +} + +describe('Architecture', () => { + + const expectedTitle = 'Architecture of Angular'; + const expectedH2 = ['Hero List', 'Sales Tax Calculator']; + + beforeAll(() => browser.get('')); + + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h2 '${expectedH2}'`, () => { + let h2 = element.all(by.css('h2')).map((elt: any) => elt.getText()); + expect(h2).toEqual(expectedH2); + }); + + describe('Hero', heroTests); + describe('Salex tax', salesTaxTests); +}); + +function heroTests() { + + const targetHero: Hero = { id: 2, name: 'Mr. Nice' }; + + it('has the right number of heroes', () => { + let page = getPageElts(); + expect(page.heroes.count()).toEqual(3); + }); + + it('has no hero details initially', function () { + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail'); + }); + + it('shows selected hero details', async () => { + await element(by.cssContainingText('li', targetHero.name)).click(); + let page = getPageElts(); + let hero = await heroFromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name); + }); + + it(`shows updated hero name in details`, async () => { + let input = element.all(by.css('input')).first(); + input.sendKeys(nameSuffix); + let page = getPageElts(); + let hero = await heroFromDetail(page.heroDetail); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); +} + +function salesTaxTests() { + it('has no sales tax initially', function () { + let page = getPageElts(); + expect(page.salesTaxDetail.isPresent()).toBeFalsy('no sales tax info'); + }); + + it('shows sales tax', async function () { + let page = getPageElts(); + page.salesTaxAmountInput.sendKeys('10', protractor.Key.ENTER); + expect(page.salesTaxDetail.getText()).toEqual('The sales tax is $1.00'); + }); +} + +// Helper functions + +function getPageElts() { + return { + heroes: element.all(by.css('my-app li')), + heroDetail: element(by.css('my-app hero-detail')), + salesTaxAmountInput: element(by.css('my-app sales-tax input')), + salesTaxDetail: element(by.css('my-app sales-tax div')) + }; +} + +async function heroFromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
+ // let _id = await detail.all(by.css('div')).first().getText(); + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + // let _name = await detail.element(by.css('h4')).getText(); + let _name = await detail.element(by.css('h4')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; +} diff --git a/public/docs/_examples/architecture/ts/app/app.component.ts b/public/docs/_examples/architecture/ts/app/app.component.ts deleted file mode 100644 index 144990a86e..0000000000 --- a/public/docs/_examples/architecture/ts/app/app.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion import -import {Component} from 'angular2/core'; -// #enddocregion import -import {HeroListComponent} from './hero-list.component'; -import {SalesTaxComponent} from './sales-tax.component'; - -@Component({ - selector: 'my-app', - template: ` - - - `, - directives: [HeroListComponent, SalesTaxComponent] -}) -// #docregion export -export class AppComponent { } -// #enddocregion export \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/backend.service.ts b/public/docs/_examples/architecture/ts/app/backend.service.ts deleted file mode 100644 index 0600fee6e0..0000000000 --- a/public/docs/_examples/architecture/ts/app/backend.service.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Injectable, Type} from 'angular2/core'; -import {Logger} from './logger.service'; -import {Hero} from './hero'; - -const HEROES = [ - new Hero('Windstorm', 'Weather mastery'), - new Hero('Mr. Nice', 'Killing them with kindness'), - new Hero('Magneta', 'Manipulates metalic objects') - ]; - -@Injectable() -export class BackendService { - constructor(private _logger: Logger) {} - - getAll(type:Type) : PromiseLike{ - if (type === Hero) { - // TODO get from the database - return Promise.resolve(HEROES); - } - let err = new Error('Cannot get object of this type'); - this._logger.error(err); - throw err; - } -} \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/hero-detail.component.html b/public/docs/_examples/architecture/ts/app/hero-detail.component.html deleted file mode 100644 index baa3e8d9f9..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero-detail.component.html +++ /dev/null @@ -1,9 +0,0 @@ -
-

{{hero.name}} Detail

-
Id: {{hero.id}}
-
Name: - - - -
-
Power:
\ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/hero-detail.component.ts b/public/docs/_examples/architecture/ts/app/hero-detail.component.ts deleted file mode 100644 index d8c7bed1a8..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero-detail.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {Component, Input} from 'angular2/core'; -import {Hero} from './hero'; - -@Component({ - selector: 'hero-detail', - templateUrl: 'app/hero-detail.component.html', - directives: [HeroDetailComponent] -}) -export class HeroDetailComponent { - @Input() hero:Hero; -} \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/hero-list.component.1.html b/public/docs/_examples/architecture/ts/app/hero-list.component.1.html deleted file mode 100644 index 7fbd8f22ac..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero-list.component.1.html +++ /dev/null @@ -1,12 +0,0 @@ - -
{{hero.name}}
- -
- - - - -
- - - diff --git a/public/docs/_examples/architecture/ts/app/hero-list.component.html b/public/docs/_examples/architecture/ts/app/hero-list.component.html deleted file mode 100644 index a3de7f2950..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero-list.component.html +++ /dev/null @@ -1,9 +0,0 @@ - -

Hero List

- -

Pick a hero from the list

-
- {{hero.name}} -
- - diff --git a/public/docs/_examples/architecture/ts/app/hero-list.component.ts b/public/docs/_examples/architecture/ts/app/hero-list.component.ts deleted file mode 100644 index 7d4c3e152d..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero-list.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -// #docplaster -import {Component, OnInit} from 'angular2/core'; -import {Hero} from './hero'; -import {HeroDetailComponent} from './hero-detail.component'; -import {HeroService} from './hero.service'; - -// #docregion metadata -// #docregion providers -@Component({ -// #enddocregion providers - selector: 'hero-list', - templateUrl: 'app/hero-list.component.html', - directives: [HeroDetailComponent], -// #docregion providers - providers: [HeroService] -}) -// #enddocregion providers -// #enddocregion metadata -/* -// #docregion metadata, providers -export class HeroesComponent { ... } -// #enddocregion metadata, providers -*/ -// #docregion class -export class HeroListComponent implements OnInit { -// #docregion ctor - constructor(private _service: HeroService){ } -// #enddocregion ctor - - heroes:Hero[]; - selectedHero: Hero; - - ngOnInit(){ - this.heroes = this._service.getHeroes(); - } - - selectHero(hero: Hero) { this.selectedHero = hero; } -} -// #enddocregion class diff --git a/public/docs/_examples/architecture/ts/app/hero.service.ts b/public/docs/_examples/architecture/ts/app/hero.service.ts deleted file mode 100644 index 4fd33a5e09..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero.service.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {Injectable} from 'angular2/core'; -import {Hero} from './hero'; -import {BackendService} from './backend.service'; -import {Logger} from './logger.service'; - -@Injectable() -// #docregion class -export class HeroService { - // #docregion ctor - constructor( - private _backend: BackendService, - private _logger: Logger) { } - // #enddocregion ctor - - private _heroes:Hero[] = []; - - getHeroes() { - this._backend.getAll(Hero).then( (heroes:Hero[]) => { - this._logger.log(`Fetched ${heroes.length} heroes.`); - this._heroes.push(...heroes); // fill cache - }); - return this._heroes; - } -} -// #enddocregion class \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/hero.ts b/public/docs/_examples/architecture/ts/app/hero.ts deleted file mode 100644 index df6c37a0f5..0000000000 --- a/public/docs/_examples/architecture/ts/app/hero.ts +++ /dev/null @@ -1,10 +0,0 @@ -export class Hero { - id:number - constructor( - public name:string, - public power?:string){ - this.id = nextId++; - } -} - -var nextId = 1; diff --git a/public/docs/_examples/architecture/ts/app/logger.service.ts b/public/docs/_examples/architecture/ts/app/logger.service.ts deleted file mode 100644 index 69a7cd6b87..0000000000 --- a/public/docs/_examples/architecture/ts/app/logger.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; - -@Injectable() -// #docregion class -export class Logger { - log(msg: any) { console.log(msg); } - error(msg: any) { console.error(msg); } - warn(msg: any) { console.warn(msg); } -} -// #enddocregion class \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/main.ts b/public/docs/_examples/architecture/ts/app/main.ts deleted file mode 100644 index 0f064932b1..0000000000 --- a/public/docs/_examples/architecture/ts/app/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -// #docregion import -import {AppComponent} from './app.component'; -// #enddocregion import -import {HeroService} from './hero.service'; -import {BackendService} from './backend.service'; -import {Logger} from './logger.service'; - -// #docregion bootstrap -bootstrap(AppComponent, [BackendService, HeroService, Logger]); -// #enddocregion bootstrap diff --git a/public/docs/_examples/architecture/ts/app/sales-tax.component.ts b/public/docs/_examples/architecture/ts/app/sales-tax.component.ts deleted file mode 100644 index 475725a0e4..0000000000 --- a/public/docs/_examples/architecture/ts/app/sales-tax.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -// #docplaster -// #docregion -import {Component} from 'angular2/core'; -import {SalesTaxService} from './sales-tax.service'; -import {TaxRateService} from './tax-rate.service'; - -// #docregion metadata -// #docregion providers -@Component({ -// #enddocregion providers - selector: 'sales-tax', - template: ` -

Sales Tax Calculator

- Amount: - -
- The sales tax is - {{ getTax(amountBox.value) | currency:'USD':true:'1.2-2' }} -
- `, -// #docregion providers - providers: [SalesTaxService, TaxRateService] -}) -// #enddocregion providers -// #enddocregion metadata -/* -// #docregion metadata, providers -export class SalesTaxComponent { ... } -// #enddocregion metadata, providers -*/ -// #docregion class -export class SalesTaxComponent { -// #docregion ctor - constructor(private _salesTaxService: SalesTaxService) { } -// #enddocregion ctor - - getTax(value:string | number){ - return this._salesTaxService.getVAT(value); - } -} -// #enddocregion class diff --git a/public/docs/_examples/architecture/ts/app/sales-tax.service.ts b/public/docs/_examples/architecture/ts/app/sales-tax.service.ts deleted file mode 100644 index 6a93d3795e..0000000000 --- a/public/docs/_examples/architecture/ts/app/sales-tax.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import {Injectable, Inject} from 'angular2/core'; -import {TaxRateService} from './tax-rate.service'; - -// #docregion class -@Injectable() -export class SalesTaxService { - constructor(private _rateService: TaxRateService) { } - getVAT(value:string | number){ - let amount:number; - if (typeof value === "string"){ - amount = parseFloat(value); - } else { - amount = value; - } - return (amount || 0) * this._rateService.getRate('VAT'); - } -} -// #enddocregion class \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/app/tax-rate.service.ts b/public/docs/_examples/architecture/ts/app/tax-rate.service.ts deleted file mode 100644 index ab4fb2b097..0000000000 --- a/public/docs/_examples/architecture/ts/app/tax-rate.service.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; - -// #docregion class -@Injectable() -export class TaxRateService { - getRate(rateName:string){return 0.10;} // always 10% everywhere -} -// #enddocregion class \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/index.html b/public/docs/_examples/architecture/ts/index.html deleted file mode 100644 index 388031aa10..0000000000 --- a/public/docs/_examples/architecture/ts/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - Intro to Angular 2 - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/architecture/ts/plnkr.json b/public/docs/_examples/architecture/ts/plnkr.json index ee199ba476..b2f47131df 100644 --- a/public/docs/_examples/architecture/ts/plnkr.json +++ b/public/docs/_examples/architecture/ts/plnkr.json @@ -1,8 +1,9 @@ { - "description": "Intro to Angular2", + "description": "Intro to Angular", + "basePath": "src/", "files":[ - "!**/*.d.ts", - "!**/*.js", + "!**/*.d.ts", + "!**/*.js", "!app/hero-list.component.1.*" ] -} \ No newline at end of file +} diff --git a/public/docs/_examples/architecture/ts/src/app/app.component.ts b/public/docs/_examples/architecture/ts/src/app/app.component.ts new file mode 100644 index 0000000000..b987f17e44 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/app.component.ts @@ -0,0 +1,14 @@ +// #docregion import +import { Component } from '@angular/core'; +// #enddocregion import + +@Component({ + selector: 'my-app', + template: ` + + + ` +}) +// #docregion export +export class AppComponent { } +// #enddocregion export diff --git a/public/docs/_examples/architecture/ts/src/app/app.module.ts b/public/docs/_examples/architecture/ts/src/app/app.module.ts new file mode 100644 index 0000000000..f6e64beecd --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/app.module.ts @@ -0,0 +1,36 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +// #docregion imports +import { NgModule } from '@angular/core'; +import { AppComponent } from './app.component'; +// #enddocregion imports +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroListComponent } from './hero-list.component'; +import { SalesTaxComponent } from './sales-tax.component'; +import { HeroService } from './hero.service'; +import { BackendService } from './backend.service'; +import { Logger } from './logger.service'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + HeroDetailComponent, + HeroListComponent, + SalesTaxComponent + ], +// #docregion providers + providers: [ + BackendService, + HeroService, + Logger + ], +// #enddocregion providers + bootstrap: [ AppComponent ] +}) +// #docregion export +export class AppModule { } +// #enddocregion export diff --git a/public/docs/_examples/architecture/ts/src/app/backend.service.ts b/public/docs/_examples/architecture/ts/src/app/backend.service.ts new file mode 100644 index 0000000000..e47cfc8ace --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/backend.service.ts @@ -0,0 +1,25 @@ +import { Injectable, Type } from '@angular/core'; + +import { Logger } from './logger.service'; +import { Hero } from './hero'; + +const HEROES = [ + new Hero('Windstorm', 'Weather mastery'), + new Hero('Mr. Nice', 'Killing them with kindness'), + new Hero('Magneta', 'Manipulates metalic objects') + ]; + +@Injectable() +export class BackendService { + constructor(private logger: Logger) {} + + getAll(type: Type): PromiseLike { + if (type === Hero) { + // TODO get from the database + return Promise.resolve(HEROES); + } + let err = new Error('Cannot get object of this type'); + this.logger.error(err); + throw err; + } +} diff --git a/public/docs/_examples/architecture/ts/src/app/hero-detail.component.html b/public/docs/_examples/architecture/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..224de8bb86 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero-detail.component.html @@ -0,0 +1,9 @@ +
+

{{hero.name}} Detail

+
Id: {{hero.id}}
+
Name: + + + +
+
Power:
diff --git a/public/docs/_examples/architecture/ts/src/app/hero-detail.component.ts b/public/docs/_examples/architecture/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..b75d6dd225 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero-detail.component.ts @@ -0,0 +1,11 @@ +import { Component, Input } from '@angular/core'; + +import { Hero } from './hero'; + +@Component({ + selector: 'hero-detail', + templateUrl: './hero-detail.component.html' +}) +export class HeroDetailComponent { + @Input() hero: Hero; +} diff --git a/public/docs/_examples/architecture/ts/src/app/hero-list.component.1.html b/public/docs/_examples/architecture/ts/src/app/hero-list.component.1.html new file mode 100644 index 0000000000..c6e6dd5133 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero-list.component.1.html @@ -0,0 +1,9 @@ + +
  • {{hero.name}}
  • + +
  • + + + +
  • + diff --git a/public/docs/_examples/architecture/ts/src/app/hero-list.component.html b/public/docs/_examples/architecture/ts/src/app/hero-list.component.html new file mode 100644 index 0000000000..b46a307bd3 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero-list.component.html @@ -0,0 +1,11 @@ + +

    Hero List

    + +

    Pick a hero from the list

    +
      +
    • + {{hero.name}} +
    • +
    + + diff --git a/public/docs/_examples/architecture/ts/src/app/hero-list.component.ts b/public/docs/_examples/architecture/ts/src/app/hero-list.component.ts new file mode 100644 index 0000000000..a3d372f00b --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero-list.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +// #docregion metadata, providers +@Component({ + selector: 'hero-list', + templateUrl: './hero-list.component.html', + providers: [ HeroService ] +}) +// #enddocregion providers +// #docregion class +export class HeroListComponent implements OnInit { + // #enddocregion metadata + heroes: Hero[]; + selectedHero: Hero; + + // #docregion ctor + constructor(private service: HeroService) { } + // #enddocregion ctor + + ngOnInit() { + this.heroes = this.service.getHeroes(); + } + + selectHero(hero: Hero) { this.selectedHero = hero; } + // #docregion metadata +} diff --git a/public/docs/_examples/architecture/ts/src/app/hero.service.ts b/public/docs/_examples/architecture/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..493f064e40 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; + +import { Hero } from './hero'; +import { BackendService } from './backend.service'; +import { Logger } from './logger.service'; + +@Injectable() +// #docregion class +export class HeroService { + private heroes: Hero[] = []; + + constructor( + private backend: BackendService, + private logger: Logger) { } + + getHeroes() { + this.backend.getAll(Hero).then( (heroes: Hero[]) => { + this.logger.log(`Fetched ${heroes.length} heroes.`); + this.heroes.push(...heroes); // fill cache + }); + return this.heroes; + } +} diff --git a/public/docs/_examples/architecture/ts/src/app/hero.ts b/public/docs/_examples/architecture/ts/src/app/hero.ts new file mode 100644 index 0000000000..b89557aa71 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/hero.ts @@ -0,0 +1,10 @@ +let nextId = 1; + +export class Hero { + id: number; + constructor( + public name: string, + public power?: string) { + this.id = nextId++; + } +} diff --git a/public/docs/_examples/architecture/ts/src/app/logger.service.ts b/public/docs/_examples/architecture/ts/src/app/logger.service.ts new file mode 100644 index 0000000000..9277ee8bc0 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/logger.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +// #docregion class +export class Logger { + log(msg: any) { console.log(msg); } + error(msg: any) { console.error(msg); } + warn(msg: any) { console.warn(msg); } +} diff --git a/public/docs/_examples/architecture/ts/src/app/mini-app.ts b/public/docs/_examples/architecture/ts/src/app/mini-app.ts new file mode 100644 index 0000000000..b064428be3 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/mini-app.ts @@ -0,0 +1,45 @@ +// #docplaster +// A mini-application +import { Injectable } from '@angular/core'; + +@Injectable() +export class Logger { + log(message: string) { console.log(message); } +} + +// #docregion import-core-component +import { Component } from '@angular/core'; +// #enddocregion import-core-component + +@Component({ + selector: 'my-app', + template: 'Welcome to Angular' +}) +export class AppComponent { + constructor(logger: Logger) { + logger.log('Let the fun begin!'); + } +} + +// #docregion module +import { NgModule } from '@angular/core'; +// #docregion import-browser-module +import { BrowserModule } from '@angular/platform-browser'; +// #enddocregion import-browser-module +@NgModule({ +// #docregion ngmodule-imports + imports: [ BrowserModule ], +// #enddocregion ngmodule-imports + providers: [ Logger ], + declarations: [ AppComponent ], + exports: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +// #docregion export +export class AppModule { } +// #enddocregion export +// #enddocregion module + +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/architecture/ts/src/app/sales-tax.component.ts b/public/docs/_examples/architecture/ts/src/app/sales-tax.component.ts new file mode 100644 index 0000000000..02201afe05 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/sales-tax.component.ts @@ -0,0 +1,25 @@ +import { Component } from '@angular/core'; + +import { SalesTaxService } from './sales-tax.service'; +import { TaxRateService } from './tax-rate.service'; + +@Component({ + selector: 'sales-tax', + template: ` +

    Sales Tax Calculator

    + Amount: + +
    + The sales tax is + {{ getTax(amountBox.value) | currency:'USD':true:'1.2-2' }} +
    + `, + providers: [SalesTaxService, TaxRateService] +}) +export class SalesTaxComponent { + constructor(private salesTaxService: SalesTaxService) { } + + getTax(value: string | number) { + return this.salesTaxService.getVAT(value); + } +} diff --git a/public/docs/_examples/architecture/ts/src/app/sales-tax.service.ts b/public/docs/_examples/architecture/ts/src/app/sales-tax.service.ts new file mode 100644 index 0000000000..d859dc1595 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/sales-tax.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; + +import { TaxRateService } from './tax-rate.service'; + +@Injectable() +export class SalesTaxService { + constructor(private rateService: TaxRateService) { } + + getVAT(value: string | number) { + let amount = (typeof value === 'string') ? + parseFloat(value) : value; + return (amount || 0) * this.rateService.getRate('VAT'); + } +} diff --git a/public/docs/_examples/architecture/ts/src/app/tax-rate.service.ts b/public/docs/_examples/architecture/ts/src/app/tax-rate.service.ts new file mode 100644 index 0000000000..fff2f4df8f --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/app/tax-rate.service.ts @@ -0,0 +1,6 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class TaxRateService { + getRate(rateName: string) { return 0.10; } // 10% everywhere +} diff --git a/public/docs/_examples/architecture/ts/src/index.html b/public/docs/_examples/architecture/ts/src/index.html new file mode 100644 index 0000000000..9aadf6e109 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/index.html @@ -0,0 +1,26 @@ + + + + Architecture of Angular + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/architecture/ts/src/main.ts b/public/docs/_examples/architecture/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/architecture/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/attribute-directives/dart/lib/app_component.dart b/public/docs/_examples/attribute-directives/dart/lib/app_component.dart deleted file mode 100644 index 0d3ad7595b..0000000000 --- a/public/docs/_examples/attribute-directives/dart/lib/app_component.dart +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'highlight_directive.dart'; - -@Component( - selector: 'my-app', - templateUrl: 'app_component.html', - directives: const [Highlight]) -class AppComponent { - String color; -} diff --git a/public/docs/_examples/attribute-directives/dart/lib/app_component.html b/public/docs/_examples/attribute-directives/dart/lib/app_component.html deleted file mode 100644 index b8fd63c8e3..0000000000 --- a/public/docs/_examples/attribute-directives/dart/lib/app_component.html +++ /dev/null @@ -1,20 +0,0 @@ - - -

    My First Attribute Directive

    -

    Pick a highlight color

    -
    - Green - Yellow - Cyan -
    - -

    Highlight me!

    - - - - -

    -Highlight me too! -

    - - diff --git a/public/docs/_examples/attribute-directives/dart/lib/app_component_1.html b/public/docs/_examples/attribute-directives/dart/lib/app_component_1.html deleted file mode 100644 index b76a260a1a..0000000000 --- a/public/docs/_examples/attribute-directives/dart/lib/app_component_1.html +++ /dev/null @@ -1,3 +0,0 @@ - -

    My First Attribute Directive

    -Highlight me! diff --git a/public/docs/_examples/attribute-directives/dart/lib/highlight_directive.dart b/public/docs/_examples/attribute-directives/dart/lib/highlight_directive.dart deleted file mode 100644 index 0fb5832160..0000000000 --- a/public/docs/_examples/attribute-directives/dart/lib/highlight_directive.dart +++ /dev/null @@ -1,52 +0,0 @@ -// #docplaster -// #docregion full -import 'package:angular2/angular2.dart'; - -@Directive(selector: '[my-highlight]', host: const { - '(mouseenter)': 'onMouseEnter()', - '(mouseleave)': 'onMouseLeave()' -}) -// #docregion class-1 -class Highlight { - // #enddocregion class-1 -// #enddocregion full - /* -// #docregion highlight - @Input() myHighlight: string; -// #enddocregion highlight - */ -// #docregion full -// #docregion class-1 -// #docregion color - @Input('my-highlight') String highlightColor; -// #enddocregion color - - String _defaultColor = 'red'; - // #enddocregion class-1 - // #docregion defaultColor - @Input() set defaultColor(String colorName) { - _defaultColor = (colorName ?? _defaultColor); - } - // #enddocregion defaultColor -// #docregion class-1 - - final ElementRef _element; - -// #docregion mouse-enter - onMouseEnter() { - _highlight(highlightColor ?? _defaultColor); - } - -// #enddocregion mouse-enter - onMouseLeave() { - _highlight(null); - } - - void _highlight(String color) { - _element.nativeElement.style.backgroundColor = color; - } - - Highlight(this._element); -} -// #enddocregion class-1 -// #enddocregion full diff --git a/public/docs/_examples/attribute-directives/dart/lib/highlight_directive_1.dart b/public/docs/_examples/attribute-directives/dart/lib/highlight_directive_1.dart deleted file mode 100644 index 4fef486203..0000000000 --- a/public/docs/_examples/attribute-directives/dart/lib/highlight_directive_1.dart +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -library attribute_directives.highlight_directive; - -import 'package:angular2/angular2.dart'; - -@Directive(selector: '[my-highlight]') -class Highlight { - Highlight(ElementRef element) { - element.nativeElement.style.backgroundColor = 'yellow'; - } -} diff --git a/public/docs/_examples/attribute-directives/dart/lib/highlight_directive_2.dart b/public/docs/_examples/attribute-directives/dart/lib/highlight_directive_2.dart deleted file mode 100644 index 1561af0535..0000000000 --- a/public/docs/_examples/attribute-directives/dart/lib/highlight_directive_2.dart +++ /dev/null @@ -1,32 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -@Directive(selector: '[my-highlight]', -// #docregion host - host: const { - '(mouseenter)': 'onMouseEnter()', - '(mouseleave)': 'onMouseLeave()' - } -// #enddocregion host - ) -class Highlight { - final ElementRef _element; -// #docregion mouse-methods - onMouseEnter() { - _highlight("yellow"); - } - - onMouseLeave() { - _highlight(null); - } - // #enddocregion mouse-methods - - void _highlight(String color) { - _element.nativeElement.style.backgroundColor = color; - } - -// #docregion ctor - Highlight(this._element); -// #enddocregion ctor -} -// #enddocregion diff --git a/public/docs/_examples/attribute-directives/dart/pubspec.yaml b/public/docs/_examples/attribute-directives/dart/pubspec.yaml deleted file mode 100644 index 417df407ad..0000000000 --- a/public/docs/_examples/attribute-directives/dart/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# #docregion -name: attribute_directives -description: Attribute directives example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/attribute-directives/dart/web/index.html b/public/docs/_examples/attribute-directives/dart/web/index.html deleted file mode 100644 index ad852ad9eb..0000000000 --- a/public/docs/_examples/attribute-directives/dart/web/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - Attribute Directives - - - - - - Loading... - - diff --git a/public/docs/_examples/attribute-directives/dart/web/main.dart b/public/docs/_examples/attribute-directives/dart/web/main.dart deleted file mode 100644 index ce74487a47..0000000000 --- a/public/docs/_examples/attribute-directives/dart/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:attribute_directives/app_component.dart'; - -main() { - bootstrap(AppComponent); -} diff --git a/public/docs/_examples/attribute-directives/e2e-spec.js b/public/docs/_examples/attribute-directives/e2e-spec.js deleted file mode 100644 index 16fa374c75..0000000000 --- a/public/docs/_examples/attribute-directives/e2e-spec.js +++ /dev/null @@ -1,26 +0,0 @@ -describe('Attribute directives', function () { - - var _title = "My First Attribute Directive"; - - beforeAll(function () { - browser.get(''); - }); - - it('should display correct title: ' + _title, function () { - expect(element(by.css('h1')).getText()).toEqual(_title); - }); - - it('should be able to select green highlight', function () { - var highlightedEle = element(by.cssContainingText('p', 'Highlight me')); - var lightGreen = "rgba(144, 238, 144, 1)"; - - expect(highlightedEle.getCssValue('background-color')).not.toEqual(lightGreen); - // var greenRb = element(by.cssContainingText('input', 'Green')); - var greenRb = element.all(by.css('input')).get(0); - greenRb.click().then(function() { - browser.actions().mouseMove(highlightedEle).perform(); - expect(highlightedEle.getCssValue('background-color')).toEqual(lightGreen); - }); - - }); -}); diff --git a/public/docs/_examples/attribute-directives/e2e-spec.ts b/public/docs/_examples/attribute-directives/e2e-spec.ts new file mode 100644 index 0000000000..79425d7923 --- /dev/null +++ b/public/docs/_examples/attribute-directives/e2e-spec.ts @@ -0,0 +1,31 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Attribute directives', function () { + + let _title = 'My First Attribute Directive'; + + beforeAll(function () { + browser.get(''); + }); + + it(`should display correct title: ${_title}`, function () { + expect(element(by.css('h1')).getText()).toEqual(_title); + }); + + it('should be able to select green highlight', function () { + let highlightedEle = element(by.cssContainingText('p', 'Highlight me!')); + let lightGreen = 'rgba(144, 238, 144, 1)'; + + expect(highlightedEle.getCssValue('background-color')).not.toEqual(lightGreen); + // let greenRb = element(by.cssContainingText('input', 'Green')); + let greenRb = element.all(by.css('input')).get(0); + greenRb.click().then(function() { + // TypeScript Todo: find the right type for highlightedEle + browser.actions().mouseMove(highlightedEle as any).perform(); + expect(highlightedEle.getCssValue('background-color')).toEqual(lightGreen); + }); + + }); +}); diff --git a/public/docs/_examples/attribute-directives/ts/.gitignore b/public/docs/_examples/attribute-directives/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/attribute-directives/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/attribute-directives/ts/app/app.component.1.html b/public/docs/_examples/attribute-directives/ts/app/app.component.1.html deleted file mode 100644 index 177c90f5da..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/app.component.1.html +++ /dev/null @@ -1,4 +0,0 @@ - -

    My First Attribute Directive

    -Highlight me! - \ No newline at end of file diff --git a/public/docs/_examples/attribute-directives/ts/app/app.component.html b/public/docs/_examples/attribute-directives/ts/app/app.component.html deleted file mode 100644 index 35b5d43aae..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/app.component.html +++ /dev/null @@ -1,22 +0,0 @@ - - -

    My First Attribute Directive

    -

    Pick a highlight color

    -
    - Green - Yellow - Cyan -
    - - -

    Highlight me!

    - - - - -

    - Highlight me too! -

    - - - \ No newline at end of file diff --git a/public/docs/_examples/attribute-directives/ts/app/app.component.ts b/public/docs/_examples/attribute-directives/ts/app/app.component.ts deleted file mode 100644 index 2cfed3b35f..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/app.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {HighlightDirective} from './highlight.directive'; - -@Component({ - selector: 'my-app', - templateUrl: 'app/app.component.html', - directives: [HighlightDirective] -}) - -export class AppComponent { } - -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/attribute-directives/ts/app/highlight.directive.1.ts b/public/docs/_examples/attribute-directives/ts/app/highlight.directive.1.ts deleted file mode 100644 index 9b4dbd7448..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/highlight.directive.1.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import {Directive, ElementRef, Input} from 'angular2/core'; - -@Directive({ - selector: '[myHighlight]' -}) - -export class HighlightDirective { - constructor(el: ElementRef) { - el.nativeElement.style.backgroundColor = 'yellow'; - } -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/attribute-directives/ts/app/highlight.directive.2.ts b/public/docs/_examples/attribute-directives/ts/app/highlight.directive.2.ts deleted file mode 100644 index 9cf0b95970..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/highlight.directive.2.ts +++ /dev/null @@ -1,29 +0,0 @@ -// #docregion -import {Directive, ElementRef, Input} from 'angular2/core'; - -@Directive({ - selector: '[myHighlight]', - // #docregion host - host: { - '(mouseenter)': 'onMouseEnter()', - '(mouseleave)': 'onMouseLeave()' - } - // #enddocregion host -}) - -export class HighlightDirective { - // #docregion ctor - constructor(private el: ElementRef) { } - // #enddocregion ctor - - // #docregion mouse-methods - onMouseEnter() { this._highlight("yellow"); } - onMouseLeave() { this._highlight(null); } - - private _highlight(color: string) { - this.el.nativeElement.style.backgroundColor = color; - } - // #enddocregion mouse-methods - -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/attribute-directives/ts/app/highlight.directive.ts b/public/docs/_examples/attribute-directives/ts/app/highlight.directive.ts deleted file mode 100644 index 6a26780057..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/highlight.directive.ts +++ /dev/null @@ -1,49 +0,0 @@ -// #docplaster -// #docregion full -import {Directive, ElementRef, Input} from 'angular2/core'; - -@Directive({ - selector: '[myHighlight]', - host: { - '(mouseenter)': 'onMouseEnter()', - '(mouseleave)': 'onMouseLeave()' - } -}) - -// #docregion class-1 -export class HighlightDirective { -// #enddocregion class-1 -// #enddocregion full - /* -// #docregion highlight - @Input() myHighlight: string; -// #enddocregion highlight - */ -// #docregion full -// #docregion class-1 -// #docregion color - @Input('myHighlight') highlightColor: string; -// #enddocregion color - - private _defaultColor = 'red'; -// #enddocregion class-1 - // #docregion defaultColor - @Input() set defaultColor(colorName:string){ - this._defaultColor = colorName || this._defaultColor; - } - // #enddocregion defaultColor -// #docregion class-1 - - constructor(private el: ElementRef) { } - -// #docregion mouse-enter - onMouseEnter() { this._highlight(this.highlightColor || this._defaultColor); } -// #enddocregion mouse-enter - onMouseLeave() { this._highlight(null); } - - private _highlight(color:string) { - this.el.nativeElement.style.backgroundColor = color; - } -} -// #enddocregion class-1 -// #enddocregion full \ No newline at end of file diff --git a/public/docs/_examples/attribute-directives/ts/app/main.ts b/public/docs/_examples/attribute-directives/ts/app/main.ts deleted file mode 100644 index 3fe89a9b15..0000000000 --- a/public/docs/_examples/attribute-directives/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); diff --git a/public/docs/_examples/attribute-directives/ts/index.html b/public/docs/_examples/attribute-directives/ts/index.html deleted file mode 100644 index 97a38048b8..0000000000 --- a/public/docs/_examples/attribute-directives/ts/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Attribute Directives - - - - - - - - - - - - - - - - - loading... - - - diff --git a/public/docs/_examples/attribute-directives/ts/plnkr.json b/public/docs/_examples/attribute-directives/ts/plnkr.json index 7124dcb6a7..112e1de6f4 100644 --- a/public/docs/_examples/attribute-directives/ts/plnkr.json +++ b/public/docs/_examples/attribute-directives/ts/plnkr.json @@ -1,9 +1,10 @@ { "description": "Attribute Directive", + "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!app/*.[1,2].*" + "!app/*.[1,2,3].*" ], "tags": ["attribute", "directive"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/attribute-directives/ts/src/app/app.component.1.html b/public/docs/_examples/attribute-directives/ts/src/app/app.component.1.html new file mode 100644 index 0000000000..9505bc9dff --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/app.component.1.html @@ -0,0 +1,14 @@ + +

    My First Attribute Directive

    + +

    Highlight me!

    + + + +

    Highlighted in yellow

    +

    Highlighted in orange

    + + + +

    Highlighted with parent component's color

    + diff --git a/public/docs/_examples/attribute-directives/ts/src/app/app.component.1.ts b/public/docs/_examples/attribute-directives/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..d9b98ef3fd --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/app.component.1.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.1.html' +}) +// #docregion class +export class AppComponent { + color = 'yellow'; +} diff --git a/public/docs/_examples/attribute-directives/ts/src/app/app.component.html b/public/docs/_examples/attribute-directives/ts/src/app/app.component.html new file mode 100644 index 0000000000..3adb52bc1e --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/app.component.html @@ -0,0 +1,24 @@ + +

    My First Attribute Directive

    + +

    Pick a highlight color

    +
    + Green + Yellow + Cyan +
    + +

    Highlight me!

    + + + +

    + Highlight me too! +

    + + +
    +

    Mouse over the following lines to see fixed highlights

    + +

    Highlighted in yellow

    +

    Highlighted in orange

    diff --git a/public/docs/_examples/attribute-directives/ts/src/app/app.component.ts b/public/docs/_examples/attribute-directives/ts/src/app/app.component.ts new file mode 100644 index 0000000000..693918d8d6 --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/app.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +// #docregion class +export class AppComponent { + color: string; +} diff --git a/public/docs/_examples/attribute-directives/ts/src/app/app.module.ts b/public/docs/_examples/attribute-directives/ts/src/app/app.module.ts new file mode 100644 index 0000000000..ca35d560fb --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/app.module.ts @@ -0,0 +1,16 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { HighlightDirective } from './highlight.directive'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ + AppComponent, + HighlightDirective + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/attribute-directives/ts/src/app/dummy.module.1.ts b/public/docs/_examples/attribute-directives/ts/src/app/dummy.module.1.ts new file mode 100644 index 0000000000..7ba41d53bb --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/dummy.module.1.ts @@ -0,0 +1,17 @@ +// Not used. Keep away from plunker +// Keeps ATLS from complaining about undeclared directives. +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component.1'; +import { HighlightDirective as HLD1 } from './highlight.directive.1'; +import { HighlightDirective as HLD2 } from './highlight.directive.2'; +import { HighlightDirective as HLD3 } from './highlight.directive.3'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ + AppComponent, HLD1, HLD2, HLD3 + ] +}) +export class DummyModule { } diff --git a/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.1.ts b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.1.ts new file mode 100644 index 0000000000..4cacc0d22e --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.1.ts @@ -0,0 +1,10 @@ +/* tslint:disable:no-unused-variable */ +// #docregion +import { Directive, ElementRef, Input } from '@angular/core'; + +@Directive({ selector: '[myHighlight]' }) +export class HighlightDirective { + constructor(el: ElementRef) { + el.nativeElement.style.backgroundColor = 'yellow'; + } +} diff --git a/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.2.ts b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.2.ts new file mode 100644 index 0000000000..4696132f64 --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.2.ts @@ -0,0 +1,41 @@ +/* tslint:disable:no-unused-variable member-ordering */ +// #docplaster +// #docregion +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; + +@Directive({ + selector: '[myHighlight]' +}) +export class HighlightDirective { + // #docregion ctor + constructor(private el: ElementRef) { } + // #enddocregion ctor + + // #docregion mouse-methods, host + @HostListener('mouseenter') onMouseEnter() { + // #enddocregion host + this.highlight('yellow'); + // #docregion host + } + + @HostListener('mouseleave') onMouseLeave() { + // #enddocregion host + this.highlight(null); + // #docregion host + } + // #enddocregion host + + private highlight(color: string) { + this.el.nativeElement.style.backgroundColor = color; + } + // #enddocregion mouse-methods, + + // #docregion color + @Input() highlightColor: string; + // #enddocregion color + + // #docregion color-2 + @Input() myHighlight: string; + // #enddocregion color-2 +} + diff --git a/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.3.ts b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.3.ts new file mode 100644 index 0000000000..bf76769c93 --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.3.ts @@ -0,0 +1,27 @@ +/* tslint:disable:member-ordering */ +// #docregion +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; + +@Directive({ + selector: '[myHighlight]' +}) +export class HighlightDirective { + + constructor(private el: ElementRef) { } + + @Input('myHighlight') highlightColor: string; + + // #docregion mouse-enter + @HostListener('mouseenter') onMouseEnter() { + this.highlight(this.highlightColor || 'red'); + } + // #enddocregion mouse-enter + + @HostListener('mouseleave') onMouseLeave() { + this.highlight(null); + } + + private highlight(color: string) { + this.el.nativeElement.style.backgroundColor = color; + } +} diff --git a/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.ts b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.ts new file mode 100644 index 0000000000..97b1497013 --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/app/highlight.directive.ts @@ -0,0 +1,34 @@ +/* tslint:disable:member-ordering */ +// #docregion imports, +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; +// #enddocregion imports + +@Directive({ + selector: '[myHighlight]' +}) +export class HighlightDirective { + + constructor(private el: ElementRef) { } + + // #docregion defaultColor + @Input() defaultColor: string; + // #enddocregion defaultColor + + // #docregion color + @Input('myHighlight') highlightColor: string; + // #enddocregion color + + // #docregion mouse-enter + @HostListener('mouseenter') onMouseEnter() { + this.highlight(this.highlightColor || this.defaultColor || 'red'); + } + // #enddocregion mouse-enter + + @HostListener('mouseleave') onMouseLeave() { + this.highlight(null); + } + + private highlight(color: string) { + this.el.nativeElement.style.backgroundColor = color; + } +} diff --git a/public/docs/_examples/attribute-directives/ts/src/index.html b/public/docs/_examples/attribute-directives/ts/src/index.html new file mode 100644 index 0000000000..97662437f0 --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/index.html @@ -0,0 +1,25 @@ + + + + + + Attribute Directives + + + + + + + + + + + + + + + loading... + + diff --git a/public/docs/_examples/attribute-directives/ts/src/main.ts b/public/docs/_examples/attribute-directives/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/attribute-directives/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/e2e-spec.js b/public/docs/_examples/cb-a1-a2-quick-reference/e2e-spec.js deleted file mode 100644 index 4ab84e3947..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/e2e-spec.js +++ /dev/null @@ -1,110 +0,0 @@ -describe('Angular 1 to 2 Quick Reference Tests', function () { - - beforeAll(function () { - browser.get(''); - }); - - it('should display no poster images after bootstrap', function () { - testImagesAreDisplayed(false); - }); - - it('should display proper movie data', function () { - // We check only a few samples - var expectedSamples = [ - {row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true}, - {row: 0, column: 2, value: 'Celeritas'}, - {row: 1, column: 3, value: 'Dec 17, 2015'}, - {row: 1, column: 5, value: '$14.95'}, - {row: 2, column: 4, value: 'PG-13'}, - {row: 2, column: 7, value: '100%'}, - {row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.png', contains: true}, - ]; - - // Go through the samples - var movieRows = getMovieRows(); - for (var i = 0; i < expectedSamples.length; i++) { - var sample = expectedSamples[i]; - var tableCell = movieRows.get(sample.row) - .all(by.tagName('td')).get(sample.column); - // Check the cell or its nested element - var elementToCheck = sample.element - ? tableCell.element(by.tagName(sample.element)) - : tableCell; - - // Check element attribute or text - var valueToCheck = sample.attr - ? elementToCheck.getAttribute(sample.attr) - : elementToCheck.getText(); - - // Test for equals/contains - if (sample.contains) { - expect(valueToCheck).toContain(sample.value); - } else { - expect(valueToCheck).toEqual(sample.value); - } - } - }); - - it('should display images after Show Poster', function () { - testPosterButtonClick("Show Poster", true); - }); - - it('should hide images after Hide Poster', function () { - testPosterButtonClick("Hide Poster", false); - }); - - it('should display no movie when no favorite hero is specified', function () { - testFavoriteHero(null, "Please enter your favorite hero."); - }); - - it('should display no movie for Magneta', function () { - testFavoriteHero("Magneta", "No movie, sorry!"); - }); - - it('should display a movie for Mr. Nice', function () { - testFavoriteHero("Mr. Nice", "Excellent choice!"); - }); - - function testImagesAreDisplayed(isDisplayed) { - var expectedMovieCount = 3; - - var movieRows = getMovieRows(); - expect(movieRows.count()).toBe(expectedMovieCount); - for (var i = 0; i < expectedMovieCount; i++) { - var movieImage = movieRows.get(i).element(by.css('td > img')); - expect(movieImage.isDisplayed()).toBe(isDisplayed); - } - } - - function testPosterButtonClick(expectedButtonText, isDisplayed) { - var posterButton = element(by.css('movie-list tr > th > button')); - expect(posterButton.getText()).toBe(expectedButtonText); - - posterButton.click().then(function () { - testImagesAreDisplayed(isDisplayed); - }) - } - - function getMovieRows() { - return element.all(by.css('movie-list tbody > tr')); - } - - function testFavoriteHero(heroName, expectedLabel) { - var movieListComp = element(by.tagName('movie-list')); - var heroInput = movieListComp.element(by.tagName('input')); - var favoriteHeroLabel = movieListComp.element(by.tagName('h3')); - var resultLabel = movieListComp.element(by.css('span > p')); - - heroInput.clear().then(function () { - sendKeys(heroInput, heroName || '').then(function () { - expect(resultLabel.getText()).toBe(expectedLabel); - if (heroName) { - expect(favoriteHeroLabel.isDisplayed()).toBe(true); - expect(favoriteHeroLabel.getText()).toContain(heroName); - } else { - expect(favoriteHeroLabel.isDisplayed()).toBe(false); - } - }) - }) - } -}); diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/.gitignore b/public/docs/_examples/cb-a1-a2-quick-reference/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.html b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.html deleted file mode 100644 index e0be283708..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.html +++ /dev/null @@ -1,112 +0,0 @@ - -

    {{title}}

    - -

    Routed Movies

    - - - -
    - -

    Example Snippets

    - - -
    - - [ngClass] active -
    - -
    - - [ngClass] active and boldly important -
    - -
    - - [class.active] -
    - -

    - -Angular Docs - - -

    -
    - - - - -

    Image toggle event type was {{eventType}}

    -
    - -

    -
    - - - -
    - -

    - -
    - - color preference #1 -
    - -
    - - color preference #2 -
    - -

    Movie as JSON

    - -
    {{movie | json}}
    - - -

    Movie Titles via local variable

    - - - - - - -
    {{movie.title}}
    - -

    Sliced Movies with pipes

    - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    {{movie.title | uppercase}}{{movie.title | lowercase}}{{movie.releaseDate | date}}{{movie.price | currency:'USD':true}}{{movie.starRating | number}}{{movie.starRating | number:'1.1-2'}}{{movie.approvalRating | percent: '1.0-2'}}
    diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.ts deleted file mode 100644 index 6c19c4c4d6..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS} from "angular2/router"; - -import {MovieListComponent} from './movie-list.component'; -import {MovieService} from './movie.service'; -import {IMovie} from './movie'; -import {StringSafeDatePipe} from './date.pipe'; - -@Component({ - selector: 'my-app', - templateUrl: 'app/app.component.html', - styleUrls: ['app/app.component.css'], - directives: [MovieListComponent, ROUTER_DIRECTIVES], - pipes: [StringSafeDatePipe], - providers: [MovieService, ROUTER_PROVIDERS] -}) -@RouteConfig([ - {path: '/movies', name: 'Movies', component: MovieListComponent, useAsDefault: true} -]) -export class AppComponent { - - angularDocsUrl = "https://angular.io/"; - colorPreference = 'red'; - eventType = ''; - isActive = true; - isImportant = true; - movie: IMovie = null; - movies: IMovie[] = []; - showImage = true; - title: string = "A1-A2 Quick Ref Cookbook"; - toggleImage(event:UIEvent) { - this.showImage = !this.showImage; - this.eventType = (event && event.type) || 'not provided'; - } - - constructor(movieService: MovieService) { - this.movies = movieService.getMovies(); - this.movie = this.movies[0]; - } -} diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/date.pipe.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/date.pipe.ts deleted file mode 100644 index f9746ceef9..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/date.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {Injectable, Pipe} from 'angular2/core'; -import {DatePipe} from 'angular2/common'; - -@Injectable() -// #docregion date-pipe -@Pipe({name: 'date', pure: true}) -export class StringSafeDatePipe extends DatePipe { - transform(value: any, args: any[]): string { - value = typeof value === 'string' ? - Date.parse(value) : value - return super.transform(value, args); - } -} -// #enddocregion date-pipe diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/main.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/main.ts deleted file mode 100644 index ec4c9d12d6..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.ts deleted file mode 100644 index 73b55af51f..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -// #docplaster -// #docregion import -import {Component} from 'angular2/core'; -import {ROUTER_DIRECTIVES} from "angular2/router"; -// #enddocregion import -import {MovieService} from './movie.service'; -import {IMovie} from './movie'; -import {StringSafeDatePipe} from './date.pipe'; - - -// #docregion component -@Component({ - selector: 'movie-list', - templateUrl:'app/movie-list.component.html', -// #enddocregion component -// #docregion style-url - styleUrls: ['app/movie-list.component.css'], -// #enddocregion style-url -// #docregion date-pipe - pipes: [StringSafeDatePipe] -// #enddocregion date-pipe -}) -// #enddocregion component -// #docregion class -export class MovieListComponent { -// #enddocregion class - favoriteHero: string; - showImage: boolean = false; - movies: IMovie[]; - -// #docregion di - constructor(movieService: MovieService) { -// #enddocregion di - this.movies = movieService.getMovies(); -// #docregion di - } -// #enddocregion di - - toggleImage(): void { - this.showImage = !this.showImage; - } - - checkMovieHero(value: string): boolean { - return this.movies.filter(movie => movie.hero === value).length > 0 ; - } -// #docregion class -} -// #enddocregion class diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.service.ts b/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.service.ts deleted file mode 100644 index b601d9274f..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.service.ts +++ /dev/null @@ -1,43 +0,0 @@ -import {Injectable} from 'angular2/core'; -import {IMovie} from './movie'; - -@Injectable() -export class MovieService { - getMovies() : IMovie[] { - return [ - { - hero: "Celeritas", - imageurl: "images/hero.png", - movieId: 1, - mpaa: "pg-13", - releaseDate: "2015-12-19T00:00:00", - title: "Celeritas Reigns", - price: 12.95, - starRating: 4.925, - approvalRating: .97 - }, - { - hero: "Mr. Nice", - imageurl: "images/villain.png", - movieId: 2, - mpaa: "pg-13", - releaseDate: "2015-12-18T00:00:00", - title: "No More Mr. Nice Guy", - price: 14.95, - starRating: 4.6, - approvalRating: .94 - }, - { - hero: "Angular", - imageurl: "images/ng-logo.png", - movieId: 3, - mpaa: "pg-13", - releaseDate: "2015-12-17T00:00:00", - title: "Angular to the Rescue", - price: 15.95, - starRating: 4.98, - approvalRating: .9995 - } - ]; - } -} diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/hero.png b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/hero.png deleted file mode 100644 index b60c3ecc30..0000000000 Binary files a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/hero.png and /dev/null differ diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/ng-logo.png b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/ng-logo.png deleted file mode 100644 index 7929242740..0000000000 Binary files a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/ng-logo.png and /dev/null differ diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/villain.png b/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/villain.png deleted file mode 100644 index d1e71cf00b..0000000000 Binary files a/public/docs/_examples/cb-a1-a2-quick-reference/ts/images/villain.png and /dev/null differ diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html b/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html deleted file mode 100644 index 37dda86237..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Angular 1 to Angular 2 Quick Reference - - - - - - - - - - - - - - - - - - - - Loading app... - - - diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/plnkr.json b/public/docs/_examples/cb-a1-a2-quick-reference/ts/plnkr.json deleted file mode 100644 index 4f3ebce61d..0000000000 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/plnkr.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "Angular 1 to Angular 2 Quick Reference", - "files":[ - "!**/*.d.ts", - "!**/*.js", - "!**/*.[1].*" - ], - "tags":["cookbook"] -} diff --git a/public/docs/_examples/cb-ajs-quick-reference/e2e-spec.ts b/public/docs/_examples/cb-ajs-quick-reference/e2e-spec.ts new file mode 100644 index 0000000000..81a5faa5e7 --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/e2e-spec.ts @@ -0,0 +1,115 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('AngularJS to Angular Quick Reference Tests', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should display no poster images after bootstrap', function () { + testImagesAreDisplayed(false); + }); + + it('should display proper movie data', function () { + // We check only a few samples + let expectedSamples: any[] = [ + {row: 0, column: 0, element: 'img', attr: 'src', value: 'images/hero.png', contains: true}, + {row: 0, column: 2, value: 'Celeritas'}, + {row: 1, column: 3, matches: /Dec 1[678], 2015/}, // absorb timezone dif; we care about date format + {row: 1, column: 5, value: '$14.95'}, + {row: 2, column: 4, value: 'PG-13'}, + {row: 2, column: 7, value: '100%'}, + {row: 2, column: 0, element: 'img', attr: 'src', value: 'images/ng-logo.png', contains: true}, + ]; + + // Go through the samples + let movieRows = getMovieRows(); + for (let i = 0; i < expectedSamples.length; i++) { + let sample = expectedSamples[i]; + let tableCell = movieRows.get(sample.row) + .all(by.tagName('td')).get(sample.column); + // Check the cell or its nested element + let elementToCheck = sample.element + ? tableCell.element(by.tagName(sample.element)) + : tableCell; + + // Check element attribute or text + let valueToCheck = sample.attr + ? elementToCheck.getAttribute(sample.attr) + : elementToCheck.getText(); + + // Test for equals/contains/match + if (sample.contains) { + expect(valueToCheck).toContain(sample.value); + } else if (sample.matches) { + expect(valueToCheck).toMatch(sample.matches); + } else { + expect(valueToCheck).toEqual(sample.value); + } + } + }); + + it('should display images after Show Poster', function () { + testPosterButtonClick('Show Poster', true); + }); + + it('should hide images after Hide Poster', function () { + testPosterButtonClick('Hide Poster', false); + }); + + it('should display no movie when no favorite hero is specified', function () { + testFavoriteHero(null, 'Please enter your favorite hero.'); + }); + + it('should display no movie for Magneta', function () { + testFavoriteHero('Magneta', 'No movie, sorry!'); + }); + + it('should display a movie for Mr. Nice', function () { + testFavoriteHero('Mr. Nice', 'Excellent choice!'); + }); + + function testImagesAreDisplayed(isDisplayed: boolean) { + let expectedMovieCount = 3; + + let movieRows = getMovieRows(); + expect(movieRows.count()).toBe(expectedMovieCount); + for (let i = 0; i < expectedMovieCount; i++) { + let movieImage = movieRows.get(i).element(by.css('td > img')); + expect(movieImage.isDisplayed()).toBe(isDisplayed); + } + } + + function testPosterButtonClick(expectedButtonText: string, isDisplayed: boolean) { + let posterButton = element(by.css('movie-list tr > th > button')); + expect(posterButton.getText()).toBe(expectedButtonText); + + posterButton.click().then(function () { + testImagesAreDisplayed(isDisplayed); + }); + } + + function getMovieRows() { + return element.all(by.css('movie-list tbody > tr')); + } + + function testFavoriteHero(heroName: string, expectedLabel: string) { + let movieListComp = element(by.tagName('movie-list')); + let heroInput = movieListComp.element(by.tagName('input')); + let favoriteHeroLabel = movieListComp.element(by.tagName('h3')); + let resultLabel = movieListComp.element(by.css('span > p')); + + heroInput.clear().then(function () { + heroInput.sendKeys(heroName || ''); + expect(resultLabel.getText()).toBe(expectedLabel); + if (heroName) { + expect(favoriteHeroLabel.isDisplayed()).toBe(true); + expect(favoriteHeroLabel.getText()).toContain(heroName); + } else { + expect(favoriteHeroLabel.isDisplayed()).toBe(false); + } + }); + } +}); diff --git a/public/docs/_examples/example-config.json b/public/docs/_examples/cb-ajs-quick-reference/ts/example-config.json similarity index 100% rename from public/docs/_examples/example-config.json rename to public/docs/_examples/cb-ajs-quick-reference/ts/example-config.json diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/plnkr.json b/public/docs/_examples/cb-ajs-quick-reference/ts/plnkr.json new file mode 100644 index 0000000000..1ff34275f7 --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "AngularJS to Angular Quick Reference", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags":["cookbook", "angularjs"] +} diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app-routing.module.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..a7cbe8a74d --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app-routing.module.ts @@ -0,0 +1,16 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +import { MovieListComponent } from './movie-list.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/movies', pathMatch: 'full' }, + { path: 'movies', component: MovieListComponent } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.css b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.css similarity index 100% rename from public/docs/_examples/cb-a1-a2-quick-reference/ts/app/app.component.css rename to public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.css diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.html b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.html new file mode 100644 index 0000000000..72fd3de86f --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.html @@ -0,0 +1,112 @@ + +

    {{title}}

    + +

    Routed Movies

    + + + +
    + +

    Example Snippets

    + + +
    + + [ngClass] active +
    + +
    + + [ngClass] active and boldly important +
    + +
    + + [class.active] +
    + +

    + +Angular Docs + + +

    +
    + + + + +

    Image toggle event type was {{eventType}}

    +
    + +

    +
    + + + +
    + +

    + +
    + + color preference #1 +
    + +
    + + color preference #2 +
    + +

    Movie as JSON

    + +
    {{movie | json}}
    + + +

    Movie Titles via local variable

    + + + + + + +
    {{movie.title}}
    + +

    Sliced Movies with pipes

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{movie.title | uppercase}}{{movie.title | lowercase}}{{movie.releaseDate | date}}{{movie.price | currency:'USD':true}}{{movie.starRating | number}}{{movie.starRating | number:'1.1-2'}}{{movie.approvalRating | percent: '1.0-2'}}
    diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.ts new file mode 100644 index 0000000000..e1b71e37dc --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.component.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; + +import { MovieService } from './movie.service'; +import { IMovie } from './movie'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ], + providers: [ MovieService ] +}) +export class AppComponent { + + angularDocsUrl = 'https://angular.io/'; + colorPreference = 'red'; + eventType = ''; + isActive = true; + isImportant = true; + movie: IMovie = null; + movies: IMovie[] = []; + showImage = true; + title: string = 'AngularJS to Angular Quick Ref Cookbook'; + toggleImage(event: UIEvent) { + this.showImage = !this.showImage; + this.eventType = (event && event.type) || 'not provided'; + } + + constructor(movieService: MovieService) { + this.movies = movieService.getMovies(); + this.movie = this.movies[0]; + } +} diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.module.1.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..5b24020186 --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.module.1.ts @@ -0,0 +1,12 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.module.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.module.ts new file mode 100644 index 0000000000..1dc46ad17c --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/app.module.ts @@ -0,0 +1,22 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { MovieListComponent } from './movie-list.component'; +import { AppRoutingModule } from './app-routing.module'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + MovieListComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/date.pipe.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/date.pipe.ts new file mode 100644 index 0000000000..e1421fa530 --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/date.pipe.ts @@ -0,0 +1,14 @@ +import { Injectable, Pipe, PipeTransform } from '@angular/core'; +import { DatePipe } from '@angular/common'; + +@Injectable() +// #docregion date-pipe +@Pipe({name: 'date', pure: true}) +export class StringSafeDatePipe extends DatePipe implements PipeTransform { + transform(value: any, format: string): string { + value = typeof value === 'string' ? + Date.parse(value) : value; + return super.transform(value, format); + } +} +// #enddocregion date-pipe diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.css b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie-list.component.css similarity index 100% rename from public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.css rename to public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie-list.component.css diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.html b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie-list.component.html similarity index 95% rename from public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.html rename to public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie-list.component.html index 59edc28556..9de98806d7 100644 --- a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie-list.component.html +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie-list.component.html @@ -10,10 +10,10 @@

    Movie List

    -

    +

    Excellent choice!

    -

    +

    No movie, sorry!

    @@ -54,7 +54,7 @@

    - + movie.hero === value).length > 0 ; + } +// #docregion class +} +// #enddocregion class diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie.service.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie.service.ts new file mode 100644 index 0000000000..404fd4454c --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie.service.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; + +import { IMovie } from './movie'; + +@Injectable() +export class MovieService { + getMovies(): IMovie[] { + return [ + { + hero: 'Celeritas', + imageurl: 'images/hero.png', + movieId: 1, + mpaa: 'pg-13', + releaseDate: '2015-12-19T00:00:00', + title: 'Celeritas Reigns', + price: 12.95, + starRating: 4.925, + approvalRating: .97 + }, + { + hero: 'Mr. Nice', + imageurl: 'images/villain.png', + movieId: 2, + mpaa: 'pg-13', + releaseDate: '2015-12-18T00:00:00', + title: 'No More Mr. Nice Guy', + price: 14.95, + starRating: 4.6, + approvalRating: .94 + }, + { + hero: 'Angular', + imageurl: 'images/ng-logo.png', + movieId: 3, + mpaa: 'pg-13', + releaseDate: '2015-12-17T00:00:00', + title: 'Angular to the Rescue', + price: 15.95, + starRating: 4.98, + approvalRating: .9995 + } + ]; + } +} diff --git a/public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie.ts similarity index 100% rename from public/docs/_examples/cb-a1-a2-quick-reference/ts/app/movie.ts rename to public/docs/_examples/cb-ajs-quick-reference/ts/src/app/movie.ts diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/hero.png b/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/hero.png new file mode 100644 index 0000000000..2a128ac367 Binary files /dev/null and b/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/hero.png differ diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/ng-logo.png b/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/ng-logo.png new file mode 100644 index 0000000000..1e488b1a49 Binary files /dev/null and b/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/ng-logo.png differ diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/villain.png b/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/villain.png new file mode 100644 index 0000000000..26697d1a42 Binary files /dev/null and b/public/docs/_examples/cb-ajs-quick-reference/ts/src/images/villain.png differ diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/index.html b/public/docs/_examples/cb-ajs-quick-reference/ts/src/index.html new file mode 100644 index 0000000000..829f080ae3 --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/index.html @@ -0,0 +1,28 @@ + + + + + + AngularJS to Angular Quick Reference + + + + + + + + + + + + + + + + + Loading app... + + + diff --git a/public/docs/_examples/cb-ajs-quick-reference/ts/src/main.ts b/public/docs/_examples/cb-ajs-quick-reference/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/cb-ajs-quick-reference/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-aot-compiler/e2e-spec.ts b/public/docs/_examples/cb-aot-compiler/e2e-spec.ts new file mode 100644 index 0000000000..4744f06e50 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/e2e-spec.ts @@ -0,0 +1,27 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +/* tslint:disable:quotemark */ +describe('AOT Compilation', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should load page and click button', function (done: any) { + let headingSelector = element.all(by.css('h1')).get(0); + expect(headingSelector.getText()).toEqual('Hello Angular'); + + expect(element.all(by.xpath('//div[text()="Magneta"]')).get(0).isPresent()).toBe(true); + expect(element.all(by.xpath('//div[text()="Bombasto"]')).get(0).isPresent()).toBe(true); + expect(element.all(by.xpath('//div[text()="Magma"]')).get(0).isPresent()).toBe(true); + expect(element.all(by.xpath('//div[text()="Tornado"]')).get(0).isPresent()).toBe(true); + + let toggleButton = element.all(by.css('button')).get(0); + toggleButton.click().then(function() { + expect(headingSelector.isPresent()).toBe(false); + done(); + }); + }); +}); diff --git a/public/docs/_examples/cb-aot-compiler/ts/.gitignore b/public/docs/_examples/cb-aot-compiler/ts/.gitignore new file mode 100644 index 0000000000..91da4c79a2 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/.gitignore @@ -0,0 +1,7 @@ +**/*.ngfactory.ts +**/*.ngsummary.json +**/*.shim.ngstyle.ts +**/*.metadata.json +dist +!app/tsconfig.json +!rollup-config.js diff --git a/public/docs/_examples/cb-aot-compiler/ts/example-config.json b/public/docs/_examples/cb-aot-compiler/ts/example-config.json new file mode 100644 index 0000000000..473b80a572 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:aot" +} diff --git a/public/docs/_examples/cb-aot-compiler/ts/rollup-config.js b/public/docs/_examples/cb-aot-compiler/ts/rollup-config.js new file mode 100644 index 0000000000..1cd25515ba --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/rollup-config.js @@ -0,0 +1,34 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +// #docregion config +export default { + entry: 'src/main.js', + dest: 'src/build.js', // output a single application bundle + sourceMap: false, + format: 'iife', + onwarn: function(warning) { + // Skip certain warnings + + // should intercept ... but doesn't in some rollup versions + if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } + + // console.warn everything else + console.warn( warning.message ); + }, + plugins: [ + nodeResolve({jsnext: true, module: true}), + // #docregion commonjs + commonjs({ + include: 'node_modules/rxjs/**', + }), + // #enddocregion commonjs + // #docregion uglify + uglify() + // #enddocregion uglify + ] +} +// #enddocregion config diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/app/app.component.html b/public/docs/_examples/cb-aot-compiler/ts/src/app/app.component.html new file mode 100644 index 0000000000..1d3a8de932 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/app/app.component.html @@ -0,0 +1,7 @@ + + +

    Hello Angular

    + +

    List of Heroes

    +
    {{hero}}
    + diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/app/app.component.ts b/public/docs/_examples/cb-aot-compiler/ts/src/app/app.component.ts new file mode 100644 index 0000000000..879f7f663c --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/app/app.component.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { + showHeading = true; + heroes = ['Magneta', 'Bombasto', 'Magma', 'Tornado']; + + toggleHeading() { + this.showHeading = !this.showHeading; + } +} diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/app/app.module.ts b/public/docs/_examples/cb-aot-compiler/ts/src/app/app.module.ts new file mode 100644 index 0000000000..b4fc185c24 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/app/app.module.ts @@ -0,0 +1,12 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/index-jit.html b/public/docs/_examples/cb-aot-compiler/ts/src/index-jit.html new file mode 100644 index 0000000000..713a04970e --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/index-jit.html @@ -0,0 +1,24 @@ + + + + + Ahead of time compilation (JIT) + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/index.html b/public/docs/_examples/cb-aot-compiler/ts/src/index.html new file mode 100644 index 0000000000..09e5f0de0e --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/index.html @@ -0,0 +1,20 @@ + + + + + Ahead of time compilation + + + + + + + + + + Loading... + + + + + diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/main-jit.ts b/public/docs/_examples/cb-aot-compiler/ts/src/main-jit.ts new file mode 100644 index 0000000000..88e2c16ed5 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/main-jit.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +console.log('Running JIT compiled'); +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-aot-compiler/ts/src/main.ts b/public/docs/_examples/cb-aot-compiler/ts/src/main.ts new file mode 100644 index 0000000000..4446bc07d1 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +console.log('Running AOT compiled'); +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/public/docs/_examples/cb-aot-compiler/ts/tsconfig-aot.json b/public/docs/_examples/cb-aot-compiler/ts/tsconfig-aot.json new file mode 100644 index 0000000000..d0a3d00ad4 --- /dev/null +++ b/public/docs/_examples/cb-aot-compiler/ts/tsconfig-aot.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + }, + + "files": [ + "src/app/app.module.ts", + "src/main.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/cb-component-communication/e2e-spec.js b/public/docs/_examples/cb-component-communication/e2e-spec.js deleted file mode 100644 index 84729e0cef..0000000000 --- a/public/docs/_examples/cb-component-communication/e2e-spec.js +++ /dev/null @@ -1,210 +0,0 @@ -describe('Component Communication Cookbook Tests', function () { - - - beforeAll(function () { - browser.get(''); - }); - - describe('Parent-to-child communication', function() { - // #docregion parent-to-child - // ... - var _heroNames = ['Mr. IQ', 'Magneta', 'Bombasto']; - var _masterName = 'Master'; - - it('should pass properties to children properly', function () { - var parent = element.all(by.tagName('hero-parent')).get(0); - var heroes = parent.all(by.tagName('hero-child')); - - for (var i = 0; i < _heroNames.length; i++) { - var childTitle = heroes.get(i).element(by.tagName('h3')).getText(); - var childDetail = heroes.get(i).element(by.tagName('p')).getText(); - expect(childTitle).toEqual(_heroNames[i] + ' says:') - expect(childDetail).toContain(_masterName) - } - }); - // ... - // #enddocregion parent-to-child - }); - - describe('Parent-to-child communication with setter', function() { - // #docregion parent-to-child-setter - // ... - it('should display trimmed, non-empty names', function () { - var _nonEmptyNameIndex = 0; - var _nonEmptyName = '"Mr. IQ"'; - var parent = element.all(by.tagName('name-parent')).get(0); - var hero = parent.all(by.tagName('name-child')).get(_nonEmptyNameIndex); - - var displayName = hero.element(by.tagName('h3')).getText(); - expect(displayName).toEqual(_nonEmptyName) - }); - - it('should replace empty name with default name', function () { - var _emptyNameIndex = 1; - var _defaultName = '""'; - var parent = element.all(by.tagName('name-parent')).get(0); - var hero = parent.all(by.tagName('name-child')).get(_emptyNameIndex); - - var displayName = hero.element(by.tagName('h3')).getText(); - expect(displayName).toEqual(_defaultName) - }); - // ... - // #enddocregion parent-to-child-setter - }); - - describe('Parent-to-child communication with ngOnChanges', function() { - // #docregion parent-to-child-onchanges - // ... - // Test must all execute in this exact order - it('should set expected initial values', function () { - var actual = getActual(); - - var initialLabel = "Version 1.23"; - var initialLog = 'major changed from {} to 1, minor changed from {} to 23'; - - expect(actual.label).toBe(initialLabel); - expect(actual.count).toBe(1); - expect(actual.logs.get(0).getText()).toBe(initialLog); - }); - - it('should set expected values after clicking "Minor" twice', function () { - var repoTag = element(by.tagName('version-parent')); - var newMinorButton = repoTag.all(by.tagName('button')).get(0); - - newMinorButton.click().then(function() { - newMinorButton.click().then(function() { - var actual = getActual(); - - var labelAfter2Minor = "Version 1.25"; - var logAfter2Minor = 'minor changed from 24 to 25'; - - expect(actual.label).toBe(labelAfter2Minor); - expect(actual.count).toBe(3); - expect(actual.logs.get(2).getText()).toBe(logAfter2Minor); - }) - }); - }); - - it('should set expected values after clicking "Major" once', function () { - var repoTag = element(by.tagName('version-parent')); - var newMajorButton = repoTag.all(by.tagName('button')).get(1); - - newMajorButton.click().then(function() { - var actual = getActual(); - - var labelAfterMajor = "Version 2.0"; - var logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0'; - - expect(actual.label).toBe(labelAfterMajor); - expect(actual.count).toBe(4); - expect(actual.logs.get(3).getText()).toBe(logAfterMajor); - }); - }); - - function getActual() { - var versionTag = element(by.tagName('version-child')); - var label = versionTag.element(by.tagName('h3')).getText(); - var ul = versionTag.element((by.tagName('ul'))); - var logs = ul.all(by.tagName('li')); - - return { - label: label, - logs: logs, - count: logs.count() - }; - } - // ... - // #enddocregion parent-to-child-onchanges - - }); - - describe('Child-to-parent communication', function() { - // #docregion child-to-parent - // ... - it('should not emit the event initially', function () { - var voteLabel = element(by.tagName('vote-taker')) - .element(by.tagName('h3')).getText(); - expect(voteLabel).toBe("Agree: 0, Disagree: 0"); - }); - - it('should process Agree vote', function () { - var agreeButton1 = element.all(by.tagName('my-voter')).get(0) - .all(by.tagName('button')).get(0); - agreeButton1.click().then(function() { - var voteLabel = element(by.tagName('vote-taker')) - .element(by.tagName('h3')).getText(); - expect(voteLabel).toBe("Agree: 1, Disagree: 0"); - }); - }); - - it('should process Disagree vote', function () { - var agreeButton1 = element.all(by.tagName('my-voter')).get(1) - .all(by.tagName('button')).get(1); - agreeButton1.click().then(function() { - var voteLabel = element(by.tagName('vote-taker')) - .element(by.tagName('h3')).getText(); - expect(voteLabel).toBe("Agree: 1, Disagree: 1"); - }); - }); - // ... - // #enddocregion child-to-parent - }); - - describe('Parent calls ViewChild', function() { - // #docregion parent-to-view-child - // ... - it('should stop the countdown', function () { - var stopButton = element - .all(by.tagName('countdown-parent')).get(0) - .all(by.tagName('button')).get(1); - - stopButton.click().then(function() { - var message = element(by.tagName('countdown-timer')) - .element(by.tagName('p')).getText(); - expect(message).toContain('Holding'); - }); - }); - // ... - // #enddocregion parent-to-view-child - }); - - describe('Parent and children communicate via a service', function() { - // #docregion bidirectional-service - // ... - it('should announce a mission', function () { - var missionControl = element(by.tagName('mission-control')); - var announceButton = missionControl.all(by.tagName('button')).get(0); - announceButton.click().then(function () { - var history = missionControl.all(by.tagName('li')); - expect(history.count()).toBe(1); - expect(history.get(0).getText()).toMatch(/Mission.* announced/); - }); - }); - - it('should confirm the mission by Lovell', function () { - testConfirmMission(1, 2, 'Lovell'); - }); - - it('should confirm the mission by Haise', function () { - testConfirmMission(3, 3, 'Haise'); - }); - - it('should confirm the mission by Swigert', function () { - testConfirmMission(2, 4, 'Swigert'); - }); - - function testConfirmMission(buttonIndex, expectedLogCount, astronaut) { - var _confirmedLog = ' confirmed the mission'; - var missionControl = element(by.tagName('mission-control')); - var confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex); - confirmButton.click().then(function () { - var history = missionControl.all(by.tagName('li')); - expect(history.count()).toBe(expectedLogCount); - expect(history.get(expectedLogCount-1).getText()).toBe(astronaut + _confirmedLog); - }); - } - // ... - // #enddocregion bidirectional-service - }); - -}); diff --git a/public/docs/_examples/cb-component-communication/e2e-spec.ts b/public/docs/_examples/cb-component-communication/e2e-spec.ts new file mode 100644 index 0000000000..d78e0784d9 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/e2e-spec.ts @@ -0,0 +1,232 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Component Communication Cookbook Tests', function () { + + // Note: '?e2e' which app can read to know it is running in protractor + // e.g. `if (!/e2e/.test(location.search)) { ...` + beforeAll(function () { + browser.get('?e2e'); + }); + + describe('Parent-to-child communication', function() { + // #docregion parent-to-child + // ... + let _heroNames = ['Mr. IQ', 'Magneta', 'Bombasto']; + let _masterName = 'Master'; + + it('should pass properties to children properly', function () { + let parent = element.all(by.tagName('hero-parent')).get(0); + let heroes = parent.all(by.tagName('hero-child')); + + for (let i = 0; i < _heroNames.length; i++) { + let childTitle = heroes.get(i).element(by.tagName('h3')).getText(); + let childDetail = heroes.get(i).element(by.tagName('p')).getText(); + expect(childTitle).toEqual(_heroNames[i] + ' says:'); + expect(childDetail).toContain(_masterName); + } + }); + // ... + // #enddocregion parent-to-child + }); + + describe('Parent-to-child communication with setter', function() { + // #docregion parent-to-child-setter + // ... + it('should display trimmed, non-empty names', function () { + let _nonEmptyNameIndex = 0; + let _nonEmptyName = '"Mr. IQ"'; + let parent = element.all(by.tagName('name-parent')).get(0); + let hero = parent.all(by.tagName('name-child')).get(_nonEmptyNameIndex); + + let displayName = hero.element(by.tagName('h3')).getText(); + expect(displayName).toEqual(_nonEmptyName); + }); + + it('should replace empty name with default name', function () { + let _emptyNameIndex = 1; + let _defaultName = '""'; + let parent = element.all(by.tagName('name-parent')).get(0); + let hero = parent.all(by.tagName('name-child')).get(_emptyNameIndex); + + let displayName = hero.element(by.tagName('h3')).getText(); + expect(displayName).toEqual(_defaultName); + }); + // ... + // #enddocregion parent-to-child-setter + }); + + describe('Parent-to-child communication with ngOnChanges', function() { + // #docregion parent-to-child-onchanges + // ... + // Test must all execute in this exact order + it('should set expected initial values', function () { + let actual = getActual(); + + let initialLabel = 'Version 1.23'; + let initialLog = 'Initial value of major set to 1, Initial value of minor set to 23'; + + expect(actual.label).toBe(initialLabel); + expect(actual.count).toBe(1); + expect(actual.logs.get(0).getText()).toBe(initialLog); + }); + + it('should set expected values after clicking \'Minor\' twice', function () { + let repoTag = element(by.tagName('version-parent')); + let newMinorButton = repoTag.all(by.tagName('button')).get(0); + + newMinorButton.click().then(function() { + newMinorButton.click().then(function() { + let actual = getActual(); + + let labelAfter2Minor = 'Version 1.25'; + let logAfter2Minor = 'minor changed from 24 to 25'; + + expect(actual.label).toBe(labelAfter2Minor); + expect(actual.count).toBe(3); + expect(actual.logs.get(2).getText()).toBe(logAfter2Minor); + }); + }); + }); + + it('should set expected values after clicking \'Major\' once', function () { + let repoTag = element(by.tagName('version-parent')); + let newMajorButton = repoTag.all(by.tagName('button')).get(1); + + newMajorButton.click().then(function() { + let actual = getActual(); + + let labelAfterMajor = 'Version 2.0'; + let logAfterMajor = 'major changed from 1 to 2, minor changed from 25 to 0'; + + expect(actual.label).toBe(labelAfterMajor); + expect(actual.count).toBe(4); + expect(actual.logs.get(3).getText()).toBe(logAfterMajor); + }); + }); + + function getActual() { + let versionTag = element(by.tagName('version-child')); + let label = versionTag.element(by.tagName('h3')).getText(); + let ul = versionTag.element((by.tagName('ul'))); + let logs = ul.all(by.tagName('li')); + + return { + label: label, + logs: logs, + count: logs.count() + }; + } + // ... + // #enddocregion parent-to-child-onchanges + + }); + + describe('Child-to-parent communication', function() { + // #docregion child-to-parent + // ... + it('should not emit the event initially', function () { + let voteLabel = element(by.tagName('vote-taker')) + .element(by.tagName('h3')).getText(); + expect(voteLabel).toBe('Agree: 0, Disagree: 0'); + }); + + it('should process Agree vote', function () { + let agreeButton1 = element.all(by.tagName('my-voter')).get(0) + .all(by.tagName('button')).get(0); + agreeButton1.click().then(function() { + let voteLabel = element(by.tagName('vote-taker')) + .element(by.tagName('h3')).getText(); + expect(voteLabel).toBe('Agree: 1, Disagree: 0'); + }); + }); + + it('should process Disagree vote', function () { + let agreeButton1 = element.all(by.tagName('my-voter')).get(1) + .all(by.tagName('button')).get(1); + agreeButton1.click().then(function() { + let voteLabel = element(by.tagName('vote-taker')) + .element(by.tagName('h3')).getText(); + expect(voteLabel).toBe('Agree: 1, Disagree: 1'); + }); + }); + // ... + // #enddocregion child-to-parent + }); + + // Can't run timer tests in protractor because + // interaction w/ zones causes all tests to freeze & timeout. + xdescribe('Parent calls child via local var', function() { + countDownTimerTests('countdown-parent-lv'); + }); + + xdescribe('Parent calls ViewChild', function() { + countDownTimerTests('countdown-parent-vc'); + }); + + function countDownTimerTests(parentTag: string) { + // #docregion countdown-timer-tests + // ... + it('timer and parent seconds should match', function () { + let parent = element(by.tagName(parentTag)); + let message = parent.element(by.tagName('countdown-timer')).getText(); + browser.sleep(10); // give `seconds` a chance to catchup with `message` + let seconds = parent.element(by.className('seconds')).getText(); + expect(message).toContain(seconds); + }); + + it('should stop the countdown', function () { + let parent = element(by.tagName(parentTag)); + let stopButton = parent.all(by.tagName('button')).get(1); + + stopButton.click().then(function() { + let message = parent.element(by.tagName('countdown-timer')).getText(); + expect(message).toContain('Holding'); + }); + }); + // ... + // #enddocregion countdown-timer-tests + } + + + describe('Parent and children communicate via a service', function() { + // #docregion bidirectional-service + // ... + it('should announce a mission', function () { + let missionControl = element(by.tagName('mission-control')); + let announceButton = missionControl.all(by.tagName('button')).get(0); + announceButton.click().then(function () { + let history = missionControl.all(by.tagName('li')); + expect(history.count()).toBe(1); + expect(history.get(0).getText()).toMatch(/Mission.* announced/); + }); + }); + + it('should confirm the mission by Lovell', function () { + testConfirmMission(1, 2, 'Lovell'); + }); + + it('should confirm the mission by Haise', function () { + testConfirmMission(3, 3, 'Haise'); + }); + + it('should confirm the mission by Swigert', function () { + testConfirmMission(2, 4, 'Swigert'); + }); + + function testConfirmMission(buttonIndex: number, expectedLogCount: number, astronaut: string) { + let _confirmedLog = ' confirmed the mission'; + let missionControl = element(by.tagName('mission-control')); + let confirmButton = missionControl.all(by.tagName('button')).get(buttonIndex); + confirmButton.click().then(function () { + let history = missionControl.all(by.tagName('li')); + expect(history.count()).toBe(expectedLogCount); + expect(history.get(expectedLogCount - 1).getText()).toBe(astronaut + _confirmedLog); + }); + } + // ... + // #enddocregion bidirectional-service + }); + +}); diff --git a/public/docs/_examples/cb-component-communication/ts/app/app.component.html b/public/docs/_examples/cb-component-communication/ts/app/app.component.html deleted file mode 100644 index 6cfb5b76ed..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/app.component.html +++ /dev/null @@ -1,44 +0,0 @@ -

    Component Communication Cookbook

    - -Pass data from parent to child with input binding
    -Intercept input property changes with a setter
    -Intercept input property changes with ngOnChanges
    -Parent listens for child event
    -Parent calls ViewChild
    -Parent and children communicate via a service
    - -
    - -
    -Back to Top - -
    -
    - -
    -Back to Top - -
    -
    - -
    -Back to Top - -
    -
    - -
    -Back to Top -
    - -
    - -
    -Back to Top -
    - -
    - -
    -Back to Top -
    diff --git a/public/docs/_examples/cb-component-communication/ts/app/app.component.ts b/public/docs/_examples/cb-component-communication/ts/app/app.component.ts deleted file mode 100644 index a1d11ed518..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/app.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import {Component} from 'angular2/core'; -import {HeroParentComponent} from './hero-parent.component'; -import {NameParentComponent} from './name-parent.component'; -import {VersionParentComponent} from './version-parent.component'; -import {VoteTakerComponent} from './votetaker.component'; -import {CountdownParentComponent} from './countdown-parent.component'; -import {MissionControlComponent} from './missioncontrol.component'; - -@Component({ - selector: 'app', - templateUrl: 'app/app.component.html', - directives: [ - HeroParentComponent, - NameParentComponent, - VersionParentComponent, - VoteTakerComponent, - CountdownParentComponent, - MissionControlComponent - ] -}) -export class AppComponent { } \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/astronaut.component.ts b/public/docs/_examples/cb-component-communication/ts/app/astronaut.component.ts deleted file mode 100644 index 686543be33..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/astronaut.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -// #docregion -import {Component, Input, OnDestroy} from 'angular2/core'; -import {MissionService} from './mission.service'; -import {Subscription} from 'rxjs/Subscription'; - -@Component({ - selector: 'my-astronaut', - template: ` -

    - {{astronaut}}: {{mission}} - -

    - ` -}) -export class AstronautComponent implements OnDestroy{ - @Input() astronaut: string; - mission = ""; - confirmed = false; - announced = false; - subscription:Subscription; - - constructor(private missionService: MissionService) { - this.subscription = missionService.missionAnnounced$.subscribe( - mission => { - this.mission = mission; - this.announced = true; - this.confirmed = false; - }) - } - - confirm() { - this.confirmed = true; - this.missionService.confirmMission(this.astronaut); - } - - ngOnDestroy(){ - // prevent memory leak when component destroyed - this.subscription.unsubscribe(); - } -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/countdown-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/app/countdown-parent.component.ts deleted file mode 100644 index d1e2a00cc9..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/countdown-parent.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import {Component, ViewChild} from 'angular2/core'; -import {CountdownTimerComponent} from './countdown-timer.component'; - -@Component({ - selector:'countdown-parent', - template: ` -

    Countdown to Liftoff

    - - - - `, - directives: [CountdownTimerComponent] -}) -export class CountdownParentComponent { - - @ViewChild(CountdownTimerComponent) - private _timerComponent:CountdownTimerComponent; - - start(){ this._timerComponent.start(); } - stop() { this._timerComponent.stop(); } -} \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/countdown-timer.component.ts b/public/docs/_examples/cb-component-communication/ts/app/countdown-timer.component.ts deleted file mode 100644 index 0175993303..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/countdown-timer.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -// #docregion -import {Component, OnInit, OnDestroy} from 'angular2/core'; - -@Component({ - selector:'countdown-timer', - template: '

    {{message}}

    ' -}) -export class CountdownTimerComponent implements OnInit, OnDestroy { - - intervalId = 0; - message = ''; - seconds = 11; - - clearTimer() {clearInterval(this.intervalId);} - - ngOnInit() { this.start(); } - ngOnDestroy() { this.clearTimer(); } - - start() { this._countDown(); } - stop() { - this.clearTimer(); - this.message = `Holding at T-${this.seconds} seconds`; - } - - private _countDown() { - this.clearTimer(); - this.intervalId = setInterval(()=>{ - this.seconds -= 1; - if (this.seconds == 0) { - this.message = "Blast off!"; - this.seconds = 11; // reset - } else { - this.message = `T-${this.seconds} seconds and counting`; - } - }, 1000); - } -} \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/hero-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/app/hero-parent.component.ts deleted file mode 100644 index 17a2dcc93c..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/hero-parent.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {HeroChildComponent} from './hero-child.component'; -import {HEROES} from './hero'; - -@Component({ - selector: 'hero-parent', - template: ` -

    {{master}} controls {{heroes.length}} heroes

    - - - `, - directives: [HeroChildComponent] -}) -export class HeroParentComponent { - heroes = HEROES; - master: string = 'Master'; -} -// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/app/hero.ts b/public/docs/_examples/cb-component-communication/ts/app/hero.ts deleted file mode 100644 index 5b99f17132..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/hero.ts +++ /dev/null @@ -1,9 +0,0 @@ -export interface Hero { - name: string; -} - -export const HEROES = [ - {name: 'Mr. IQ'}, - {name: 'Magneta'}, - {name: 'Bombasto'} -]; \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/main.ts b/public/docs/_examples/cb-component-communication/ts/app/main.ts deleted file mode 100644 index dc1879e9b5..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/mission.service.ts b/public/docs/_examples/cb-component-communication/ts/app/mission.service.ts deleted file mode 100644 index b651646b4b..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/mission.service.ts +++ /dev/null @@ -1,25 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core' -import {Subject} from 'rxjs/Subject'; - -@Injectable() -export class MissionService { - - // Observable string sources - private _missionAnnouncedSource = new Subject(); - private _missionConfirmedSource = new Subject(); - - // Observable string streams - missionAnnounced$ = this._missionAnnouncedSource.asObservable(); - missionConfirmed$ = this._missionConfirmedSource.asObservable(); - - // Service message commands - announceMission(mission: string) { - this._missionAnnouncedSource.next(mission) - } - - confirmMission(astronaut: string) { - this._missionConfirmedSource.next(astronaut); - } -} -// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/app/missioncontrol.component.ts b/public/docs/_examples/cb-component-communication/ts/app/missioncontrol.component.ts deleted file mode 100644 index 2f0ac129c0..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/missioncontrol.component.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {AstronautComponent} from './astronaut.component'; -import {MissionService} from './mission.service'; - -@Component({ - selector: 'mission-control', - template: ` -

    Mission Control

    - - - -

    History

    -
      -
    • {{event}}
    • -
    - `, - directives: [AstronautComponent], - providers: [MissionService] -}) -export class MissionControlComponent { - astronauts = ['Lovell', 'Swigert', 'Haise'] - history: string[] = []; - missions = ['Fly to the moon!', - 'Fly to mars!', - 'Fly to Vegas!']; - nextMission = 0; - - constructor(private missionService: MissionService) { - missionService.missionConfirmed$.subscribe( - astronaut => { - this.history.push(`${astronaut} confirmed the mission`); - }) - } - - announce() { - let mission = this.missions[this.nextMission++]; - this.missionService.announceMission(mission); - this.history.push(`Mission "${mission}" announced`); - if (this.nextMission >= this.missions.length) { this.nextMission = 0; } - } -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/name-child.component.ts b/public/docs/_examples/cb-component-communication/ts/app/name-child.component.ts deleted file mode 100644 index a02fa7949e..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/name-child.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import {Component, Input} from 'angular2/core'; - -@Component({ - selector: 'name-child', - template: ` -

    "{{name}}"

    - ` -}) -export class NameChildComponent { - _name: string = ''; - - @Input() - set name(name: string) { - this._name = (name && name.trim()) || ''; - } - - get name() { return this._name; } -} -// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/app/name-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/app/name-parent.component.ts deleted file mode 100644 index ec99f31675..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/name-parent.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {NameChildComponent} from './name-child.component'; - -@Component({ - selector: 'name-parent', - template: ` -

    Master controls {{names.length}} names

    - - - `, - directives: [NameChildComponent] -}) -export class NameParentComponent { - // Displays 'Mr. IQ', '', 'Bombasto' - names = ['Mr. IQ', ' ', ' Bombasto ']; -} -// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/app/version-child.component.ts b/public/docs/_examples/cb-component-communication/ts/app/version-child.component.ts deleted file mode 100644 index 944c2888f6..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/version-child.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -// #docregion -import {Component, Input, OnChanges, SimpleChange} from 'angular2/core'; - -@Component({ - selector: 'version-child', - template: ` -

    Version {{major}}.{{minor}}

    -

    Change log:

    -
      -
    • {{change}}
    • -
    - ` -}) -export class VersionChildComponent implements OnChanges { - @Input() major: number; - @Input() minor: number; - changeLog: string[] = []; - - ngOnChanges(changes: {[propKey:string]: SimpleChange}){ - let log: string[] = []; - for (let propName in changes) { - let changedProp = changes[propName]; - let from = JSON.stringify(changedProp.previousValue); - let to = JSON.stringify(changedProp.currentValue); - log.push( `${propName} changed from ${from} to ${to}`); - } - this.changeLog.push(log.join(', ')); - } -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/app/votetaker.component.ts b/public/docs/_examples/cb-component-communication/ts/app/votetaker.component.ts deleted file mode 100644 index 02aeda9fd9..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/app/votetaker.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {VoterComponent} from './voter.component'; - -@Component({ - selector: 'vote-taker', - template: ` -

    Should mankind colonize the Universe?

    -

    Agree: {{agreed}}, Disagree: {{disagreed}}

    - - - `, - directives: [VoterComponent] -}) -export class VoteTakerComponent { - agreed = 0; - disagreed = 0; - voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto'] - - onVoted(agreed: boolean) { - agreed ? this.agreed++ : this.disagreed++; - } -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/cb-component-communication/ts/index.html b/public/docs/_examples/cb-component-communication/ts/index.html deleted file mode 100644 index 8678794506..0000000000 --- a/public/docs/_examples/cb-component-communication/ts/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - Passing information from parent to child - - - - - - - - - - - - - - - - - loading... - - - diff --git a/public/docs/_examples/cb-component-communication/ts/plnkr.json b/public/docs/_examples/cb-component-communication/ts/plnkr.json index 3c83b2d0f9..03bd55cd1a 100644 --- a/public/docs/_examples/cb-component-communication/ts/plnkr.json +++ b/public/docs/_examples/cb-component-communication/ts/plnkr.json @@ -1,8 +1,9 @@ { "description": "Component Communication Cookbook samples", + "basePath": "src/", "files":[ - "!**/*.d.ts", + "!**/*.d.ts", "!**/*.js" ], "tags":["cookbook", "component"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/app.component.html b/public/docs/_examples/cb-component-communication/ts/src/app/app.component.html new file mode 100644 index 0000000000..ef94020efb --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/app.component.html @@ -0,0 +1,51 @@ +

    Component Communication Cookbook

    + +Pass data from parent to child with input binding ("Heroes")
    +Intercept input property changes with a setter ("Master")
    +Intercept input property changes with ngOnChanges ("Source code version")
    +Parent listens for child event ("Colonize Universe")
    +Parent to child via local variable("Countdown to Liftoff")
    +Parent calls ViewChild("Countdown to Liftoff")
    +Parent and children communicate via a service ("Mission Control")
    + +
    + +
    +Back to Top + +
    +
    + +
    +Back to Top + +
    +
    + +
    +Back to Top + +
    +
    + +
    +Back to Top +
    + +
    + +
    +Back to Top +
    + +
    + +
    +Back to Top +
    + +
    + +
    +Back to Top +
    diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/app.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/app.component.ts new file mode 100644 index 0000000000..7556beb1ff --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/app.module.ts b/public/docs/_examples/cb-component-communication/ts/src/app/app.module.ts new file mode 100644 index 0000000000..a008fc5486 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/app.module.ts @@ -0,0 +1,54 @@ +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { AstronautComponent } from './astronaut.component'; +import { CountdownLocalVarParentComponent, CountdownViewChildParentComponent } from './countdown-parent.component'; +import { CountdownTimerComponent } from './countdown-timer.component'; +import { HeroChildComponent } from './hero-child.component'; +import { HeroParentComponent } from './hero-parent.component'; +import { MissionControlComponent } from './missioncontrol.component'; +import { NameChildComponent } from './name-child.component'; +import { NameParentComponent } from './name-parent.component'; +import { VersionChildComponent } from './version-child.component'; +import { VersionParentComponent } from './version-parent.component'; +import { VoterComponent } from './voter.component'; +import { VoteTakerComponent } from './votetaker.component'; + +let directives: any[] = [ + AppComponent, + AstronautComponent, + CountdownTimerComponent, + HeroChildComponent, + HeroParentComponent, + MissionControlComponent, + NameChildComponent, + NameParentComponent, + VersionChildComponent, + VersionParentComponent, + VoterComponent, + VoteTakerComponent + ]; + +let schemas: any[] = []; + +// Include Countdown examples +// unless in e2e tests which they break. +if (!/e2e/.test(location.search)) { + console.log('adding countdown timer examples'); + directives.push(CountdownLocalVarParentComponent); + directives.push(CountdownViewChildParentComponent); +} else { + // In e2e test use CUSTOM_ELEMENTS_SCHEMA to supress unknown element errors + schemas.push(CUSTOM_ELEMENTS_SCHEMA); +} + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: directives, + bootstrap: [ AppComponent ], + schemas: schemas +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/astronaut.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/astronaut.component.ts new file mode 100644 index 0000000000..bc24964f86 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/astronaut.component.ts @@ -0,0 +1,46 @@ +// #docregion +import { Component, Input, OnDestroy } from '@angular/core'; + +import { MissionService } from './mission.service'; +import { Subscription } from 'rxjs/Subscription'; + +@Component({ + selector: 'my-astronaut', + template: ` +

    + {{astronaut}}: {{mission}} + +

    + ` +}) +export class AstronautComponent implements OnDestroy { + @Input() astronaut: string; + mission = ''; + confirmed = false; + announced = false; + subscription: Subscription; + + constructor(private missionService: MissionService) { + this.subscription = missionService.missionAnnounced$.subscribe( + mission => { + this.mission = mission; + this.announced = true; + this.confirmed = false; + }); + } + + confirm() { + this.confirmed = true; + this.missionService.confirmMission(this.astronaut); + } + + ngOnDestroy() { + // prevent memory leak when component destroyed + this.subscription.unsubscribe(); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/countdown-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/countdown-parent.component.ts new file mode 100644 index 0000000000..5bcf0645c9 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/countdown-parent.component.ts @@ -0,0 +1,57 @@ +// #docplaster +// #docregion vc +import { AfterViewInit, ViewChild } from '@angular/core'; +// #docregion lv +import { Component } from '@angular/core'; +import { CountdownTimerComponent } from './countdown-timer.component'; + +// #enddocregion lv +// #enddocregion vc + +//// Local variable, #timer, version +// #docregion lv +@Component({ + selector: 'countdown-parent-lv', + template: ` +

    Countdown to Liftoff (via local variable)

    + + +
    {{timer.seconds}}
    + + `, + styleUrls: ['demo.css'] +}) +export class CountdownLocalVarParentComponent { } +// #enddocregion lv + +//// View Child version +// #docregion vc +@Component({ + selector: 'countdown-parent-vc', + template: ` +

    Countdown to Liftoff (via ViewChild)

    + + +
    {{ seconds() }}
    + + `, + styleUrls: ['demo.css'] +}) +export class CountdownViewChildParentComponent implements AfterViewInit { + + @ViewChild(CountdownTimerComponent) + private timerComponent: CountdownTimerComponent; + + seconds() { return 0; } + + ngAfterViewInit() { + // Redefine `seconds()` to get from the `CountdownTimerComponent.seconds` ... + // but wait a tick first to avoid one-time devMode + // unidirectional-data-flow-violation error + setTimeout(() => this.seconds = () => this.timerComponent.seconds, 0); + } + + start() { this.timerComponent.start(); } + stop() { this.timerComponent.stop(); } +} +// #enddocregion vc diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/countdown-timer.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/countdown-timer.component.ts new file mode 100644 index 0000000000..a9a1a2fa7c --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/countdown-timer.component.ts @@ -0,0 +1,37 @@ +// #docregion +import { Component, OnDestroy, OnInit } from '@angular/core'; + +@Component({ + selector: 'countdown-timer', + template: '

    {{message}}

    ' +}) +export class CountdownTimerComponent implements OnInit, OnDestroy { + + intervalId = 0; + message = ''; + seconds = 11; + + clearTimer() { clearInterval(this.intervalId); } + + ngOnInit() { this.start(); } + ngOnDestroy() { this.clearTimer(); } + + start() { this.countDown(); } + stop() { + this.clearTimer(); + this.message = `Holding at T-${this.seconds} seconds`; + } + + private countDown() { + this.clearTimer(); + this.intervalId = window.setInterval(() => { + this.seconds -= 1; + if (this.seconds === 0) { + this.message = 'Blast off!'; + } else { + if (this.seconds < 0) { this.seconds = 10; } // reset + this.message = `T-${this.seconds} seconds and counting`; + } + }, 1000); + } +} diff --git a/public/docs/_examples/cb-component-communication/ts/app/hero-child.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/hero-child.component.ts similarity index 77% rename from public/docs/_examples/cb-component-communication/ts/app/hero-child.component.ts rename to public/docs/_examples/cb-component-communication/ts/src/app/hero-child.component.ts index 748d543983..7447542a74 100644 --- a/public/docs/_examples/cb-component-communication/ts/app/hero-child.component.ts +++ b/public/docs/_examples/cb-component-communication/ts/src/app/hero-child.component.ts @@ -1,6 +1,7 @@ // #docregion -import {Component, Input} from 'angular2/core'; -import {Hero} from './hero'; +import { Component, Input } from '@angular/core'; + +import { Hero } from './hero'; @Component({ selector: 'hero-child', diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/hero-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/hero-parent.component.ts new file mode 100644 index 0000000000..bf3861c455 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/hero-parent.component.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component } from '@angular/core'; + +import { HEROES } from './hero'; + +@Component({ + selector: 'hero-parent', + template: ` +

    {{master}} controls {{heroes.length}} heroes

    + + + ` +}) +export class HeroParentComponent { + heroes = HEROES; + master: string = 'Master'; +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/hero.ts b/public/docs/_examples/cb-component-communication/ts/src/app/hero.ts new file mode 100644 index 0000000000..a7b70f48e8 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/hero.ts @@ -0,0 +1,9 @@ +export class Hero { + name: string; +} + +export const HEROES = [ + {name: 'Mr. IQ'}, + {name: 'Magneta'}, + {name: 'Bombasto'} +]; diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/mission.service.ts b/public/docs/_examples/cb-component-communication/ts/src/app/mission.service.ts new file mode 100644 index 0000000000..25c86866b0 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/mission.service.ts @@ -0,0 +1,25 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +@Injectable() +export class MissionService { + + // Observable string sources + private missionAnnouncedSource = new Subject(); + private missionConfirmedSource = new Subject(); + + // Observable string streams + missionAnnounced$ = this.missionAnnouncedSource.asObservable(); + missionConfirmed$ = this.missionConfirmedSource.asObservable(); + + // Service message commands + announceMission(mission: string) { + this.missionAnnouncedSource.next(mission); + } + + confirmMission(astronaut: string) { + this.missionConfirmedSource.next(astronaut); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/missioncontrol.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/missioncontrol.component.ts new file mode 100644 index 0000000000..a27e9b16b1 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/missioncontrol.component.ts @@ -0,0 +1,43 @@ +// #docregion +import { Component } from '@angular/core'; + +import { MissionService } from './mission.service'; + +@Component({ + selector: 'mission-control', + template: ` +

    Mission Control

    + + + +

    History

    +
      +
    • {{event}}
    • +
    + `, + providers: [MissionService] +}) +export class MissionControlComponent { + astronauts = ['Lovell', 'Swigert', 'Haise']; + history: string[] = []; + missions = ['Fly to the moon!', + 'Fly to mars!', + 'Fly to Vegas!']; + nextMission = 0; + + constructor(private missionService: MissionService) { + missionService.missionConfirmed$.subscribe( + astronaut => { + this.history.push(`${astronaut} confirmed the mission`); + }); + } + + announce() { + let mission = this.missions[this.nextMission++]; + this.missionService.announceMission(mission); + this.history.push(`Mission "${mission}" announced`); + if (this.nextMission >= this.missions.length) { this.nextMission = 0; } + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/name-child.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/name-child.component.ts new file mode 100644 index 0000000000..bc6d3c6f59 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/name-child.component.ts @@ -0,0 +1,18 @@ +// #docregion +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'name-child', + template: '

    "{{name}}"

    ' +}) +export class NameChildComponent { + private _name = ''; + + @Input() + set name(name: string) { + this._name = (name && name.trim()) || ''; + } + + get name(): string { return this._name; } +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/name-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/name-parent.component.ts new file mode 100644 index 0000000000..99753303aa --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/name-parent.component.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'name-parent', + template: ` +

    Master controls {{names.length}} names

    + + ` +}) +export class NameParentComponent { + // Displays 'Mr. IQ', '', 'Bombasto' + names = ['Mr. IQ', ' ', ' Bombasto ']; +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/version-child.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/version-child.component.ts new file mode 100644 index 0000000000..89d365cf9f --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/version-child.component.ts @@ -0,0 +1,35 @@ +/* tslint:disable:forin */ +// #docregion +import { Component, Input, OnChanges, SimpleChange } from '@angular/core'; + +@Component({ + selector: 'version-child', + template: ` +

    Version {{major}}.{{minor}}

    +

    Change log:

    +
      +
    • {{change}}
    • +
    + ` +}) +export class VersionChildComponent implements OnChanges { + @Input() major: number; + @Input() minor: number; + changeLog: string[] = []; + + ngOnChanges(changes: {[propKey: string]: SimpleChange}) { + let log: string[] = []; + for (let propName in changes) { + let changedProp = changes[propName]; + let to = JSON.stringify(changedProp.currentValue); + if (changedProp.isFirstChange()) { + log.push(`Initial value of ${propName} set to ${to}`); + } else { + let from = JSON.stringify(changedProp.previousValue); + log.push(`${propName} changed from ${from} to ${to}`); + } + } + this.changeLog.push(log.join(', ')); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/app/version-parent.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/version-parent.component.ts similarity index 76% rename from public/docs/_examples/cb-component-communication/ts/app/version-parent.component.ts rename to public/docs/_examples/cb-component-communication/ts/src/app/version-parent.component.ts index fa3cff767a..bbc9101702 100644 --- a/public/docs/_examples/cb-component-communication/ts/app/version-parent.component.ts +++ b/public/docs/_examples/cb-component-communication/ts/src/app/version-parent.component.ts @@ -1,6 +1,5 @@ // #docregion -import {Component} from 'angular2/core'; -import {VersionChildComponent} from './version-child.component'; +import { Component } from '@angular/core'; @Component({ selector: 'version-parent', @@ -9,8 +8,7 @@ import {VersionChildComponent} from './version-child.component'; - `, - directives: [VersionChildComponent] + ` }) export class VersionParentComponent { major: number = 1; diff --git a/public/docs/_examples/cb-component-communication/ts/app/voter.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/voter.component.ts similarity index 78% rename from public/docs/_examples/cb-component-communication/ts/app/voter.component.ts rename to public/docs/_examples/cb-component-communication/ts/src/app/voter.component.ts index 1c5fd16e25..c0cb23abc0 100644 --- a/public/docs/_examples/cb-component-communication/ts/app/voter.component.ts +++ b/public/docs/_examples/cb-component-communication/ts/src/app/voter.component.ts @@ -1,5 +1,5 @@ // #docregion -import {Component, EventEmitter, Input, Output} from 'angular2/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; @Component({ selector: 'my-voter', @@ -14,9 +14,9 @@ export class VoterComponent { @Output() onVoted = new EventEmitter(); voted = false; - vote(agreed:boolean){ + vote(agreed: boolean) { this.onVoted.emit(agreed); this.voted = true; } } -// #enddocregion \ No newline at end of file +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/app/votetaker.component.ts b/public/docs/_examples/cb-component-communication/ts/src/app/votetaker.component.ts new file mode 100644 index 0000000000..87f06161f5 --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/app/votetaker.component.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'vote-taker', + template: ` +

    Should mankind colonize the Universe?

    +

    Agree: {{agreed}}, Disagree: {{disagreed}}

    + + + ` +}) +export class VoteTakerComponent { + agreed = 0; + disagreed = 0; + voters = ['Mr. IQ', 'Ms. Universe', 'Bombasto']; + + onVoted(agreed: boolean) { + agreed ? this.agreed++ : this.disagreed++; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-component-communication/ts/src/demo.css b/public/docs/_examples/cb-component-communication/ts/src/demo.css new file mode 100644 index 0000000000..b63a8b38dd --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/demo.css @@ -0,0 +1,9 @@ +/* Component Communication cookbook specific styles */ +.seconds { + background-color: black; + color: red; + font-size: 3em; + margin: 0.3em 0; + text-align: center; + width: 1.5em; +} diff --git a/public/docs/_examples/cb-component-communication/ts/src/index.html b/public/docs/_examples/cb-component-communication/ts/src/index.html new file mode 100644 index 0000000000..64c8a3430f --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/index.html @@ -0,0 +1,29 @@ + + + + + Passing information from parent to child + + + + + + + + + + + + + + + + + loading... + + + diff --git a/public/docs/_examples/cb-component-communication/ts/src/main.ts b/public/docs/_examples/cb-component-communication/ts/src/main.ts new file mode 100644 index 0000000000..311c44b76d --- /dev/null +++ b/public/docs/_examples/cb-component-communication/ts/src/main.ts @@ -0,0 +1,5 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-dependency-injection/e2e-spec.ts b/public/docs/_examples/cb-dependency-injection/e2e-spec.ts new file mode 100644 index 0000000000..8c9d163d5e --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/e2e-spec.ts @@ -0,0 +1,102 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Dependency Injection Cookbook', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should render Logged in User example', function () { + let loggedInUser = element.all(by.xpath('//h3[text()="Logged in user"]')).get(0); + expect(loggedInUser).toBeDefined(); + }); + + it('"Bombasto" should be the logged in user', function () { + let loggedInUser = element.all(by.xpath('//div[text()="Name: Bombasto"]')).get(0); + expect(loggedInUser).toBeDefined(); + }); + + it('should render sorted heroes', function () { + let sortedHeroes = element.all(by.xpath('//h3[text()="Sorted Heroes" and position()=1]')).get(0); + expect(sortedHeroes).toBeDefined(); + }); + + it('Mr. Nice should be in sorted heroes', function () { + let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Mr. Nice" and position()=2]')).get(0); + expect(sortedHero).toBeDefined(); + }); + + it('RubberMan should be in sorted heroes', function () { + let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="RubberMan" and position()=3]')).get(0); + expect(sortedHero).toBeDefined(); + }); + + it('Magma should be in sorted heroes', function () { + let sortedHero = element.all(by.xpath('//sorted-heroes/[text()="Magma"]')).get(0); + expect(sortedHero).toBeDefined(); + }); + + it('should render Hero of the Month', function () { + let heroOfTheMonth = element.all(by.xpath('//h3[text()="Hero of the month"]')).get(0); + expect(heroOfTheMonth).toBeDefined(); + }); + + it('should render Hero Bios', function () { + let heroBios = element.all(by.xpath('//h3[text()="Hero Bios"]')).get(0); + expect(heroBios).toBeDefined(); + }); + + it('should render Magma\'s description in Hero Bios', function () { + let magmaText = element.all(by.xpath('//textarea[text()="Hero of all trades"]')).get(0); + expect(magmaText).toBeDefined(); + }); + + it('should render Magma\'s phone in Hero Bios and Contacts', function () { + let magmaPhone = element.all(by.xpath('//div[text()="Phone #: 555-555-5555"]')).get(0); + expect(magmaPhone).toBeDefined(); + }); + + it('should render Hero-of-the-Month runner-ups', function () { + let runnersUp = element(by.id('rups1')).getText(); + expect(runnersUp).toContain('RubberMan, Mr. Nice'); + }); + + it('should render DateLogger log entry in Hero-of-the-Month', function () { + let logs = element.all(by.id('logs')).get(0).getText(); + expect(logs).toContain('INFO: starting up at'); + }); + + it('should highlight Hero Bios and Contacts container when mouseover', function () { + let target = element(by.css('div[myHighlight="yellow"]')); + let yellow = 'rgba(255, 255, 0, 1)'; + + expect(target.getCssValue('background-color')).not.toEqual(yellow); + browser.actions().mouseMove(target.getWebElement()).perform(); + expect(target.getCssValue('background-color')).toEqual(yellow); + }); + + describe('in Parent Finder', function () { + let cathy1 = element(by.css('alex cathy')); + let craig1 = element(by.css('alex craig')); + let carol1 = element(by.css('alex carol p')); + let carol2 = element(by.css('barry carol p')); + + it('"Cathy" should find "Alex" via the component class', function () { + expect(cathy1.getText()).toContain('Found Alex via the component'); + }); + + it('"Craig" should not find "Alex" via the base class', function () { + expect(craig1.getText()).toContain('Did not find Alex via the base'); + }); + + it('"Carol" within "Alex" should have "Alex" parent', function () { + expect(carol1.getText()).toContain('Alex'); + }); + + it('"Carol" within "Barry" should have "Barry" parent', function () { + expect(carol2.getText()).toContain('Barry'); + }); + }); +}); diff --git a/public/docs/_examples/tutorial/ts/example-config.json b/public/docs/_examples/cb-dependency-injection/ts/example-config.json similarity index 100% rename from public/docs/_examples/tutorial/ts/example-config.json rename to public/docs/_examples/cb-dependency-injection/ts/example-config.json diff --git a/public/docs/_examples/cb-dependency-injection/ts/plnkr.json b/public/docs/_examples/cb-dependency-injection/ts/plnkr.json new file mode 100644 index 0000000000..ff0aedca01 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Dependency Injection", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/app-routing.module.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..09a0592d00 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/app-routing.module.ts @@ -0,0 +1,11 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = []; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + providers: [], + exports: [RouterModule] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/app.component.html b/public/docs/_examples/cb-dependency-injection/ts/src/app/app.component.html new file mode 100644 index 0000000000..a715e484fe --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/app.component.html @@ -0,0 +1,38 @@ +

    DI Cookbook

    +
    +

    Logged in user

    +
    Name: {{userContext.name}}
    +
    Role: {{userContext.role}}
    +
    + +
    +

    Hero Bios

    + +
    + + +
    +

    Hero Bios and Contacts

    +
    + +
    +
    + + +
    + +
    + +
    +

    Unsorted Heroes

    + +
    + +
    +

    Sorted Heroes

    + +
    + +
    + +
    diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/app.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/app.component.ts new file mode 100644 index 0000000000..3045893c58 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/app.component.ts @@ -0,0 +1,29 @@ +// #docregion +import { Component } from '@angular/core'; + +// #docregion import-services +import { LoggerService } from './logger.service'; +import { UserContextService } from './user-context.service'; +import { UserService } from './user.service'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', +// #docregion providers + providers: [ LoggerService, UserContextService, UserService ] +// #enddocregion providers +}) +export class AppComponent { +// #enddocregion import-services + + private userId: number = 1; + + // #docregion ctor + constructor(logger: LoggerService, public userContext: UserContextService) { + userContext.loadUser(this.userId); + logger.logInfo('AppComponent initialized'); + } + // #enddocregion ctor +// #docregion import-services +} +// #enddocregion import-services diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/app.module.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/app.module.ts new file mode 100644 index 0000000000..a240e21f7c --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/app.module.ts @@ -0,0 +1,74 @@ +// #docregion +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +// import { AppRoutingModule } from './app-routing.module'; +import { LocationStrategy, + HashLocationStrategy } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { HeroData } from './hero-data'; +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; + + +import { AppComponent } from './app.component'; +import { HeroBioComponent } from './hero-bio.component'; +import { HeroBiosComponent, + HeroBiosAndContactsComponent } from './hero-bios.component'; +import { HeroOfTheMonthComponent } from './hero-of-the-month.component'; +import { HeroContactComponent } from './hero-contact.component'; +import { HeroesBaseComponent, + SortedHeroesComponent } from './sorted-heroes.component'; +import { HighlightDirective } from './highlight.directive'; +import { ParentFinderComponent, + AlexComponent, + AliceComponent, + CarolComponent, + ChrisComponent, + CraigComponent, + CathyComponent, + BarryComponent, + BethComponent, + BobComponent } from './parent-finder.component'; + +const declarations = [ + AppComponent, + HeroBiosComponent, HeroBiosAndContactsComponent, HeroBioComponent, + HeroesBaseComponent, SortedHeroesComponent, + HeroOfTheMonthComponent, HeroContactComponent, + HighlightDirective, + ParentFinderComponent, +]; + +const a_components = [AliceComponent, AlexComponent ]; + +const b_components = [ BarryComponent, BethComponent, BobComponent ]; + +const c_components = [ + CarolComponent, ChrisComponent, CraigComponent, + CathyComponent +]; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + InMemoryWebApiModule.forRoot(HeroData) + // AppRoutingModule TODO: add routes + ], + declarations: [ + declarations, + a_components, + b_components, + c_components, + ], + bootstrap: [ AppComponent ], + // #docregion providers + providers: [ + { provide: LocationStrategy, useClass: HashLocationStrategy } + ] + // #enddocregion providers +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/date-logger.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/date-logger.service.ts new file mode 100644 index 0000000000..875779be40 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/date-logger.service.ts @@ -0,0 +1,19 @@ +/* tslint:disable:one-line:check-open-brace*/ +// #docregion +import { Injectable } from '@angular/core'; + +import { LoggerService } from './logger.service'; + +// #docregion date-logger-service +@Injectable() +// #docregion date-logger-service-signature +export class DateLoggerService extends LoggerService +// #enddocregion date-logger-service-signature +{ + logInfo(msg: any) { super.logInfo(stamp(msg)); } + logDebug(msg: any) { super.logInfo(stamp(msg)); } + logError(msg: any) { super.logError(stamp(msg)); } +} + +function stamp(msg: any) { return msg + ' at ' + new Date(); } +// #enddocregion date-logger-service diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-bio.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-bio.component.ts new file mode 100644 index 0000000000..84f8e05e66 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-bio.component.ts @@ -0,0 +1,27 @@ +// #docregion +import { Component, Input, OnInit } from '@angular/core'; + +import { HeroCacheService } from './hero-cache.service'; + +// #docregion component +@Component({ + selector: 'hero-bio', + // #docregion template + template: ` +

    {{hero.name}}

    + + `, + // #enddocregion template + providers: [HeroCacheService] +}) + +export class HeroBioComponent implements OnInit { + @Input() heroId: number; + + constructor(private heroCache: HeroCacheService) { } + + ngOnInit() { this.heroCache.fetchCachedHero(this.heroId); } + + get hero() { return this.heroCache.hero; } +} +// #enddocregion component diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-bios.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-bios.component.ts new file mode 100644 index 0000000000..217c5edcd0 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-bios.component.ts @@ -0,0 +1,48 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +import { HeroService } from './hero.service'; +import { LoggerService } from './logger.service'; + +//////// HeroBiosComponent //// +// #docregion simple +@Component({ + selector: 'hero-bios', + template: ` + + + `, + providers: [HeroService] +}) +export class HeroBiosComponent { +// #enddocregion simple +// #docregion ctor + constructor(logger: LoggerService) { + logger.logInfo('Creating HeroBiosComponent'); + } +// #enddocregion ctor +// #docregion simple +} +// #enddocregion simple + +//////// HeroBiosAndContactsComponent //// +// #docregion hero-bios-and-contacts +@Component({ + selector: 'hero-bios-and-contacts', + // #docregion template + template: ` + + + `, + // #enddocregion template + // #docregion class-provider + providers: [HeroService] + // #enddocregion class-provider +}) +export class HeroBiosAndContactsComponent { + constructor(logger: LoggerService) { + logger.logInfo('Creating HeroBiosAndContactsComponent'); + } +} +// #enddocregion hero-bios-and-contacts diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-cache.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-cache.service.ts new file mode 100644 index 0000000000..6dbc7a0c4f --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-cache.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +// #docregion service +@Injectable() +export class HeroCacheService { + hero: Hero; + constructor(private heroService: HeroService) {} + + fetchCachedHero(id: number) { + if (!this.hero) { + this.hero = this.heroService.getHeroById(id); + } + return this.hero; + } +} +// #enddocregion service diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-contact.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-contact.component.ts new file mode 100644 index 0000000000..add6df91c5 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-contact.component.ts @@ -0,0 +1,40 @@ +// #docplaster +// #docregion +import { Component, Host, Optional } from '@angular/core'; + +import { HeroCacheService } from './hero-cache.service'; +import { LoggerService } from './logger.service'; + +// #docregion component +@Component({ + selector: 'hero-contact', + template: ` +
    Phone #: {{phoneNumber}} + !!!
    ` +}) +export class HeroContactComponent { + + hasLogger = false; + + constructor( + // #docregion ctor-params + @Host() // limit to the host component's instance of the HeroCacheService + private heroCache: HeroCacheService, + + @Host() // limit search for logger; hides the application-wide logger + @Optional() // ok if the logger doesn't exist + private loggerService: LoggerService + // #enddocregion ctor-params + ) { + if (loggerService) { + this.hasLogger = true; + loggerService.logInfo('HeroContactComponent can log!'); + } + // #docregion ctor + } + // #enddocregion ctor + + get phoneNumber() { return this.heroCache.hero.phone; } + +} +// #enddocregion component diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-data.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-data.ts new file mode 100644 index 0000000000..10cdbcaab1 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-data.ts @@ -0,0 +1,14 @@ +// #docregion +import { Hero } from './hero'; + +export class HeroData { + createDb() { + let heroes = [ + new Hero(1, 'Windstorm'), + new Hero(2, 'Bombasto'), + new Hero(3, 'Magneta'), + new Hero(4, 'Tornado') + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.1.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.1.ts new file mode 100644 index 0000000000..da2c57aeaf --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.1.ts @@ -0,0 +1,26 @@ +// Illustrative (not used), mini-version of the actual HeroOfTheMonthComponent +// Injecting with the MinimalLogger "interface-class" +import { Component, NgModule } from '@angular/core'; +import { LoggerService } from './logger.service'; +import { MinimalLogger } from './minimal-logger.service'; + +// #docregion +@Component({ + selector: 'hero-of-the-month', + templateUrl: './hero-of-the-month.component.html', + // Todo: move this aliasing, `useExisting` provider to the AppModule + providers: [{ provide: MinimalLogger, useExisting: LoggerService }] +}) +export class HeroOfTheMonthComponent { + logs: string[] = []; + constructor(logger: MinimalLogger) { + logger.logInfo('starting up'); + } +} +// #enddocregion + +// This NgModule exists only to avoid the Angular language service's "undeclared component" error +@NgModule({ + declarations: [ HeroOfTheMonthComponent ] +}) +class NoopModule {} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.html b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.html new file mode 100644 index 0000000000..f0ae619d6a --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.html @@ -0,0 +1,9 @@ +

    {{title}}

    +
    Winner: {{heroOfTheMonth.name}}
    +
    Reason for award: {{heroOfTheMonth.description}}
    +
    Runners-up: {{runnersUp}}
    + +

    Logs:

    +
    +
    {{log}}
    +
    diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts new file mode 100644 index 0000000000..90ad13d639 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero-of-the-month.component.ts @@ -0,0 +1,63 @@ +/* tslint:disable:one-line:check-open-brace*/ +// #docplaster +// #docregion injection-token +import { InjectionToken } from '@angular/core'; + +export const TITLE = new InjectionToken('title'); +// #enddocregion injection-token + +// #docregion hero-of-the-month +import { Component, Inject } from '@angular/core'; + +import { DateLoggerService } from './date-logger.service'; +import { Hero } from './hero'; +import { HeroService } from './hero.service'; +import { LoggerService } from './logger.service'; +import { MinimalLogger } from './minimal-logger.service'; +import { RUNNERS_UP, + runnersUpFactory } from './runners-up'; + +// #enddocregion hero-of-the-month +// #docregion some-hero +const someHero = new Hero(42, 'Magma', 'Had a great month!', '555-555-5555'); +// #enddocregion some-hero + +// #docregion hero-of-the-month +@Component({ + selector: 'hero-of-the-month', + templateUrl: './hero-of-the-month.component.html', + providers: [ + // #docregion use-value + { provide: Hero, useValue: someHero }, + // #docregion provide-injection-token + { provide: TITLE, useValue: 'Hero of the Month' }, + // #enddocregion provide-injection-token + // #enddocregion use-value + // #docregion use-class + { provide: HeroService, useClass: HeroService }, + { provide: LoggerService, useClass: DateLoggerService }, + // #enddocregion use-class + // #docregion use-existing + { provide: MinimalLogger, useExisting: LoggerService }, + // #enddocregion use-existing + // #docregion provide-injection-token, use-factory + { provide: RUNNERS_UP, useFactory: runnersUpFactory(2), deps: [Hero, HeroService] } + // #enddocregion provide-injection-token, use-factory + ] +}) +export class HeroOfTheMonthComponent { + logs: string[] = []; + +// #docregion ctor-signature + constructor( + logger: MinimalLogger, + public heroOfTheMonth: Hero, + @Inject(RUNNERS_UP) public runnersUp: string, + @Inject(TITLE) public title: string) +// #enddocregion ctor-signature + { + this.logs = logger.logs; + logger.logInfo('starting up'); + } +} +// #enddocregion hero-of-the-month diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..2063c30d7a --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero.service.ts @@ -0,0 +1,22 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Hero } from './hero'; + +@Injectable() +export class HeroService { + + // TODO move to database + private heroes: Array = [ + new Hero(1, 'RubberMan', 'Hero of many talents', '123-456-7899'), + new Hero(2, 'Magma', 'Hero of all trades', '555-555-5555'), + new Hero(3, 'Mr. Nice', 'The name says it all', '111-222-3333') + ]; + + getHeroById(id: number): Hero { + return this.heroes.find(hero => hero.id === id); + } + + getAllHeroes(): Array { + return this.heroes; + } +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/hero.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero.ts new file mode 100644 index 0000000000..c17069e727 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/hero.ts @@ -0,0 +1,9 @@ +// #docregion +export class Hero { + constructor( + public id: number, + public name: string, + public description?: string, + public phone?: string) { + } +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/highlight.directive.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/highlight.directive.ts new file mode 100644 index 0000000000..e220114daa --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/highlight.directive.ts @@ -0,0 +1,29 @@ +// #docplaster +// #docregion +import { Directive, ElementRef, HostListener, Input } from '@angular/core'; + +@Directive({ + selector: '[myHighlight]' +}) +export class HighlightDirective { + + @Input('myHighlight') highlightColor: string; + + private el: HTMLElement; + + constructor(el: ElementRef) { + this.el = el.nativeElement; + } + + @HostListener('mouseenter') onMouseEnter() { + this.highlight(this.highlightColor || 'cyan'); + } + + @HostListener('mouseleave') onMouseLeave() { + this.highlight(null); + } + + private highlight(color: string) { + this.el.style.backgroundColor = color; + } +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/logger.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/logger.service.ts new file mode 100644 index 0000000000..df8ee6b9c7 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/logger.service.ts @@ -0,0 +1,16 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +export class LoggerService { + logs: string[] = []; + + logInfo(msg: any) { this.log(`INFO: ${msg}`); } + logDebug(msg: any) { this.log(`DEBUG: ${msg}`); } + logError(msg: any) { this.log(`ERROR: ${msg}`, true); } + + private log(msg: any, isErr = false) { + this.logs.push(msg); + isErr ? console.error(msg) : console.log(msg); + } +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/minimal-logger.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/minimal-logger.service.ts new file mode 100644 index 0000000000..d87fa594d1 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/minimal-logger.service.ts @@ -0,0 +1,22 @@ +// #docregion +// Class used as a "narrowing" interface that exposes a minimal logger +// Other members of the actual implementation are invisible +export abstract class MinimalLogger { + logs: string[]; + logInfo: (msg: string) => void; +} +// #enddocregion + +/* +// Transpiles to: +// #docregion minimal-logger-transpiled + var MinimalLogger = (function () { + function MinimalLogger() {} + return MinimalLogger; + }()); + exports("MinimalLogger", MinimalLogger); +// #enddocregion minimal-logger-transpiled +*/ + +// See http://stackoverflow.com/questions/43154832/unexpected-token-export-in-angular-app-with-systemjs-and-typescript/ +export const _ = 0; diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/parent-finder.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/parent-finder.component.ts new file mode 100644 index 0000000000..c6f208f79b --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/parent-finder.component.ts @@ -0,0 +1,215 @@ +/* tslint:disable:no-unused-variable component-selector-name one-line check-open-brace */ +/* tslint:disable:*/ +// #docplaster +// #docregion +import { Component, forwardRef, Optional, SkipSelf } from '@angular/core'; + +// A component base class (see AlexComponent) +export abstract class Base { name = 'Count Basie'; } + +// Marker class, used as an interface +// #docregion parent +export abstract class Parent { name: string; } +// #enddocregion parent + +const DifferentParent = Parent; + +// #docregion provide-parent, provide-the-parent +// Helper method to provide the current component instance in the name of a `parentType`. +// #enddocregion provide-the-parent +// The `parentType` defaults to `Parent` when omitting the second parameter. +// #docregion provide-the-parent +const provideParent = +// #enddocregion provide-parent, provide-the-parent +// #docregion provide-parent + (component: any, parentType?: any) => { + return { provide: parentType || Parent, useExisting: forwardRef(() => component) }; + }; +// #enddocregion provide-parent + +// Simpler syntax version that always provides the component in the name of `Parent`. +const provideTheParent = +// #docregion provide-the-parent + (component: any) => { + return { provide: Parent, useExisting: forwardRef(() => component) }; + }; +// #enddocregion provide-the-parent + + +///////// C - Child ////////// +// #docregion carol +const templateC = ` +
    +

    {{name}}

    +

    My parent is {{parent?.name}}

    +
    `; + +@Component({ + selector: 'carol', + template: templateC +}) +// #docregion carol-class +export class CarolComponent { + name= 'Carol'; + // #docregion carol-ctor + constructor( @Optional() public parent: Parent ) { } + // #enddocregion carol-ctor +} +// #enddocregion carol-class +// #enddocregion carol + +@Component({ + selector: 'chris', + template: templateC +}) +export class ChrisComponent { + name= 'Chris'; + constructor( @Optional() public parent: Parent ) { } +} + +////// Craig /////////// +/** + * Show we cannot inject a parent by its base class. + */ +// #docregion craig +@Component({ + selector: 'craig', + template: ` +
    +

    Craig

    + {{alex ? 'Found' : 'Did not find'}} Alex via the base class. +
    ` +}) +export class CraigComponent { + constructor( @Optional() public alex: Base ) { } +} +// #enddocregion craig + +//////// B - Parent ///////// +// #docregion barry +const templateB = ` +
    +
    +

    {{name}}

    +

    My parent is {{parent?.name}}

    +
    + + +
    `; + +@Component({ + selector: 'barry', + template: templateB, + providers: [{ provide: Parent, useExisting: forwardRef(() => BarryComponent) }] +}) +export class BarryComponent implements Parent { + name = 'Barry'; +// #docregion barry-ctor + constructor( @SkipSelf() @Optional() public parent: Parent ) { } +// #enddocregion barry-ctor +} +// #enddocregion barry + +@Component({ + selector: 'bob', + template: templateB, + providers: [ provideParent(BobComponent) ] +}) +export class BobComponent implements Parent { + name= 'Bob'; + constructor( @SkipSelf() @Optional() public parent: Parent ) { } +} + +@Component({ + selector: 'beth', + template: templateB, +// #docregion beth-providers + providers: [ provideParent(BethComponent, DifferentParent) ] +// #enddocregion beth-providers +}) +export class BethComponent implements Parent { + name= 'Beth'; + constructor( @SkipSelf() @Optional() public parent: Parent ) { } +} + +///////// A - Grandparent ////// + +// #docregion alex, alex-1 +@Component({ + selector: 'alex', + template: ` +
    +

    {{name}}

    + + + +
    `, +// #enddocregion alex-1 +// #docregion alex-providers + providers: [{ provide: Parent, useExisting: forwardRef(() => AlexComponent) }], +// #enddocregion alex-providers +// #docregion alex-1 +}) +// #enddocregion alex-1 +// Todo: Add `... implements Parent` to class signature +// #docregion alex-1 +// #docregion alex-class-signature +export class AlexComponent extends Base +// #enddocregion alex-class-signature +{ + name= 'Alex'; +} +// #enddocregion alex, alex-1 + +///// + +// #docregion alice +@Component({ + selector: 'alice', + template: ` +
    +

    {{name}}

    + + + + +
    `, +// #docregion alice-providers + providers: [ provideParent(AliceComponent) ] +// #enddocregion alice-providers +}) +// #docregion alice-class-signature +export class AliceComponent implements Parent +// #enddocregion alice-class-signature +{ + name= 'Alice'; +} +// #enddocregion alice + +////// Cathy /////////// +/** + * Show we can inject a parent by component type + */ +// #docregion cathy +@Component({ + selector: 'cathy', + template: ` +
    +

    Cathy

    + {{alex ? 'Found' : 'Did not find'}} Alex via the component class.
    +
    ` +}) +export class CathyComponent { + constructor( @Optional() public alex: AlexComponent ) { } +} +// #enddocregion cathy + +///////// ParentFinder ////// +@Component({ + selector: 'parent-finder', + template: ` +

    Parent Finder

    + + ` +}) +export class ParentFinderComponent { } diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/runners-up.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/runners-up.ts new file mode 100644 index 0000000000..0ce81ca55c --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/runners-up.ts @@ -0,0 +1,26 @@ +// #docplaster +// #docregion +import { InjectionToken } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +// #docregion runners-up +export const RUNNERS_UP = new InjectionToken('RunnersUp'); +// #enddocregion runners-up + +// #docregion factory-synopsis +export function runnersUpFactory(take: number) { + return (winner: Hero, heroService: HeroService): string => { + /* ... */ +// #enddocregion factory-synopsis + return heroService + .getAllHeroes() + .filter((hero) => hero.name !== winner.name) + .map(hero => hero.name) + .slice(0, Math.max(0, take)) + .join(', '); +// #docregion factory-synopsis + }; +}; +// #enddocregion factory-synopsis diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/sorted-heroes.component.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/sorted-heroes.component.ts new file mode 100644 index 0000000000..8cb6e3c69c --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/sorted-heroes.component.ts @@ -0,0 +1,52 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +/////// HeroesBaseComponent ///// +// #docregion heroes-base, injection +@Component({ + selector: 'unsorted-heroes', + template: `
    {{hero.name}}
    `, + providers: [HeroService] +}) +export class HeroesBaseComponent implements OnInit { + constructor(private heroService: HeroService) { } +// #enddocregion injection + + heroes: Array; + + ngOnInit() { + this.heroes = this.heroService.getAllHeroes(); + this.afterGetHeroes(); + } + + // Post-process heroes in derived class override. + protected afterGetHeroes() {} + +// #docregion injection +} +// #enddocregion heroes-base,injection + +/////// SortedHeroesComponent ///// +// #docregion sorted-heroes +@Component({ + selector: 'sorted-heroes', + template: `
    {{hero.name}}
    `, + providers: [HeroService] +}) +export class SortedHeroesComponent extends HeroesBaseComponent { + constructor(heroService: HeroService) { + super(heroService); + } + + protected afterGetHeroes() { + this.heroes = this.heroes.sort((h1, h2) => { + return h1.name < h2.name ? -1 : + (h1.name > h2.name ? 1 : 0); + }); + } +} +// #enddocregion sorted-heroes diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/user-context.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/user-context.service.ts new file mode 100644 index 0000000000..ed394fc734 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/user-context.service.ts @@ -0,0 +1,33 @@ +// #docplaster +// #docregion +import { Injectable } from '@angular/core'; + +import { LoggerService } from './logger.service'; +import { UserService } from './user.service'; + +// #docregion injectables, injectable +@Injectable() +export class UserContextService { +// #enddocregion injectables, injectable + name: string; + role: string; + loggedInSince: Date; + + // #docregion ctor, injectables + constructor(private userService: UserService, private loggerService: LoggerService) { + // #enddocregion ctor, injectables + this.loggedInSince = new Date(); + // #docregion ctor, injectables + } + // #enddocregion ctor, injectables + + loadUser(userId: number) { + let user = this.userService.getUserById(userId); + this.name = user.name; + this.role = user.role; + + this.loggerService.logDebug('loaded User'); + } +// #docregion injectables, injectable +} +// #enddocregion injectables, injectable diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/app/user.service.ts b/public/docs/_examples/cb-dependency-injection/ts/src/app/user.service.ts new file mode 100644 index 0000000000..c48b025a08 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/app/user.service.ts @@ -0,0 +1,10 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +export class UserService { + + getUserById(userId: number): any { + return {name: 'Bombasto', role: 'Admin'}; + } +} diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/index.html b/public/docs/_examples/cb-dependency-injection/ts/src/index.html new file mode 100644 index 0000000000..0308c72155 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/index.html @@ -0,0 +1,29 @@ + + + + + + Dependency Injection + + + + + + + + + + + + + + + + + + Loading app... + + + diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/main.ts b/public/docs/_examples/cb-dependency-injection/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-dependency-injection/ts/src/sample.css b/public/docs/_examples/cb-dependency-injection/ts/src/sample.css new file mode 100644 index 0000000000..a8b59efd05 --- /dev/null +++ b/public/docs/_examples/cb-dependency-injection/ts/src/sample.css @@ -0,0 +1,26 @@ +.di-component{ + padding: 10px; + width:300px; + margin-bottom: 10px; +} +div[myHighlight] { + padding: 2px 8px; +} + +/* Parent Finder */ +.a, .b, .c { + margin: 6px 2px 6px; + padding: 4px 6px; +} +.a { + border: solid 2px black; +} +.b { + background: lightblue; + border: solid 1px darkblue; + display: flex; +} +.c { + background: pink; + border: solid 1px red; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-dynamic-component-loader/e2e-spec.ts b/public/docs/_examples/cb-dynamic-component-loader/e2e-spec.ts new file mode 100644 index 0000000000..5036ac2a88 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/e2e-spec.ts @@ -0,0 +1,21 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +/* tslint:disable:quotemark */ +describe('Dynamic Component Loader', function () { + + beforeEach(function () { + browser.get(''); + }); + + it('should load ad banner', function () { + let headline = element(by.xpath("//h4[text()='Featured Hero Profile']")); + let name = element(by.xpath("//h3[text()='Bombasto']")); + let bio = element(by.xpath("//p[text()='Brave as they come']")); + + expect(name).toBeDefined(); + expect(headline).toBeDefined(); + expect(bio).toBeDefined(); + }); +}); diff --git a/public/docs/_examples/upgrade/ts/classes/app/css/.gitkeep b/public/docs/_examples/cb-dynamic-component-loader/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/classes/app/css/.gitkeep rename to public/docs/_examples/cb-dynamic-component-loader/ts/example-config.json diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/plnkr.json b/public/docs/_examples/cb-dynamic-component-loader/ts/plnkr.json new file mode 100644 index 0000000000..c43fb15c12 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "Dynamic Component Loader", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags":["cookbook component"] +} diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts new file mode 100644 index 0000000000..8489fce5b2 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts @@ -0,0 +1,57 @@ +// #docregion +import { Component, Input, AfterViewInit, ViewChild, ComponentFactoryResolver, OnDestroy } from '@angular/core'; + +import { AdDirective } from './ad.directive'; +import { AdItem } from './ad-item'; +import { AdComponent } from './ad.component'; + +@Component({ + selector: 'add-banner', + // #docregion ad-host + template: ` +
    +

    Advertisements

    + +
    + ` + // #enddocregion ad-host +}) +// #docregion class +export class AdBannerComponent implements AfterViewInit, OnDestroy { + @Input() ads: AdItem[]; + currentAddIndex: number = -1; + @ViewChild(AdDirective) adHost: AdDirective; + subscription: any; + interval: any; + + constructor(private _componentFactoryResolver: ComponentFactoryResolver) { } + + ngAfterViewInit() { + this.loadComponent(); + this.getAds(); + } + + ngOnDestroy() { + clearInterval(this.interval); + } + + loadComponent() { + this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length; + let adItem = this.ads[this.currentAddIndex]; + + let componentFactory = this._componentFactoryResolver.resolveComponentFactory(adItem.component); + + let viewContainerRef = this.adHost.viewContainerRef; + viewContainerRef.clear(); + + let componentRef = viewContainerRef.createComponent(componentFactory); + (componentRef.instance).data = adItem.data; + } + + getAds() { + this.interval = setInterval(() => { + this.loadComponent(); + }, 3000); + } +} +// #enddocregion class diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-item.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-item.ts new file mode 100644 index 0000000000..ef8ca70577 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-item.ts @@ -0,0 +1,6 @@ +// #docregion +import { Type } from '@angular/core'; + +export class AdItem { + constructor(public component: Type, public data: any) {} +} diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.component.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.component.ts new file mode 100644 index 0000000000..dee3b47953 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.component.ts @@ -0,0 +1,4 @@ +// #docregion +export interface AdComponent { + data: any; +} diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.directive.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.directive.ts new file mode 100644 index 0000000000..312e605228 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.directive.ts @@ -0,0 +1,10 @@ +// #docregion +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[ad-host]', +}) +export class AdDirective { + constructor(public viewContainerRef: ViewContainerRef) { } +} + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.service.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.service.ts new file mode 100644 index 0000000000..91b0758771 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad.service.ts @@ -0,0 +1,23 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { HeroJobAdComponent } from './hero-job-ad.component'; +import { HeroProfileComponent } from './hero-profile.component'; +import { AdItem } from './ad-item'; + +@Injectable() +export class AdService { + getAds() { + return [ + new AdItem(HeroProfileComponent, {name: 'Bombasto', bio: 'Brave as they come'}), + + new AdItem(HeroProfileComponent, {name: 'Dr IQ', bio: 'Smart as they come'}), + + new AdItem(HeroJobAdComponent, {headline: 'Hiring for several positions', + body: 'Submit your resume today!'}), + + new AdItem(HeroJobAdComponent, {headline: 'Openings in all departments', + body: 'Apply today'}), + ]; + } +} diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/app.component.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/app.component.ts new file mode 100644 index 0000000000..89359ccdf6 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/app.component.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { AdService } from './ad.service'; +import { AdItem } from './ad-item'; + +@Component({ + selector: 'my-app', + template: ` +
    + +
    + ` +}) +export class AppComponent implements OnInit { + ads: AdItem[]; + + constructor(private adService: AdService) {} + + ngOnInit() { + this.ads = this.adService.getAds(); + } +} + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/app.module.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/app.module.ts new file mode 100644 index 0000000000..a65d394709 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/app.module.ts @@ -0,0 +1,27 @@ +// #docregion +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { AppComponent } from './app.component'; +import { HeroJobAdComponent } from './hero-job-ad.component'; +import { AdBannerComponent } from './ad-banner.component'; +import { HeroProfileComponent } from './hero-profile.component'; +import { AdDirective } from './ad.directive'; +import { AdService } from './ad.service'; + +@NgModule({ + imports: [ BrowserModule ], + providers: [AdService], + declarations: [ AppComponent, + AdBannerComponent, + HeroJobAdComponent, + HeroProfileComponent, + AdDirective ], + // #docregion entry-components + entryComponents: [ HeroJobAdComponent, HeroProfileComponent ], + // #enddocregion entry-components + bootstrap: [ AppComponent ] +}) +export class AppModule { + constructor() {} +} + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/hero-job-ad.component.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/hero-job-ad.component.ts new file mode 100644 index 0000000000..675a03d0e0 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/hero-job-ad.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component, Input } from '@angular/core'; + +import { AdComponent } from './ad.component'; + +@Component({ + template: ` +
    +

    {{data.headline}}

    + + {{data.body}} +
    + ` +}) +export class HeroJobAdComponent implements AdComponent { + @Input() data: any; + +} + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/hero-profile.component.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/hero-profile.component.ts new file mode 100644 index 0000000000..1c266db3c9 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/app/hero-profile.component.ts @@ -0,0 +1,22 @@ +// #docregion +import { Component, Input } from '@angular/core'; + +import { AdComponent } from './ad.component'; + +@Component({ + template: ` +
    +

    Featured Hero Profile

    +

    {{data.name}}

    + +

    {{data.bio}}

    + + Hire this hero today! +
    + ` +}) +export class HeroProfileComponent implements AdComponent { + @Input() data: any; +} + + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/index.html b/public/docs/_examples/cb-dynamic-component-loader/ts/src/index.html new file mode 100644 index 0000000000..9239d91d9a --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + + Dynamic Component Loader + + + + + + + + + + + + + + + Loading app... + + + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/main.ts b/public/docs/_examples/cb-dynamic-component-loader/ts/src/main.ts new file mode 100644 index 0000000000..53d16fa43a --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); + diff --git a/public/docs/_examples/cb-dynamic-component-loader/ts/src/sample.css b/public/docs/_examples/cb-dynamic-component-loader/ts/src/sample.css new file mode 100644 index 0000000000..7a2ca1f2dc --- /dev/null +++ b/public/docs/_examples/cb-dynamic-component-loader/ts/src/sample.css @@ -0,0 +1,23 @@ +.hero-profile { + border: 1px solid gray; + padding: 5px; + padding-bottom: 20px; + padding-left: 20px; + border-radius: 10px; + background-color: lightgreen; + color: black; +} + +.job-ad { + border: 1px solid gray; + padding: 5px; + padding-bottom: 20px; + padding-left: 20px; + border-radius: 10px; + background-color: lightblue; + color: black; +} + +.ad-banner { + width: 400px; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-dynamic-form/e2e-spec.ts b/public/docs/_examples/cb-dynamic-form/e2e-spec.ts new file mode 100644 index 0000000000..408ac75766 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/e2e-spec.ts @@ -0,0 +1,29 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +/* tslint:disable:quotemark */ +describe('Dynamic Form', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should submit form', function () { + let firstNameElement = element.all(by.css('input[id=firstName]')).get(0); + expect(firstNameElement.getAttribute('value')).toEqual('Bombasto'); + + let emailElement = element.all(by.css('input[id=emailAddress]')).get(0); + let email = 'test@test.com'; + emailElement.sendKeys(email); + expect(emailElement.getAttribute('value')).toEqual(email); + + element(by.css('select option[value="solid"]')).click(); + + let saveButton = element.all(by.css('button')).get(0); + saveButton.click().then(function(){ + expect(element(by.xpath("//strong[contains(text(),'Saved the following values')]")).isPresent()).toBe(true); + }); + }); + +}); diff --git a/public/docs/_examples/upgrade/ts/classes/app/img/.gitkeep b/public/docs/_examples/cb-dynamic-form/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/classes/app/img/.gitkeep rename to public/docs/_examples/cb-dynamic-form/ts/example-config.json diff --git a/public/docs/_examples/cb-dynamic-form/ts/plnkr.json b/public/docs/_examples/cb-dynamic-form/ts/plnkr.json new file mode 100644 index 0000000000..1f50b4a992 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Dynamic Form", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/app.component.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/app.component.ts new file mode 100644 index 0000000000..582daced2e --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/app.component.ts @@ -0,0 +1,22 @@ +// #docregion +import { Component } from '@angular/core'; + +import { QuestionService } from './question.service'; + +@Component({ + selector: 'my-app', + template: ` +
    +

    Job Application for Heroes

    + +
    + `, + providers: [QuestionService] +}) +export class AppComponent { + questions: any[]; + + constructor(service: QuestionService) { + this.questions = service.getQuestions(); + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/app.module.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/app.module.ts new file mode 100644 index 0000000000..7a68e45a92 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/app.module.ts @@ -0,0 +1,18 @@ +// #docregion +import { BrowserModule } from '@angular/platform-browser'; +import { ReactiveFormsModule } from '@angular/forms'; +import { NgModule } from '@angular/core'; + +import { AppComponent } from './app.component'; +import { DynamicFormComponent } from './dynamic-form.component'; +import { DynamicFormQuestionComponent } from './dynamic-form-question.component'; + +@NgModule({ + imports: [ BrowserModule, ReactiveFormsModule ], + declarations: [ AppComponent, DynamicFormComponent, DynamicFormQuestionComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { + constructor() { + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form-question.component.html b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form-question.component.html new file mode 100644 index 0000000000..9f1b8cd4a6 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form-question.component.html @@ -0,0 +1,17 @@ + +
    + + +
    + + + + + +
    + +
    {{question.label}} is required
    +
    diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form-question.component.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form-question.component.ts new file mode 100644 index 0000000000..024571a7c2 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form-question.component.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +import { QuestionBase } from './question-base'; + +@Component({ + selector: 'df-question', + templateUrl: './dynamic-form-question.component.html' +}) +export class DynamicFormQuestionComponent { + @Input() question: QuestionBase; + @Input() form: FormGroup; + get isValid() { return this.form.controls[this.question.key].valid; } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form.component.html b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form.component.html new file mode 100644 index 0000000000..717f09ff71 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form.component.html @@ -0,0 +1,17 @@ + +
    +
    + +
    + +
    + +
    + +
    +
    + +
    + Saved the following values
    {{payLoad}} +
    +
    diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form.component.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form.component.ts new file mode 100644 index 0000000000..8d95c0d3a4 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/dynamic-form.component.ts @@ -0,0 +1,28 @@ +// #docregion +import { Component, Input, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +import { QuestionBase } from './question-base'; +import { QuestionControlService } from './question-control.service'; + +@Component({ + selector: 'dynamic-form', + templateUrl: './dynamic-form.component.html', + providers: [ QuestionControlService ] +}) +export class DynamicFormComponent implements OnInit { + + @Input() questions: QuestionBase[] = []; + form: FormGroup; + payLoad = ''; + + constructor(private qcs: QuestionControlService) { } + + ngOnInit() { + this.form = this.qcs.toFormGroup(this.questions); + } + + onSubmit() { + this.payLoad = JSON.stringify(this.form.value); + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/question-base.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-base.ts new file mode 100644 index 0000000000..2b32b00f2a --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-base.ts @@ -0,0 +1,25 @@ +// #docregion +export class QuestionBase{ + value: T; + key: string; + label: string; + required: boolean; + order: number; + controlType: string; + + constructor(options: { + value?: T, + key?: string, + label?: string, + required?: boolean, + order?: number, + controlType?: string + } = {}) { + this.value = options.value; + this.key = options.key || ''; + this.label = options.label || ''; + this.required = !!options.required; + this.order = options.order === undefined ? 1 : options.order; + this.controlType = options.controlType || ''; + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/question-control.service.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-control.service.ts new file mode 100644 index 0000000000..1378ba8490 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-control.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; + +import { QuestionBase } from './question-base'; + +@Injectable() +export class QuestionControlService { + constructor() { } + + toFormGroup(questions: QuestionBase[] ) { + let group: any = {}; + + questions.forEach(question => { + group[question.key] = question.required ? new FormControl(question.value || '', Validators.required) + : new FormControl(question.value || ''); + }); + return new FormGroup(group); + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/question-dropdown.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-dropdown.ts new file mode 100644 index 0000000000..35a9074c74 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-dropdown.ts @@ -0,0 +1,12 @@ +// #docregion +import { QuestionBase } from './question-base'; + +export class DropdownQuestion extends QuestionBase { + controlType = 'dropdown'; + options: {key: string, value: string}[] = []; + + constructor(options: {} = {}) { + super(options); + this.options = options['options'] || []; + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/question-textbox.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-textbox.ts new file mode 100644 index 0000000000..aaa7edf267 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/question-textbox.ts @@ -0,0 +1,12 @@ +// #docregion +import { QuestionBase } from './question-base'; + +export class TextboxQuestion extends QuestionBase { + controlType = 'textbox'; + type: string; + + constructor(options: {} = {}) { + super(options); + this.type = options['type'] || ''; + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/app/question.service.ts b/public/docs/_examples/cb-dynamic-form/ts/src/app/question.service.ts new file mode 100644 index 0000000000..bb452cf5e6 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/app/question.service.ts @@ -0,0 +1,47 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { DropdownQuestion } from './question-dropdown'; +import { QuestionBase } from './question-base'; +import { TextboxQuestion } from './question-textbox'; + +@Injectable() +export class QuestionService { + + // Todo: get from a remote source of question metadata + // Todo: make asynchronous + getQuestions() { + + let questions: QuestionBase[] = [ + + new DropdownQuestion({ + key: 'brave', + label: 'Bravery Rating', + options: [ + {key: 'solid', value: 'Solid'}, + {key: 'great', value: 'Great'}, + {key: 'good', value: 'Good'}, + {key: 'unproven', value: 'Unproven'} + ], + order: 3 + }), + + new TextboxQuestion({ + key: 'firstName', + label: 'First name', + value: 'Bombasto', + required: true, + order: 1 + }), + + new TextboxQuestion({ + key: 'emailAddress', + label: 'Email', + type: 'email', + order: 2 + }) + ]; + + return questions.sort((a, b) => a.order - b.order); + } +} diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/index.html b/public/docs/_examples/cb-dynamic-form/ts/src/index.html new file mode 100644 index 0000000000..01963f71e2 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/index.html @@ -0,0 +1,28 @@ + + + + + + Dynamic Form + + + + + + + + + + + + + + + + + Loading app... + + + diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/main.ts b/public/docs/_examples/cb-dynamic-form/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-dynamic-form/ts/src/sample.css b/public/docs/_examples/cb-dynamic-form/ts/src/sample.css new file mode 100644 index 0000000000..fe2cc28481 --- /dev/null +++ b/public/docs/_examples/cb-dynamic-form/ts/src/sample.css @@ -0,0 +1,7 @@ +.errorMessage{ + color:red; +} + +.form-row{ + margin-top: 10px; +} \ No newline at end of file diff --git a/public/docs/_examples/cb-form-validation/e2e-spec.ts b/public/docs/_examples/cb-form-validation/e2e-spec.ts new file mode 100644 index 0000000000..8ffc01e250 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/e2e-spec.ts @@ -0,0 +1,182 @@ +'use strict'; // necessary for node! + +import { browser, element, by, protractor, ElementFinder, ElementArrayFinder } from 'protractor'; +import { appLang, describeIf } from '../protractor-helpers'; + +// THESE TESTS ARE INCOMPLETE +describeIf(appLang.appIsTs || appLang.appIsJs, 'Form Validation Tests', function () { + + beforeAll(function () { + browser.get(''); + }); + + describe('Hero Form 1', () => { + beforeAll(() => { + getPage('hero-form-template1'); + }); + + tests(); + }); + + describe('Hero Form 2', () => { + beforeAll(() => { + getPage('hero-form-template2'); + }); + + tests(); + bobTests(); + }); + + describe('Hero Form 3 (Reactive)', () => { + beforeAll(() => { + getPage('hero-form-reactive3'); + makeNameTooLong(); + }); + + tests(); + bobTests(); + }); +}); + +////////// + +const testName = 'Test Name'; + +let page: { + section: ElementFinder, + form: ElementFinder, + title: ElementFinder, + nameInput: ElementFinder, + alterEgoInput: ElementFinder, + powerSelect: ElementFinder, + errorMessages: ElementArrayFinder, + heroFormButtons: ElementArrayFinder, + heroSubmitted: ElementFinder +}; + +function getPage(sectionTag: string) { + let section = element(by.css(sectionTag)); + let buttons = section.all(by.css('button')); + + page = { + section: section, + form: section.element(by.css('form')), + title: section.element(by.css('h1')), + nameInput: section.element(by.css('#name')), + alterEgoInput: section.element(by.css('#alterEgo')), + powerSelect: section.element(by.css('#power')), + errorMessages: section.all(by.css('div.alert')), + heroFormButtons: buttons, + heroSubmitted: section.element(by.css('hero-submitted > div')) + }; +} + +function tests() { + it('should display correct title', function () { + expect(page.title.getText()).toContain('Hero Form'); + }); + + it('should not display submitted message before submit', function () { + expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(false); + }); + + it('should have form buttons', function () { + expect(page.heroFormButtons.count()).toEqual(2); + }); + + it('should have error at start', function () { + expectFormIsInvalid(); + }); + + // it('showForm', function () { + // page.form.getInnerHtml().then(html => console.log(html)); + // }); + + it('should have disabled submit button', function () { + expect(page.heroFormButtons.get(0).isEnabled()).toBe(false); + }); + + it('resetting name to valid name should clear errors', function () { + const ele = page.nameInput; + expect(ele.isPresent()).toBe(true, 'nameInput should exist'); + ele.clear(); + ele.sendKeys(testName); + expectFormIsValid(); + }); + + it('should produce "required" error after clearing name', function () { + page.nameInput.clear(); + // page.alterEgoInput.click(); // to blur ... didn't work + page.nameInput.sendKeys('x', protractor.Key.BACK_SPACE); // ugh! + expect(page.form.getAttribute('class')).toMatch('ng-invalid'); + expect(page.errorMessages.get(0).getText()).toContain('required'); + }); + + it('should produce "at least 4 characters" error when name="x"', function () { + page.nameInput.clear(); + page.nameInput.sendKeys('x'); // too short + expectFormIsInvalid(); + expect(page.errorMessages.get(0).getText()).toContain('at least 4 characters'); + }); + + it('resetting name to valid name again should clear errors', function () { + page.nameInput.sendKeys(testName); + expectFormIsValid(); + }); + + it('should have enabled submit button', function () { + const submitBtn = page.heroFormButtons.get(0); + expect(submitBtn.isEnabled()).toBe(true); + }); + + it('should hide form after submit', function () { + page.heroFormButtons.get(0).click(); + expect(page.title.isDisplayed()).toBe(false); + }); + + it('submitted form should be displayed', function () { + expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(true); + }); + + it('submitted form should have new hero name', function () { + expect(page.heroSubmitted.getText()).toContain(testName); + }); + + it('clicking edit button should reveal form again', function () { + const editBtn = page.heroSubmitted.element(by.css('button')); + editBtn.click(); + expect(page.heroSubmitted.isElementPresent(by.css('h2'))) + .toBe(false, 'submitted hidden again'); + expect(page.title.isDisplayed()).toBe(true, 'can see form title'); + }); +} + +function expectFormIsValid() { + expect(page.form.getAttribute('class')).toMatch('ng-valid'); +} + +function expectFormIsInvalid() { + expect(page.form.getAttribute('class')).toMatch('ng-invalid'); +} + +function bobTests() { + const emsg = 'Someone named "Bob" cannot be a hero.'; + + it('should produce "no bob" error after setting name to "Bobby"', function () { + page.nameInput.clear(); + page.nameInput.sendKeys('Bobby'); + expectFormIsInvalid(); + expect(page.errorMessages.get(0).getText()).toBe(emsg); + }); + + it('should be ok again with valid name', function () { + page.nameInput.clear(); + page.nameInput.sendKeys(testName); + expectFormIsValid(); + }); +} + +function makeNameTooLong() { + // make the first name invalid + page.nameInput.sendKeys('ThisHeroNameHasWayWayTooManyLetters'); +} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/css/.gitkeep b/public/docs/_examples/cb-form-validation/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/ng2_components/app/css/.gitkeep rename to public/docs/_examples/cb-form-validation/ts/example-config.json diff --git a/public/docs/_examples/cb-form-validation/ts/plnkr.json b/public/docs/_examples/cb-form-validation/ts/plnkr.json new file mode 100644 index 0000000000..c5656d77f7 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/plnkr.json @@ -0,0 +1,8 @@ +{ + "description": "Validation", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ] +} diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/app.component.ts b/public/docs/_examples/cb-form-validation/ts/src/app/app.component.ts new file mode 100644 index 0000000000..2da4dc4d0a --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/app.component.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +
    + +
    + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/app.module.ts b/public/docs/_examples/cb-form-validation/ts/src/app/app.module.ts new file mode 100644 index 0000000000..72b4e3a770 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/app.module.ts @@ -0,0 +1,18 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { HeroFormTemplateModule } from './template/hero-form-template.module'; +import { HeroFormReactiveModule } from './reactive/hero-form-reactive.module'; + +@NgModule({ + imports: [ + BrowserModule, + HeroFormTemplateModule, + HeroFormReactiveModule + ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.html b/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.html new file mode 100644 index 0000000000..149537bd3e --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.html @@ -0,0 +1,47 @@ + +
    +
    +

    Hero Form 3 (Reactive)

    + +
    + +
    + + + + + +
    + {{ formErrors.name }} +
    + +
    + +
    + + +
    + +
    + + + +
    + {{ formErrors.power }} +
    +
    + + + +
    +
    + + +
    diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts b/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts new file mode 100644 index 0000000000..241ff1e782 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.component.ts @@ -0,0 +1,116 @@ +/* tslint:disable: member-ordering forin */ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; + +import { Hero } from '../shared/hero'; +import { forbiddenNameValidator } from '../shared/forbidden-name.directive'; + +@Component({ + selector: 'hero-form-reactive3', + templateUrl: './hero-form-reactive.component.html' +}) +export class HeroFormReactiveComponent implements OnInit { + + powers = ['Really Smart', 'Super Flexible', 'Weather Changer']; + + hero = new Hero(18, 'Dr. WhatIsHisName', this.powers[0], 'Dr. What'); + + submitted = false; + + // #docregion on-submit + onSubmit() { + this.submitted = true; + this.hero = this.heroForm.value; + } + // #enddocregion on-submit +// #enddocregion + + // Reset the form with a new hero AND restore 'pristine' class state + // by toggling 'active' flag which causes the form + // to be removed/re-added in a tick via NgIf + // TODO: Workaround until NgForm has a reset method (#6822) + active = true; +// #docregion class + // #docregion add-hero + addHero() { + this.hero = new Hero(42, '', ''); + this.buildForm(); + // #enddocregion add-hero +// #enddocregion class + + this.active = false; + setTimeout(() => this.active = true, 0); +// #docregion + // #docregion add-hero + } + // #enddocregion add-hero + + // #docregion form-builder + heroForm: FormGroup; + constructor(private fb: FormBuilder) { } + + ngOnInit(): void { + this.buildForm(); + } + + buildForm(): void { + this.heroForm = this.fb.group({ + // #docregion name-validators + 'name': [this.hero.name, [ + Validators.required, + Validators.minLength(4), + Validators.maxLength(24), + forbiddenNameValidator(/bob/i) + ] + ], + // #enddocregion name-validators + 'alterEgo': [this.hero.alterEgo], + 'power': [this.hero.power, Validators.required] + }); + + this.heroForm.valueChanges + .subscribe(data => this.onValueChanged(data)); + + this.onValueChanged(); // (re)set validation messages now + } + + // #enddocregion form-builder + + onValueChanged(data?: any) { + if (!this.heroForm) { return; } + const form = this.heroForm; + + for (const field in this.formErrors) { + // clear previous error message (if any) + this.formErrors[field] = ''; + const control = form.get(field); + + if (control && control.dirty && !control.valid) { + const messages = this.validationMessages[field]; + for (const key in control.errors) { + this.formErrors[field] += messages[key] + ' '; + } + } + } + } + + formErrors = { + 'name': '', + 'power': '' + }; + + validationMessages = { + 'name': { + 'required': 'Name is required.', + 'minlength': 'Name must be at least 4 characters long.', + 'maxlength': 'Name cannot be more than 24 characters long.', + 'forbiddenName': 'Someone named "Bob" cannot be a hero.' + }, + 'power': { + 'required': 'Power is required.' + } + }; +} +// #enddocregion diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.module.ts b/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.module.ts new file mode 100644 index 0000000000..6ff9265e92 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/reactive/hero-form-reactive.module.ts @@ -0,0 +1,13 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; + +import { SharedModule } from '../shared/shared.module'; +import { HeroFormReactiveComponent } from './hero-form-reactive.component'; + +@NgModule({ + imports: [ SharedModule, ReactiveFormsModule ], + declarations: [ HeroFormReactiveComponent ], + exports: [ HeroFormReactiveComponent ] +}) +export class HeroFormReactiveModule { } diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/shared/forbidden-name.directive.ts b/public/docs/_examples/cb-form-validation/ts/src/app/shared/forbidden-name.directive.ts new file mode 100644 index 0000000000..870f514842 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/shared/forbidden-name.directive.ts @@ -0,0 +1,43 @@ +// #docregion +import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } from '@angular/forms'; + +// #docregion custom-validator +/** A hero's name can't match the given regular expression */ +export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn { + return (control: AbstractControl): {[key: string]: any} => { + const name = control.value; + const no = nameRe.test(name); + return no ? {'forbiddenName': {name}} : null; + }; +} +// #enddocregion custom-validator + +// #docregion directive +@Directive({ + selector: '[forbiddenName]', + // #docregion directive-providers + providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}] + // #enddocregion directive-providers +}) +export class ForbiddenValidatorDirective implements Validator, OnChanges { + @Input() forbiddenName: string; + private valFn = Validators.nullValidator; + + ngOnChanges(changes: SimpleChanges): void { + const change = changes['forbiddenName']; + if (change) { + const val: string | RegExp = change.currentValue; + const re = val instanceof RegExp ? val : new RegExp(val, 'i'); + this.valFn = forbiddenNameValidator(re); + } else { + this.valFn = Validators.nullValidator; + } + } + + validate(control: AbstractControl): {[key: string]: any} { + return this.valFn(control); + } +} +// #enddocregion directive + diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/shared/hero.ts b/public/docs/_examples/cb-form-validation/ts/src/app/shared/hero.ts new file mode 100644 index 0000000000..fe2b55e51a --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/shared/hero.ts @@ -0,0 +1,9 @@ +// #docregion +export class Hero { + constructor( + public id: number, + public name: string, + public power: string, + public alterEgo?: string + ) { } +} diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/shared/shared.module.ts b/public/docs/_examples/cb-form-validation/ts/src/app/shared/shared.module.ts new file mode 100644 index 0000000000..2b0ada59bd --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/shared/shared.module.ts @@ -0,0 +1,14 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { ForbiddenValidatorDirective } from './forbidden-name.directive'; +import { SubmittedComponent } from './submitted.component'; + +@NgModule({ + imports: [ CommonModule], + declarations: [ ForbiddenValidatorDirective, SubmittedComponent ], + exports: [ ForbiddenValidatorDirective, SubmittedComponent, + CommonModule ] +}) +export class SharedModule { } diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/shared/submitted.component.ts b/public/docs/_examples/cb-form-validation/ts/src/app/shared/submitted.component.ts new file mode 100644 index 0000000000..18cea6563f --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/shared/submitted.component.ts @@ -0,0 +1,32 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +import { Hero } from './hero'; + +@Component({ + selector: 'hero-submitted', + template: ` +
    +

    You submitted the following:

    +
    +
    Name
    +
    {{ hero.name }}
    +
    +
    +
    Alter Ego
    +
    {{ hero.alterEgo }}
    +
    +
    +
    Power
    +
    {{ hero.power }}
    +
    +
    + +
    ` +}) +export class SubmittedComponent { + @Input() hero: Hero; + @Input() submitted = false; + @Output() submittedChange = new EventEmitter(); + onClick() { this.submittedChange.emit(false); } +} diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template.module.ts b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template.module.ts new file mode 100644 index 0000000000..042c019d5e --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template.module.ts @@ -0,0 +1,14 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { SharedModule } from '../shared/shared.module'; +import { HeroFormTemplate1Component } from './hero-form-template1.component'; +import { HeroFormTemplate2Component } from './hero-form-template2.component'; + +@NgModule({ + imports: [ SharedModule, FormsModule ], + declarations: [ HeroFormTemplate1Component, HeroFormTemplate2Component ], + exports: [ HeroFormTemplate1Component, HeroFormTemplate2Component ] +}) +export class HeroFormTemplateModule { } diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template1.component.html b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template1.component.html new file mode 100644 index 0000000000..22b374b622 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template1.component.html @@ -0,0 +1,61 @@ + +
    +
    +

    Hero Form 1 (Template)

    + +
    + +
    + + + + + +
    +
    + Name is required +
    +
    + Name must be at least 4 characters long. +
    +
    + Name cannot be more than 24 characters long. +
    +
    + +
    + +
    + + +
    + +
    + + + +
    +
    Power is required
    +
    +
    + + + +
    +
    + + +
    diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template1.component.ts b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template1.component.ts new file mode 100644 index 0000000000..1bc29db44d --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template1.component.ts @@ -0,0 +1,47 @@ +/* tslint:disable: member-ordering */ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + + +import { Hero } from '../shared/hero'; + +@Component({ + selector: 'hero-form-template1', + templateUrl: './hero-form-template1.component.html' +}) +// #docregion class +export class HeroFormTemplate1Component { + + powers = ['Really Smart', 'Super Flexible', 'Weather Changer']; + + hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What'); + + submitted = false; + + onSubmit() { + this.submitted = true; + } +// #enddocregion class +// #enddocregion + // Reset the form with a new hero AND restore 'pristine' class state + // by toggling 'active' flag which causes the form + // to be removed/re-added in a tick via NgIf + // TODO: Workaround until NgForm has a reset method (#6822) + active = true; +// #docregion +// #docregion class + + addHero() { + this.hero = new Hero(42, '', ''); +// #enddocregion class +// #enddocregion + + this.active = false; + setTimeout(() => this.active = true, 0); +// #docregion +// #docregion class + } +} +// #enddocregion class +// #enddocregion diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template2.component.html b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template2.component.html new file mode 100644 index 0000000000..8bb7066541 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template2.component.html @@ -0,0 +1,52 @@ + +
    +
    +

    Hero Form 2 (Template & Messages)

    + +
    + +
    + + + + + + + +
    + {{ formErrors.name }} +
    + +
    + +
    + + +
    + +
    + + + +
    + {{ formErrors.power }} +
    +
    + + + +
    +
    + + +
    diff --git a/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template2.component.ts b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template2.component.ts new file mode 100644 index 0000000000..320ef09efd --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/app/template/hero-form-template2.component.ts @@ -0,0 +1,99 @@ +/* tslint:disable: member-ordering forin */ +// #docplaster +// #docregion +import { Component, AfterViewChecked, ViewChild } from '@angular/core'; +import { NgForm } from '@angular/forms'; + +import { Hero } from '../shared/hero'; + +@Component({ + selector: 'hero-form-template2', + templateUrl: './hero-form-template2.component.html' +}) +export class HeroFormTemplate2Component implements AfterViewChecked { + + powers = ['Really Smart', 'Super Flexible', 'Weather Changer']; + + hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What'); + + submitted = false; + + onSubmit() { + this.submitted = true; + } +// #enddocregion + + // Reset the form with a new hero AND restore 'pristine' class state + // by toggling 'active' flag which causes the form + // to be removed/re-added in a tick via NgIf + // TODO: Workaround until NgForm has a reset method (#6822) + active = true; +// #docregion + + addHero() { + this.hero = new Hero(42, '', ''); +// #enddocregion + + this.active = false; + setTimeout(() => this.active = true, 0); +// #docregion + } + + // #docregion view-child + heroForm: NgForm; + @ViewChild('heroForm') currentForm: NgForm; + + ngAfterViewChecked() { + this.formChanged(); + } + + formChanged() { + if (this.currentForm === this.heroForm) { return; } + this.heroForm = this.currentForm; + if (this.heroForm) { + this.heroForm.valueChanges + .subscribe(data => this.onValueChanged(data)); + } + } + // #enddocregion view-child + + // #docregion handler + onValueChanged(data?: any) { + if (!this.heroForm) { return; } + const form = this.heroForm.form; + + for (const field in this.formErrors) { + // clear previous error message (if any) + this.formErrors[field] = ''; + const control = form.get(field); + + if (control && control.dirty && !control.valid) { + const messages = this.validationMessages[field]; + for (const key in control.errors) { + this.formErrors[field] += messages[key] + ' '; + } + } + } + } + + formErrors = { + 'name': '', + 'power': '' + }; + // #enddocregion handler + + // #docregion messages + validationMessages = { + 'name': { + 'required': 'Name is required.', + 'minlength': 'Name must be at least 4 characters long.', + 'maxlength': 'Name cannot be more than 24 characters long.', + 'forbiddenName': 'Someone named "Bob" cannot be a hero.' + }, + 'power': { + 'required': 'Power is required.' + } + }; + // #enddocregion messages +} +// #enddocregion diff --git a/public/docs/_examples/cb-form-validation/ts/src/forms.css b/public/docs/_examples/cb-form-validation/ts/src/forms.css new file mode 100644 index 0000000000..67ad13037b --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/forms.css @@ -0,0 +1,7 @@ +.ng-valid[required], .ng-valid.required { + border-left: 5px solid #42A948; /* green */ +} + +.ng-invalid:not(form) { + border-left: 5px solid #a94442; /* red */ +} diff --git a/public/docs/_examples/cb-form-validation/ts/src/index.html b/public/docs/_examples/cb-form-validation/ts/src/index.html new file mode 100644 index 0000000000..e7201508d7 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/index.html @@ -0,0 +1,29 @@ + + + Hero Form with Validation + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/cb-form-validation/ts/src/main.ts b/public/docs/_examples/cb-form-validation/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/cb-form-validation/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-i18n/e2e-spec.ts b/public/docs/_examples/cb-i18n/e2e-spec.ts new file mode 100644 index 0000000000..3dcca5a670 --- /dev/null +++ b/public/docs/_examples/cb-i18n/e2e-spec.ts @@ -0,0 +1,33 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('i18n E2E Tests', () => { + + beforeEach(function () { + browser.get(''); + }); + + it('should display i18n translated welcome: ¡Hola i18n!', function () { + expect(element(by.css('h1')).getText()).toEqual('¡Hola i18n!'); + }); + + it('should display the node texts without elements', function () { + expect(element(by.css('my-app')).getText()).toContain('No genero ningún elemento'); + expect(element(by.css('my-app')).getText()).toContain('Yo tampoco genero ningún elemento'); + }); + + it('should display the translated title attribute', function () { + const title = element(by.css('img')).getAttribute('title'); + expect(title).toBe('Logo de Angular'); + }); + + it('should display the plural of: a horde of wolves', function () { + expect(element.all(by.css('span')).get(0).getText()).toBe('ningún lobo'); + }); + + it('should display the select of gender', function () { + expect(element.all(by.css('span')).get(1).getText()).toBe('El heroe es mujer'); + }); + +}); diff --git a/public/docs/_examples/cb-i18n/ts/.gitignore b/public/docs/_examples/cb-i18n/ts/.gitignore new file mode 100644 index 0000000000..d38bb50aa9 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/.gitignore @@ -0,0 +1,6 @@ +**/*.ngfactory.ts +**/*.metadata.json +dist +!app/tsconfig.json +!rollup.js +!src/systemjs-text-plugin.js diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/img/.gitkeep b/public/docs/_examples/cb-i18n/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/ng2_components/app/img/.gitkeep rename to public/docs/_examples/cb-i18n/ts/example-config.json diff --git a/public/docs/_examples/cb-i18n/ts/messages.xlf b/public/docs/_examples/cb-i18n/ts/messages.xlf new file mode 100644 index 0000000000..dee8b65aca --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/messages.xlf @@ -0,0 +1,47 @@ + + + + + + Hello i18n! + + An introduction header for this sample + User welcome + + + I don't output any element + + + + +I don't output any element either + + + optional description + optional meaning + + + Angular logo + + + + + + + + + + + + + + The hero is + + + + + + + + + diff --git a/public/docs/_examples/cb-i18n/ts/plnkr.json b/public/docs/_examples/cb-i18n/ts/plnkr.json new file mode 100644 index 0000000000..36f2685129 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/plnkr.json @@ -0,0 +1,19 @@ +{ + "description": "i18n", + "basePath": "src/", + "files": [ + "app/**/*.css", + "app/**/*.html", + "app/**/*.ts", + "messages.xlf", + "locale/messages.*.xlf", + + "!**/*.[1].*", + + "main.ts", + "styles.css", + "systemjs-text-plugin.js", + "index.html" + ], + "tags": ["i18n"] +} diff --git a/public/docs/_examples/cb-i18n/ts/src/app/app.component.1.html b/public/docs/_examples/cb-i18n/ts/src/app/app.component.1.html new file mode 100644 index 0000000000..cc7d4f1155 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/app/app.component.1.html @@ -0,0 +1,15 @@ + +

    Hello i18n!

    + + + +

    Hello i18n!

    + + + +

    Hello i18n!

    + + + + + diff --git a/public/docs/_examples/cb-i18n/ts/src/app/app.component.html b/public/docs/_examples/cb-i18n/ts/src/app/app.component.html new file mode 100644 index 0000000000..39ace24f79 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/app/app.component.html @@ -0,0 +1,34 @@ + + +

    Hello i18n!

    + + + +I don't output any element + + +
    + + + +I don't output any element either + + + +
    + + + + +
    + + +{wolves, plural, =0 {no wolves} =1 {one wolf} =2 {two wolves} other {a wolf pack}} + +({{wolves}}) +

    + + +The hero is {gender, select, m {male} f {female}} + +
    diff --git a/public/docs/_examples/cb-i18n/ts/src/app/app.component.ts b/public/docs/_examples/cb-i18n/ts/src/app/app.component.ts new file mode 100644 index 0000000000..09b8722e9b --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { + wolves = 0; + gender = 'f'; + fly = true; + logo = 'https://angular.io/resources/images/logos/angular/angular.png'; + inc(i: number) { + this.wolves = Math.min(5, Math.max(0, this.wolves + i)); + } + male() { this.gender = 'm'; } + female() { this.gender = 'f'; } +} + diff --git a/public/docs/_examples/cb-i18n/ts/src/app/app.module.ts b/public/docs/_examples/cb-i18n/ts/src/app/app.module.ts new file mode 100644 index 0000000000..64ad44075b --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/app/app.module.ts @@ -0,0 +1,13 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) + +export class AppModule { } diff --git a/public/docs/_examples/cb-i18n/ts/src/app/i18n-providers.ts b/public/docs/_examples/cb-i18n/ts/src/app/i18n-providers.ts new file mode 100644 index 0000000000..f0bb662dc3 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/app/i18n-providers.ts @@ -0,0 +1,33 @@ +// #docregion +import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core'; + +export function getTranslationProviders(): Promise { + + // Get the locale id from the global + const locale = document['locale'] as string; + + // return no providers if fail to get translation file for locale + const noProviders: Object[] = []; + + // No locale or U.S. English: no translation providers + if (!locale || locale === 'en-US') { + return Promise.resolve(noProviders); + } + + // Ex: 'locale/messages.es.xlf` + const translationFile = `./locale/messages.${locale}.xlf`; + + return getTranslationsWithSystemJs(translationFile) + .then( (translations: string ) => [ + { provide: TRANSLATIONS, useValue: translations }, + { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }, + { provide: LOCALE_ID, useValue: locale } + ]) + .catch(() => noProviders); // ignore if file not found +} + +declare var System: any; + +function getTranslationsWithSystemJs(file: string) { + return System.import(file + '!text'); // relies on text plugin +} diff --git a/public/docs/_examples/cb-i18n/ts/src/index.html b/public/docs/_examples/cb-i18n/ts/src/index.html new file mode 100644 index 0000000000..ce90cd24c4 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/index.html @@ -0,0 +1,39 @@ + + + + + Angular i18n example + + + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/cb-i18n/ts/src/locale/messages.es.xlf b/public/docs/_examples/cb-i18n/ts/src/locale/messages.es.xlf new file mode 100644 index 0000000000..7b813c38dd --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/locale/messages.es.xlf @@ -0,0 +1,41 @@ + + + + + + Hello i18n! + ¡Hola i18n! + An introduction header for this sample + User welcome + + + I don't output any element + No genero ningún elemento + + + +I don't output any element either + + Yo tampoco genero ningún elemento + optional description + optional meaning + + + Angular logo + Logo de Angular + + + + {wolves, plural, =0 {ningún lobo} =1 {un lobo} =2 {dos lobos} other {una horda de lobos}} + + + The hero is + El heroe es + + + + {gender, select, m {hombre} f {mujer}} + + + + diff --git a/public/docs/_examples/cb-i18n/ts/src/locale/messages.es.xlf.html b/public/docs/_examples/cb-i18n/ts/src/locale/messages.es.xlf.html new file mode 100644 index 0000000000..a6cdccc6c1 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/locale/messages.es.xlf.html @@ -0,0 +1,54 @@ + + + + + + + + + Hello i18n! + ¡Hola i18n! + An introduction header for this sample + User welcome + + + + + I don't output any element + No genero ningún elemento + + + I don't output any element either + Yo tampoco genero ningún elemento + optional description + optional meaning + + + Angular logo + Logo de Angular + + + + + + {wolves, plural, =0 {ningún lobo} =1 {un lobo} =2 {dos lobos} other {una horda de lobos}} + + + + + + The hero is + El heroe es + + + + + + {gender, select, m {hombre} f {mujer}} + + + + + + + diff --git a/public/docs/_examples/cb-i18n/ts/src/main.1.ts b/public/docs/_examples/cb-i18n/ts/src/main.1.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/main.1.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-i18n/ts/src/main.ts b/public/docs/_examples/cb-i18n/ts/src/main.ts new file mode 100644 index 0000000000..894cecfb10 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/main.ts @@ -0,0 +1,10 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { getTranslationProviders } from './app/i18n-providers'; + +import { AppModule } from './app/app.module'; + +getTranslationProviders().then(providers => { + const options = { providers }; + platformBrowserDynamic().bootstrapModule(AppModule, options); +}); diff --git a/public/docs/_examples/cb-i18n/ts/src/systemjs-text-plugin.js b/public/docs/_examples/cb-i18n/ts/src/systemjs-text-plugin.js new file mode 100644 index 0000000000..d5ca508fe0 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/src/systemjs-text-plugin.js @@ -0,0 +1,14 @@ +// #docregion +/* + SystemJS Text plugin from + https://github.com/systemjs/plugin-text/blob/master/text.js +*/ +exports.translate = function(load) { + if (this.builder && this.transpiler) { + load.metadata.format = 'esm'; + return 'exp' + 'ort var __useDefault = true; exp' + 'ort default ' + JSON.stringify(load.source) + ';'; + } + + load.metadata.format = 'amd'; + return 'def' + 'ine(function() {\nreturn ' + JSON.stringify(load.source) + ';\n});'; +} diff --git a/public/docs/_examples/cb-set-document-title/e2e-spec.ts b/public/docs/_examples/cb-set-document-title/e2e-spec.ts new file mode 100644 index 0000000000..801b732995 --- /dev/null +++ b/public/docs/_examples/cb-set-document-title/e2e-spec.ts @@ -0,0 +1,31 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; + +// gulp run-e2e-tests --filter=cb-set-document-title +describe('Set Document Title', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should set the document title', function () { + + let titles = [ + 'Good morning!', + 'Good afternoon!', + 'Good evening!' + ]; + + element.all( by.css( 'ul li a' ) ).each( + function iterator( element: ElementFinder, i: number ) { + + element.click(); + expect( browser.getTitle() ).toEqual( titles[ i ] ); + + } + ); + + }); + +}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/css/.gitkeep b/public/docs/_examples/cb-set-document-title/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/ng2_final/app/css/.gitkeep rename to public/docs/_examples/cb-set-document-title/ts/example-config.json diff --git a/public/docs/_examples/cb-set-document-title/ts/plnkr.json b/public/docs/_examples/cb-set-document-title/ts/plnkr.json new file mode 100644 index 0000000000..020d5a1db2 --- /dev/null +++ b/public/docs/_examples/cb-set-document-title/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Set The Document Title In Angular", + "basePath": "src/", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*" + ], + "tags": [ "cookbook" ] +} diff --git a/public/docs/_examples/cb-set-document-title/ts/src/app/app.component.ts b/public/docs/_examples/cb-set-document-title/ts/src/app/app.component.ts new file mode 100644 index 0000000000..f1905e635d --- /dev/null +++ b/public/docs/_examples/cb-set-document-title/ts/src/app/app.component.ts @@ -0,0 +1,29 @@ +// #docplaster +// #docregion +// Import the native Angular services. +import { Component } from '@angular/core'; +import { Title } from '@angular/platform-browser'; + +@Component({ +selector: 'my-app', +template: + `

    + Select a title to set on the current HTML document: +

    + + + ` +}) +// #docregion class +export class AppComponent { + public constructor(private titleService: Title ) { } + + public setTitle( newTitle: string) { + this.titleService.setTitle( newTitle ); + } +} +// #enddocregion class diff --git a/public/docs/_examples/cb-set-document-title/ts/src/app/app.module.ts b/public/docs/_examples/cb-set-document-title/ts/src/app/app.module.ts new file mode 100644 index 0000000000..81f13c244c --- /dev/null +++ b/public/docs/_examples/cb-set-document-title/ts/src/app/app.module.ts @@ -0,0 +1,19 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule, Title } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent + ], + providers: [ + Title + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/cb-set-document-title/ts/src/index.html b/public/docs/_examples/cb-set-document-title/ts/src/index.html new file mode 100644 index 0000000000..6b00948530 --- /dev/null +++ b/public/docs/_examples/cb-set-document-title/ts/src/index.html @@ -0,0 +1,39 @@ + + + + + + + + + Setting The Document Title Using The Title Service + + + + + + + + + + + + + + + + + + +

    + Setting The Document Title Using The Title Service +

    + + Loading app... + + + diff --git a/public/docs/_examples/cb-set-document-title/ts/src/main.ts b/public/docs/_examples/cb-set-document-title/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/cb-set-document-title/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-ts-to-js/e2e-spec.ts b/public/docs/_examples/cb-ts-to-js/e2e-spec.ts new file mode 100644 index 0000000000..bc67bac8f0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/e2e-spec.ts @@ -0,0 +1,77 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('TypeScript to Javascript tests', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should display the basic component example', function () { + testTag('hero-view', 'Hero Detail: Windstorm'); + }); + + it('should display the component example with lifecycle methods', function () { + testTag('hero-lifecycle', 'Hero: Windstorm'); + }); + + it('should display component with DI example', function () { + testTag('hero-di', 'Hero: Windstorm'); + }); + + it('should display component with DI using @Inject example', function () { + testTag('hero-di-inject', 'Hero: Windstorm'); + }); + + it('should support optional, attribute, and query injections', function () { + let app = element(by.css('hero-di-inject-additional')); + let h1 = app.element(by.css('h1')); + let okMsg = app.element(by.css('p')); + + expect(h1.getText()).toBe('Tour of Heroes'); + app.element(by.buttonText('OK')).click(); + expect(okMsg.getText()).toBe('OK!'); + }); + + it('should support component with inputs and outputs', function () { + let app = element(by.css('hero-io')); + let confirmComponent = app.element(by.css('app-confirm')); + + confirmComponent.element(by.buttonText('OK')).click(); + expect(app.element(by.cssContainingText('span', 'OK clicked')).isPresent()).toBe(true); + + confirmComponent.element(by.buttonText('Cancel')).click(); + expect(app.element(by.cssContainingText('span', 'Cancel clicked')).isPresent()).toBe(true); + }); + + it('should support host bindings and host listeners', function() { + let app = element(by.css('hero-host')); + let h1 = app.element(by.css('h1')); + + expect(app.getAttribute('class')).toBe('heading'); + expect(app.getAttribute('title')).toContain('Tooltip'); + + h1.click(); + expect(h1.getAttribute('class')).toBe('active'); + + h1.click(); + browser.actions().doubleClick(h1.getWebElement()).perform(); + expect(h1.getAttribute('class')).toBe('active'); + }); + + it('should support content and view queries', function() { + let app = element(by.css('hero-queries')); + let windstorm = app.element(by.css('view-child:first-child')); + + app.element(by.css('button')).click(); + expect(windstorm.element(by.css('h2')).getAttribute('class')).toBe('active'); + expect(windstorm.element(by.css('content-child')).getText()).toBe('Active'); + }); + + function testTag(selector: string, expectedText: string) { + let component = element(by.css(selector)); + expect(component.getText()).toBe(expectedText); + } + +}); diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/example-config.json b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/example-config.json new file mode 100644 index 0000000000..81f31aaf0d --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:babel" +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/plnkr.json b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/plnkr.json new file mode 100644 index 0000000000..447fc5f605 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "TypeScript to JavaScript", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/.babelrc b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/.babelrc new file mode 100644 index 0000000000..3aaf507508 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "es2015", + "angular2" + ] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.component.es6 new file mode 100644 index 0000000000..d425788f46 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.component.es6 @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] +}) +export class AppComponent { + title = 'ES6 JavaScript with Decorators'; +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.component.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.component.html new file mode 100644 index 0000000000..995645073a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.component.html @@ -0,0 +1,31 @@ + +

    {{title}}

    +Classes and Class Metadata
    +Input and Output Decorators
    +Dependency Injection
    +Host Metadata
    +View and Child Metadata
    + +
    +

    Classes and Class Metadata

    + + + +
    +

    Input and Output Metadata

    + + +
    +

    Dependency Injection

    + + + + +
    +

    Host Metadata

    + + + +
    +

    View and Child Metadata

    + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.module.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.module.es6 new file mode 100644 index 0000000000..9c248a7ad3 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/app.module.es6 @@ -0,0 +1,55 @@ +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ConfirmComponent } from './confirm.component'; +// #docregion appimport +import { HeroComponent } from './hero.component'; +// #enddocregion appimport +import { HeroComponent as HeroDIComponent } from './hero-di.component'; +import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component'; +import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component'; +import { HeroHostComponent } from './hero-host.component'; +import { HeroHostMetaComponent } from './hero-host-meta.component'; +import { HeroIOComponent } from './hero-io.component'; +import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component'; +import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component'; +import { HeroTitleComponent } from './hero-title.component'; + +import { DataService } from './data.service'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent, + ConfirmComponent, + HeroComponent, + HeroDIComponent, + HeroDIInjectComponent, + HeroDIInjectAdditionalComponent, + HeroHostComponent, HeroHostMetaComponent, + HeroIOComponent, + HeroLifecycleComponent, + HeroQueriesComponent, ViewChildComponent, ContentChildComponent, + HeroTitleComponent + ], + providers: [ + DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ AppComponent ], + + // schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging +}) +export class AppModule { } + +/* tslint:disable no-unused-variable */ +// #docregion ng2import +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { + LocationStrategy, + HashLocationStrategy +} from '@angular/common'; +// #enddocregion ng2import diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/confirm.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/confirm.component.es6 new file mode 100644 index 0000000000..f01fa4de40 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/confirm.component.es6 @@ -0,0 +1,21 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +// #docregion +@Component({ + selector: 'app-confirm', + templateUrl: './confirm.component.html' +}) +export class ConfirmComponent { + @Input() okMsg = ''; + @Input('cancelMsg') notOkMsg = ''; + @Output() ok = new EventEmitter(); + @Output('cancel') notOk = new EventEmitter(); + + onOkClick() { + this.ok.emit(true); + } + onNotOkClick() { + this.notOk.emit(true); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/confirm.component.html new file mode 100644 index 0000000000..45275d218a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/data.service.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/data.service.es6 new file mode 100644 index 0000000000..cd7f9e1aae --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/data.service.es6 @@ -0,0 +1,10 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class DataService { + constructor() { } + + getHeroName() { + return 'Windstorm'; + } +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject-additional.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject-additional.component.es6 new file mode 100644 index 0000000000..ec460a9dbc --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject-additional.component.es6 @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-di-inject-additional', + template: `` +}) +export class HeroComponent { } diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject.component.es6 new file mode 100644 index 0000000000..94b42f956a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di-inject.component.es6 @@ -0,0 +1,13 @@ +import { Component, Inject } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-di-inject', + template: `

    Hero: {{name}}

    ` +}) +export class HeroComponent { + constructor(@Inject('heroName') name) { + this.name = name; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di.component.es6 new file mode 100644 index 0000000000..3a17abd281 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-di.component.es6 @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; +import { DataService } from './data.service'; + +@Component({ + selector: 'hero-di', + template: `

    Hero: {{name}}

    ` +}) +export class HeroComponent { + name = ''; + constructor(dataService: DataService) { + this.name = dataService.getHeroName(); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-host-meta.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-host-meta.component.es6 new file mode 100644 index 0000000000..fefe4a5470 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-host-meta.component.es6 @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host-meta', + template: ` +

    Hero Host in Metadata

    +
    Heading clicks: {{clicks}}
    + `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + + // HostListeners on the entire element + '(click)': 'clicked()', + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: coral;}'] +}) +export class HeroHostMetaComponent { + title = 'Hero Host in Metadata Tooltip'; + headingClass = true; + + active = false; + clicks = 0; + + clicked() { + this.clicks += 1; + } + + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-host.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-host.component.es6 new file mode 100644 index 0000000000..e8d72233c8 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-host.component.es6 @@ -0,0 +1,39 @@ +import { Component, HostBinding, HostListener } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host', + template: ` +

    Hero Host in Decorators

    +
    Heading clicks: {{clicks}}
    + `, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] +}) +export class HeroHostComponent { + // HostBindings to the element + @HostBinding() title = 'Hero Host in Decorators Tooltip'; + @HostBinding('class.heading') headingClass = true; + + active = false; + clicks = 0; + + // HostListeners on the entire element + @HostListener('click') + clicked() { + this.clicks += 1; + } + + @HostListener('mouseenter', ['$event']) + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + @HostListener('mouseleave', ['$event']) + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-io.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-io.component.es6 new file mode 100644 index 0000000000..4b36411e78 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-io.component.es6 @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-io', + template: ` + + + OK clicked + Cancel clicked + ` +}) +export class HeroIOComponent { + okClicked = false; + cancelClicked = false; + + onOk() { + this.okClicked = true; + } + + onCancel() { + this.cancelClicked = true; + } +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-lifecycle.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-lifecycle.component.es6 new file mode 100644 index 0000000000..2539266597 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-lifecycle.component.es6 @@ -0,0 +1,14 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-lifecycle', + template: `

    Hero: {{name}}

    ` +}) +export class HeroComponent { + name = ''; + ngOnInit() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-queries.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-queries.component.es6 new file mode 100644 index 0000000000..fced43d4d7 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-queries.component.es6 @@ -0,0 +1,81 @@ +import { + Component, + ContentChild, + Input, + QueryList, + ViewChildren +} from '@angular/core'; + +@Component({ + selector: 'content-child', + template: ` + + Active + ` +}) +export class ContentChildComponent { + active = false; + + activate() { + this.active = true; + } +} + +//////////////////// + +// #docregion content +@Component({ + selector: 'view-child', + template: ` +

    + {{hero.name}} + +

    `, + styles: ['.active {font-weight: bold; background-color: skyblue;}'] +}) +export class ViewChildComponent { + @Input() hero; + active = false; + + @ContentChild(ContentChildComponent) content; + + activate() { + this.active = !this.active; + this.content.activate(); + } +} +// #enddocregion content + +//////////////////// + +// #docregion view +@Component({ + selector: 'hero-queries', + template: ` + + + + + ` +}) +export class HeroQueriesComponent { + active = false; + heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + + @ViewChildren(ViewChildComponent) views; + + activate() { + this.active = !this.active; + this.views.forEach( + view => view.activate() + ); + } + + get buttonLabel() { + return this.active ? 'Deactivate' : 'Activate'; + } +} +// #enddocregion view diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.es6 new file mode 100644 index 0000000000..04c14a9631 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.es6 @@ -0,0 +1,25 @@ +import { Attribute, Component, Inject, Optional } from '@angular/core'; + +// #docregion +// #docregion templateUrl +@Component({ + selector: 'hero-title', + templateUrl: './hero-title.component.html' +}) +// #enddocregion templateUrl +export class HeroTitleComponent { + msg = ''; + constructor( + @Inject('titlePrefix') @Optional() titlePrefix, + @Attribute('title') title + ) { + this.titlePrefix = titlePrefix; + this.title = title; + } + + ok() { + this.msg = 'OK!'; + } +} +// #enddocregion + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.html new file mode 100644 index 0000000000..164683cb7c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

    {{titlePrefix}} {{title}}

    + +

    {{ msg }}

    diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero.component.es6 new file mode 100644 index 0000000000..2976ec605e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/app/hero.component.es6 @@ -0,0 +1,15 @@ +// #docregion +// #docregion metadata +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-view', + template: '

    {{title}}: {{getName()}}

    ' +}) +// #docregion appexport, class +export class HeroComponent { + title = 'Hero Detail'; + getName() {return 'Windstorm'; } +} +// #enddocregion appexport, class +// #enddocregion metadata diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/index.html b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/index.html new file mode 100644 index 0000000000..2a94db38cc --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/index.html @@ -0,0 +1,26 @@ + + + + + + + + TypeScript to JavaScript + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/main.es6 b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/main.es6 new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6-decorators/src/main.es6 @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/example-config.json b/public/docs/_examples/cb-ts-to-js/js-es6/example-config.json new file mode 100644 index 0000000000..81f31aaf0d --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:babel" +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/plnkr.json b/public/docs/_examples/cb-ts-to-js/js-es6/plnkr.json new file mode 100644 index 0000000000..447fc5f605 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "TypeScript to JavaScript", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/.babelrc b/public/docs/_examples/cb-ts-to-js/js-es6/src/.babelrc new file mode 100644 index 0000000000..3c078e9f99 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "es2015" + ] +} diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.component.es6 new file mode 100644 index 0000000000..6079f7f246 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.component.es6 @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +export class AppComponent { + constructor() { + this.title = 'Plain ES6 JavaScript'; + } +} + +AppComponent.annotations = [ + new Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.component.html b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.component.html new file mode 100644 index 0000000000..52b9b4580e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.component.html @@ -0,0 +1,30 @@ + +

    {{title}}

    +Classes and Class Metadata
    +Input and Output Metadata
    +Dependency Injection
    +Host Metadata
    +View and Child Metadata
    + +
    +

    Classes and Class Metadata

    + + + +
    +

    Input and Output Metadata

    + + +
    +

    Dependency Injection

    + + + + +
    +

    Host Metadata

    + + +
    +

    View and Child Metadata

    + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.module.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.module.es6 new file mode 100644 index 0000000000..f31141e78f --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/app.module.es6 @@ -0,0 +1,56 @@ +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ConfirmComponent } from './confirm.component'; +// #docregion appimport +import { HeroComponent } from './hero.component'; + +// #enddocregion appimport +import { HeroComponent as HeroDIComponent } from './hero-di.component'; +import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component'; +import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component'; +import { HeroHostComponent } from './hero-host.component'; +import { HeroIOComponent } from './hero-io.component'; +import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component'; +import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component'; +import { HeroTitleComponent } from './hero-title.component'; + +import { DataService } from './data.service'; + +export class AppModule { } + +AppModule.annotations = [ + new NgModule({ + imports: [ BrowserModule], + declarations: [ + AppComponent, + ConfirmComponent, + HeroComponent, + HeroDIComponent, + HeroDIInjectComponent, + HeroDIInjectAdditionalComponent, + HeroHostComponent, + HeroIOComponent, + HeroLifecycleComponent, + HeroQueriesComponent, ViewChildComponent, ContentChildComponent, + HeroTitleComponent + ], + providers: [ + DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ AppComponent ], + + // schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging + }) +] + +/* tslint:disable no-unused-variable */ +// #docregion ng2import +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { + LocationStrategy, + HashLocationStrategy +} from '@angular/common'; +// #enddocregion ng2import diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/confirm.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/confirm.component.es6 new file mode 100644 index 0000000000..296268dda4 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/confirm.component.es6 @@ -0,0 +1,31 @@ +import { Component, EventEmitter } from '@angular/core'; + +// #docregion +export class ConfirmComponent { + constructor(){ + this.ok = new EventEmitter(); + this.notOk = new EventEmitter(); + } + onOkClick() { + this.ok.emit(true); + } + onNotOkClick() { + this.notOk.emit(true); + } +} + +ConfirmComponent.annotations = [ + new Component({ + selector: 'app-confirm', + templateUrl: './confirm.component.html', + inputs: [ + 'okMsg', + 'notOkMsg: cancelMsg' + ], + outputs: [ + 'ok', + 'notOk: cancel' + ] + }) +]; +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/confirm.component.html new file mode 100644 index 0000000000..45275d218a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/data.service.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/data.service.es6 new file mode 100644 index 0000000000..de023ce5a0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/data.service.es6 @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; + +export class DataService { + constructor() { + } + getHeroName() { + return 'Windstorm'; + } +} + +DataService.annotations = [ + new Injectable() +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di-inject-additional.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di-inject-additional.component.es6 new file mode 100644 index 0000000000..5eb9bab815 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di-inject-additional.component.es6 @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +export class HeroComponent { } + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-di-inject-additional', + template: `` + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di-inject.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di-inject.component.es6 new file mode 100644 index 0000000000..2f95a0b981 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di-inject.component.es6 @@ -0,0 +1,20 @@ +import { Component, Inject } from '@angular/core'; + +// #docregion +export class HeroComponent { + constructor(name) { + this.name = name; + } +} + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-di-inject', + template: `

    Hero: {{name}}

    ` + }) +]; + +HeroComponent.parameters = [ + [new Inject('heroName')] +]; +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di.component.es6 new file mode 100644 index 0000000000..a18b1ba777 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-di.component.es6 @@ -0,0 +1,21 @@ +// #docregion +import { Component } from '@angular/core'; +import { DataService } from './data.service'; + +export class HeroComponent { + constructor(dataService) { + this.name = dataService.getHeroName(); + } +} + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-di', + template: `

    Hero: {{name}}

    ` + }) +]; + +HeroComponent.parameters = [ + [DataService] +]; +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-host.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-host.component.es6 new file mode 100644 index 0000000000..b06701ee8d --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-host.component.es6 @@ -0,0 +1,50 @@ +import { Component } from '@angular/core'; + +// #docregion +export class HeroHostComponent { + constructor() { + this.active = false; + this.clicks = 0; + this.headingClass = true; + this.title = 'Hero Host Tooltip'; + } + + clicked() { + this.clicks += 1; + } + + enter(event) { + this.active = true; + this.headingClass = false; + } + + leave(event) { + this.active = false; + this.headingClass = true; + } +} + +// #docregion metadata +HeroHostComponent.annotations = [ + new Component({ + selector: 'hero-host', + template: ` +

    Hero Host

    +
    Heading clicks: {{clicks}}
    + `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + '(click)': 'clicked()', + + // HostListeners on the entire element + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] + }) +]; +// #enddocregion metadata +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-io.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-io.component.es6 new file mode 100644 index 0000000000..0dc8c08f2d --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-io.component.es6 @@ -0,0 +1,31 @@ +import { Component } from '@angular/core'; + +export class HeroIOComponent { + constructor() { + this.okClicked = false; + this.cancelClicked = false; + } + + onOk() { + this.okClicked = true; + } + + onCancel() { + this.cancelClicked = true; + } +} + +HeroIOComponent.annotations = [ + new Component({ + selector: 'hero-io', + template: ` + + + OK clicked + Cancel clicked + ` + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-lifecycle.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-lifecycle.component.es6 new file mode 100644 index 0000000000..b394ff59aa --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-lifecycle.component.es6 @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; +export class HeroComponent { + ngOnInit() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } +} + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-lifecycle', + template: `

    Hero: {{name}}

    ` + }) +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-queries.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-queries.component.es6 new file mode 100644 index 0000000000..bf3b914406 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-queries.component.es6 @@ -0,0 +1,97 @@ +import { + Component, + ContentChild, + Input, + QueryList, + ViewChildren +} from '@angular/core'; + +export class ContentChildComponent { + constructor() { + this.active = false; + } + + activate() { + this.active = !this.active; + } +} + +ContentChildComponent.annotations = [ + new Component({ + selector: 'content-child', + template: ` + + Active + ` + }) +]; + +//////////////////// + +// #docregion content +export class ViewChildComponent { + constructor() { + this.active = false; + } + + activate() { + this.active = !this.active; + this.content.activate(); + } +} + +ViewChildComponent.annotations = [ + new Component({ + selector: 'view-child', + template: `

    + {{hero.name}} + +

    `, + styles: ['.active {font-weight: bold; background-color: skyblue;}'], + inputs: ['hero'], + queries: { + content: new ContentChild(ContentChildComponent) + } + }) +]; +// #enddocregion content + +//////////////////// + +// #docregion view +export class HeroQueriesComponent { + constructor(){ + this.active = false; + this.heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + } + + activate() { + this.active = !this.active; + this.views.forEach( + view => view.activate() + ); + } + + get buttonLabel() { + return this.active ? 'Deactivate' : 'Activate'; + } +} + +HeroQueriesComponent.annotations = [ + new Component({ + selector: 'hero-queries', + template: ` + + + + + `, + queries: { + views: new ViewChildren(ViewChildComponent) + } + }) +]; +// #enddocregion view diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-title.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-title.component.es6 new file mode 100644 index 0000000000..4b89dfba83 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-title.component.es6 @@ -0,0 +1,28 @@ +import { Attribute, Component, Inject, Optional } from '@angular/core'; + +// #docregion +export class HeroTitleComponent { + constructor(titlePrefix, title) { + this.titlePrefix = titlePrefix; + this.title = title; + this.msg = ''; + } + + ok() { + this.msg = 'OK!'; + } +} + +// #docregion templateUrl +HeroTitleComponent.annotations = [ + new Component({ + selector: 'hero-title', + templateUrl: './hero-title.component.html' + }) +]; +// #enddocregion templateUrl + +HeroTitleComponent.parameters = [ + [new Optional(), new Inject('titlePrefix')], + [new Attribute('title')] +]; diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-title.component.html new file mode 100644 index 0000000000..164683cb7c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

    {{titlePrefix}} {{title}}

    + +

    {{ msg }}

    diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero.component.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero.component.es6 new file mode 100644 index 0000000000..350f946460 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/app/hero.component.es6 @@ -0,0 +1,21 @@ +// #docplaster +// #docregion +// #docregion metadata +import { Component } from '@angular/core'; + +// #docregion appexport, class +export class HeroComponent { + constructor() { + this.title = 'Hero Detail'; + } + getName() {return 'Windstorm'; } +} +// #enddocregion appexport, class + +HeroComponent.annotations = [ + new Component({ + selector: 'hero-view', + template: '

    {{title}}: {{getName()}}

    ' + }) +]; +// #enddocregion metadata diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/index.html b/public/docs/_examples/cb-ts-to-js/js-es6/src/index.html new file mode 100644 index 0000000000..2a94db38cc --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/index.html @@ -0,0 +1,26 @@ + + + + + + + + TypeScript to JavaScript + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/cb-ts-to-js/js-es6/src/main.es6 b/public/docs/_examples/cb-ts-to-js/js-es6/src/main.es6 new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js-es6/src/main.es6 @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-ts-to-js/js/example-config.json b/public/docs/_examples/cb-ts-to-js/js/example-config.json new file mode 100644 index 0000000000..81f31aaf0d --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:babel" +} diff --git a/public/docs/_examples/cb-ts-to-js/js/plnkr.json b/public/docs/_examples/cb-ts-to-js/js/plnkr.json new file mode 100644 index 0000000000..5e1eb188be --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/plnkr.json @@ -0,0 +1,8 @@ +{ + "description": "TypeScript to JavaScript", + "basePath": "src/", + "files":[ + "!**/karma*.*" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/app.component.html b/public/docs/_examples/cb-ts-to-js/js/src/app/app.component.html new file mode 100644 index 0000000000..4ca26f2657 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/app.component.html @@ -0,0 +1,47 @@ + +

    {{title}}

    +Classes and Class Metadata
    +Interfaces
    +Input and Output Metadata
    +Dependency Injection
    +Host Metadata
    +View and Child Metadata
    + +
    +

    Classes and Class Metadata

    + +

    Classes and Class Metadata (DSL)

    + + +
    +

    Interfaces

    + +

    Interfaces (DSL)

    + + +
    +

    Input and Output Metadata

    + +

    Input and Output Metadata (DSL)

    + + +
    +

    Dependency Injection

    + + + + +

    Dependency Injection (DSL)

    + + + + +
    +

    Host Metadata

    + +

    Host Metadata (DSL)

    + + +
    +

    View and Child Metadata (DSL)

    + diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/app.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/app.component.js new file mode 100644 index 0000000000..b6d1ec29b0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/app.component.js @@ -0,0 +1,20 @@ +(function(app) { + +app.AppComponent = AppComponent; +function AppComponent() { + this.title = 'ES5 JavaScript'; +} + +AppComponent.annotations = [ + new ng.core.Component({ + selector: 'my-app', + templateUrl: 'app/app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host, hero-host-dsl { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] + }) +]; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/app.module.js b/public/docs/_examples/cb-ts-to-js/js/src/app/app.module.js new file mode 100644 index 0000000000..fc2300a89b --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/app.module.js @@ -0,0 +1,46 @@ +(function(app) { + +app.AppModule = AppModule; +function AppModule() { } + +AppModule.annotations = [ + new ng.core.NgModule({ + imports: [ ng.platformBrowser.BrowserModule ], + declarations: [ + app.AppComponent, + app.ConfirmComponent, app.ConfirmDslComponent, + app.HeroComponent, app.HeroDslComponent, + app.HeroDIComponent, app.HeroDIDslComponent, + app.HeroDIInjectComponent, app.HeroDIInjectDslComponent, + app.HeroDIInjectAdditionalComponent, app.HeroDIInjectAdditionalDslComponent, + app.HeroHostComponent, app.HeroHostDslComponent, + app.HeroIOComponent, app.HeroIODslComponent, + app.HeroLifecycleComponent, app.HeroLifecycleDslComponent, + app.heroQueries.HeroQueriesComponent, app.heroQueries.ViewChildComponent, app.heroQueries.ContentChildComponent, + app.HeroTitleComponent, app.HeroTitleDslComponent + ], + providers: [ + app.DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ app.AppComponent ], + + // schemas: [ ng.core.NO_ERRORS_SCHEMA ] // helpful for debugging! + }) +] + +})(window.app = window.app || {}); + + +///// For documentation only ///// +(function () { + // #docregion appimport + var HeroComponent = app.HeroComponent; + // #enddocregion appimport + + // #docregion ng2import + var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic; + var LocationStrategy = ng.common.LocationStrategy; + var HashLocationStrategy = ng.common.HashLocationStrategy; + // #enddocregion ng2import +}) diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/js/src/app/confirm.component.html new file mode 100644 index 0000000000..45275d218a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/confirm.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/confirm.component.js new file mode 100644 index 0000000000..b76d3f54aa --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/confirm.component.js @@ -0,0 +1,75 @@ +(function(app) { + + // #docregion + app.ConfirmComponent = ConfirmComponent; + + ConfirmComponent.annotations = [ + new ng.core.Component({ + selector: 'app-confirm', + templateUrl: 'app/confirm.component.html', + inputs: [ + 'okMsg', + 'notOkMsg: cancelMsg' + ], + outputs: [ + 'ok', + 'notOk: cancel' + ] + }) + ]; + + function ConfirmComponent() { + this.ok = new ng.core.EventEmitter(); + this.notOk = new ng.core.EventEmitter(); + } + + ConfirmComponent.prototype.onOkClick = function() { + this.ok.emit(true); + } + + ConfirmComponent.prototype.onNotOkClick = function() { + this.notOk.emit(true); + } + // #enddocregion + +})(window.app = window.app || {}); + +/////// DSL version //////// + +(function(app) { + + var old = app.ConfirmComponent; + + // #docregion dsl + app.ConfirmComponent = ng.core.Component({ + selector: 'app-confirm-dsl', + templateUrl: 'app/confirm.component.html', + inputs: [ + 'okMsg', + 'notOkMsg: cancelMsg' + ], + outputs: [ + 'ok', + 'notOk: cancel' + ] + }) + .Class({ + constructor: function ConfirmComponent() { + this.ok = new ng.core.EventEmitter(); + this.notOk = new ng.core.EventEmitter(); + }, + + onOkClick: function() { + this.ok.emit(true); + }, + + onNotOkClick: function() { + this.notOk.emit(true); + } + }); + // #enddocregion dsl + + app.ConfirmDslComponent = app.ConfirmComponent; + app.ConfirmComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/data.service.js b/public/docs/_examples/cb-ts-to-js/js/src/app/data.service.js new file mode 100644 index 0000000000..643bb57dca --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/data.service.js @@ -0,0 +1,10 @@ +(function(app) { + + app.DataService = DataService; + function DataService() { } + + DataService.prototype.getHeroName = function() { + return 'Windstorm'; + }; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di-inject-additional.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di-inject-additional.component.js new file mode 100644 index 0000000000..450cc53847 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di-inject-additional.component.js @@ -0,0 +1,36 @@ +(function(app) { + + var old = app.HeroComponent; + + app.HeroComponent = HeroComponent; + + HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-di-inject-additional', + template: '' + }) + ]; + + function HeroComponent() {} + + app.HeroDIInjectAdditionalComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); + +////// DSL Version ///////// +(function(app) { + + var old = app.HeroComponent; + + app.HeroComponent = ng.core.Component({ + selector: 'hero-di-inject-additional-dsl', + template: '' + }).Class({ + constructor: function HeroComponent() { } + }); + + app.HeroDIInjectAdditionalDslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di-inject.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di-inject.component.js new file mode 100644 index 0000000000..879365208c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di-inject.component.js @@ -0,0 +1,51 @@ +(function(app) { + + var old = app.HeroComponent; + + // #docregion + app.HeroComponent = HeroComponent; + + HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-di-inject', + template: '

    Hero: {{name}}

    ' + }) + ]; + + HeroComponent.parameters = [ 'heroName' ]; + + function HeroComponent(name) { + this.name = name; + } + // #enddocregion + + app.HeroDIInjectComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); + +/////// DSL version //////// + +(function(app) { + + var old = app.HeroComponent; + + // #docregion dsl + app.HeroComponent = ng.core.Component({ + selector: 'hero-di-inject-dsl', + template: '

    Hero: {{name}}

    ' + }) + .Class({ + constructor: [ + new ng.core.Inject('heroName'), + function HeroComponent(name) { + this.name = name; + } + ] + }); + // #enddocregion dsl + + app.HeroDIInjectDslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di.component.js new file mode 100644 index 0000000000..2f49a85079 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-di.component.js @@ -0,0 +1,51 @@ +(function(app) { + + var old = app.HeroComponent; + + // #docregion + app.HeroComponent = HeroComponent; + + HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-di', + template: '

    Hero: {{name}}

    ' + }) + ]; + + HeroComponent.parameters = [ app.DataService ]; + + function HeroComponent(dataService) { + this.name = dataService.getHeroName(); + } + // #enddocregion + + app.HeroDIComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); + +////// DSL Version ///// + +(function(app) { + + var old = app.HeroComponent; + + // #docregion dsl + app.HeroComponent = ng.core.Component({ + selector: 'hero-di-dsl', + template: '

    Hero: {{name}}

    ' + }) + .Class({ + constructor: [ + app.DataService, + function HeroComponent(service) { + this.name = service.getHeroName(); + } + ] + }); + // #enddocregion dsl + + app.HeroDIDslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-host.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-host.component.js new file mode 100644 index 0000000000..b73e50aae0 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-host.component.js @@ -0,0 +1,107 @@ +(function(app) { + + var old = app.HeroComponent + + // #docregion + app.HeroComponent = HeroComponent; + + HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-host', + template: + '

    Hero Host

    ' + + '
    Heading clicks: {{clicks}}
    ', + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + '(click)': 'clicked()', + + // HostListeners on the entire element + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] + }) + ]; + + function HeroComponent() { + this.clicks = 0; + this.headingClass = true; + this.title = 'Hero Host Tooltip content'; + } + + HeroComponent.prototype.clicked = function() { + this.clicks += 1; + } + + HeroComponent.prototype.enter = function(event) { + this.active = true; + this.headingClass = false; + } + + HeroComponent.prototype.leave = function(event) { + this.active = false; + this.headingClass = true; + } + // #enddocregion + + app.HeroHostComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); + +//// DSL Version //// + +(function(app) { + + var old = app.HeroComponent; + + // #docregion dsl + app.HeroComponent = ng.core.Component({ + selector: 'hero-host-dsl', + template: ` +

    Hero Host (DSL)

    +
    Heading clicks: {{clicks}}
    + `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + '(click)': 'clicked()', + + // HostListeners on the entire element + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: coral;}'] + }) + .Class({ + constructor: function HeroComponent() { + this.clicks = 0; + this.headingClass = true; + this.title = 'Hero Host Tooltip DSL content'; + }, + + clicked() { + this.clicks += 1; + }, + + enter(event) { + this.active = true; + this.headingClass = false; + }, + + leave(event) { + this.active = false; + this.headingClass = true; + } + }); + // #enddocregion dsl + + app.HeroHostDslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io-dsl.component.html b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io-dsl.component.html new file mode 100644 index 0000000000..c8023ccb45 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io-dsl.component.html @@ -0,0 +1,7 @@ + + +OK clicked +Cancel clicked diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io.component.html b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io.component.html new file mode 100644 index 0000000000..215ddccf92 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io.component.html @@ -0,0 +1,7 @@ + + +OK clicked +Cancel clicked diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io.component.js new file mode 100644 index 0000000000..b09208ce68 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-io.component.js @@ -0,0 +1,52 @@ +(function(app) { + + var old = app.HeroComponent + + app.HeroComponent = HeroComponent; + + HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-io', + templateUrl: 'app/hero-io.component.html' + }) + ]; + + function HeroComponent() { } + + HeroComponent.prototype.onOk = function() { + this.okClicked = true; + } + + HeroComponent.prototype.onCancel = function() { + this.cancelClicked = true; + } + + app.HeroIOComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); + +///// DSL Version //// + +(function(app) { + + var old = app.HeroComponent + + app.HeroComponent = ng.core.Component({ + selector: 'hero-io-dsl', + templateUrl: 'app/hero-io-dsl.component.html' + }) + .Class({ + constructor: function HeroComponent() { }, + onOk: function() { + this.okClicked = true; + }, + onCancel: function() { + this.cancelClicked = true; + } + }); + + app.HeroIODslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-lifecycle.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-lifecycle.component.js new file mode 100644 index 0000000000..2a68288f92 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-lifecycle.component.js @@ -0,0 +1,52 @@ +// #docplaster +(function(app) { + + var old = app.HeroComponent; + + // #docregion + app.HeroComponent = HeroComponent; + + HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-lifecycle', + template: '

    Hero: {{name}}

    ' + }) + ]; + + function HeroComponent() { } + + HeroComponent.prototype.ngOnInit = function() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + }; + // #enddocregion + + app.HeroLifecycleComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); + +/////// DSL version //// + +(function(app) { + + var old = app.HeroComponent; + + // #docregion dsl + app.HeroComponent = ng.core.Component({ + selector: 'hero-lifecycle-dsl', + template: '

    Hero: {{name}}

    ' + }) + .Class({ + constructor: function HeroComponent() { }, + ngOnInit: function() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } + }); + // #enddocregion dsl + + app.HeroLifecycleDslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-queries.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-queries.component.js new file mode 100644 index 0000000000..5e8de58d41 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-queries.component.js @@ -0,0 +1,92 @@ +(function(app) { + + app.heroQueries = app.heroQueries || {}; + + app.heroQueries.ContentChildComponent = ng.core.Component({ + selector: 'content-child', + template: + '' + + 'Active' + + '' + }).Class({ + constructor: function ContentChildComponent() { + this.active = false; + }, + + activate: function() { + this.active = !this.active; + } + }); + + //////////////////// + + // #docregion content + app.heroQueries.ViewChildComponent = ng.core.Component({ + selector: 'view-child', + template: + '

    ' + + '{{hero.name}} ' + + '' + + '

    ', + styles: ['.active {font-weight: bold; background-color: skyblue;}'], + inputs: ['hero'], + queries: { + content: new ng.core.ContentChild(app.heroQueries.ContentChildComponent) + } + }) + .Class({ + constructor: function HeroQueriesHeroComponent() { + this.active = false; + }, + + activate: function() { + this.active = !this.active; + this.content.activate(); + } + }); + // #enddocregion content + + //////////////////// + + // #docregion view + app.heroQueries.HeroQueriesComponent = ng.core.Component({ + selector: 'hero-queries', + template: + '' + + '' + + '' + + '', + queries: { + views: new ng.core.ViewChildren(app.heroQueries.ViewChildComponent) + } + }) + .Class({ + constructor: function HeroQueriesComponent() { + this.active = false; + this.heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + }, + + activate: function() { + this.active = !this.active; + this.views.forEach(function(view) { + view.activate(); + }); + }, + }); + + // #docregion defined-property + // add prototype property w/ getter outside the DSL + var proto = app.heroQueries.HeroQueriesComponent.prototype; + Object.defineProperty(proto, "buttonLabel", { + get: function () { + return this.active ? 'Deactivate' : 'Activate'; + }, + enumerable: true + }); + // #enddocregion defined-property + // #enddocregion view + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-title.component.html new file mode 100644 index 0000000000..164683cb7c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

    {{titlePrefix}} {{title}}

    + +

    {{ msg }}

    diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero-title.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-title.component.js new file mode 100644 index 0000000000..f0770e1228 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero-title.component.js @@ -0,0 +1,64 @@ +(function(app) { + + // #docregion + app.HeroTitleComponent = HeroTitleComponent; + + // #docregion templateUrl + HeroTitleComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-title', + templateUrl: 'app/hero-title.component.html' + }) + ]; + // #enddocregion templateUrl + + function HeroTitleComponent(titlePrefix, title) { + this.titlePrefix = titlePrefix; + this.title = title; + this.msg = ''; + } + + HeroTitleComponent.prototype.ok = function() { + this.msg = 'OK!'; + } + + HeroTitleComponent.parameters = [ + [new ng.core.Optional(), new ng.core.Inject('titlePrefix')], + [new ng.core.Attribute('title')] + ]; + // #enddocregion + +})(window.app = window.app || {}); + +////////// DSL version //////////// + +(function(app) { + + var old = app.HeroTitleComponent; + + // #docregion dsl + app.HeroTitleComponent = ng.core.Component({ + selector: 'hero-title-dsl', + templateUrl: 'app/hero-title.component.html' + }) + .Class({ + constructor: [ + [ new ng.core.Optional(), new ng.core.Inject('titlePrefix') ], + new ng.core.Attribute('title'), + function HeroTitleComponent(titlePrefix, title) { + this.titlePrefix = titlePrefix; + this.title = title; + this.msg = ''; + } + ], + + ok: function() { + this.msg = 'OK!'; + } + }); + // #enddocregion dsl + + app.HeroTitleDslComponent = app.HeroTitleComponent; + app.HeroTitleComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/app/hero.component.js b/public/docs/_examples/cb-ts-to-js/js/src/app/hero.component.js new file mode 100644 index 0000000000..e1407b2635 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/app/hero.component.js @@ -0,0 +1,53 @@ +// #docplaster +(function(app) { + +// #docregion +// #docregion appexport +// #docregion metadata +app.HeroComponent = HeroComponent; // "export" + +HeroComponent.annotations = [ + new ng.core.Component({ + selector: 'hero-view', + template: '

    {{title}}: {{getName()}}

    ' + }) +]; + +// #docregion constructorproto +function HeroComponent() { + this.title = "Hero Detail"; +} + +HeroComponent.prototype.getName = function() { return 'Windstorm'; }; +// #enddocregion constructorproto + +// #enddocregion metadata +// #enddocregion appexport +// #enddocregion + +})(window.app = window.app || {}); + +//////////// DSL version /////////// + +(function(app) { + + var old = app.HeroComponent; + + // #docregion dsl + app.HeroComponent = ng.core.Component({ + selector: 'hero-view-dsl', + template: '

    {{title}}: {{getName()}}

    ', + }) + .Class({ + constructor: function HeroComponent() { + this.title = "Hero Detail"; + }, + + getName: function() { return 'Windstorm'; } + }); + // #enddocregion dsl + + app.HeroDslComponent = app.HeroComponent; + app.HeroComponent = old; + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/cb-ts-to-js/js/src/index.html b/public/docs/_examples/cb-ts-to-js/js/src/index.html new file mode 100644 index 0000000000..00338aa55a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/index.html @@ -0,0 +1,43 @@ + + + + + + + TypeScript to JavaScript + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/cb-ts-to-js/js/src/main.js b/public/docs/_examples/cb-ts-to-js/js/src/main.js new file mode 100644 index 0000000000..fd3e737c9e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/js/src/main.js @@ -0,0 +1,9 @@ +(function(app) { + +var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic; + +document.addEventListener('DOMContentLoaded', function() { + platformBrowserDynamic().bootstrapModule(app.AppModule); +}); + +})(window.app = window.app || {}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/img/.gitkeep b/public/docs/_examples/cb-ts-to-js/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/ng2_final/app/img/.gitkeep rename to public/docs/_examples/cb-ts-to-js/ts/example-config.json diff --git a/public/docs/_examples/cb-ts-to-js/ts/plnkr.json b/public/docs/_examples/cb-ts-to-js/ts/plnkr.json new file mode 100644 index 0000000000..447fc5f605 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "TypeScript to JavaScript", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags":["cookbook"] +} diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/app.component.html b/public/docs/_examples/cb-ts-to-js/ts/src/app/app.component.html new file mode 100644 index 0000000000..995645073a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/app.component.html @@ -0,0 +1,31 @@ + +

    {{title}}

    +Classes and Class Metadata
    +Input and Output Decorators
    +Dependency Injection
    +Host Metadata
    +View and Child Metadata
    + +
    +

    Classes and Class Metadata

    + + + +
    +

    Input and Output Metadata

    + + +
    +

    Dependency Injection

    + + + + +
    +

    Host Metadata

    + + + +
    +

    View and Child Metadata

    + diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/app.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/app.component.ts new file mode 100644 index 0000000000..912c9e1a80 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/app.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styles: [ + // See hero-di-inject-additional.component + 'hero-host, hero-host-meta { border: 1px dashed black; display: block; padding: 4px;}', + '.heading {font-style: italic}' + ] +}) +export class AppComponent { + title = 'TypeScript'; +} diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/app.module.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/app.module.ts new file mode 100644 index 0000000000..992c3c3514 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/app.module.ts @@ -0,0 +1,56 @@ +/* tslint:disable-next-line:no-unused-variable */ +import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ConfirmComponent } from './confirm.component'; +// #docregion appimport +import { HeroComponent } from './hero.component'; +// #enddocregion appimport +import { HeroComponent as HeroDIComponent } from './hero-di.component'; +import { HeroComponent as HeroDIInjectComponent } from './hero-di-inject.component'; +import { HeroComponent as HeroDIInjectAdditionalComponent } from './hero-di-inject-additional.component'; +import { HeroHostComponent } from './hero-host.component'; +import { HeroHostMetaComponent } from './hero-host-meta.component'; +import { HeroIOComponent } from './hero-io.component'; +import { HeroComponent as HeroLifecycleComponent } from './hero-lifecycle.component'; +import { HeroQueriesComponent, ViewChildComponent, ContentChildComponent } from './hero-queries.component'; +import { HeroTitleComponent } from './hero-title.component'; + +import { DataService } from './data.service'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent, + ConfirmComponent, + HeroComponent, + HeroDIComponent, + HeroDIInjectComponent, + HeroDIInjectAdditionalComponent, + HeroHostComponent, HeroHostMetaComponent, + HeroIOComponent, + HeroLifecycleComponent, + HeroQueriesComponent, ViewChildComponent, ContentChildComponent, + HeroTitleComponent + ], + providers: [ + DataService, + { provide: 'heroName', useValue: 'Windstorm' } + ], + bootstrap: [ AppComponent ], + + // schemas: [ NO_ERRORS_SCHEMA ] // helpful for debugging! +}) +export class AppModule { } + +/* tslint:disable no-unused-variable */ +// #docregion ng2import +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { + LocationStrategy, + HashLocationStrategy +} from '@angular/common'; +// #enddocregion ng2import diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/confirm.component.html b/public/docs/_examples/cb-ts-to-js/ts/src/app/confirm.component.html new file mode 100644 index 0000000000..45275d218a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/confirm.component.html @@ -0,0 +1,6 @@ + + diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/confirm.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/confirm.component.ts new file mode 100644 index 0000000000..f01fa4de40 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/confirm.component.ts @@ -0,0 +1,21 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +// #docregion +@Component({ + selector: 'app-confirm', + templateUrl: './confirm.component.html' +}) +export class ConfirmComponent { + @Input() okMsg = ''; + @Input('cancelMsg') notOkMsg = ''; + @Output() ok = new EventEmitter(); + @Output('cancel') notOk = new EventEmitter(); + + onOkClick() { + this.ok.emit(true); + } + onNotOkClick() { + this.notOk.emit(true); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/data.service.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/data.service.ts new file mode 100644 index 0000000000..cd7f9e1aae --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/data.service.ts @@ -0,0 +1,10 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class DataService { + constructor() { } + + getHeroName() { + return 'Windstorm'; + } +} diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di-inject-additional.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di-inject-additional.component.ts new file mode 100644 index 0000000000..ec460a9dbc --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di-inject-additional.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-di-inject-additional', + template: `` +}) +export class HeroComponent { } diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di-inject.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di-inject.component.ts new file mode 100644 index 0000000000..c583a1b0f6 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di-inject.component.ts @@ -0,0 +1,11 @@ +import { Component, Inject } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-di-inject', + template: `

    Hero: {{name}}

    ` +}) +export class HeroComponent { + constructor(@Inject('heroName') private name: string) { } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di.component.ts new file mode 100644 index 0000000000..3a17abd281 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-di.component.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; +import { DataService } from './data.service'; + +@Component({ + selector: 'hero-di', + template: `

    Hero: {{name}}

    ` +}) +export class HeroComponent { + name = ''; + constructor(dataService: DataService) { + this.name = dataService.getHeroName(); + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-host-meta.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-host-meta.component.ts new file mode 100644 index 0000000000..fefe4a5470 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-host-meta.component.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host-meta', + template: ` +

    Hero Host in Metadata

    +
    Heading clicks: {{clicks}}
    + `, + host: { + // HostBindings to the element + '[title]': 'title', + '[class.heading]': 'headingClass', + + // HostListeners on the entire element + '(click)': 'clicked()', + '(mouseenter)': 'enter($event)', + '(mouseleave)': 'leave($event)' + }, + // Styles within (but excluding) the element + styles: ['.active {background-color: coral;}'] +}) +export class HeroHostMetaComponent { + title = 'Hero Host in Metadata Tooltip'; + headingClass = true; + + active = false; + clicks = 0; + + clicked() { + this.clicks += 1; + } + + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-host.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-host.component.ts new file mode 100644 index 0000000000..e8d72233c8 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-host.component.ts @@ -0,0 +1,39 @@ +import { Component, HostBinding, HostListener } from '@angular/core'; + +// #docregion +@Component({ + selector: 'hero-host', + template: ` +

    Hero Host in Decorators

    +
    Heading clicks: {{clicks}}
    + `, + // Styles within (but excluding) the element + styles: ['.active {background-color: yellow;}'] +}) +export class HeroHostComponent { + // HostBindings to the element + @HostBinding() title = 'Hero Host in Decorators Tooltip'; + @HostBinding('class.heading') headingClass = true; + + active = false; + clicks = 0; + + // HostListeners on the entire element + @HostListener('click') + clicked() { + this.clicks += 1; + } + + @HostListener('mouseenter', ['$event']) + enter(event: Event) { + this.active = true; + this.headingClass = false; + } + + @HostListener('mouseleave', ['$event']) + leave(event: Event) { + this.active = false; + this.headingClass = true; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-io.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-io.component.ts new file mode 100644 index 0000000000..4b36411e78 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-io.component.ts @@ -0,0 +1,26 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-io', + template: ` + + + OK clicked + Cancel clicked + ` +}) +export class HeroIOComponent { + okClicked = false; + cancelClicked = false; + + onOk() { + this.okClicked = true; + } + + onCancel() { + this.cancelClicked = true; + } +} diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-lifecycle.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-lifecycle.component.ts new file mode 100644 index 0000000000..2629c85a1a --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-lifecycle.component.ts @@ -0,0 +1,14 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'hero-lifecycle', + template: `

    Hero: {{name}}

    ` +}) +export class HeroComponent implements OnInit { + name: string; + ngOnInit() { + // todo: fetch from server async + setTimeout(() => this.name = 'Windstorm', 0); + } +} diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-queries.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-queries.component.ts new file mode 100644 index 0000000000..8b2d91ea85 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-queries.component.ts @@ -0,0 +1,83 @@ +import { + Component, + ContentChild, + Input, + QueryList, + ViewChildren +} from '@angular/core'; + +@Component({ + selector: 'content-child', + template: ` + + Active + ` +}) +export class ContentChildComponent { + active = false; + + activate() { + this.active = !this.active; + } +} + +//////////////////// + +// #docregion content +@Component({ + selector: 'view-child', + template: ` +

    + {{hero.name}} + +

    `, + styles: ['.active {font-weight: bold; background-color: skyblue;}'] +}) +export class ViewChildComponent { + @Input() hero: any; + active = false; + + @ContentChild(ContentChildComponent) content: ContentChildComponent; + + activate() { + this.active = !this.active; + this.content.activate(); + } +} +// #enddocregion content + +//////////////////// + +// #docregion view +@Component({ + selector: 'hero-queries', + template: ` + + + + + ` +}) +export class HeroQueriesComponent { + active = false; + heroData = [ + {id: 1, name: 'Windstorm'}, + {id: 2, name: 'LaughingGas'} + ]; + + @ViewChildren(ViewChildComponent) views: QueryList; + + activate() { + this.active = !this.active; + this.views.forEach( + view => view.activate() + ); + } + + // #docregion defined-property + get buttonLabel() { + return this.active ? 'Deactivate' : 'Activate'; + } + // #enddocregion defined-property +} +// #enddocregion view diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-title.component.html b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-title.component.html new file mode 100644 index 0000000000..164683cb7c --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-title.component.html @@ -0,0 +1,4 @@ + +

    {{titlePrefix}} {{title}}

    + +

    {{ msg }}

    diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-title.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-title.component.ts new file mode 100644 index 0000000000..48aaae7d44 --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero-title.component.ts @@ -0,0 +1,21 @@ +import { Attribute, Component, Inject, Optional } from '@angular/core'; + +// #docregion +// #docregion templateUrl +@Component({ + selector: 'hero-title', + templateUrl: './hero-title.component.html' +}) +// #enddocregion templateUrl +export class HeroTitleComponent { + msg: string = ''; + constructor( + @Inject('titlePrefix') @Optional() private titlePrefix: string, + @Attribute('title') private title: string + ) { } + + ok() { + this.msg = 'OK!'; + } +} +// #enddocregion diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/app/hero.component.ts b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero.component.ts new file mode 100644 index 0000000000..2976ec605e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/app/hero.component.ts @@ -0,0 +1,15 @@ +// #docregion +// #docregion metadata +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-view', + template: '

    {{title}}: {{getName()}}

    ' +}) +// #docregion appexport, class +export class HeroComponent { + title = 'Hero Detail'; + getName() {return 'Windstorm'; } +} +// #enddocregion appexport, class +// #enddocregion metadata diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/index.html b/public/docs/_examples/cb-ts-to-js/ts/src/index.html new file mode 100644 index 0000000000..d9ad1f7aef --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + + + + TypeScript to JavaScript + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/cb-ts-to-js/ts/src/main.ts b/public/docs/_examples/cb-ts-to-js/ts/src/main.ts new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/cb-ts-to-js/ts/src/main.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-visual-studio-2015/ts/.gitignore b/public/docs/_examples/cb-visual-studio-2015/ts/.gitignore new file mode 100644 index 0000000000..ca3f2dbd5e --- /dev/null +++ b/public/docs/_examples/cb-visual-studio-2015/ts/.gitignore @@ -0,0 +1 @@ +!tsconfig.json diff --git a/public/docs/_examples/cb-visual-studio-2015/ts/tsconfig.json b/public/docs/_examples/cb-visual-studio-2015/ts/tsconfig.json new file mode 100644 index 0000000000..2624488890 --- /dev/null +++ b/public/docs/_examples/cb-visual-studio-2015/ts/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types" + ] + }, + "compileOnSave": true +} diff --git a/public/docs/_examples/cli-quickstart/e2e-spec.ts b/public/docs/_examples/cli-quickstart/e2e-spec.ts new file mode 100644 index 0000000000..59816e13c2 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/e2e-spec.ts @@ -0,0 +1,14 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('cli-quickstart App', () => { + beforeEach(() => { + return browser.get('/'); + }); + + it('should display message saying app works', () => { + let pageTitle = element(by.css('app-root h1')).getText(); + expect(pageTitle).toEqual('My First Angular App'); + }); +}); diff --git a/public/docs/_examples/cli-quickstart/ts/.angular-cli.json b/public/docs/_examples/cli-quickstart/ts/.angular-cli.json new file mode 100644 index 0000000000..49a6b93bd0 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/.angular-cli.json @@ -0,0 +1,57 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "project": { + "name": "master-project" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico" + ], + "index": "index.html", + "main": "main.ts", + "polyfills": "polyfills.ts", + "test": "test.ts", + "tsconfig": "tsconfig.app.json", + "testTsconfig": "tsconfig.spec.json", + "prefix": "app", + "styles": [ + "styles.css" + ], + "scripts": [], + "environmentSource": "environments/environment.ts", + "environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "e2e": { + "protractor": { + "config": "./protractor.conf.js" + } + }, + "lint": [ + { + "project": "src/tsconfig.app.json" + }, + { + "project": "src/tsconfig.spec.json" + }, + { + "project": "e2e/tsconfig.e2e.json" + } + ], + "test": { + "karma": { + "config": "./karma.conf.js" + } + }, + "defaults": { + "styleExt": "css", + "component": {} + } +} diff --git a/public/docs/_examples/cli-quickstart/ts/.editorconfig b/public/docs/_examples/cli-quickstart/ts/.editorconfig new file mode 100644 index 0000000000..6e87a003da --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/public/docs/_examples/cli-quickstart/ts/.gitignore b/public/docs/_examples/cli-quickstart/ts/.gitignore new file mode 100644 index 0000000000..04a48dc643 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/.gitignore @@ -0,0 +1,45 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage/* +/libpeerconnection.log +npm-debug.log +testem.log +/typings + +# e2e +/e2e/*.js +/e2e/*.map + +#System Files +.DS_Store +Thumbs.db + +!src/styles.css +!karma.conf.js +!protractor.conf.js diff --git a/public/docs/_examples/cli-quickstart/ts/README.md b/public/docs/_examples/cli-quickstart/ts/README.md new file mode 100644 index 0000000000..efe9ec67ae --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/README.md @@ -0,0 +1,27 @@ +# MasterProject + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.0.0-rc.0. + +## Development server +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +Before running the tests make sure you are serving the app via `ng serve`. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/public/docs/_examples/cli-quickstart/ts/bs-config.cli.json b/public/docs/_examples/cli-quickstart/ts/bs-config.cli.json new file mode 100644 index 0000000000..ac61d35f83 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/bs-config.cli.json @@ -0,0 +1,11 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "dist", + "middleware": { + "0": null + } + } +} diff --git a/public/docs/_examples/cli-quickstart/ts/e2e/app.e2e-spec.ts b/public/docs/_examples/cli-quickstart/ts/e2e/app.e2e-spec.ts new file mode 100644 index 0000000000..4346d120c8 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/e2e/app.e2e-spec.ts @@ -0,0 +1,14 @@ +import { MyAppPage } from './app.po'; + +describe('my-app App', function() { + let page: MyAppPage; + + beforeEach(() => { + page = new MyAppPage(); + }); + + it('should display message saying app works', () => { + page.navigateTo(); + expect(page.getParagraphText()).toEqual('app works!'); + }); +}); diff --git a/public/docs/_examples/cli-quickstart/ts/e2e/app.po.ts b/public/docs/_examples/cli-quickstart/ts/e2e/app.po.ts new file mode 100644 index 0000000000..5d82157326 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/e2e/app.po.ts @@ -0,0 +1,11 @@ +import { browser, element, by } from 'protractor'; + +export class MyAppPage { + navigateTo() { + return browser.get('/'); + } + + getParagraphText() { + return element(by.css('app-root h1')).getText(); + } +} diff --git a/public/docs/_examples/cli-quickstart/ts/e2e/tsconfig.e2e.json b/public/docs/_examples/cli-quickstart/ts/e2e/tsconfig.e2e.json new file mode 100644 index 0000000000..74c2bca131 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/e2e/tsconfig.e2e.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2016" + ], + "outDir": "../dist/out-tsc-e2e", + "module": "commonjs", + "target": "es6", + "types":[ + "jasmine", + "node" + ] + } +} diff --git a/public/docs/_examples/cli-quickstart/ts/example-config.json b/public/docs/_examples/cli-quickstart/ts/example-config.json new file mode 100644 index 0000000000..313764c3c6 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/example-config.json @@ -0,0 +1,4 @@ +{ + "build": "build:cli", + "run": "serve:cli" +} diff --git a/public/docs/_examples/cli-quickstart/ts/karma.conf.js b/public/docs/_examples/cli-quickstart/ts/karma.conf.js new file mode 100644 index 0000000000..84b4cd5aca --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/karma.conf.js @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/0.13/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular/cli'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular/cli/plugins/karma') + ], + client:{ + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + files: [ + { pattern: './src/test.ts', watched: false } + ], + preprocessors: { + './src/test.ts': ['@angular/cli'] + }, + mime: { + 'text/x-typescript': ['ts','tsx'] + }, + coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: true + }, + angularCli: { + environment: 'dev' + }, + reporters: config.angularCli && config.angularCli.codeCoverage + ? ['progress', 'coverage-istanbul'] + : ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/public/docs/_examples/cli-quickstart/ts/protractor.conf.js b/public/docs/_examples/cli-quickstart/ts/protractor.conf.js new file mode 100644 index 0000000000..2cbc329391 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/protractor.conf.js @@ -0,0 +1,31 @@ +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +/*global jasmine */ +const { SpecReporter } = require('jasmine-spec-reporter'); + +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './e2e/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + beforeLaunch: function() { + require('ts-node').register({ + project: 'e2e/tsconfig.e2e.json' + }); + }, + onPrepare() { + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; diff --git a/public/docs/_examples/cli-quickstart/ts/src/app/app.component.css b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.css new file mode 100644 index 0000000000..a2b21fae82 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.css @@ -0,0 +1,6 @@ +/* #docregion */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} diff --git a/public/docs/_examples/cli-quickstart/ts/src/app/app.component.html b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.html new file mode 100644 index 0000000000..b6931b538a --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.html @@ -0,0 +1,3 @@ +

    + {{title}} +

    diff --git a/public/docs/_examples/cli-quickstart/ts/src/app/app.component.spec.ts b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.spec.ts new file mode 100644 index 0000000000..c740bcd745 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.spec.ts @@ -0,0 +1,32 @@ +import { TestBed, async } from '@angular/core/testing'; + +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + }).compileComponents(); + })); + + it('should create the app', async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + })); + + it(`should have as title 'app works!'`, async(() => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app.title).toEqual('app works!'); + })); + + it('should render title in a h1 tag', async(() => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain('app works!'); + })); +}); diff --git a/public/docs/_examples/cli-quickstart/ts/src/app/app.component.ts b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.ts new file mode 100644 index 0000000000..4c1b4a9bf7 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/app/app.component.ts @@ -0,0 +1,16 @@ +// #docregion import +import { Component } from '@angular/core'; +// #enddocregion import + +// #docregion metadata +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +// #enddocregion metadata +// #docregion title, class +export class AppComponent { + title = 'My First Angular App'; +} +// #enddocregion title, class diff --git a/public/docs/_examples/cli-quickstart/ts/src/app/app.module.ts b/public/docs/_examples/cli-quickstart/ts/src/app/app.module.ts new file mode 100644 index 0000000000..67ae49119b --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/app/app.module.ts @@ -0,0 +1,20 @@ +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppComponent } from './app.component'; + +@NgModule({ + declarations: [ + AppComponent + ], + imports: [ + BrowserModule, + FormsModule, + HttpModule + ], + providers: [], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/.gitkeep b/public/docs/_examples/cli-quickstart/ts/src/assets/.gitkeep similarity index 100% rename from public/docs/_examples/upgrade/ts/ng2_initial/app/css/.gitkeep rename to public/docs/_examples/cli-quickstart/ts/src/assets/.gitkeep diff --git a/public/docs/_examples/cli-quickstart/ts/src/environments/environment.prod.ts b/public/docs/_examples/cli-quickstart/ts/src/environments/environment.prod.ts new file mode 100644 index 0000000000..3612073bc3 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/public/docs/_examples/cli-quickstart/ts/src/environments/environment.ts b/public/docs/_examples/cli-quickstart/ts/src/environments/environment.ts new file mode 100644 index 0000000000..b7f639aeca --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/environments/environment.ts @@ -0,0 +1,8 @@ +// The file contents for the current environment will overwrite these during build. +// The build system defaults to the dev environment which uses `environment.ts`, but if you do +// `ng build --env=prod` then `environment.prod.ts` will be used instead. +// The list of which env maps to which file can be found in `.angular-cli.json`. + +export const environment = { + production: false +}; diff --git a/public/docs/_examples/cli-quickstart/ts/src/favicon.ico b/public/docs/_examples/cli-quickstart/ts/src/favicon.ico new file mode 100644 index 0000000000..8081c7ceaf Binary files /dev/null and b/public/docs/_examples/cli-quickstart/ts/src/favicon.ico differ diff --git a/public/docs/_examples/cli-quickstart/ts/src/index.html b/public/docs/_examples/cli-quickstart/ts/src/index.html new file mode 100644 index 0000000000..8a1a7b32b3 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/index.html @@ -0,0 +1,14 @@ + + + + + MyApp + + + + + + + Loading... + + diff --git a/public/docs/_examples/cli-quickstart/ts/src/main.ts b/public/docs/_examples/cli-quickstart/ts/src/main.ts new file mode 100644 index 0000000000..a9ca1caf8c --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/main.ts @@ -0,0 +1,11 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cli-quickstart/ts/src/polyfills.ts b/public/docs/_examples/cli-quickstart/ts/src/polyfills.ts new file mode 100644 index 0000000000..53bdaf1b86 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/polyfills.ts @@ -0,0 +1,68 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/set'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following to support `@angular/animation`. */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + +/** Evergreen browsers require these. **/ +import 'core-js/es6/reflect'; +import 'core-js/es7/reflect'; + + +/** ALL Firefox browsers require the following to support `@angular/animation`. **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + + + +/*************************************************************************************************** + * Zone JS is required by Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +/** + * Date, currency, decimal and percent pipes. + * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 + */ +// import 'intl'; // Run `npm install --save intl`. diff --git a/public/docs/_examples/cli-quickstart/ts/src/styles.css b/public/docs/_examples/cli-quickstart/ts/src/styles.css new file mode 100644 index 0000000000..d81835d0cd --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/styles.css @@ -0,0 +1,116 @@ +/* #docregion , quickstart, toh */ +/* Master Styles */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +h2, h3 { + color: #444; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +/* #enddocregion quickstart */ +body, input[text], button { + color: #888; + font-family: Cambria, Georgia; +} +/* #enddocregion toh */ +a { + cursor: pointer; + cursor: hand; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} + +/* Navigation link styles */ +nav a { + padding: 5px 10px; + text-decoration: none; + margin-right: 10px; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} + +/* items class */ +.items { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 24em; +} +.items li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.items li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.items li.selected { + background-color: #CFD8DC; + color: white; +} +.items li.selected:hover { + background-color: #BBD8DC; +} +.items .text { + position: relative; + top: -3px; +} +.items .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +/* #docregion toh */ +/* everywhere else */ +* { + font-family: Arial, Helvetica, sans-serif; +} diff --git a/public/docs/_examples/cli-quickstart/ts/src/test.ts b/public/docs/_examples/cli-quickstart/ts/src/test.ts new file mode 100644 index 0000000000..9bf72267e9 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/test.ts @@ -0,0 +1,32 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. +declare var __karma__: any; +declare var require: any; + +// Prevent Karma from running prematurely. +__karma__.loaded = function () {}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); +// Finally, start Karma to run the tests. +__karma__.start(); diff --git a/public/docs/_examples/cli-quickstart/ts/src/tsconfig.app.json b/public/docs/_examples/cli-quickstart/ts/src/tsconfig.app.json new file mode 100644 index 0000000000..9f12c4b849 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/tsconfig.app.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2016", + "dom" + ], + "outDir": "../out-tsc/app", + "target": "es5", + "module": "es2015", + "baseUrl": "", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ] +} diff --git a/public/docs/_examples/cli-quickstart/ts/src/tsconfig.spec.json b/public/docs/_examples/cli-quickstart/ts/src/tsconfig.spec.json new file mode 100644 index 0000000000..6c5160e12e --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/src/tsconfig.spec.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2016" + ], + "outDir": "../out-tsc/spec", + "module": "commonjs", + "target": "es6", + "baseUrl": "", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts" + ], + "include": [ + "**/*.spec.ts" + ] +} diff --git a/public/docs/_examples/cli-quickstart/ts/tsconfig.json b/public/docs/_examples/cli-quickstart/ts/tsconfig.json new file mode 100644 index 0000000000..cde5e35054 --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ + "es2016" + ] + } +} diff --git a/public/docs/_examples/cli-quickstart/ts/zipper.json b/public/docs/_examples/cli-quickstart/ts/zipper.json new file mode 100644 index 0000000000..70bf41659e --- /dev/null +++ b/public/docs/_examples/cli-quickstart/ts/zipper.json @@ -0,0 +1,11 @@ +{ + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[0-9].*", + ".angular-cli.json", + "protractor.conf.js" + ], + "removeSystemJsConfig": true, + "type": "cli" +} diff --git a/public/docs/_examples/component-styles/e2e-spec.ts b/public/docs/_examples/component-styles/e2e-spec.ts new file mode 100644 index 0000000000..32bd30832c --- /dev/null +++ b/public/docs/_examples/component-styles/e2e-spec.ts @@ -0,0 +1,68 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Component Style Tests', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('scopes component styles to component view', function() { + let componentH1 = element(by.css('hero-app > h1')); + let externalH1 = element(by.css('body > h1')); + + expect(componentH1.getCssValue('fontWeight')).toEqual('normal'); + expect(externalH1.getCssValue('fontWeight')).not.toEqual('normal'); + }); + + + it('allows styling :host element', function() { + let host = element(by.css('hero-details')); + + expect(host.getCssValue('borderWidth')).toEqual('1px'); + }); + + it('supports :host() in function form', function() { + let host = element(by.css('hero-details')); + + host.element(by.buttonText('Activate')).click(); + expect(host.getCssValue('borderWidth')).toEqual('3px'); + }); + + it('allows conditional :host-context() styling', function() { + let h2 = element(by.css('hero-details h2')); + + expect(h2.getCssValue('backgroundColor')).toEqual('rgba(238, 238, 255, 1)'); // #eeeeff + }); + + it('styles both view and content children with /deep/', function() { + let viewH3 = element(by.css('hero-team h3')); + let contentH3 = element(by.css('hero-controls h3')); + + expect(viewH3.getCssValue('fontStyle')).toEqual('italic'); + expect(contentH3.getCssValue('fontStyle')).toEqual('italic'); + }); + + it('includes styles loaded with CSS @import', function() { + let host = element(by.css('hero-details')); + + expect(host.getCssValue('padding')).toEqual('10px'); + }); + + it('processes template inline styles', function() { + let button = element(by.css('hero-controls button')); + let externalButton = element(by.css('body > button')); + expect(button.getCssValue('backgroundColor')).toEqual('rgba(255, 255, 255, 1)'); // #ffffff + expect(externalButton.getCssValue('backgroundColor')).not.toEqual('rgba(255, 255, 255, 1)'); + }); + + it('processes template s', function() { + let li = element(by.css('hero-team li:first-child')); + let externalLi = element(by.css('body > ul li')); + + expect(li.getCssValue('listStyleType')).toEqual('square'); + expect(externalLi.getCssValue('listStyleType')).not.toEqual('square'); + }); + +}); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/.gitkeep b/public/docs/_examples/component-styles/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/ng2_initial/app/img/.gitkeep rename to public/docs/_examples/component-styles/ts/example-config.json diff --git a/public/docs/_examples/component-styles/ts/plnkr.json b/public/docs/_examples/component-styles/ts/plnkr.json new file mode 100644 index 0000000000..e045ebcb38 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Component Styles", + "basePath": "src/", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.native.*" + ], + "tags": ["CSS"] +} diff --git a/public/docs/_examples/component-styles/ts/src/app/app.module.ts b/public/docs/_examples/component-styles/ts/src/app/app.module.ts new file mode 100644 index 0000000000..31c72cbbf2 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/app.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { HeroAppComponent } from './hero-app.component'; +import { HeroAppMainComponent } from './hero-app-main.component'; +import { HeroDetailsComponent } from './hero-details.component'; +import { HeroControlsComponent } from './hero-controls.component'; +import { QuestSummaryComponent } from './quest-summary.component'; +import { HeroTeamComponent } from './hero-team.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ + HeroAppComponent, + HeroAppMainComponent, + HeroDetailsComponent, + HeroControlsComponent, + QuestSummaryComponent, + HeroTeamComponent + ], + bootstrap: [ HeroAppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-app-main.component.ts b/public/docs/_examples/component-styles/ts/src/app/hero-app-main.component.ts new file mode 100644 index 0000000000..aebb1f729e --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-app-main.component.ts @@ -0,0 +1,16 @@ +import { Component, Input } from '@angular/core'; + +import { Hero } from './hero'; + +@Component({ + selector: 'hero-app-main', + template: ` + + + + + ` +}) +export class HeroAppMainComponent { + @Input() hero: Hero; +} diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-app.component.ts b/public/docs/_examples/component-styles/ts/src/app/hero-app.component.ts new file mode 100644 index 0000000000..5f1923e6f3 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-app.component.ts @@ -0,0 +1,24 @@ +import { Component, HostBinding } from '@angular/core'; +import { Hero } from './hero'; + +// #docregion +@Component({ + selector: 'hero-app', + template: ` +

    Tour of Heroes

    + `, + styles: ['h1 { font-weight: normal; }'] +}) +export class HeroAppComponent { +// #enddocregion + hero = new Hero( + 'Human Torch', + ['Mister Fantastic', 'Invisible Woman', 'Thing'] + ); + + @HostBinding('class') get themeClass() { + return 'theme-light'; + } +// #docregion +} +// #enddocregion diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-controls.component.ts b/public/docs/_examples/component-styles/ts/src/app/hero-controls.component.ts new file mode 100644 index 0000000000..5d293596d2 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-controls.component.ts @@ -0,0 +1,25 @@ +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +// #docregion inlinestyles +@Component({ + selector: 'hero-controls', + template: ` + +

    Controls

    + + ` +}) +// #enddocregion inlinestyles +export class HeroControlsComponent { + @Input() hero: Hero; + + activate() { + this.hero.active = true; + } +} diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-details-box.css b/public/docs/_examples/component-styles/ts/src/app/hero-details-box.css new file mode 100644 index 0000000000..f240073005 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-details-box.css @@ -0,0 +1,3 @@ +:host { + padding: 10px; +} diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-details.component.css b/public/docs/_examples/component-styles/ts/src/app/hero-details.component.css new file mode 100644 index 0000000000..fd938ca55c --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-details.component.css @@ -0,0 +1,28 @@ +/* #docregion import */ +@import 'hero-details-box.css'; +/* #enddocregion import */ + +/* #docregion host */ +:host { + display: block; + border: 1px solid black; +} +/* #enddocregion host */ + +/* #docregion hostfunction */ +:host(.active) { + border-width: 3px; +} +/* #enddocregion hostfunction */ + +/* #docregion hostcontext */ +:host-context(.theme-light) h2 { + background-color: #eef; +} +/* #enddocregion hostcontext */ + +/* #docregion deep */ +:host /deep/ h3 { + font-style: italic; +} +/* #enddocregion deep */ diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-details.component.ts b/public/docs/_examples/component-styles/ts/src/app/hero-details.component.ts new file mode 100644 index 0000000000..bd86a63e04 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-details.component.ts @@ -0,0 +1,18 @@ +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +// #docregion styleurls +@Component({ + selector: 'hero-details', + template: ` +

    {{hero.name}}

    + + + `, + styleUrls: ['app/hero-details.component.css'] +}) +export class HeroDetailsComponent { + // #enddocregion styleurls + @Input() hero: Hero; + // #docregion styleurls +} diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-team.component.css b/public/docs/_examples/component-styles/ts/src/app/hero-team.component.css new file mode 100644 index 0000000000..b87679886b --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-team.component.css @@ -0,0 +1,3 @@ +li { + list-style-type: square; +} diff --git a/public/docs/_examples/component-styles/ts/src/app/hero-team.component.ts b/public/docs/_examples/component-styles/ts/src/app/hero-team.component.ts new file mode 100644 index 0000000000..4f092d2827 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero-team.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +// #docregion stylelink +@Component({ + selector: 'hero-team', + template: ` + +

    Team

    +
      +
    • + {{member}} +
    • +
    ` +}) +// #enddocregion stylelink +export class HeroTeamComponent { + @Input() hero: Hero; +} diff --git a/public/docs/_examples/component-styles/ts/src/app/hero.ts b/public/docs/_examples/component-styles/ts/src/app/hero.ts new file mode 100644 index 0000000000..7f8969e682 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/hero.ts @@ -0,0 +1,7 @@ +export class Hero { + active: boolean; + + constructor(public name: string, + public team: string[]) { + } +} diff --git a/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.css b/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.css new file mode 100644 index 0000000000..207fa981dd --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.css @@ -0,0 +1,5 @@ +:host { + display: block; + background-color: green; + color: white; +} diff --git a/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.html b/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.html new file mode 100644 index 0000000000..ace27d2a1c --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.html @@ -0,0 +1 @@ +

    No quests in progress

    diff --git a/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.ts b/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.ts new file mode 100644 index 0000000000..2a2dc65fe0 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/app/quest-summary.component.ts @@ -0,0 +1,20 @@ +/* tslint:disable:no-unused-variable */ +// #docplaster +import { Component, ViewEncapsulation } from '@angular/core'; + +// #docregion +@Component({ + selector: 'quest-summary', + // #docregion urls + templateUrl: './quest-summary.component.html', + styleUrls: ['./quest-summary.component.css'] + // #enddocregion urls +}) +export class QuestSummaryComponent { } +// #enddocregion +/* + // #docregion encapsulation.native + // warning: few browsers support shadow DOM encapsulation at this time + encapsulation: ViewEncapsulation.Native + // #enddocregion encapsulation.native +*/ diff --git a/public/docs/_examples/component-styles/ts/src/index.html b/public/docs/_examples/component-styles/ts/src/index.html new file mode 100644 index 0000000000..6e9dc51b32 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/index.html @@ -0,0 +1,31 @@ + + + + + Component Styles + + + + + + + + + + + + + + + +

    External H1 Title for E2E test

    + + +
      +
    • External list for E2E test
    • +
    + + + diff --git a/public/docs/_examples/component-styles/ts/src/main.ts b/public/docs/_examples/component-styles/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/component-styles/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/dependency-injection/dart/lib/app_component.dart b/public/docs/_examples/dependency-injection/dart/lib/app_component.dart deleted file mode 100644 index 4e01554a42..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/app_component.dart +++ /dev/null @@ -1,63 +0,0 @@ -// #docplaster - -// #docregion - -// #docregion imports -import 'package:angular2/core.dart'; -import 'car/car_component.dart'; -import 'heroes/heroes_component.dart'; -import 'app_config.dart'; -import 'logger_service.dart'; -import 'user_service.dart'; - -// #enddocregion imports -import 'injector_component.dart'; -import 'providers_component.dart'; - -@Component( - selector: 'my-app', - template: ''' -

    {{title}}

    - - - -

    User

    -

    - {{userInfo}} - -

    - - - ''', - directives: const [CarComponent, HeroesComponent, InjectorComponent, ProvidersComponent], -// #docregion providers - providers: const [Logger, UserService, const Provider(Config, useValue: CONFIG)] -// #enddocregion providers - ) -class AppComponent { - UserService _userService; - String title; - - //#docregion ctor - AppComponent(Config config, this._userService) { - title = config.title; - } - - // #enddocregion ctor - bool get isAuthorized { - return user.isAuthorized; - } - - void nextUser() { - _userService.getNewUser(); - } - - User get user { - return _userService.user; - } - - String get userInfo { - return 'Current user, ${user.name}, is ${isAuthorized ? "" : "not"} authorized. '; - } -} -// #enddocregion diff --git a/public/docs/_examples/dependency-injection/dart/lib/app_component_1.dart b/public/docs/_examples/dependency-injection/dart/lib/app_component_1.dart deleted file mode 100644 index 7c3b7b9808..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/app_component_1.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Early versions - -// #docregion -import 'package:angular2/core.dart'; -import 'car/car_component.dart'; -import 'heroes/heroes_component_1.dart'; - -@Component( - selector: 'my-app', - template: ''' -

    {{title}}

    - - - ''', - directives: const [CarComponent, HeroesComponent]) -class AppComponent { - var title = 'Dependency Injection'; -} -// #enddocregion - -/* -//#docregion ctor-di-fail -// FAIL! Injectable `config` is not a class! -AppComponent(HeroService heroService, Map config) { - title = config['title']; -} -//#enddocregion ctor-di-fail -*/ diff --git a/public/docs/_examples/dependency-injection/dart/lib/app_component_2.dart b/public/docs/_examples/dependency-injection/dart/lib/app_component_2.dart deleted file mode 100644 index 7bf4249ee2..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/app_component_2.dart +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion - -// #docregion imports -import 'package:angular2/core.dart'; -import 'car/car_component.dart'; -import 'heroes/heroes_component_1.dart'; -import 'app_config.dart'; -import 'logger_service.dart'; - -// #enddocregion imports -@Component( - selector: 'my-app', - template: ''' -

    {{title}}

    - - - ''', - directives: const [ - CarComponent, - HeroesComponent - ], - providers: const [ - Logger, - // #docregion provider-config - const Provider('app.config', useValue: CONFIG) - ]) -class AppComponent { - String title; - - // #docregion ctor - AppComponent(@Inject('app.config') Config config) { - title = config.title; - } -} -// #enddocregion diff --git a/public/docs/_examples/dependency-injection/dart/lib/app_config.dart b/public/docs/_examples/dependency-injection/dart/lib/app_config.dart deleted file mode 100644 index 8fc877f188..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/app_config.dart +++ /dev/null @@ -1,29 +0,0 @@ -//#docregion - -// #docregion token -import 'package:angular2/core.dart'; - -const APP_CONFIG = const OpaqueToken('app.config'); -// #enddocregion token - -//#docregion config -abstract class Config { - final String apiEndpoint; - final String title; - - const Config({this.apiEndpoint, this.title}); -} - -class ConfigImpl implements Config { - final String apiEndpoint; - final String title; - - const ConfigImpl({this.apiEndpoint, this.title}); -} - -const CONFIG = const ConfigImpl(apiEndpoint: 'api.heroes.com', title: 'Dependency Injection'); -//#enddocregion config - -//#docregion config-hash -const CONFIG_HASH = const {'apiEndpoint': 'api.heroes.com', 'title': 'Dependency Injection'}; -//#enddocregion config-hash diff --git a/public/docs/_examples/dependency-injection/dart/lib/car/car.dart b/public/docs/_examples/dependency-injection/dart/lib/car/car.dart deleted file mode 100644 index 4c8d1025e7..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/car/car.dart +++ /dev/null @@ -1,32 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; - -// #docregion engine -class Engine { - int cylinders = 4; -} -// #enddocregion engine - -// #docregion tires -class Tires { - String make = 'Flintstone'; - String model = 'Square'; -} - -// #enddocregion tires -@Injectable() -class Car { - //#docregion car-ctor - Engine engine; - Tires tires; - String description = 'DI'; - - Car(this.engine, this.tires); - - // #enddocregion car-ctor - - // Method using the engine and tires - String drive() => '$description car with ${engine.cylinders} cylinders and ${tires.make} tires.'; -} -// #enddocregion car diff --git a/public/docs/_examples/dependency-injection/dart/lib/car/car_component.dart b/public/docs/_examples/dependency-injection/dart/lib/car/car_component.dart deleted file mode 100644 index e8e3ccc0e0..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/car/car_component.dart +++ /dev/null @@ -1,33 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'car.dart'; -import 'car_no_di.dart' as carNoDi; -import 'car_factory.dart'; -import 'car_creations.dart' as carCreations; -import 'car_injector.dart'; - -@Component( - selector: 'my-car', - template: ''' -

    Cars

    -
    {{car.drive()}}
    -
    {{noDiCar.drive()}}
    -
    {{injectorCar.drive()}}
    -
    {{factoryCar.drive()}}
    -
    {{simpleCar.drive()}}
    -
    {{superCar.drive()}}
    -
    {{testCar.drive()}}
    - ''', - providers: const [Car, Engine, Tires]) -class CarComponent { - Car car; - - CarComponent(this.car) {} - Car factoryCar = (new CarFactory()).createCar(); - Car injectorCar = useInjector(); - carNoDi.Car noDiCar = new carNoDi.Car(); - Car simpleCar = carCreations.simpleCar(); - Car superCar = carCreations.superCar(); - Car testCar = carCreations.testCar(); -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/car/car_creations.dart b/public/docs/_examples/dependency-injection/dart/lib/car/car_creations.dart deleted file mode 100644 index 33dfa05828..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/car/car_creations.dart +++ /dev/null @@ -1,56 +0,0 @@ -// Examples with car and engine variations - -// #docplaster -import 'car.dart'; - -///////// example 1 //////////// -Car simpleCar() { - //#docregion car-ctor-instantiation - - // Simple car with 4 cylinders and Flintstone tires. - var car = new Car(new Engine(), new Tires()); - //#enddocregion car-ctor-instantiation - car.description = 'Simple'; - return car; -} -///////// example 2 //////////// - -//#docregion car-ctor-instantiation-with-param -class Engine2 implements Engine { - int cylinders; - - Engine2(this.cylinders); -} - -//#enddocregion car-ctor-instantiation-with-param -Car superCar() { - //#docregion car-ctor-instantiation-with-param - - // Super car with 12 cylinders and Flintstone tires. - var bigCylinders = 12; - var car = new Car(new Engine2(bigCylinders), new Tires()); - //#enddocregion car-ctor-instantiation-with-param - car.description = 'Super'; - return car; -} -/////////// example 3 ////////// - -//#docregion car-ctor-instantiation-with-mocks -class MockEngine extends Engine { - int cylinders = 8; -} - -class MockTires extends Tires { - String make = 'YokoGoodStone'; -} - -//#enddocregion car-ctor-instantiation-with-mocks -Car testCar() { - //#docregion car-ctor-instantiation-with-mocks - - // Test car with 8 cylinders and YokoGoodStone tires. - var car = new Car(new MockEngine(), new MockTires()); - //#enddocregion car-ctor-instantiation-with-mocks - car.description = 'Test'; - return car; -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/car/car_factory.dart b/public/docs/_examples/dependency-injection/dart/lib/car/car_factory.dart deleted file mode 100644 index 76b8a4cc63..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/car/car_factory.dart +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion - -import 'car.dart'; - -class CarFactory { - Car createCar() { - var car = new Car(createEngine(), createTires()); - car.description = 'Factory'; - return car; - } - - Engine createEngine() => new Engine(); - - Tires createTires() => new Tires(); -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/car/car_injector.dart b/public/docs/_examples/dependency-injection/dart/lib/car/car_injector.dart deleted file mode 100644 index 1dbadd9fab..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/car/car_injector.dart +++ /dev/null @@ -1,36 +0,0 @@ -// #docplaster - -//#docregion -import 'package:angular2/core.dart'; -import 'car.dart'; -import '../logger_service.dart'; - -//#docregion injector -Car useInjector() { - Injector injector; - //#enddocregion injector - - /* -//#docregion injector-no-new - // Cannot 'new' an Injector like this! - var injector = new Injector([Car, Engine, Tires, Logger]); -//#enddocregion injector-no-new -*/ - - //#docregion injector - - //#docregion injector-create-and-call - injector = Injector.resolveAndCreate([Car, Engine, Tires, Logger]); - //#docregion injector-call - var car = injector.get(Car); - //#enddocregion injector-call - - //#enddocregion injector-create-and-call - car.description = 'Injector'; - var logger = injector.get(Logger); - logger.log('Injector car.drive() said: ' + car.drive()); - return car; -} -//#enddocregion injector - -//#enddocregion diff --git a/public/docs/_examples/dependency-injection/dart/lib/car/car_no_di.dart b/public/docs/_examples/dependency-injection/dart/lib/car/car_no_di.dart deleted file mode 100644 index 32972c3dc1..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/car/car_no_di.dart +++ /dev/null @@ -1,22 +0,0 @@ -// Car without DI - -import 'car.dart'; - -//#docregion car -class Car { - //#docregion car-ctor - Engine engine; - Tires tires; - var description = 'No DI'; - - Car() { - engine = new Engine(); - tires = new Tires(); - } - - //#enddocregion car-ctor - - // Method using the engine and tires - drive() => '$description car with ${engine.cylinders} cylinders and ${tires.make} tires.'; -} -//#enddocregion car diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero.dart deleted file mode 100644 index ea10276b7c..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion - -class Hero { - num id; - String name; - bool isSecret = false; -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component.dart deleted file mode 100644 index c4eeb14f1b..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component.dart +++ /dev/null @@ -1,21 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero.dart'; -import 'hero_service.dart'; - -@Component( - selector: 'hero-list', - template: ''' -
    - {{hero.id}} - {{hero.name}} - ({{hero.isSecret ? \'secret\' : \'public\'}}) -
    - ''') -class HeroListComponent { - List heroes; - -//#docregion ctor-signature - HeroListComponent(HeroService heroService) : heroes = heroService.getHeroes(); -//#enddocregion ctor-signature -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component_1.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component_1.dart deleted file mode 100644 index 3aeef5aefb..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component_1.dart +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero.dart'; -import 'mock_heroes.dart'; - -@Component( - selector: 'hero-list', - template: ''' -
    - {{hero.id}} - {{hero.name}} -
    - ''') -class HeroListComponent { - List heroes = HEROES; -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component_2.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component_2.dart deleted file mode 100644 index 2b76419505..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_list_component_2.dart +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero.dart'; -import 'hero_service.dart'; - -@Component( - selector: 'hero-list', - template: ''' -
    - {{hero.id}} - {{hero.name}} -
    - ''') -class HeroListComponent { - List heroes; - -//#docregion ctor - HeroListComponent(HeroService heroService) : heroes = heroService.getHeroes(); -//#enddocregion ctor -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service.dart deleted file mode 100644 index 2dda48cb70..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service.dart +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero.dart'; -import 'mock_heroes.dart'; -import '../logger_service.dart'; - -@Injectable() -class HeroService { - // #docregion internals - Logger _logger; - bool _isAuthorized; - - HeroService(this._logger, this._isAuthorized); - - List getHeroes() { - var auth = _isAuthorized ? 'authorized' : 'unauthorized'; - _logger.log('Getting heroes for ${auth} user.'); - return HEROES.where((hero) => _isAuthorized || !hero.isSecret).toList(); - } -// #enddocregion internals -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_1.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_1.dart deleted file mode 100644 index 7ee6a642b4..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_1.dart +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion - -import 'hero.dart'; -import 'mock_heroes.dart'; - -class HeroService { - List getHeroes() => HEROES; -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_2.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_2.dart deleted file mode 100644 index 25146a76f9..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_2.dart +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero.dart'; -import 'mock_heroes.dart'; -import '../logger_service.dart'; - -@Injectable() -class HeroService { - Logger _logger; - - //#docregion ctor - HeroService(this._logger); - - //#enddocregion ctor - List getHeroes() { - _logger.log('Getting heroes ...'); - return HEROES; - } -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_provider.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_provider.dart deleted file mode 100644 index b783f0edc5..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/hero_service_provider.dart +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero_service.dart'; -import '../logger_service.dart'; -import '../user_service.dart'; - -// #docregion factory -heroServiceFactory(Logger logger, UserService userService) => - new HeroService(logger, userService.user.isAuthorized); -// #enddocregion factory - -// #docregion provider -const heroServiceProvider = - const Provider(HeroService, useFactory: heroServiceFactory, deps: const [Logger, UserService]); -// #enddocregion provider diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/heroes_component.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/heroes_component.dart deleted file mode 100644 index 45e310cd30..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/heroes_component.dart +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; -import 'hero_list_component.dart'; -import 'hero_service_provider.dart'; - -@Component( - selector: 'my-heroes', - template: ''' -

    Heroes

    - - ''', - providers: const [heroServiceProvider], - directives: const [HeroListComponent]) -class HeroesComponent {} diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/heroes_component_1.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/heroes_component_1.dart deleted file mode 100644 index 80d7ad8f2e..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/heroes_component_1.dart +++ /dev/null @@ -1,25 +0,0 @@ -// #docplaster - -// #docregion -// #docregion v1 -import 'package:angular2/core.dart'; -import 'hero_list_component.dart'; - -// #enddocregion v1 -import 'hero_service.dart'; - -// #docregion v1 -@Component( - selector: 'my-heroes', - template: ''' -

    Heroes

    - - ''', -// #enddocregion v1 -// #docregion providers - providers: const [HeroService], -// #enddocregion providers -// #docregion v1 - directives: const [HeroListComponent]) -class HeroesComponent {} -// #enddocregion v1 diff --git a/public/docs/_examples/dependency-injection/dart/lib/heroes/mock_heroes.dart b/public/docs/_examples/dependency-injection/dart/lib/heroes/mock_heroes.dart deleted file mode 100644 index 9f49bf208c..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/heroes/mock_heroes.dart +++ /dev/null @@ -1,46 +0,0 @@ -// #docregion - -import 'hero.dart'; - -List HEROES = [ - new Hero() - ..id = 11 - ..isSecret = false - ..name = 'Mr. Nice', - new Hero() - ..id = 12 - ..isSecret = false - ..name = 'Narco', - new Hero() - ..id = 13 - ..isSecret = false - ..name = 'Bombasto', - new Hero() - ..id = 14 - ..isSecret = false - ..name = 'Celeritas', - new Hero() - ..id = 15 - ..isSecret = false - ..name = 'Magneta', - new Hero() - ..id = 16 - ..isSecret = false - ..name = 'RubberMan', - new Hero() - ..id = 17 - ..isSecret = false - ..name = 'Dynama', - new Hero() - ..id = 18 - ..isSecret = true - ..name = 'Dr IQ', - new Hero() - ..id = 19 - ..isSecret = true - ..name = 'Magma', - new Hero() - ..id = 20 - ..isSecret = true - ..name = 'Tornado' -]; diff --git a/public/docs/_examples/dependency-injection/dart/lib/injector_component.dart b/public/docs/_examples/dependency-injection/dart/lib/injector_component.dart deleted file mode 100644 index 24e1598f13..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/injector_component.dart +++ /dev/null @@ -1,58 +0,0 @@ -// #docplaster - -//#docregion -import 'package:angular2/core.dart'; -import 'car/car.dart'; -import 'heroes/hero_service.dart'; -import 'heroes/hero_service_provider.dart'; -import 'logger_service.dart'; -import 'package:dependency_injection/heroes/hero.dart'; - -//#docregion injector -@Component( - selector: 'my-injectors', - template: ''' -

    Other Injections

    -
    {{car.drive()}}
    -
    {{hero.name}}
    -
    {{rodent}}
    - ''', - providers: const [ - Car, - Engine, - Tires, - const Provider(HeroService, useFactory: heroServiceFactory), - Logger - ]) -class InjectorComponent { - Injector _injector; - - InjectorComponent(this._injector) { - car = _injector.get(Car); - heroService = _injector.get(HeroService); - hero = heroService.getHeroes()[0]; - } - - Car car; - - //#docregion get-hero-service - HeroService heroService; - - //#enddocregion get-hero-service - Hero hero; - - String get rodent { - var rous = _injector.getOptional(ROUS); - if (rous != null) { - throw new Exception('Aaaargh!'); - } - return "R.O.U.S.'s? I don't think they exist!"; - } -} -//#enddocregion injector - -/** - * R.O.U.S. - Rodents Of Unusual Size - * // https://www.youtube.com/watch?v=BOv5ZjAOpC8 - */ -class ROUS {} diff --git a/public/docs/_examples/dependency-injection/dart/lib/logger_service.dart b/public/docs/_examples/dependency-injection/dart/lib/logger_service.dart deleted file mode 100644 index 452daefd22..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/logger_service.dart +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; - -@Injectable() -class Logger { - List logs = []; - - void log(String message) { - logs.add(message); - print(message); - } -} diff --git a/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart b/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart deleted file mode 100644 index 83d461deb2..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/providers_component.dart +++ /dev/null @@ -1,360 +0,0 @@ -// Examples of provider arrays - -//#docplaster -import 'package:angular2/core.dart'; -import 'app_config.dart'; -import 'heroes/hero_service_provider.dart'; -import 'heroes/hero_service.dart'; -import 'logger_service.dart'; -import 'user_service.dart'; - -// #docregion import-optional -import 'package:angular2/core.dart' show Optional; -// #enddocregion import-optional - -const template = '{{log}}'; - -////////////////////////////////////////// -@Component(selector: 'provider-1', template: '{{log}}', providers: -//#docregion providers-1 -const [Logger] -//#enddocregion providers-1 -) -class ProviderComponent1 { - String log; - - ProviderComponent1(Logger logger) { - logger.log('Hello from logger provided with Logger class'); - log = logger.logs[0]; - } -} - -////////////////////////////////////////// -@Component(selector: 'provider-2', template: '{{log}}', providers: -//#docregion providers-2 -const [const Provider(Logger, useClass: Logger)] -//#enddocregion providers-2 -) -class ProviderComponent2 { - String log; - - ProviderComponent2(Logger logger) { - logger.log('Hello from logger provided with Provider class and useClass'); - log = logger.logs[0]; - } -} - -////////////////////////////////////////// -@Component( - selector: 'provider-3', - template: '{{log}}', - providers: const [const Provider(Logger, useClass: Logger)] -/* -//#docregion providers-3 - const [provide(Logger, useClass: Logger)] -//#enddocregion providers-3 -*/ -) -class ProviderComponent3 { - String log; - - ProviderComponent3(Logger logger) { - logger.log('Hello from logger provided with useClass'); - log = logger.logs[0]; - } -} - -////////////////////////////////////////// -class BetterLogger extends Logger {} - -@Component(selector: 'provider-4', template: '{{log}}', providers: -//#docregion providers-4 -const [const Provider(Logger, useClass: BetterLogger)] -//#enddocregion providers-4 -) -class ProviderComponent4 { - String log; - - ProviderComponent4(Logger logger) { - logger.log('Hello from logger provided with useClass:BetterLogger'); - log = logger.logs[0]; - } -} -////////////////////////////////////////// - -// #docregion EvenBetterLogger -@Injectable() -class EvenBetterLogger implements Logger { - UserService _userService; - - List logs = []; - - EvenBetterLogger(this._userService); - - log(String message) { - message = 'Message to ${ _userService.user.name}: ${ message}.'; - print(message); - logs.add(message); - } -} - -// #enddocregion EvenBetterLogger -@Component(selector: 'provider-5', template: '{{log}}', providers: -//#docregion providers-5 -const [UserService, const Provider(Logger, useClass: EvenBetterLogger)] -//#enddocregion providers-5 -) -class ProviderComponent5 { - String log; - - ProviderComponent5(Logger logger) { - logger.log('Hello from EvenBetterlogger'); - log = logger.logs[0]; - } -} - -////////////////////////////////////////// -class NewLogger extends Logger implements OldLogger {} - -class OldLogger { - List logs = []; - - log(String message) { - throw new Exception('Should not call the old logger!'); - } -} - -@Component(selector: 'provider-6a', template: '{{log}}', providers: -//#docregion providers-6a -const [ - NewLogger, -// Not aliased! Creates two instances of `NewLogger` - const Provider(OldLogger, useClass: NewLogger) -] -//#enddocregion providers-6a -) -class ProviderComponent6a { - String log; - - ProviderComponent6a(NewLogger newLogger, OldLogger oldLogger) { - if (identical(newLogger, oldLogger)) { - throw new Exception('expected the two loggers to be different instances'); - } - oldLogger.log('Hello OldLogger (but we want NewLogger)'); - // The newLogger wasn't called so no logs[] - - // display the logs of the oldLogger. - log = newLogger.logs == null || newLogger.logs.isEmpty ? oldLogger.logs[0] : newLogger.logs[0]; - } -} - -@Component(selector: 'provider-6b', template: '{{log}}', providers: -//#docregion providers-6b -const [ - NewLogger, -// Alias OldLogger w/ reference to NewLogger - const Provider(OldLogger, useExisting: NewLogger) -//#enddocregion providers-6b -]) -class ProviderComponent6b { - String log; - - ProviderComponent6b(NewLogger newLogger, OldLogger oldLogger) { - if (!identical(newLogger, oldLogger)) { - throw new Exception('expected the two loggers to be the same instance'); - } - oldLogger.log('Hello from NewLogger (via aliased OldLogger)'); - log = newLogger.logs[0]; - } -} -////////////////////////////////////////// - -// #docregion silent-logger - -// An object in the shape of the logger service -class SilentLogger /*implements Logger*/ { - const SilentLogger({this.logs}); - - final List logs; - - log(String message) {} -} - -const silentLogger = const SilentLogger( - logs: const ['Silent logger says "Shhhhh!". Provided via "useValue"']); -// #enddocregion silent-logger - -@Component(selector: 'provider-7', template: '{{log}}', providers: -//#docregion providers-7 -const [const Provider(SilentLogger, useValue: silentLogger)] -//#enddocregion providers-7 -/* -//#docregion providers-7-unchecked -const [const Provider(Logger, useValue: silentLogger)] -//#enddocregion providers-7-unchecked - */ -) -class ProviderComponent7 { - String log; - - ProviderComponent7(SilentLogger logger) { - logger.log('Hello from logger provided with useValue'); - log = logger.logs[0]; - } -} - -///////////////// -@Component(selector: 'provider-8', template: '{{log}}', providers: const [ - const Provider(HeroService, useFactory: heroServiceFactory), - Logger, - UserService -]) -class ProviderComponent8 { - // #docregion provider-8-ctor - ProviderComponent8(HeroService heroService); - - // #enddocregion provider-8-ctor - - // must be true else this component would have blown up at runtime - var log = 'Hero service injected successfully'; -} - -///////////////// -@Component(selector: 'provider-9a', template: '{{log}}', providers: -/* - // #docregion providers-9a-interface - // WOKRKS! Can use abstract class as provider token - [provide(Config, {useValue: CONFIG})] - // #enddocregion providers-9a-interface - */ - -// #docregion providers-9a -// Use string as provider token -const [const Provider('app.config', useValue: CONFIG_HASH)] -//#enddocregion providers-9a -) -class ProviderComponent9a implements OnInit { - Config _config; - - String log; - - /* - // #docregion provider-9a-ctor-interface - // WORKS! Can inject using the abstract class as the parameter type - Config _config; - - ProviderComponent9a(this._config); - // #enddocregion provider-9a-ctor-interface - */ - - // #docregion provider-9a-ctor - - // @Inject(token) to inject the dependency - ProviderComponent9a(@Inject('app.config') Map config) { - _config = new ConfigImpl(apiEndpoint: config['apiEndpoint'], title: config['title']); - } - - // #enddocregion provider-9a-ctor - ngOnInit() { - log = '\'app.config\' Application title is ' + _config.title; - } -} - -@Component(selector: 'provider-9b', template: '{{log}}', providers: -// #docregion providers-9b -const [const Provider(APP_CONFIG, useValue: CONFIG_HASH)]) // #enddocregion providers-9b -class ProviderComponent9b - implements OnInit { - Config _config; - - String log; - - // #docregion provider-9b-ctor - ProviderComponent9b(@Inject(APP_CONFIG) Map config) { - _config = new ConfigImpl(apiEndpoint: config['apiEndpoint'], title: config['title']); - } - - // #enddocregion provider-9b-ctor - ngOnInit() { - log = 'APP_CONFIG Application title is ' + _config.title; - } -} -////////////////////////////////////////// - -// Normal required logger -@Component(selector: 'provider-10a', template: '{{log}}', -//#docregion providers-logger - providers: const [Logger] -//#enddocregion providers-logger -) -class ProviderComponent10a { - String log; - - ProviderComponent10a(Logger logger) { - logger.log('Hello from the required logger.'); - log = logger.logs[0]; - } -} - -// Optional logger -@Component(selector: 'provider-10b', template: '{{log}}') -class ProviderComponent10b implements OnInit { - Logger _logger; - - // #docregion provider-10-ctor - String log; - - ProviderComponent10b(@Optional() this._logger); - - // #enddocregion provider-10-ctor - ngOnInit() { - // #docregion provider-10-logger - - // No logger? Make one! - if (_logger == null) { - _logger = new Logger(); - // #enddocregion provider-10-logger - _logger.log('Optional logger was not available.'); - } else { - _logger.log('Hello from the injected logger.'); - log = _logger.logs[0]; - } - log = _logger.logs[0]; - } -} - -///////////////// -@Component( - selector: 'my-providers', - template: ''' -

    Provider variations

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - ''', - directives: const [ - ProviderComponent1, - ProviderComponent2, - ProviderComponent3, - ProviderComponent4, - ProviderComponent5, - ProviderComponent6a, - ProviderComponent6b, - ProviderComponent7, - ProviderComponent8, - ProviderComponent9a, - ProviderComponent9b, - ProviderComponent10a, - ProviderComponent10b - ]) -class ProvidersComponent {} diff --git a/public/docs/_examples/dependency-injection/dart/lib/user_service.dart b/public/docs/_examples/dependency-injection/dart/lib/user_service.dart deleted file mode 100644 index 682a42b967..0000000000 --- a/public/docs/_examples/dependency-injection/dart/lib/user_service.dart +++ /dev/null @@ -1,27 +0,0 @@ -// #docregion - -import 'package:angular2/core.dart'; - -@Injectable() -class UserService { - UserService() { - user = _bob; - } - - // Todo: get the user; don't 'new' it. - User _alice = new User('Alice', true); - User _bob = new User('Bob', false); - - // initial user is Bob - User user; - - // swaps users - User getNewUser() => user = user == _bob ? _alice : _bob; -} - -class User { - String name; - bool isAuthorized; - - User(this.name, [this.isAuthorized = false]); -} diff --git a/public/docs/_examples/dependency-injection/dart/pubspec.yaml b/public/docs/_examples/dependency-injection/dart/pubspec.yaml deleted file mode 100644 index fce5b7f954..0000000000 --- a/public/docs/_examples/dependency-injection/dart/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# #docregion -name: dependency_injection -description: Dependency injection sample -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES' - platform_pipes: 'package:angular2/common.dart#COMMON_PIPES' - entry_points: web/main.dart -- dart_to_js_script_rewriter -dev_dependencies: - test: any diff --git a/public/docs/_examples/dependency-injection/dart/test/hero_list_component_test.dart b/public/docs/_examples/dependency-injection/dart/test/hero_list_component_test.dart deleted file mode 100644 index 0dd76b4f15..0000000000 --- a/public/docs/_examples/dependency-injection/dart/test/hero_list_component_test.dart +++ /dev/null @@ -1,34 +0,0 @@ -// A simple test -// More details will be in the testing chapter. -import 'package:angular2/angular2.dart'; -import 'package:dependency_injection/heroes/hero.dart'; -import 'package:dependency_injection/heroes/hero_list_component.dart'; -import 'package:dependency_injection/heroes/hero_service.dart'; -import 'package:test/test.dart'; - -/////////////////////////////////////// -////#docregion spec -List expectedHeroes = [ - new Hero() - ..id = 1 - ..name = 'hero1', - new Hero() - ..id = 2 - ..name = 'hero2' - ..isSecret = true -]; - -class HeroServiceMock implements HeroService { - @override - List getHeroes() => expectedHeroes; -} - -var mockService = new HeroServiceMock(); - -void main() { - test('should have heroes when HeroListComponent created', () { - var hlc = new HeroListComponent(mockService); - expect(hlc.heroes.length, expectedHeroes.length); - }); -} -//#enddocregion spec \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/dart/web/index.html b/public/docs/_examples/dependency-injection/dart/web/index.html deleted file mode 100644 index dd40fd6c61..0000000000 --- a/public/docs/_examples/dependency-injection/dart/web/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Dependency Injection - - - - - -Loading my-app ... -Loading my-providers ... - - - diff --git a/public/docs/_examples/dependency-injection/dart/web/main.dart b/public/docs/_examples/dependency-injection/dart/web/main.dart deleted file mode 100644 index 8e908cc892..0000000000 --- a/public/docs/_examples/dependency-injection/dart/web/main.dart +++ /dev/null @@ -1,12 +0,0 @@ -//#docregion - -import 'package:angular2/platform/browser.dart'; -import 'package:dependency_injection/app_component.dart'; -import 'package:dependency_injection/providers_component.dart'; - -main() { - //#docregion bootstrap - bootstrap(AppComponent); - //#enddocregion bootstrap - bootstrap(ProvidersComponent); -} \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/dart/web/main_1.dart b/public/docs/_examples/dependency-injection/dart/web/main_1.dart deleted file mode 100644 index ff9166ccf1..0000000000 --- a/public/docs/_examples/dependency-injection/dart/web/main_1.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:angular2/platform/browser.dart'; -import 'package:dependency_injection/app_component.dart'; -import 'package:dependency_injection/heroes/hero_service.dart'; -//#docregion bootstrap - -main() { -// Injecting services in bootstrap works but is discouraged - bootstrap(AppComponent, [HeroService]); -//#enddocregion bootstrap -} \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/e2e-spec.js b/public/docs/_examples/dependency-injection/e2e-spec.js deleted file mode 100644 index e5e146c158..0000000000 --- a/public/docs/_examples/dependency-injection/e2e-spec.js +++ /dev/null @@ -1,213 +0,0 @@ - -describe('Dependency Injection Tests', function () { - - - var expectedMsg; - - beforeAll(function () { - browser.get(''); - }); - - describe('Cars:', function() { - - it('DI car displays as expected', function () { - expectedMsg = 'DI car with 4 cylinders and Flintstone tires.'; - expect(element(by.css('#di')).getText()).toEqual(expectedMsg); - }); - - it('No DI car displays as expected', function () { - expectedMsg = 'No DI car with 4 cylinders and Flintstone tires.'; - expect(element(by.css('#nodi')).getText()).toEqual(expectedMsg); - }); - - it('Injector car displays as expected', function () { - expectedMsg = 'Injector car with 4 cylinders and Flintstone tires.'; - expect(element(by.css('#injector')).getText()).toEqual(expectedMsg); - }); - - it('Factory car displays as expected', function () { - expectedMsg = 'Factory car with 4 cylinders and Flintstone tires.'; - expect(element(by.css('#factory')).getText()).toEqual(expectedMsg); - }); - - it('Simple car displays as expected', function () { - expectedMsg = 'Simple car with 4 cylinders and Flintstone tires.'; - expect(element(by.css('#simple')).getText()).toEqual(expectedMsg); - }); - - it('Super car displays as expected', function () { - expectedMsg = 'Super car with 12 cylinders and Flintstone tires.'; - expect(element(by.css('#super')).getText()).toEqual(expectedMsg); - }); - - it('Test car displays as expected', function () { - expectedMsg = 'Test car with 8 cylinders and YokoGoodStone tires.'; - expect(element(by.css('#test')).getText()).toEqual(expectedMsg); - }); - }); - - describe('Other Injections:', function() { - it('DI car displays as expected', function () { - expectedMsg = 'DI car with 4 cylinders and Flintstone tires.'; - expect(element(by.css('#car')).getText()).toEqual(expectedMsg); - }); - - it('Hero displays as expected', function () { - expectedMsg = 'Mr. Nice'; - expect(element(by.css('#hero')).getText()).toEqual(expectedMsg); - }); - - it('Optional injection displays as expected', function () { - expectedMsg = 'R.O.U.S.\'s? I don\'t think they exist!'; - expect(element(by.css('#rodent')).getText()).toEqual(expectedMsg); - }); - }); - - describe('Tests:', function() { - - it('Tests display as expected', function () { - expectedMsg = /Tests passed/; - expect(element(by.css('#tests')).getText()).toMatch(expectedMsg); - }); - - }); - - describe('Provider variations:', function() { - - it('P1 (class) displays as expected', function () { - expectedMsg = 'Hello from logger provided with Logger class'; - expect(element(by.css('#p1')).getText()).toEqual(expectedMsg); - }); - - it('P2 (Provider) displays as expected', function () { - expectedMsg = 'Hello from logger provided with Provider class and useClass'; - expect(element(by.css('#p2')).getText()).toEqual(expectedMsg); - }); - - it('P3 (provide) displays as expected', function () { - expectedMsg = 'Hello from logger provided with useClass'; - expect(element(by.css('#p3')).getText()).toEqual(expectedMsg); - }); - - it('P4 (useClass:BetterLogger) displays as expected', function () { - expectedMsg = 'Hello from logger provided with useClass:BetterLogger'; - expect(element(by.css('#p4')).getText()).toEqual(expectedMsg); - }); - - it('P5 (useClass:EvenBetterLogger - dependency) displays as expected', function () { - expectedMsg = 'Message to Bob: Hello from EvenBetterlogger.'; - expect(element(by.css('#p5')).getText()).toEqual(expectedMsg); - }); - - it('P6a (no alias) displays as expected', function () { - expectedMsg = 'Hello OldLogger (but we want NewLogger)'; - expect(element(by.css('#p6a')).getText()).toEqual(expectedMsg); - }); - - it('P6b (alias) displays as expected', function () { - expectedMsg = 'Hello from NewLogger (via aliased OldLogger)'; - expect(element(by.css('#p6b')).getText()).toEqual(expectedMsg); - }); - - it('P7 (useValue) displays as expected', function () { - expectedMsg = 'Silent logger says "Shhhhh!". Provided via "useValue"'; - expect(element(by.css('#p7')).getText()).toEqual(expectedMsg); - }); - - it('P8 (useFactory) displays as expected', function () { - expectedMsg = 'Hero service injected successfully'; - expect(element(by.css('#p8')).getText()).toEqual(expectedMsg); - }); - - it('P9a (string token) displays as expected', function () { - expectedMsg = '"app.config" Application title is Dependency Injection'; - expect(element(by.css('#p9a')).getText()).toEqual(expectedMsg); - }); - - it('P9b (OpaqueToken) displays as expected', function () { - expectedMsg = 'APP_CONFIG Application title is Dependency Injection'; - expect(element(by.css('#p9b')).getText()).toEqual(expectedMsg); - }); - - it('P10a (required dependency) displays as expected', function () { - expectedMsg = 'Hello from the required logger.'; - expect(element(by.css('#p10a')).getText()).toEqual(expectedMsg); - }); - - it('P10b (optional dependency) displays as expected', function () { - expectedMsg = 'Optional logger was not available.'; - expect(element(by.css('#p10b')).getText()).toEqual(expectedMsg); - }) - }); - - describe('User/Heroes:', function() { - it('User is Bob - unauthorized', function () { - expectedMsg = /Bob, is not authorized/; - expect(element(by.css('#user')).getText()).toMatch(expectedMsg); - }); - - it('should have button', function () { - expect(element.all(by.cssContainingText('button','Next User')) - .get(0).isDisplayed()).toBe(true, "'Next User' button should be displayed"); - }); - - it('unauthorized user should have multiple unauthorized heroes', function () { - var heroes = element.all(by.css('#unauthorized hero-list div')); - expect(heroes.count()).toBeGreaterThan(0); - }); - - it('unauthorized user should have no secret heroes', function () { - var heroes = element.all(by.css('#unauthorized hero-list div')); - expect(heroes.count()).toBeGreaterThan(0); - - heroes.filter(function(elem, index){ - return elem.getText().then(function(text) { - return /secret/.test(text); - }); - }).then(function(filteredElements) { - //console.log("******Secret heroes count: "+filteredElements.length); - expect(filteredElements.length).toEqual(0); - }); - }); - - it('unauthorized user should have no authorized heros listed', function () { - expect(element.all(by.css('#authorized hero-list div')).count()).toEqual(0); - }); - - describe('after button click', function() { - - beforeAll(function (done) { - var buttonEle = element.all(by.cssContainingText('button','Next User')).get(0); - buttonEle.click().then(done,done); - }); - - it('User is Alice - authorized', function () { - expectedMsg = /Alice, is authorized/; - expect(element(by.css('#user')).getText()).toMatch(expectedMsg); - }); - - it('authorized user should have multiple authorized heroes ', function () { - var heroes = element.all(by.css('#authorized hero-list div')); - expect(heroes.count()).toBeGreaterThan(0); - }); - - it('authorized user should have secret heroes', function () { - var heroes = element.all(by.css('#authorized hero-list div')); - expect(heroes.count()).toBeGreaterThan(0); - - heroes.filter(function(elem, index){ - return elem.getText().then(function(text) { - return /secret/.test(text); - }); - }).then(function(filteredElements) { - //console.log("******Secret heroes count: "+filteredElements.length); - expect(filteredElements.length).toBeGreaterThan(0); - }); - }); - - it('authorized user should have no unauthorized heros listed', function () { - expect(element.all(by.css('#unauthorized hero-list div')).count()).toEqual(0); - }); - }); - }); -}); diff --git a/public/docs/_examples/dependency-injection/e2e-spec.ts b/public/docs/_examples/dependency-injection/e2e-spec.ts new file mode 100644 index 0000000000..5b46dd77d9 --- /dev/null +++ b/public/docs/_examples/dependency-injection/e2e-spec.ts @@ -0,0 +1,199 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; + +describe('Dependency Injection Tests', function () { + + let expectedMsg: string; + let expectedMsgRx: RegExp; + + beforeAll(function () { + browser.get(''); + }); + + describe('Cars:', function() { + + it('DI car displays as expected', function () { + expectedMsg = 'DI car with 4 cylinders and Flintstone tires.'; + expect(element(by.css('#di')).getText()).toEqual(expectedMsg); + }); + + it('No DI car displays as expected', function () { + expectedMsg = 'No DI car with 4 cylinders and Flintstone tires.'; + expect(element(by.css('#nodi')).getText()).toEqual(expectedMsg); + }); + + it('Injector car displays as expected', function () { + expectedMsg = 'Injector car with 4 cylinders and Flintstone tires.'; + expect(element(by.css('#injector')).getText()).toEqual(expectedMsg); + }); + + it('Factory car displays as expected', function () { + expectedMsg = 'Factory car with 4 cylinders and Flintstone tires.'; + expect(element(by.css('#factory')).getText()).toEqual(expectedMsg); + }); + + it('Simple car displays as expected', function () { + expectedMsg = 'Simple car with 4 cylinders and Flintstone tires.'; + expect(element(by.css('#simple')).getText()).toEqual(expectedMsg); + }); + + it('Super car displays as expected', function () { + expectedMsg = 'Super car with 12 cylinders and Flintstone tires.'; + expect(element(by.css('#super')).getText()).toEqual(expectedMsg); + }); + + it('Test car displays as expected', function () { + expectedMsg = 'Test car with 8 cylinders and YokoGoodStone tires.'; + expect(element(by.css('#test')).getText()).toEqual(expectedMsg); + }); + }); + + describe('Other Injections:', function() { + it('DI car displays as expected', function () { + expectedMsg = 'DI car with 4 cylinders and Flintstone tires.'; + expect(element(by.css('#car')).getText()).toEqual(expectedMsg); + }); + + it('Hero displays as expected', function () { + expectedMsg = 'Mr. Nice'; + expect(element(by.css('#hero')).getText()).toEqual(expectedMsg); + }); + + it('Optional injection displays as expected', function () { + expectedMsg = 'R.O.U.S.\'s? I don\'t think they exist!'; + expect(element(by.css('#rodent')).getText()).toEqual(expectedMsg); + }); + }); + + describe('Tests:', function() { + + it('Tests display as expected', function () { + expectedMsgRx = /Tests passed/; + expect(element(by.css('#tests')).getText()).toMatch(expectedMsgRx); + }); + + }); + + describe('Provider variations:', function() { + + it('P1 (class) displays as expected', function () { + expectedMsg = 'Hello from logger provided with Logger class'; + expect(element(by.css('#p1')).getText()).toEqual(expectedMsg); + }); + + it('P3 (provide) displays as expected', function () { + expectedMsg = 'Hello from logger provided with useClass:Logger'; + expect(element(by.css('#p3')).getText()).toEqual(expectedMsg); + }); + + it('P4 (useClass:BetterLogger) displays as expected', function () { + expectedMsg = 'Hello from logger provided with useClass:BetterLogger'; + expect(element(by.css('#p4')).getText()).toEqual(expectedMsg); + }); + + it('P5 (useClass:EvenBetterLogger - dependency) displays as expected', function () { + expectedMsg = 'Message to Bob: Hello from EvenBetterlogger'; + expect(element(by.css('#p5')).getText()).toEqual(expectedMsg); + }); + + it('P6a (no alias) displays as expected', function () { + expectedMsg = 'Hello OldLogger (but we want NewLogger)'; + expect(element(by.css('#p6a')).getText()).toEqual(expectedMsg); + }); + + it('P6b (alias) displays as expected', function () { + expectedMsg = 'Hello from NewLogger (via aliased OldLogger)'; + expect(element(by.css('#p6b')).getText()).toEqual(expectedMsg); + }); + + it('P7 (useValue) displays as expected', function () { + expectedMsg = 'Silent logger says "Shhhhh!". Provided via "useValue"'; + expect(element(by.css('#p7')).getText()).toEqual(expectedMsg); + }); + + it('P8 (useFactory) displays as expected', function () { + expectedMsg = 'Hero service injected successfully via heroServiceProvider'; + expect(element(by.css('#p8')).getText()).toEqual(expectedMsg); + }); + + it('P9 (OpaqueToken) displays as expected', function () { + expectedMsg = 'APP_CONFIG Application title is Dependency Injection'; + expect(element(by.css('#p9')).getText()).toEqual(expectedMsg); + }); + + it('P10 (optional dependency) displays as expected', function () { + expectedMsg = 'Optional logger was not available'; + expect(element(by.css('#p10')).getText()).toEqual(expectedMsg); + }); + }); + + describe('User/Heroes:', function() { + it('User is Bob - unauthorized', function () { + expectedMsgRx = /Bob, is not authorized/; + expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx); + }); + + it('should have button', function () { + expect(element.all(by.cssContainingText('button', 'Next User')) + .get(0).isDisplayed()).toBe(true, '\'Next User\' button should be displayed'); + }); + + it('unauthorized user should have multiple unauthorized heroes', function () { + let heroes = element.all(by.css('#unauthorized hero-list div')); + expect(heroes.count()).toBeGreaterThan(0); + }); + + it('unauthorized user should have no secret heroes', function () { + let heroes = element.all(by.css('#unauthorized hero-list div')); + expect(heroes.count()).toBeGreaterThan(0); + + let filteredHeroes = heroes.filter((elem: ElementFinder, index: number) => { + return elem.getText().then((text: string) => { + return /secret/.test(text); + }); + }); + + expect(filteredHeroes.count()).toEqual(0); + }); + + it('unauthorized user should have no authorized heroes listed', function () { + expect(element.all(by.css('#authorized hero-list div')).count()).toEqual(0); + }); + + describe('after button click', function() { + + beforeAll(function (done: any) { + let buttonEle = element.all(by.cssContainingText('button', 'Next User')).get(0); + buttonEle.click().then(done, done); + }); + + it('User is Alice - authorized', function () { + expectedMsgRx = /Alice, is authorized/; + expect(element(by.css('#user')).getText()).toMatch(expectedMsgRx); + }); + + it('authorized user should have multiple authorized heroes ', function () { + let heroes = element.all(by.css('#authorized hero-list div')); + expect(heroes.count()).toBeGreaterThan(0); + }); + + it('authorized user should have secret heroes', function () { + let heroes = element.all(by.css('#authorized hero-list div')); + expect(heroes.count()).toBeGreaterThan(0); + + let filteredHeroes = heroes.filter(function(elem: ElementFinder, index: number){ + return elem.getText().then(function(text: string) { + return /secret/.test(text); + }); + }); + + expect(filteredHeroes.count()).toBeGreaterThan(0); + }); + + it('authorized user should have no unauthorized heroes listed', function () { + expect(element.all(by.css('#unauthorized hero-list div')).count()).toEqual(0); + }); + }); + }); +}); diff --git a/public/docs/_examples/dependency-injection/ts/.gitignore b/public/docs/_examples/dependency-injection/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/dependency-injection/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/dependency-injection/ts/app/app.component.1.ts b/public/docs/_examples/dependency-injection/ts/app/app.component.1.ts deleted file mode 100644 index 480765e870..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/app.component.1.ts +++ /dev/null @@ -1,31 +0,0 @@ -// Early versions - -// #docregion -import {Component} from 'angular2/core'; -import {CarComponent} from './car/car.component'; -import {HeroesComponent} from './heroes/heroes.component.1'; - -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - - `, - directives:[CarComponent, HeroesComponent] -}) - -export class AppComponent { - title = 'Dependency Injection'; -} -// #enddocregion - - -/* -//#docregion ctor-di-fail -// FAIL! Injectable `config` is not a class! -constructor(heroService: HeroService, config: config) { - this.title = config.title; -} -//#enddocregion ctor-di-fail -*/ diff --git a/public/docs/_examples/dependency-injection/ts/app/app.component.2.ts b/public/docs/_examples/dependency-injection/ts/app/app.component.2.ts deleted file mode 100644 index e935f4c6e1..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/app.component.2.ts +++ /dev/null @@ -1,39 +0,0 @@ -// #docregion -// #docregion imports -import {Component} from 'angular2/core'; -import {CarComponent} from './car/car.component'; -import {HeroesComponent} from './heroes/heroes.component.1'; - -import {provide, Inject} from 'angular2/core'; -import {Config, CONFIG} from './app.config'; -import {Logger} from './logger.service'; -// #enddocregion imports - -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - - `, - directives:[CarComponent, HeroesComponent], -// #docregion providers - providers: [ - Logger, - // #docregion provider-config - provide('app.config', {useValue: CONFIG}) - // #enddocregion provider-config - ] -// #docregion providers -}) -export class AppComponent { - title:string; - - // #docregion ctor - constructor(@Inject('app.config') config:Config) { - - this.title = config.title; - } - // #docregion ctor -} -// #enddocregion diff --git a/public/docs/_examples/dependency-injection/ts/app/app.component.ts b/public/docs/_examples/dependency-injection/ts/app/app.component.ts deleted file mode 100644 index ef81e0630c..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/app.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -// #docplaster -// #docregion -// #docregion imports -import {Component, Inject, provide} from 'angular2/core'; - -import {CarComponent} from './car/car.component'; -import {HeroesComponent} from './heroes/heroes.component'; - -import {APP_CONFIG, - Config, CONFIG} from './app.config'; -import {Logger} from './logger.service'; - -import {User, UserService} from './user.service'; -// #enddocregion imports -import {InjectorComponent} from './injector.component'; -import {TestComponent} from './test.component'; -import {ProvidersComponent} from './providers.component'; - -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - - -

    User

    -

    - {{userInfo}} - -

    - - - `, - directives:[CarComponent, HeroesComponent, - InjectorComponent, TestComponent, ProvidersComponent], -// #docregion providers - providers: [ - Logger, - UserService, - provide(APP_CONFIG, {useValue: CONFIG}) - ] -// #enddocregion providers -}) -export class AppComponent { - title:string; - - //#docregion ctor - constructor( - @Inject(APP_CONFIG) config:Config, - private _userService: UserService) { - - this.title = config.title; - } - // #enddocregion ctor - - get isAuthorized() { return this.user.isAuthorized;} - nextUser() { this._userService.getNewUser(); } - get user() { return this._userService.user; } - - get userInfo() { - return `Current user, ${this.user.name}, is `+ - `${this.isAuthorized ? '' : 'not'} authorized. `; - } -} -// #enddocregion diff --git a/public/docs/_examples/dependency-injection/ts/app/app.config.ts b/public/docs/_examples/dependency-injection/ts/app/app.config.ts deleted file mode 100644 index 39f304d31a..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/app.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -//#docregion -// #docregion token -import {OpaqueToken} from 'angular2/core'; - -export let APP_CONFIG = new OpaqueToken('app.config'); -// #enddocregion token - -//#docregion config -export interface Config { - apiEndpoint: string, - title: string -} - -export const CONFIG:Config = { - apiEndpoint: 'api.heroes.com', - title: 'Dependency Injection' -}; -//#enddocregion config \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/ts/app/car/car-creations.ts b/public/docs/_examples/dependency-injection/ts/app/car/car-creations.ts deleted file mode 100644 index b6e56b85eb..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/car/car-creations.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Examples with car and engine variations - -// #docplaster -import {Car, Engine, Tires} from './car'; - -///////// example 1 //////////// -export function simpleCar() { - //#docregion car-ctor-instantiation - // Simple car with 4 cylinders and Flintstone tires. - var car = new Car(new Engine(), new Tires()); - //#enddocregion car-ctor-instantiation - car.description = 'Simple'; - return car; -} - - -///////// example 2 //////////// -//#docregion car-ctor-instantiation-with-param - class Engine2 { - constructor(public cylinders: number) { } - } -//#enddocregion car-ctor-instantiation-with-param -export function superCar() { -//#docregion car-ctor-instantiation-with-param - // Super car with 12 cylinders and Flintstone tires. - var bigCylinders = 12; - var car = new Car(new Engine2(bigCylinders), new Tires()); -//#enddocregion car-ctor-instantiation-with-param - car.description = 'Super'; - return car; -} - -/////////// example 3 ////////// - //#docregion car-ctor-instantiation-with-mocks - class MockEngine extends Engine { cylinders = 8; } - class MockTires extends Tires { make = "YokoGoodStone"; } - - //#enddocregion car-ctor-instantiation-with-mocks -export function testCar() { - //#docregion car-ctor-instantiation-with-mocks - // Test car with 8 cylinders and YokoGoodStone tires. - var car = new Car(new MockEngine(), new MockTires()); - //#enddocregion car-ctor-instantiation-with-mocks - car.description = 'Test'; - return car; -} diff --git a/public/docs/_examples/dependency-injection/ts/app/car/car-injector.ts b/public/docs/_examples/dependency-injection/ts/app/car/car-injector.ts deleted file mode 100644 index a94202585c..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/car/car-injector.ts +++ /dev/null @@ -1,37 +0,0 @@ -// #docplaster -//#docregion -import { Injector } from 'angular2/core'; - -import {Car, Engine, Tires} from './car'; -import {Logger} from '../logger.service'; - -//#docregion injector -export function useInjector() { - var injector:Injector; - -//#enddocregion injector -/* -//#docregion injector-no-new - // Cannot 'new' an Injector like this! - var injector = new Injector([Car, Engine, Tires, Logger]); -//#enddocregion injector-no-new -*/ - -//#docregion injector - //#docregion injector-create-and-call - injector = Injector.resolveAndCreate([Car, Engine, Tires, Logger]); - //#docregion injector-call - var car = injector.get(Car); - //#enddocregion injector-call - //#enddocregion injector-create-and-call - car.description = 'Injector'; - - var logger = injector.get(Logger); - logger.log('Injector car.drive() said: '+car.drive()); - - return car; -} -//#enddocregion injector - - -//#enddocregion diff --git a/public/docs/_examples/dependency-injection/ts/app/car/car-no-di.ts b/public/docs/_examples/dependency-injection/ts/app/car/car-no-di.ts deleted file mode 100644 index 9556bffcab..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/car/car-no-di.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Car without DI -import {Engine, Tires} from './car'; - -//#docregion car -export class Car { - - //#docregion car-ctor - public engine: Engine; - public tires: Tires; - public description = 'No DI'; - - constructor() { - this.engine = new Engine(); - this.tires = new Tires(); - } - //#enddocregion car-ctor - - // Method using the engine and tires - drive() { - return `${this.description} car with ` + - `${this.engine.cylinders} cylinders and ${this.tires.make} tires.` - } -} -//#enddocregion car \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/ts/app/car/car.ts b/public/docs/_examples/dependency-injection/ts/app/car/car.ts deleted file mode 100644 index e80483ed55..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/car/car.ts +++ /dev/null @@ -1,32 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; - -// #docregion engine -export class Engine { - public cylinders = 4; // default -} -// #enddocregion engine - -// #docregion tires -export class Tires { - public make = 'Flintstone'; - public model = 'Square'; -} -// #enddocregion tires - -@Injectable() -// #docregion car -export class Car { - //#docregion car-ctor - public description = 'DI'; - - constructor(public engine: Engine, public tires: Tires) { } - // #enddocregion car-ctor - - // Method using the engine and tires - drive() { - return `${this.description} car with ` + - `${this.engine.cylinders} cylinders and ${this.tires.make} tires.` - } -} -// #enddocregion car diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.1.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.1.ts deleted file mode 100644 index f82ced305d..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.1.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import { Component } from 'angular2/core'; -import { Hero } from './hero'; -import { HEROES } from './mock-heroes'; - -@Component({ - selector: 'hero-list', - template: ` -

    - {{hero.id}} - {{hero.name}} -
    - `, -}) -export class HeroListComponent { - heroes = HEROES; -} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.2.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.2.ts deleted file mode 100644 index 4c78e6a190..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.2.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import { Component } from 'angular2/core'; -import { Hero } from './hero'; -import { HeroService } from './hero.service'; - -@Component({ - selector: 'hero-list', - template: ` -
    - {{hero.id}} - {{hero.name}} -
    - `, -}) -export class HeroListComponent { - heroes: Hero[]; - - //#docregion ctor - constructor(heroService: HeroService) { - this.heroes = heroService.getHeroes(); - } - //#enddocregion ctor -} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.ts deleted file mode 100644 index b244d6d38c..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero-list.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import { Component } from 'angular2/core'; -import { Hero } from './hero'; -import { HeroService } from './hero.service'; - -@Component({ - selector: 'hero-list', - template: ` -
    - {{hero.id}} - {{hero.name}} - ({{hero.isSecret ? 'secret' : 'public'}}) -
    - `, -}) -export class HeroListComponent { - heroes: Hero[]; - - //#docregion ctor-signature - constructor(heroService: HeroService) { - //#enddocregion ctor-signature - this.heroes = heroService.getHeroes(); - } -} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.1.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.1.ts deleted file mode 100644 index ae962bd9b6..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.1.ts +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import {Hero} from './hero'; -import {HEROES} from './mock-heroes'; - -export class HeroService { - getHeroes() { return HEROES; } -} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.2.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.2.ts deleted file mode 100644 index d0737bb611..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.2.ts +++ /dev/null @@ -1,18 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; -import {Hero} from './hero'; -import {HEROES} from './mock-heroes'; -import {Logger} from '../logger.service'; - -@Injectable() -export class HeroService { - - //#docregion ctor - constructor(private _logger: Logger) { } - //#enddocregion ctor - - getHeroes() { - this._logger.log('Getting heroes ...') - return HEROES; - } -} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.provider.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.provider.ts deleted file mode 100644 index 9f259df0da..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.provider.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import {provide} from 'angular2/core'; -import {HeroService} from './hero.service'; -import {Logger} from '../logger.service'; -import {UserService} from '../user.service'; - -// #docregion factory -let heroServiceFactory = (logger: Logger, userService: UserService) => { - return new HeroService(logger, userService.user.isAuthorized); -} -// #enddocregion factory - -// #docregion provider -export let heroServiceProvider = - provide(HeroService, { - useFactory: heroServiceFactory, - deps: [Logger, UserService] - }); -// #enddocregion provider diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.ts deleted file mode 100644 index 0eaf72848b..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.service.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; -import {Hero} from './hero'; -import {HEROES} from './mock-heroes'; -import {Logger} from '../logger.service'; - -@Injectable() -export class HeroService { - private _user:string; - - // #docregion internals - constructor( - private _logger: Logger, - private _isAuthorized: boolean) { } - - getHeroes() { - let auth = this._isAuthorized ? 'authorized ': 'unauthorized'; - this._logger.log(`Getting heroes for ${auth} user.`); - return HEROES.filter(hero => this._isAuthorized || !hero.isSecret); - } - // #enddocregion internals -} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/heroes.component.1.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/heroes.component.1.ts deleted file mode 100644 index 86b8520140..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/heroes.component.1.ts +++ /dev/null @@ -1,24 +0,0 @@ -// #docplaster -// #docregion -// #docregion v1 -import { Component } from 'angular2/core'; -import { HeroListComponent } from './hero-list.component'; -// #enddocregion v1 -import { HeroService } from './hero.service'; -// #docregion v1 - -@Component({ - selector: 'my-heroes', - template: ` -

    Heroes

    - - `, - // #enddocregion v1 - // #docregion providers - providers:[HeroService], - // #enddocregion providers -// #docregion v1 - directives:[HeroListComponent] -}) -export class HeroesComponent { } -// #enddocregion v1 diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/heroes.component.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/heroes.component.ts deleted file mode 100644 index e7b1bd741d..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/heroes.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import { Component } from 'angular2/core'; -import { HeroListComponent } from './hero-list.component'; -import { heroServiceProvider} from './hero.service.provider'; - -@Component({ - selector: 'my-heroes', - template: ` -

    Heroes

    - - `, - providers:[heroServiceProvider], - directives:[HeroListComponent] -}) -export class HeroesComponent { } diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/mock-heroes.ts b/public/docs/_examples/dependency-injection/ts/app/heroes/mock-heroes.ts deleted file mode 100644 index 83726eb2f3..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/heroes/mock-heroes.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import { Hero } from './hero'; - -export var HEROES: Hero[] = [ - { "id": 11, isSecret: false, "name": "Mr. Nice" }, - { "id": 12, isSecret: false, "name": "Narco" }, - { "id": 13, isSecret: false, "name": "Bombasto" }, - { "id": 14, isSecret: false, "name": "Celeritas" }, - { "id": 15, isSecret: false, "name": "Magneta" }, - { "id": 16, isSecret: false, "name": "RubberMan" }, - { "id": 17, isSecret: false, "name": "Dynama" }, - { "id": 18, isSecret: true, "name": "Dr IQ" }, - { "id": 19, isSecret: true, "name": "Magma" }, - { "id": 20, isSecret: true, "name": "Tornado" } -]; diff --git a/public/docs/_examples/dependency-injection/ts/app/injector.component.ts b/public/docs/_examples/dependency-injection/ts/app/injector.component.ts deleted file mode 100644 index 300eaee9d3..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/injector.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docplaster -//#docregion -import {Component, Injector} from 'angular2/core'; - -import {Car, Engine, Tires} from './car/car'; -import {HeroService} from './heroes/hero.service'; -import {heroServiceProvider} from './heroes/hero.service.provider'; -import {Logger} from './logger.service'; - -//#docregion injector -@Component({ - selector: 'my-injectors', - template: ` -

    Other Injections

    -
    {{car.drive()}}
    -
    {{hero.name}}
    -
    {{rodent}}
    - `, - providers: [Car, Engine, Tires, - heroServiceProvider, Logger] -}) -export class InjectorComponent { - constructor(private _injector: Injector) { } - - car:Car = this._injector.get(Car); - - //#docregion get-hero-service - heroService:HeroService = this._injector.get(HeroService); - //#enddocregion get-hero-service - hero = this.heroService.getHeroes()[0]; - - get rodent() { - let rous = this._injector.getOptional(ROUS); - if (rous) { - throw new Error('Aaaargh!') - } - return "R.O.U.S.'s? I don't think they exist!"; - } -} -//#enddocregion injector - -/** - * R.O.U.S. - Rodents Of Unusual Size - * // https://www.youtube.com/watch?v=BOv5ZjAOpC8 - */ -class ROUS { } diff --git a/public/docs/_examples/dependency-injection/ts/app/logger.service.ts b/public/docs/_examples/dependency-injection/ts/app/logger.service.ts deleted file mode 100644 index 4afbd04017..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/logger.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; - -@Injectable() -export class Logger { - logs:string[] = []; // capture logs for testing - log(message: string){ - this.logs.push(message); - console.log(message); - } -} diff --git a/public/docs/_examples/dependency-injection/ts/app/main.1.ts b/public/docs/_examples/dependency-injection/ts/app/main.1.ts deleted file mode 100644 index a3eaa1245c..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/main.1.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; -import {HeroService} from './heroes/hero.service'; - -//#docregion bootstrap -bootstrap(AppComponent, - [HeroService]); // DISCOURAGED (but works) -//#enddocregion bootstrap diff --git a/public/docs/_examples/dependency-injection/ts/app/main.ts b/public/docs/_examples/dependency-injection/ts/app/main.ts deleted file mode 100644 index 8470a28175..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -//#docregion -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; -import {ProvidersComponent} from './providers.component'; - -//#docregion bootstrap -bootstrap(AppComponent); -//#enddocregion bootstrap -bootstrap(ProvidersComponent); \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/ts/app/providers.component.ts b/public/docs/_examples/dependency-injection/ts/app/providers.component.ts deleted file mode 100644 index de698f70e9..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/providers.component.ts +++ /dev/null @@ -1,352 +0,0 @@ -// Examples of provider arrays -//#docplaster -import { Component, Host, Inject, Injectable, - provide, Provider} from 'angular2/core'; - -import { APP_CONFIG, - Config, CONFIG } from './app.config'; - -import { HeroService} from './heroes/hero.service'; -import { heroServiceProvider } from './heroes/hero.service.provider'; -import { Logger } from './logger.service'; -import { User, UserService } from './user.service'; - -let template = '{{log}}'; - -////////////////////////////////////////// -@Component({ - selector: 'provider-1', - template: template, - providers: - //#docregion providers-1 - [Logger] - //#enddocregion providers-1 -}) -export class ProviderComponent1 { - log:string; - constructor(logger: Logger) { - logger.log('Hello from logger provided with Logger class'); - this.log = logger.logs[0]; - } -} - -////////////////////////////////////////// -@Component({ - selector: 'provider-2', - template: template, - providers: - //#docregion providers-2 - [new Provider(Logger, {useClass: Logger})] - //#enddocregion providers-2 -}) -export class ProviderComponent2 { - log:string; - constructor(logger: Logger) { - logger.log('Hello from logger provided with Provider class and useClass'); - this.log = logger.logs[0]; - } -} - -////////////////////////////////////////// -@Component({ - selector: 'provider-3', - template: template, - providers: - //#docregion providers-3 - [provide(Logger, {useClass: Logger})] - //#enddocregion providers-3 -}) -export class ProviderComponent3 { - log:string; - constructor(logger: Logger) { - logger.log('Hello from logger provided with useClass'); - this.log = logger.logs[0]; - } -} - -////////////////////////////////////////// -class BetterLogger extends Logger {} - -@Component({ - selector: 'provider-4', - template: template, - providers: - //#docregion providers-4 - [provide(Logger, {useClass: BetterLogger})] - //#enddocregion providers-4 -}) -export class ProviderComponent4 { - log:string; - constructor(logger: Logger) { - logger.log('Hello from logger provided with useClass:BetterLogger'); - this.log = logger.logs[0]; - } -} - -////////////////////////////////////////// -// #docregion EvenBetterLogger -@Injectable() -class EvenBetterLogger { - logs:string[] = []; - - constructor(private _userService: UserService) { } - - log(message:string){ - message = `Message to ${this._userService.user.name}: ${message}.`; - console.log(message); - this.logs.push(message); - } -} -// #enddocregion EvenBetterLogger - -@Component({ - selector: 'provider-5', - template: template, - providers: - //#docregion providers-5 - [ UserService, - provide(Logger, {useClass: EvenBetterLogger}) ] - //#enddocregion providers-5 -}) -export class ProviderComponent5 { - log:string; - constructor(logger: Logger) { - logger.log('Hello from EvenBetterlogger'); - this.log = logger.logs[0]; - } -} - -////////////////////////////////////////// -class NewLogger extends Logger {} -class OldLogger { - logs:string[] = []; - log(message:string) { - throw new Error('Should not call the old logger!') - }; -} - -@Component({ - selector: 'provider-6a', - template: template, - providers: - //#docregion providers-6a - [ NewLogger, - // Not aliased! Creates two instances of `NewLogger` - provide(OldLogger, {useClass:NewLogger}) ] - //#enddocregion providers-6a -}) -export class ProviderComponent6a { - log:string; - constructor(newLogger:NewLogger, oldLogger: OldLogger) { - if (newLogger === oldLogger){ - throw new Error('expected the two loggers to be different instances'); - } - oldLogger.log('Hello OldLogger (but we want NewLogger)'); - // The newLogger wasn't called so no logs[] - // display the logs of the oldLogger. - this.log = newLogger.logs[0] || oldLogger.logs[0]; - } -} - -@Component({ - selector: 'provider-6b', - template: template, - providers: - //#docregion providers-6b - [ NewLogger, - // Alias OldLogger w/ reference to NewLogger - provide(OldLogger, {useExisting: NewLogger}) ] - //#enddocregion providers-6b -}) -export class ProviderComponent6b { - log:string; - constructor(newLogger:NewLogger, oldLogger: OldLogger) { - if (newLogger !== oldLogger){ - throw new Error('expected the two loggers to be the same instance'); - } - oldLogger.log('Hello from NewLogger (via aliased OldLogger)'); - this.log = newLogger.logs[0]; - } -} - -////////////////////////////////////////// -// #docregion silent-logger -// An object in the shape of the logger service -let silentLogger = { - logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'], - log: () => {} -} -// #enddocregion silent-logger - -@Component({ - selector: 'provider-7', - template: template, - providers: - //#docregion providers-7 - [provide(Logger, {useValue: silentLogger})] - //#enddocregion providers-7 -}) -export class ProviderComponent7 { - log:string; - constructor(logger: Logger) { - logger.log('Hello from logger provided with useValue'); - this.log = logger.logs[0]; - } -} -///////////////// - -@Component({ - selector: 'provider-8', - template: template, - providers:[heroServiceProvider, Logger, UserService] -}) -export class ProviderComponent8{ - // #docregion provider-8-ctor - constructor(heroService: HeroService){ } - // #enddocregion provider-8-ctor - - // must be true else this component would have blown up at runtime - log = 'Hero service injected successfully' -} - -///////////////// -@Component({ - selector: 'provider-9a', - template: template, - providers: - /* - // #docregion providers-9a-interface - // FAIL! Can't use interface as provider token - [provide(Config, {useValue: CONFIG})] - // #enddocregion providers-9a-interface - */ - // #docregion providers-9a - // Use string as provider token - [provide('app.config', {useValue: CONFIG})] - // #enddocregion providers-9a -}) -export class ProviderComponent9a { - log: string; - /* - // #docregion provider-9a-ctor-interface - // FAIL! Can't inject using the interface as the parameter type - constructor(private _config: Config){ } - // #enddocregion provider-9a-ctor-interface - */ - - // #docregion provider-9a-ctor - // @Inject(token) to inject the dependency - constructor(@Inject('app.config') private _config: Config){ } - // #enddocregion provider-9a-ctor - - ngOnInit() { - this.log = '"app.config" Application title is ' + this._config.title; - } -} - -@Component({ - selector: 'provider-9b', - template: template, - // #docregion providers-9b - providers:[provide(APP_CONFIG, {useValue: CONFIG})] - // #enddocregion providers-9b -}) -export class ProviderComponent9b { - log: string; - // #docregion provider-9b-ctor - constructor(@Inject(APP_CONFIG) private _config: Config){ } - // #enddocregion provider-9b-ctor - - ngOnInit() { - this.log = 'APP_CONFIG Application title is ' + this._config.title; - } -} -////////////////////////////////////////// -// Normal required logger -@Component({ - selector: 'provider-10a', - template: template, - //#docregion providers-logger - providers: [Logger] - //#enddocregion providers-logger -}) -export class ProviderComponent10a { - log:string; - constructor(logger: Logger) { - logger.log('Hello from the required logger.'); - this.log = logger.logs[0]; - } -} - -// Optional logger -// #docregion import-optional -import {Optional} from 'angular2/core'; -// #enddocregion import-optional - -@Component({ - selector: 'provider-10b', - template: template -}) -export class ProviderComponent10b { - // #docregion provider-10-ctor - log:string; - constructor(@Optional() private _logger:Logger) { } - // #enddocregion provider-10-ctor - - ngOnInit() { - // #docregion provider-10-logger - // No logger? Make one! - if (!this._logger) { - this._logger = { - log: (msg:string)=> this._logger.logs.push(msg), - logs: [] - } - // #enddocregion provider-10-logger - this._logger.log("Optional logger was not available.") - // #docregion provider-10-logger - } - // #enddocregion provider-10-logger - else { - this._logger.log('Hello from the injected logger.') - this.log = this._logger.logs[0]; - } - this.log = this._logger.logs[0]; - } -} - -///////////////// -@Component({ - selector: 'my-providers', - template: ` -

    Provider variations

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - `, - directives:[ - ProviderComponent1, - ProviderComponent2, - ProviderComponent3, - ProviderComponent4, - ProviderComponent5, - ProviderComponent6a, - ProviderComponent6b, - ProviderComponent7, - ProviderComponent8, - ProviderComponent9a, - ProviderComponent9b, - ProviderComponent10a, - ProviderComponent10b, - ], -}) -export class ProvidersComponent { } \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/ts/app/test.component.ts b/public/docs/_examples/dependency-injection/ts/app/test.component.ts deleted file mode 100644 index 6499edec65..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/test.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Simulate a simple test -// Reader should look to the testing chapter for the real thing - -import {Component} from 'angular2/core'; -import { HeroService } from './heroes/hero.service'; -import { HeroListComponent } from './heroes/hero-list.component'; - -@Component({ - selector: 'my-tests', - template: ` -

    Tests

    -

    Tests {{results.pass}}: {{results.message}}

    - ` -}) -export class TestComponent { - results = runTests(); -} - -///////////////////////////////////// -function runTests() { - - //#docregion spec - let expectedHeroes = [{name: 'A'}, {name: 'B'}] - let mockService = {getHeroes: () => expectedHeroes } - - it("should have heroes when HeroListComponent created", () => { - let hlc = new HeroListComponent(mockService); - expect(hlc.heroes.length).toEqual(expectedHeroes.length); - }) - //#enddocregion spec - - return testResults; -} - -////////////////////////////////// -// Fake Jasmine infrastructure -var testName:string; -var testResults: {pass:string; message:string}; - -function expect(actual:any) { - return { - toEqual: function(expected:any){ - testResults = actual === expected? - {pass:'passed', message: `${testName}`} : - {pass:'failed', message: `${testName}; expected ${actual} to equal ${expected}.`}; - } - } -} - -function it(label:string, test: () => void) { - testName = label; - test(); -} \ No newline at end of file diff --git a/public/docs/_examples/dependency-injection/ts/app/user.service.ts b/public/docs/_examples/dependency-injection/ts/app/user.service.ts deleted file mode 100644 index 1fd5b46516..0000000000 --- a/public/docs/_examples/dependency-injection/ts/app/user.service.ts +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; - -@Injectable() -export class UserService { - // Todo: get the user; don't 'new' it. - private _alice = new User('Alice', true); - private _bob = new User('Bob', false); - - // initial user is Bob - user = this._bob; - - // swaps users - getNewUser() { - return this.user = this.user === this._bob ? this._alice : this._bob; - } -} - -export class User { - constructor( - public name:string, - public isAuthorized:boolean = false) { } -} diff --git a/public/docs/_examples/dependency-injection/ts/index.html b/public/docs/_examples/dependency-injection/ts/index.html deleted file mode 100644 index 04cc28901d..0000000000 --- a/public/docs/_examples/dependency-injection/ts/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Dependency Injection - - - - - - - - - - - - - - - - - Loading my-app ... - Loading my-providers ... - - - diff --git a/public/docs/_examples/dependency-injection/ts/plnkr.json b/public/docs/_examples/dependency-injection/ts/plnkr.json index dff3dc4110..e8d1ab24b2 100644 --- a/public/docs/_examples/dependency-injection/ts/plnkr.json +++ b/public/docs/_examples/dependency-injection/ts/plnkr.json @@ -1,9 +1,10 @@ { "description": "Dependency Injection", + "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", "!**/*.[1,2].*" ], "tags": ["dependency", "di"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/app.component.1.ts b/public/docs/_examples/dependency-injection/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..b398ebeb57 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/app.component.1.ts @@ -0,0 +1,17 @@ +// Early versions + +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + + ` +}) + +export class AppComponent { + title = 'Dependency Injection'; +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/app.component.2.ts b/public/docs/_examples/dependency-injection/ts/src/app/app.component.2.ts new file mode 100644 index 0000000000..d24df5568c --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/app.component.2.ts @@ -0,0 +1,25 @@ +// #docregion +// #docregion imports +import { Component } from '@angular/core'; +import { Inject } from '@angular/core'; + +import { APP_CONFIG, AppConfig } from './app.config'; +// #enddocregion imports + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + + ` +}) +export class AppComponent { + title: string; + + // #docregion ctor + constructor(@Inject(APP_CONFIG) config: AppConfig) { + this.title = config.title; + } + // #enddocregion ctor +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/app.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/app.component.ts new file mode 100644 index 0000000000..3563fdc070 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/app.component.ts @@ -0,0 +1,48 @@ +// #docplaster +// #docregion +// #docregion imports +import { Component, Inject } from '@angular/core'; + +import { APP_CONFIG, AppConfig } from './app.config'; +import { Logger } from './logger.service'; +import { UserService } from './user.service'; +// #enddocregion imports + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + + +

    User

    +

    + {{userInfo}} + +

    + + + + `, + providers: [Logger] +}) +export class AppComponent { + title: string; + + // #docregion ctor + constructor( + @Inject(APP_CONFIG) config: AppConfig, + private userService: UserService) { + this.title = config.title; + } + // #enddocregion ctor + + get isAuthorized() { return this.user.isAuthorized; } + nextUser() { this.userService.getNewUser(); } + get user() { return this.userService.user; } + + get userInfo() { + return `Current user, ${this.user.name}, is ` + + `${this.isAuthorized ? '' : 'not'} authorized. `; + } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/app.config.ts b/public/docs/_examples/dependency-injection/ts/src/app/app.config.ts new file mode 100644 index 0000000000..f224e6e1ab --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/app.config.ts @@ -0,0 +1,16 @@ +// #docregion token +import { InjectionToken } from '@angular/core'; + +export let APP_CONFIG = new InjectionToken('app.config'); +// #enddocregion token + +// #docregion config +export interface AppConfig { + apiEndpoint: string; + title: string; +} + +export const HERO_DI_CONFIG: AppConfig = { + apiEndpoint: 'api.heroes.com', + title: 'Dependency Injection' +}; diff --git a/public/docs/_examples/dependency-injection/ts/src/app/app.module.ts b/public/docs/_examples/dependency-injection/ts/src/app/app.module.ts new file mode 100644 index 0000000000..67ae8ae913 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/app.module.ts @@ -0,0 +1,60 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { CarComponent } from './car/car.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { HeroListComponent } from './heroes/hero-list.component'; +import { InjectorComponent } from './injector.component'; +import { TestComponent } from './test.component'; +import { APP_CONFIG, HERO_DI_CONFIG } from './app.config'; +import { UserService } from './user.service'; +import { + ProvidersComponent, + Provider1Component, + Provider3Component, + Provider4Component, + Provider5Component, + Provider6aComponent, + Provider6bComponent, + Provider7Component, + Provider8Component, + Provider9Component, + Provider10Component, +} from './providers.component'; + +// #docregion ngmodule +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent, + CarComponent, + HeroesComponent, + // #enddocregion ngmodule + HeroListComponent, + InjectorComponent, + TestComponent, + ProvidersComponent, + Provider1Component, + Provider3Component, + Provider4Component, + Provider5Component, + Provider6aComponent, + Provider6bComponent, + Provider7Component, + Provider8Component, + Provider9Component, + Provider10Component, + // #docregion ngmodule + ], + // #docregion ngmodule-providers + providers: [ + UserService, + { provide: APP_CONFIG, useValue: HERO_DI_CONFIG } + ], + // #enddocregion ngmodule-providers + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/dependency-injection/ts/src/app/car/car-creations.ts b/public/docs/_examples/dependency-injection/ts/src/app/car/car-creations.ts new file mode 100644 index 0000000000..c758c72951 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/car/car-creations.ts @@ -0,0 +1,46 @@ +// Examples with car and engine variations + +// #docplaster +import { Car, Engine, Tires } from './car'; + +///////// example 1 //////////// +export function simpleCar() { + // #docregion car-ctor-instantiation + // Simple car with 4 cylinders and Flintstone tires. + let car = new Car(new Engine(), new Tires()); + // #enddocregion car-ctor-instantiation + car.description = 'Simple'; + return car; +} + + +///////// example 2 //////////// +// #docregion car-ctor-instantiation-with-param + class Engine2 { + constructor(public cylinders: number) { } + } +// #enddocregion car-ctor-instantiation-with-param +export function superCar() { +// #docregion car-ctor-instantiation-with-param + // Super car with 12 cylinders and Flintstone tires. + let bigCylinders = 12; + let car = new Car(new Engine2(bigCylinders), new Tires()); +// #enddocregion car-ctor-instantiation-with-param + car.description = 'Super'; + return car; +} + +/////////// example 3 ////////// + // #docregion car-ctor-instantiation-with-mocks + class MockEngine extends Engine { cylinders = 8; } + class MockTires extends Tires { make = 'YokoGoodStone'; } + + // #enddocregion car-ctor-instantiation-with-mocks +export function testCar() { + // #docregion car-ctor-instantiation-with-mocks + // Test car with 8 cylinders and YokoGoodStone tires. + let car = new Car(new MockEngine(), new MockTires()); + // #enddocregion car-ctor-instantiation-with-mocks + car.description = 'Test'; + return car; +} diff --git a/public/docs/_examples/dependency-injection/ts/app/car/car-factory.ts b/public/docs/_examples/dependency-injection/ts/src/app/car/car-factory.ts similarity index 86% rename from public/docs/_examples/dependency-injection/ts/app/car/car-factory.ts rename to public/docs/_examples/dependency-injection/ts/src/app/car/car-factory.ts index 6d869b6ee3..06daafe63b 100644 --- a/public/docs/_examples/dependency-injection/ts/app/car/car-factory.ts +++ b/public/docs/_examples/dependency-injection/ts/src/app/car/car-factory.ts @@ -1,5 +1,5 @@ // #docregion -import {Engine, Tires, Car} from './car'; +import { Engine, Tires, Car } from './car'; // BAD pattern! export class CarFactory { diff --git a/public/docs/_examples/dependency-injection/ts/src/app/car/car-injector.ts b/public/docs/_examples/dependency-injection/ts/src/app/car/car-injector.ts new file mode 100644 index 0000000000..4f7498ee4e --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/car/car-injector.ts @@ -0,0 +1,27 @@ +import { ReflectiveInjector } from '@angular/core'; + +import { Car, Engine, Tires } from './car'; +import { Logger } from '../logger.service'; + +// #docregion injector +export function useInjector() { + let injector: ReflectiveInjector; + // #enddocregion injector + /* + // #docregion injector-no-new + // Cannot instantiate an ReflectiveInjector like this! + let injector = new ReflectiveInjector([Car, Engine, Tires]); + // #enddocregion injector-no-new + */ + // #docregion injector, injector-create-and-call + injector = ReflectiveInjector.resolveAndCreate([Car, Engine, Tires]); + // #docregion injector-call + let car = injector.get(Car); + // #enddocregion injector-call, injector-create-and-call + car.description = 'Injector'; + + injector = ReflectiveInjector.resolveAndCreate([Logger]); + let logger = injector.get(Logger); + logger.log('Injector car.drive() said: ' + car.drive()); + return car; +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/car/car-no-di.ts b/public/docs/_examples/dependency-injection/ts/src/app/car/car-no-di.ts new file mode 100644 index 0000000000..9026edebc2 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/car/car-no-di.ts @@ -0,0 +1,24 @@ +// Car without DI +import { Engine, Tires } from './car'; + +// #docregion car +export class Car { + + // #docregion car-ctor + public engine: Engine; + public tires: Tires; + public description = 'No DI'; + + constructor() { + this.engine = new Engine(); + this.tires = new Tires(); + } + // #enddocregion car-ctor + + // Method using the engine and tires + drive() { + return `${this.description} car with ` + + `${this.engine.cylinders} cylinders and ${this.tires.make} tires.`; + } +} +// #enddocregion car diff --git a/public/docs/_examples/dependency-injection/ts/app/car/car.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/car/car.component.ts similarity index 80% rename from public/docs/_examples/dependency-injection/ts/app/car/car.component.ts rename to public/docs/_examples/dependency-injection/ts/src/app/car/car.component.ts index c66e0fbcce..9a835ef124 100644 --- a/public/docs/_examples/dependency-injection/ts/app/car/car.component.ts +++ b/public/docs/_examples/dependency-injection/ts/src/app/car/car.component.ts @@ -1,8 +1,9 @@ // #docregion -import { Component, Injector} from 'angular2/core'; -import { Car, Engine, Tires } from './car'; -import { Car as CarNoDi } from './car-no-di'; -import { CarFactory} from './car-factory'; +import { Component } from '@angular/core'; + +import { Car, Engine, Tires } from './car'; +import { Car as CarNoDi } from './car-no-di'; +import { CarFactory } from './car-factory'; import { testCar, simpleCar, @@ -26,12 +27,12 @@ import { useInjector } from './car-injector'; providers: [Car, Engine, Tires] }) export class CarComponent { - constructor(public car: Car) {} - factoryCar = (new CarFactory).createCar(); injectorCar = useInjector(); noDiCar = new CarNoDi; simpleCar = simpleCar(); superCar = superCar(); testCar = testCar(); + + constructor(public car: Car) {} } diff --git a/public/docs/_examples/dependency-injection/ts/src/app/car/car.ts b/public/docs/_examples/dependency-injection/ts/src/app/car/car.ts new file mode 100644 index 0000000000..37162c570b --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/car/car.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@angular/core'; + +export class Engine { + public cylinders = 4; +} + +export class Tires { + public make = 'Flintstone'; + public model = 'Square'; +} + +@Injectable() +export class Car { + // #docregion car-ctor + public description = 'DI'; + + constructor(public engine: Engine, public tires: Tires) { } + // #enddocregion car-ctor + + // Method using the engine and tires + drive() { + return `${this.description} car with ` + + `${this.engine.cylinders} cylinders and ${this.tires.make} tires.`; + } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.1.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.1.ts new file mode 100644 index 0000000000..ba32366aa9 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.1.ts @@ -0,0 +1,16 @@ +// #docregion +import { Component } from '@angular/core'; + +import { HEROES } from './mock-heroes'; + +@Component({ + selector: 'hero-list', + template: ` +

    + {{hero.id}} - {{hero.name}} +
    + ` +}) +export class HeroListComponent { + heroes = HEROES; +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.2.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.2.ts new file mode 100644 index 0000000000..cb23d3257c --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.2.ts @@ -0,0 +1,31 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +import { Hero } from './hero'; +// #enddocregion +import { HeroService } from './hero.service.1'; +/* +// #docregion +import { HeroService } from './hero.service'; +// #enddocregion +*/ +// #docregion + +@Component({ + selector: 'hero-list', + template: ` +
    + {{hero.id}} - {{hero.name}} +
    + ` +}) +export class HeroListComponent { + heroes: Hero[]; + + // #docregion ctor + constructor(heroService: HeroService) { + this.heroes = heroService.getHeroes(); + } + // #enddocregion ctor +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.ts new file mode 100644 index 0000000000..db3a325bdb --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero-list.component.ts @@ -0,0 +1,26 @@ +/* tslint:disable:one-line */ +// #docregion +import { Component } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'hero-list', + template: ` +
    + {{hero.id}} - {{hero.name}} + ({{hero.isSecret ? 'secret' : 'public'}}) +
    + `, +}) +export class HeroListComponent { + heroes: Hero[]; + + // #docregion ctor-signature + constructor(heroService: HeroService) + // #enddocregion ctor-signature + { + this.heroes = heroService.getHeroes(); + } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.1.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.1.ts new file mode 100644 index 0000000000..2e0e3ca734 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.1.ts @@ -0,0 +1,9 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { HEROES } from './mock-heroes'; + +@Injectable() +export class HeroService { + getHeroes() { return HEROES; } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.2.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.2.ts new file mode 100644 index 0000000000..6b3a98306a --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.2.ts @@ -0,0 +1,18 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { HEROES } from './mock-heroes'; +import { Logger } from '../logger.service'; + +@Injectable() +export class HeroService { + + // #docregion ctor + constructor(private logger: Logger) { } + // #enddocregion ctor + + getHeroes() { + this.logger.log('Getting heroes ...'); + return HEROES; + } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.provider.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.provider.ts new file mode 100644 index 0000000000..6de4ebee90 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.provider.ts @@ -0,0 +1,19 @@ +/* tslint:disable:one-line */ +// #docregion +import { HeroService } from './hero.service'; +import { Logger } from '../logger.service'; +import { UserService } from '../user.service'; + +// #docregion factory +let heroServiceFactory = (logger: Logger, userService: UserService) => { + return new HeroService(logger, userService.user.isAuthorized); +}; +// #enddocregion factory + +// #docregion provider +export let heroServiceProvider = + { provide: HeroService, + useFactory: heroServiceFactory, + deps: [Logger, UserService] + }; +// #enddocregion provider diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.ts new file mode 100644 index 0000000000..fb03ec1de6 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { HEROES } from './mock-heroes'; +import { Logger } from '../logger.service'; + +@Injectable() +export class HeroService { + // #docregion internals + constructor( + private logger: Logger, + private isAuthorized: boolean) { } + + getHeroes() { + let auth = this.isAuthorized ? 'authorized ' : 'unauthorized'; + this.logger.log(`Getting heroes for ${auth} user.`); + return HEROES.filter(hero => this.isAuthorized || !hero.isSecret); + } + // #enddocregion internals +} diff --git a/public/docs/_examples/dependency-injection/ts/app/heroes/hero.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.ts similarity index 100% rename from public/docs/_examples/dependency-injection/ts/app/heroes/hero.ts rename to public/docs/_examples/dependency-injection/ts/src/app/heroes/hero.ts diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/heroes.component.1.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/heroes.component.1.ts new file mode 100644 index 0000000000..e0e9deae08 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/heroes.component.1.ts @@ -0,0 +1,21 @@ +// #docplaster +// #docregion full, v1 +import { Component } from '@angular/core'; +// #enddocregion v1 + +import { HeroService } from './hero.service'; +// #enddocregion full + +// #docregion full, v1 + +@Component({ + selector: 'my-heroes', + // #enddocregion v1 + providers: [HeroService], + // #docregion v1 + template: ` +

    Heroes

    + + ` +}) +export class HeroesComponent { } diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/heroes.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..5923f7590b --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/heroes.component.ts @@ -0,0 +1,14 @@ +// #docregion +import { Component } from '@angular/core'; + +import { heroServiceProvider } from './hero.service.provider'; + +@Component({ + selector: 'my-heroes', + template: ` +

    Heroes

    + + `, + providers: [heroServiceProvider] +}) +export class HeroesComponent { } diff --git a/public/docs/_examples/dependency-injection/ts/src/app/heroes/mock-heroes.ts b/public/docs/_examples/dependency-injection/ts/src/app/heroes/mock-heroes.ts new file mode 100644 index 0000000000..79a91dc03a --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/heroes/mock-heroes.ts @@ -0,0 +1,15 @@ +// #docregion +import { Hero } from './hero'; + +export var HEROES: Hero[] = [ + { id: 11, isSecret: false, name: 'Mr. Nice' }, + { id: 12, isSecret: false, name: 'Narco' }, + { id: 13, isSecret: false, name: 'Bombasto' }, + { id: 14, isSecret: false, name: 'Celeritas' }, + { id: 15, isSecret: false, name: 'Magneta' }, + { id: 16, isSecret: false, name: 'RubberMan' }, + { id: 17, isSecret: false, name: 'Dynama' }, + { id: 18, isSecret: true, name: 'Dr IQ' }, + { id: 19, isSecret: true, name: 'Magma' }, + { id: 20, isSecret: true, name: 'Tornado' } +]; diff --git a/public/docs/_examples/dependency-injection/ts/src/app/injector.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/injector.component.ts new file mode 100644 index 0000000000..1b1a065e4c --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/injector.component.ts @@ -0,0 +1,49 @@ +// #docplaster +// #docregion +import { Component, Injector, OnInit } from '@angular/core'; + +import { Car, Engine, Tires } from './car/car'; +import { Hero } from './heroes/hero'; +import { HeroService } from './heroes/hero.service'; +import { heroServiceProvider } from './heroes/hero.service.provider'; +import { Logger } from './logger.service'; + +// #docregion injector +@Component({ + selector: 'my-injectors', + template: ` +

    Other Injections

    +
    {{car.drive()}}
    +
    {{hero.name}}
    +
    {{rodent}}
    + `, + providers: [Car, Engine, Tires, heroServiceProvider, Logger] +}) +export class InjectorComponent implements OnInit { + car: Car; + + // #docregion get-hero-service + heroService: HeroService; + // #enddocregion get-hero-service + hero: Hero; + + constructor(private injector: Injector) { } + + ngOnInit() { + this.car = this.injector.get(Car); + this.heroService = this.injector.get(HeroService); + this.hero = this.heroService.getHeroes()[0]; + } + + get rodent() { + let rousDontExist = `R.O.U.S.'s? I don't think they exist!`; + return this.injector.get(ROUS, rousDontExist); + } +} +// #enddocregion injector + +/** + * R.O.U.S. - Rodents Of Unusual Size + * // https://www.youtube.com/watch?v=BOv5ZjAOpC8 + */ +class ROUS { } diff --git a/public/docs/_examples/dependency-injection/ts/src/app/logger.service.ts b/public/docs/_examples/dependency-injection/ts/src/app/logger.service.ts new file mode 100644 index 0000000000..e943523ad2 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/logger.service.ts @@ -0,0 +1,12 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +export class Logger { + logs: string[] = []; // capture logs for testing + + log(message: string) { + this.logs.push(message); + console.log(message); + } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/providers.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/providers.component.ts new file mode 100644 index 0000000000..a96bfce99e --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/providers.component.ts @@ -0,0 +1,267 @@ +/* tslint:disable:one-line:check-open-brace*/ +// Examples of provider arrays +// #docplaster +import { Component, Inject, Injectable, OnInit } from '@angular/core'; + +import { APP_CONFIG, AppConfig, + HERO_DI_CONFIG } from './app.config'; + +import { HeroService } from './heroes/hero.service'; +import { heroServiceProvider } from './heroes/hero.service.provider'; +import { Logger } from './logger.service'; +import { UserService } from './user.service'; + +let template = '{{log}}'; + +////////////////////////////////////////// +@Component({ + selector: 'provider-1', + template: template, + // #docregion providers-1, providers-logger + providers: [Logger] + // #enddocregion providers-1, providers-logger +}) +export class Provider1Component { + log: string; + constructor(logger: Logger) { + logger.log('Hello from logger provided with Logger class'); + this.log = logger.logs[0]; + } +} + +////////////////////////////////////////// +@Component({ + selector: 'provider-3', + template: template, + providers: + // #docregion providers-3 + [{ provide: Logger, useClass: Logger }] + // #enddocregion providers-3 +}) +export class Provider3Component { + log: string; + constructor(logger: Logger) { + logger.log('Hello from logger provided with useClass:Logger'); + this.log = logger.logs[0]; + } +} + +////////////////////////////////////////// +class BetterLogger extends Logger {} + +@Component({ + selector: 'provider-4', + template: template, + providers: + // #docregion providers-4 + [{ provide: Logger, useClass: BetterLogger }] + // #enddocregion providers-4 +}) +export class Provider4Component { + log: string; + constructor(logger: Logger) { + logger.log('Hello from logger provided with useClass:BetterLogger'); + this.log = logger.logs[0]; + } +} + +////////////////////////////////////////// +// #docregion EvenBetterLogger +@Injectable() +class EvenBetterLogger extends Logger { + constructor(private userService: UserService) { super(); } + + log(message: string) { + let name = this.userService.user.name; + super.log(`Message to ${name}: ${message}`); + } +} +// #enddocregion EvenBetterLogger + +@Component({ + selector: 'provider-5', + template: template, + providers: + // #docregion providers-5 + [ UserService, + { provide: Logger, useClass: EvenBetterLogger }] + // #enddocregion providers-5 +}) +export class Provider5Component { + log: string; + constructor(logger: Logger) { + logger.log('Hello from EvenBetterlogger'); + this.log = logger.logs[0]; + } +} + +////////////////////////////////////////// +class NewLogger extends Logger {} +class OldLogger { + logs: string[] = []; + log(message: string) { + throw new Error('Should not call the old logger!'); + }; +} + +@Component({ + selector: 'provider-6a', + template: template, + providers: + // #docregion providers-6a + [ NewLogger, + // Not aliased! Creates two instances of `NewLogger` + { provide: OldLogger, useClass: NewLogger}] + // #enddocregion providers-6a +}) +export class Provider6aComponent { + log: string; + constructor(newLogger: NewLogger, oldLogger: OldLogger) { + if (newLogger === oldLogger){ + throw new Error('expected the two loggers to be different instances'); + } + oldLogger.log('Hello OldLogger (but we want NewLogger)'); + // The newLogger wasn't called so no logs[] + // display the logs of the oldLogger. + this.log = newLogger.logs[0] || oldLogger.logs[0]; + } +} + +@Component({ + selector: 'provider-6b', + template: template, + providers: + // #docregion providers-6b + [ NewLogger, + // Alias OldLogger w/ reference to NewLogger + { provide: OldLogger, useExisting: NewLogger}] + // #enddocregion providers-6b +}) +export class Provider6bComponent { + log: string; + constructor(newLogger: NewLogger, oldLogger: OldLogger) { + if (newLogger !== oldLogger){ + throw new Error('expected the two loggers to be the same instance'); + } + oldLogger.log('Hello from NewLogger (via aliased OldLogger)'); + this.log = newLogger.logs[0]; + } +} + +////////////////////////////////////////// +// #docregion silent-logger +// An object in the shape of the logger service +let silentLogger = { + logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'], + log: () => {} +}; +// #enddocregion silent-logger + +@Component({ + selector: 'provider-7', + template: template, + providers: + // #docregion providers-7 + [{ provide: Logger, useValue: silentLogger }] + // #enddocregion providers-7 +}) +export class Provider7Component { + log: string; + constructor(logger: Logger) { + logger.log('Hello from logger provided with useValue'); + this.log = logger.logs[0]; + } +} +///////////////// + +@Component({ + selector: 'provider-8', + template: template, + providers: [heroServiceProvider, Logger, UserService] +}) +export class Provider8Component { + // must be true else this component would have blown up at runtime + log = 'Hero service injected successfully via heroServiceProvider'; + + // #docregion provider-8-ctor + constructor(heroService: HeroService) { } + // #enddocregion provider-8-ctor +} + +///////////////// +@Component({ + selector: 'provider-9', + template: template, + /* + // #docregion providers-9-interface + // FAIL! Can't use interface as provider token + [{ provide: AppConfig, useValue: HERO_DI_CONFIG })] + // #enddocregion providers-9-interface + */ + // #docregion providers-9 + providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }] + // #enddocregion providers-9 +}) +export class Provider9Component implements OnInit { + log: string; + /* + // #docregion provider-9-ctor-interface + // FAIL! Can't inject using the interface as the parameter type + constructor(private config: AppConfig){ } + // #enddocregion provider-9-ctor-interface + */ + // #docregion provider-9-ctor + constructor(@Inject(APP_CONFIG) private config: AppConfig) { } + // #enddocregion provider-9-ctor + + ngOnInit() { + this.log = 'APP_CONFIG Application title is ' + this.config.title; + } +} +////////////////////////////////////////// +// Sample providers 1 to 7 illustrate a required logger dependency. +// Optional logger, can be null +// #docregion import-optional +import { Optional } from '@angular/core'; +// #enddocregion import-optional + +let some_message = 'Hello from the injected logger'; + +@Component({ + selector: 'provider-10', + template: template, + providers: [{ provide: Logger, useValue: null }] +}) +export class Provider10Component implements OnInit { + log: string; + // #docregion provider-10-ctor + constructor(@Optional() private logger: Logger) { + if (this.logger) { + this.logger.log(some_message); + } + } + // #enddocregion provider-10-ctor + + ngOnInit() { + this.log = this.logger ? this.logger.logs[0] : 'Optional logger was not available'; + } +} + +///////////////// +@Component({ + selector: 'my-providers', + template: ` +

    Provider variations

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + ` +}) +export class ProvidersComponent { } diff --git a/public/docs/_examples/dependency-injection/ts/src/app/test.component.ts b/public/docs/_examples/dependency-injection/ts/src/app/test.component.ts new file mode 100644 index 0000000000..fc0fef75a8 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/test.component.ts @@ -0,0 +1,55 @@ +/* tslint:disable */ +// Simulate a simple test +// Reader should look to the testing chapter for the real thing + +import { Component } from '@angular/core'; + +import { HeroService } from './heroes/hero.service'; +import { HeroListComponent } from './heroes/hero-list.component'; + +@Component({ + selector: 'my-tests', + template: ` +

    Tests

    +

    Tests {{results.pass}}: {{results.message}}

    + ` +}) +export class TestComponent { + results = runTests(); +} + +///////////////////////////////////// +function runTests() { + + // #docregion spec + let expectedHeroes = [{name: 'A'}, {name: 'B'}] + let mockService = {getHeroes: () => expectedHeroes } + + it('should have heroes when HeroListComponent created', () => { + let hlc = new HeroListComponent(mockService); + expect(hlc.heroes.length).toEqual(expectedHeroes.length); + }); + // #enddocregion spec + + return testResults; +} + +////////////////////////////////// +// Fake Jasmine infrastructure +var testName: string; +var testResults: {pass: string; message: string}; + +function expect(actual: any) { + return { + toEqual: function(expected: any){ + testResults = actual === expected ? + {pass: 'passed', message: testName} : + {pass: 'failed', message: `${testName}; expected ${actual} to equal ${expected}.`}; + } + }; +} + +function it(label: string, test: () => void) { + testName = label; + test(); +} diff --git a/public/docs/_examples/dependency-injection/ts/src/app/user.service.ts b/public/docs/_examples/dependency-injection/ts/src/app/user.service.ts new file mode 100644 index 0000000000..8fdda925db --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/app/user.service.ts @@ -0,0 +1,22 @@ +// #docregion +import { Injectable } from '@angular/core'; + +export class User { + constructor( + public name: string, + public isAuthorized = false) { } +} + +// Todo: get the user; don't 'new' it. +let alice = new User('Alice', true); +let bob = new User('Bob', false); + +@Injectable() +export class UserService { + user = bob; // initial user is Bob + + // swap users + getNewUser() { + return this.user = this.user === bob ? alice : bob; + } +} diff --git a/public/docs/_examples/dependency-injection/ts/src/index.html b/public/docs/_examples/dependency-injection/ts/src/index.html new file mode 100644 index 0000000000..87a9d7e694 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/index.html @@ -0,0 +1,27 @@ + + + + + Dependency Injection + + + + + + + + + + + + + + + + + Loading my-app ... + + + diff --git a/public/docs/_examples/dependency-injection/ts/src/main.ts b/public/docs/_examples/dependency-injection/ts/src/main.ts new file mode 100644 index 0000000000..1a1d481719 --- /dev/null +++ b/public/docs/_examples/dependency-injection/ts/src/main.ts @@ -0,0 +1,6 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +// #docregion bootstrap +platformBrowserDynamic().bootstrapModule(AppModule); +// #enddocregion bootstrap diff --git a/public/docs/_examples/deployment/ts/.gitignore b/public/docs/_examples/deployment/ts/.gitignore new file mode 100644 index 0000000000..7f794a0b16 --- /dev/null +++ b/public/docs/_examples/deployment/ts/.gitignore @@ -0,0 +1 @@ +!systemjs.config.server.js diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/.gitkeep b/public/docs/_examples/deployment/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/typescript-conversion/app/css/.gitkeep rename to public/docs/_examples/deployment/ts/example-config.json diff --git a/public/docs/_examples/deployment/ts/src/app/app.component.ts b/public/docs/_examples/deployment/ts/src/app/app.component.ts new file mode 100644 index 0000000000..47731c13a4 --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/app/app.component.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Simple Deployment

    + + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/deployment/ts/src/app/app.module.ts b/public/docs/_examples/deployment/ts/src/app/app.module.ts new file mode 100644 index 0000000000..a885bc2918 --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/app/app.module.ts @@ -0,0 +1,29 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule, Routes } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { HeroListComponent } from './hero-list.component'; + +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'heroes', component: HeroListComponent }, + + { path: '', redirectTo: '/heroes', pathMatch: 'full' } +]; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forRoot(appRoutes) + ], + declarations: [ + AppComponent, + CrisisListComponent, + HeroListComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/deployment/ts/src/app/crisis-list.component.ts b/public/docs/_examples/deployment/ts/src/app/crisis-list.component.ts new file mode 100644 index 0000000000..62ef9e7555 --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/app/crisis-list.component.ts @@ -0,0 +1,9 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    CRISIS CENTER

    +

    Get your crisis here

    ` +}) +export class CrisisListComponent { } diff --git a/public/docs/_examples/deployment/ts/src/app/hero-list.component.ts b/public/docs/_examples/deployment/ts/src/app/hero-list.component.ts new file mode 100644 index 0000000000..479f73b508 --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/app/hero-list.component.ts @@ -0,0 +1,10 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    HEROES

    +

    Get your heroes here

    + ` +}) +export class HeroListComponent { } diff --git a/public/docs/_examples/deployment/ts/src/index.html b/public/docs/_examples/deployment/ts/src/index.html new file mode 100644 index 0000000000..770e64bc4d --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/index.html @@ -0,0 +1,38 @@ + + + + + + + + + Simple Deployment + + + + + + + + + + + + + + + + + + + + + + + loading... + + + diff --git a/public/docs/_examples/deployment/ts/src/main.ts b/public/docs/_examples/deployment/ts/src/main.ts new file mode 100644 index 0000000000..6f82bbc745 --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/main.ts @@ -0,0 +1,15 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +// #docregion enableProdMode +import { enableProdMode } from '@angular/core'; + +// Enable production mode unless running locally +if (!/localhost/.test(document.location.host)) { + enableProdMode(); +} +// #enddocregion enableProdMode + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/deployment/ts/src/systemjs.config.server.js b/public/docs/_examples/deployment/ts/src/systemjs.config.server.js new file mode 100644 index 0000000000..40c4426064 --- /dev/null +++ b/public/docs/_examples/deployment/ts/src/systemjs.config.server.js @@ -0,0 +1,46 @@ +// #docregion +/** + * System configuration for deployment without installing node_modules + * Loads umd packages from the web instead + * Adjust as necessary for your application needs. + */ +(function (global) { + System.config({ + // #docregion paths + paths: { + 'npm:': 'https://unpkg.com/' // path serves as alias + }, + // #enddocregion paths + // map tells the System loader where to look for things + map: { + app: 'app', // location of transpiled app files + + // angular minimized umd bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.min.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.min.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.min.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.min.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.min.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.min.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.min.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.min.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.min.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.min.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.min.js', + + // other libraries + 'rxjs': 'npm:rxjs@5.0.1', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + app: { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + } + } + }); + })(this); diff --git a/public/docs/_examples/displaying-data/dart/lib/app_component.dart b/public/docs/_examples/displaying-data/dart/lib/app_component.dart deleted file mode 100644 index 5374ba81a8..0000000000 --- a/public/docs/_examples/displaying-data/dart/lib/app_component.dart +++ /dev/null @@ -1,32 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; - -final List _heroes = [ - new Hero(1, 'Windstorm'), - new Hero(13, 'Bombasto'), - new Hero(15, 'Magneta'), - new Hero(20, 'Tornado') -]; - -@Component( - selector: 'my-app', - template: ''' -

    {{title}}

    -

    My favorite hero is: {{myHero.name}}

    -

    Heroes:

    -
      -
    • - {{ hero.name }} -
    • -
    -// #docregion message -

    There are many heroes!

    -// #enddocregion message -''') -class AppComponent { - String title = 'Tour of Heroes'; - List heroes = _heroes; - Hero myHero = _heroes[0]; -} diff --git a/public/docs/_examples/displaying-data/dart/lib/app_component_1.dart b/public/docs/_examples/displaying-data/dart/lib/app_component_1.dart deleted file mode 100644 index 1991a6645c..0000000000 --- a/public/docs/_examples/displaying-data/dart/lib/app_component_1.dart +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -@Component( - selector: 'my-app', -// #docregion template - template: ''' -

    {{title}}

    -

    My favorite hero is: {{myHero}}

    ''' -// #enddocregion template - ) -class AppComponent { - String title = 'Tour of Heroes'; - String myHero = 'Windstorm'; -} diff --git a/public/docs/_examples/displaying-data/dart/lib/app_component_2.dart b/public/docs/_examples/displaying-data/dart/lib/app_component_2.dart deleted file mode 100644 index ff97982532..0000000000 --- a/public/docs/_examples/displaying-data/dart/lib/app_component_2.dart +++ /dev/null @@ -1,36 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -// #docregion mock-heroes -const List _heroes = const [ - 'Windstorm', - 'Bombasto', - 'Magneta', - 'Tornado' -]; -// #enddocregion mock-heroes - -@Component( - selector: 'my-app', -// #docregion template - template: ''' -

    {{title}}

    -

    My favorite hero is: {{myHero}}

    -

    Heroes:

    -
      -// #docregion li-repeater -
    • - {{ hero }} -
    • -// #enddocregion li-repeater -
    ''' -// #enddocregion template - ) -// #docregion mock-heroes -class AppComponent { - String title = 'Tour of Heroes'; - List heroes = _heroes; - String myHero = _heroes[0]; -} -// #enddocregion mock-heroes -// #enddocregion diff --git a/public/docs/_examples/displaying-data/dart/lib/app_component_3.dart b/public/docs/_examples/displaying-data/dart/lib/app_component_3.dart deleted file mode 100644 index 9a39808d18..0000000000 --- a/public/docs/_examples/displaying-data/dart/lib/app_component_3.dart +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; -// #docregion heroes -import 'hero.dart'; - -final List _heroes = [ - new Hero(1, 'Windstorm'), - new Hero(13, 'Bombasto'), - new Hero(15, 'Magneta'), - new Hero(20, 'Tornado') -]; -// #enddocregion heroes - -@Component( - selector: 'my-app', -// #docregion template - template: ''' -

    {{title}}

    -

    My favorite hero is: {{myHero.name}}

    -

    Heroes:

    -
      -
    • - {{ hero.name }} -
    • -
    ''' -// #enddocregion template - ) -// #docregion heroes -class AppComponent { - String title = 'Tour of Heroes'; - List heroes = _heroes; - Hero myHero = _heroes[0]; -} -// #enddocregion heroes -// #enddocregion diff --git a/public/docs/_examples/displaying-data/dart/lib/hero.dart b/public/docs/_examples/displaying-data/dart/lib/hero.dart deleted file mode 100644 index 6542e4f4ca..0000000000 --- a/public/docs/_examples/displaying-data/dart/lib/hero.dart +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -class Hero { - int id; - String name; - - Hero(this.id, this.name); - String toString() => '$id: $name'; -} -// #enddocregion diff --git a/public/docs/_examples/displaying-data/dart/pubspec.yaml b/public/docs/_examples/displaying-data/dart/pubspec.yaml deleted file mode 100644 index 279d82e35f..0000000000 --- a/public/docs/_examples/displaying-data/dart/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# #docregion -name: displaying_data -description: Displaying Data Example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/displaying-data/dart/web/index.html b/public/docs/_examples/displaying-data/dart/web/index.html deleted file mode 100644 index 6585d21511..0000000000 --- a/public/docs/_examples/displaying-data/dart/web/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Displaying Data - - - - - - - Loading... - - - diff --git a/public/docs/_examples/displaying-data/dart/web/main.dart b/public/docs/_examples/displaying-data/dart/web/main.dart deleted file mode 100644 index 69650f0740..0000000000 --- a/public/docs/_examples/displaying-data/dart/web/main.dart +++ /dev/null @@ -1,20 +0,0 @@ -// #docplaster -// #docregion final -import 'package:angular2/bootstrap.dart'; -// #enddocregion final -//import 'package:displaying_data/app_component_1.dart' as v1; -//import 'package:displaying_data/app_component_2.dart' as v2; -//import 'package:displaying_data/app_component_3.dart' as v3; -// #docregion final -import 'package:displaying_data/app_component.dart'; - -main() { -// #enddocregion final -// pick one -// bootstrap(v1.AppComponent); -// bootstrap(v2.AppComponent); -// bootstrap(v3.AppComponent); -// #docregion final - bootstrap(AppComponent); -} -// #enddocregion final diff --git a/public/docs/_examples/displaying-data/e2e-spec.js b/public/docs/_examples/displaying-data/e2e-spec.js deleted file mode 100644 index 4768050501..0000000000 --- a/public/docs/_examples/displaying-data/e2e-spec.js +++ /dev/null @@ -1,21 +0,0 @@ -describe('Displaying Data Tests', function () { - - var _title = "Tour of Heroes"; - var _defaultHero = 'Windstorm' - - beforeAll(function () { - browser.get(''); - }); - - it('should display correct title: ' + _title, function () { - expect(element(by.css('h1')).getText()).toEqual(_title); - }); - - it('should have correct default hero: ' + _defaultHero, function () { - expect(element(by.css('h2')).getText()).toContain(_defaultHero); - }); - - it('should have many heroes', function () { - expect(element(by.css('ul ~ p')).getText()).toContain('There are many heroes!'); - }); -}); diff --git a/public/docs/_examples/displaying-data/e2e-spec.ts b/public/docs/_examples/displaying-data/e2e-spec.ts new file mode 100644 index 0000000000..96c52c5d00 --- /dev/null +++ b/public/docs/_examples/displaying-data/e2e-spec.ts @@ -0,0 +1,29 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Displaying Data Tests', function () { + let _title = 'Tour of Heroes'; + let _defaultHero = 'Windstorm'; + + beforeAll(function () { + browser.get(''); + }); + + it('should display correct title: ' + _title, function () { + expect(element(by.css('h1')).getText()).toEqual(_title); + }); + + it('should have correct default hero: ' + _defaultHero, function () { + expect(element(by.css('h2')).getText()).toContain(_defaultHero); + }); + + it('should have heroes', function () { + let heroEls = element.all(by.css('li')); + expect(heroEls.count()).not.toBe(0, 'should have heroes'); + }); + + it('should display "there are many heroes!"', function () { + expect(element(by.css('ul ~ p')).getText()).toContain('There are many heroes!'); + }); +}); diff --git a/public/docs/_examples/displaying-data/ts/.gitignore b/public/docs/_examples/displaying-data/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/displaying-data/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/displaying-data/ts/app/app.component.1.ts b/public/docs/_examples/displaying-data/ts/app/app.component.1.ts deleted file mode 100644 index 7b1d5b8cca..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/app.component.1.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - selector: 'my-app', - // #docregion template - template: ` -

    {{title}}

    -

    My favorite hero is: {{myHero}}

    - ` - // #enddocregion template -}) -export class AppComponent { - title = 'Tour of Heroes'; - myHero = 'Windstorm'; -} diff --git a/public/docs/_examples/displaying-data/ts/app/app.component.2.ts b/public/docs/_examples/displaying-data/ts/app/app.component.2.ts deleted file mode 100644 index ed30ee0ebc..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/app.component.2.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - selector: 'my-app', - // #docregion template - template: ` -

    {{title}}

    -

    My favorite hero is: {{myHero}}

    -

    Heroes:

    -
      - // #docregion li-repeater -
    • - {{ hero }} -
    • - // #enddocregion li-repeater -
    - ` - // #enddocregion template -}) -// #docregion mock-heroes -export class AppComponent { - title = 'Tour of Heroes'; - heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado']; - myHero = this.heroes[0]; -} -// #enddocregion mock-heroes -// #enddocregion diff --git a/public/docs/_examples/displaying-data/ts/app/app.component.3.ts b/public/docs/_examples/displaying-data/ts/app/app.component.3.ts deleted file mode 100644 index 79edbfdfae..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/app.component.3.ts +++ /dev/null @@ -1,36 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -// #docregion import-hero -import {Hero} from './hero'; -// #enddocregion import-hero - -@Component({ - selector: 'my-app', - // #docregion template - template: ` -

    {{title}}

    -

    My favorite hero is: {{myHero.name}}

    -

    Heroes:

    -
      -
    • - {{ hero.name }} -
    • -
    - ` - // #enddocregion template -}) -// #docregion class -export class AppComponent { - title = 'Tour of Heroes'; - // #docregion heroes - heroes = [ - new Hero(1, 'Windstorm'), - new Hero(13, 'Bombasto'), - new Hero(15, 'Magneta'), - new Hero(20, 'Tornado') - ]; - myHero = this.heroes[0]; - // #enddocregion heroes -} -// #enddocregion class -// #enddocregion diff --git a/public/docs/_examples/displaying-data/ts/app/app.component.ts b/public/docs/_examples/displaying-data/ts/app/app.component.ts deleted file mode 100644 index a85a09081e..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/app.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -// #docplaster -// #docregion final -// #docregion imports -import {Component} from 'angular2/core'; -// #enddocregion imports -import {Hero} from './hero' - -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    -

    My favorite hero is: {{myHero.name}}

    -

    Heroes:

    -
      -
    • - {{ hero.name }} -
    • -
    - // #docregion message -

    There are many heroes!

    - // #enddocregion message -` -}) - -export class AppComponent { - title = 'Tour of Heroes'; - heroes = [ - new Hero(1, 'Windstorm'), - new Hero(13, 'Bombasto'), - new Hero(15, 'Magneta'), - new Hero(20, 'Tornado') - ]; - myHero = this.heroes[0]; -} diff --git a/public/docs/_examples/displaying-data/ts/app/hero.ts b/public/docs/_examples/displaying-data/ts/app/hero.ts deleted file mode 100644 index 8b4f06b658..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/hero.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -export class Hero { - constructor( - // #docregion id-parameter - public id:number, - // #enddocregion id-parameter - public name:string) { } -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/displaying-data/ts/app/main.1.ts b/public/docs/_examples/displaying-data/ts/app/main.1.ts deleted file mode 100644 index 511180507b..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/main.1.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppCtorComponent} from './app-ctor.component'; -import {AppComponent as v1} from './app.component.1'; -import {AppComponent as v2} from './app.component.2'; -import {AppComponent as v3} from './app.component.3'; - -import {AppComponent as final} from './app.component'; - -// pick one -//bootstrap(v1); -//bootstrap(v2); -//bootstrap(v3); -bootstrap(final); - -// for doc testing -bootstrap(AppCtorComponent); \ No newline at end of file diff --git a/public/docs/_examples/displaying-data/ts/app/main.ts b/public/docs/_examples/displaying-data/ts/app/main.ts deleted file mode 100644 index ec4c9d12d6..0000000000 --- a/public/docs/_examples/displaying-data/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); diff --git a/public/docs/_examples/displaying-data/ts/index.1.html b/public/docs/_examples/displaying-data/ts/index.1.html deleted file mode 100644 index 93fcaa763d..0000000000 --- a/public/docs/_examples/displaying-data/ts/index.1.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - Displaying Data - - - - - - - - - - - - - - - - loading... -
    - loading... - - - diff --git a/public/docs/_examples/displaying-data/ts/index.html b/public/docs/_examples/displaying-data/ts/index.html deleted file mode 100644 index 5459c0c3fa..0000000000 --- a/public/docs/_examples/displaying-data/ts/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - Displaying Data - - - - - - - - - - - - - - - - - - loading... - - - - diff --git a/public/docs/_examples/displaying-data/ts/plnkr.json b/public/docs/_examples/displaying-data/ts/plnkr.json index ee037aec0b..b4572f0fb6 100644 --- a/public/docs/_examples/displaying-data/ts/plnkr.json +++ b/public/docs/_examples/displaying-data/ts/plnkr.json @@ -1,5 +1,6 @@ { "description": "Displaying Data", + "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js", @@ -7,4 +8,4 @@ "!**/*.[1,2,3].*" ], "tags": ["Template"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/displaying-data/ts/app/app-ctor.component.ts b/public/docs/_examples/displaying-data/ts/src/app/app-ctor.component.ts similarity index 77% rename from public/docs/_examples/displaying-data/ts/app/app-ctor.component.ts rename to public/docs/_examples/displaying-data/ts/src/app/app-ctor.component.ts index 3b17bcb6e8..b275baa8e6 100644 --- a/public/docs/_examples/displaying-data/ts/app/app-ctor.component.ts +++ b/public/docs/_examples/displaying-data/ts/src/app/app-ctor.component.ts @@ -1,4 +1,4 @@ -import {Component} from 'angular2/core'; +import { Component } from '@angular/core'; @Component({ selector: 'my-app-ctor', @@ -7,7 +7,7 @@ import {Component} from 'angular2/core';

    My favorite hero is: {{myHero}}

    ` }) -// #docregion app-ctor +// #docregion class export class AppCtorComponent { title: string; myHero: string; @@ -17,4 +17,3 @@ export class AppCtorComponent { this.myHero = 'Windstorm'; } } -// #enddocregion app-ctor \ No newline at end of file diff --git a/public/docs/_examples/displaying-data/ts/src/app/app.component.1.ts b/public/docs/_examples/displaying-data/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..1cbeb0f731 --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/app/app.component.1.ts @@ -0,0 +1,16 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    {{title}}

    +

    My favorite hero is: {{myHero}}

    + ` + // #enddocregion template +}) +export class AppComponent { + title = 'Tour of Heroes'; + myHero = 'Windstorm'; +} diff --git a/public/docs/_examples/displaying-data/ts/src/app/app.component.2.ts b/public/docs/_examples/displaying-data/ts/src/app/app.component.2.ts new file mode 100644 index 0000000000..da7a653973 --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/app/app.component.2.ts @@ -0,0 +1,26 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    {{title}}

    +

    My favorite hero is: {{myHero}}

    +

    Heroes:

    +
      + // #docregion li +
    • + {{ hero }} +
    • + // #enddocregion li +
    + ` + // #enddocregion template +}) +// #docregion class +export class AppComponent { + title = 'Tour of Heroes'; + heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado']; + myHero = this.heroes[0]; +} diff --git a/public/docs/_examples/displaying-data/ts/src/app/app.component.3.ts b/public/docs/_examples/displaying-data/ts/src/app/app.component.3.ts new file mode 100644 index 0000000000..06ab060557 --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/app/app.component.3.ts @@ -0,0 +1,35 @@ +// #docregion +import { Component } from '@angular/core'; + +// #docregion import +import { Hero } from './hero'; +// #enddocregion import + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    {{title}}

    +

    My favorite hero is: {{myHero.name}}

    +

    Heroes:

    +
      +
    • + {{ hero.name }} +
    • +
    + ` + // #enddocregion template +}) +// #docregion class +export class AppComponent { + title = 'Tour of Heroes'; + // #docregion heroes + heroes = [ + new Hero(1, 'Windstorm'), + new Hero(13, 'Bombasto'), + new Hero(15, 'Magneta'), + new Hero(20, 'Tornado') + ]; + myHero = this.heroes[0]; + // #enddocregion heroes +} diff --git a/public/docs/_examples/displaying-data/ts/src/app/app.component.ts b/public/docs/_examples/displaying-data/ts/src/app/app.component.ts new file mode 100644 index 0000000000..7234959265 --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/app/app.component.ts @@ -0,0 +1,32 @@ +// #docplaster +// #docregion final +import { Component } from '@angular/core'; + +import { Hero } from './hero'; + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    +

    My favorite hero is: {{myHero.name}}

    +

    Heroes:

    +
      +
    • + {{ hero.name }} +
    • +
    + // #docregion message +

    There are many heroes!

    + // #enddocregion message +` +}) +export class AppComponent { + title = 'Tour of Heroes'; + heroes = [ + new Hero(1, 'Windstorm'), + new Hero(13, 'Bombasto'), + new Hero(15, 'Magneta'), + new Hero(20, 'Tornado') + ]; + myHero = this.heroes[0]; +} diff --git a/public/docs/_examples/displaying-data/ts/src/app/app.module.ts b/public/docs/_examples/displaying-data/ts/src/app/app.module.ts new file mode 100644 index 0000000000..362f3401fa --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/app/app.module.ts @@ -0,0 +1,16 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/displaying-data/ts/src/app/hero.ts b/public/docs/_examples/displaying-data/ts/src/app/hero.ts new file mode 100644 index 0000000000..f89d26ad63 --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/app/hero.ts @@ -0,0 +1,9 @@ +// #docregion +export class Hero { + constructor( + // #docregion id + public id: number, + // #enddocregion id + public name: string) { } +} +// #enddocregion diff --git a/public/docs/_examples/displaying-data/ts/src/index.html b/public/docs/_examples/displaying-data/ts/src/index.html new file mode 100644 index 0000000000..ddcbade46b --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/index.html @@ -0,0 +1,28 @@ + + + + Displaying Data + + + + + + + + + + + + + + + + + + loading... + + + + diff --git a/public/docs/_examples/displaying-data/ts/src/main.ts b/public/docs/_examples/displaying-data/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/displaying-data/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/forms/dart/lib/hero.dart b/public/docs/_examples/forms/dart/lib/hero.dart deleted file mode 100644 index 6ade27c4d3..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero.dart +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion all -class Hero { - int number; - String name; - String power; - String alterEgo; - - Hero(this.number, this.name, this.power, [this.alterEgo]); - - String toString() => '$number: $name ($alterEgo). Super power: $power'; -} -// #enddocregion all - -main() { - // #docregion newhero - var myHero = new Hero( - 42, 'SkyDog', 'Fetch any object at any distance', 'Leslie Rollover'); - print('My hero is ${myHero.name}.'); // "My hero is SkyDog." - // #enddocregion newhero -} diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component.dart b/public/docs/_examples/forms/dart/lib/hero_form_component.dart deleted file mode 100644 index 92f82cf0b1..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component.dart +++ /dev/null @@ -1,34 +0,0 @@ -// #docplaster -// #docregion -// #docregion no-todo -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; - -const List _powers = const [ - 'Really Smart', - 'Super Flexible', - 'Super Hot', - 'Weather Changer' -]; - -@Component( - selector: 'hero-form', - templateUrl: 'hero_form_component.html') -class HeroFormComponent { - List get powers => _powers; -// #docregion submitted - bool submitted = false; -// #enddocregion submitted - Hero model = new Hero(18, 'Dr IQ', _powers[0], 'Chuck Overstreet'); -// #enddocregion no-todo - // TODO: Remove this when we're done - String get diagnostic => 'DIAGNOSTIC: $model'; -// #docregion no-todo - -// #docregion submitted - onSubmit() { - submitted = true; - } -// #enddocregion submitted -} diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component.html b/public/docs/_examples/forms/dart/lib/hero_form_component.html deleted file mode 100644 index 22097f5e33..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component.html +++ /dev/null @@ -1,67 +0,0 @@ - - -
    - -
    -

    Hero Form

    - -
    - - -
    - - - -
    - Name is required -
    - -
    - -
    - - -
    - -
    - - -
    - - - - - -
    -
    - - - -
    -

    You submitted the following:

    -
    -
    Name
    -
    {{ model.name }}
    -
    -
    -
    Alter Ego
    -
    {{ model.alterEgo }}
    -
    -
    -
    Power
    -
    {{ model.power }}
    -
    -
    - -
    - -
    diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_initial.dart b/public/docs/_examples/forms/dart/lib/hero_form_component_initial.dart deleted file mode 100644 index 3ba6afb443..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_initial.dart +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -@Component(selector: 'hero-form', template: 'Hero form will go here') -class HeroFormComponent {} diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_initial.html b/public/docs/_examples/forms/dart/lib/hero_form_component_initial.html deleted file mode 100644 index 155ea07fa9..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_initial.html +++ /dev/null @@ -1,15 +0,0 @@ - -
    -

    Hero Form

    -
    -
    - - -
    -
    - - -
    - -
    -
    diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_ngcontrol.html b/public/docs/_examples/forms/dart/lib/hero_form_component_ngcontrol.html deleted file mode 100644 index 09ffb3b968..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_ngcontrol.html +++ /dev/null @@ -1,32 +0,0 @@ - -
    -

    Hero Form

    -
    -
    - - - - -
    - -
    - - -
    - -
    - - -
    - - -
    -
    diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodel2.html b/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodel2.html deleted file mode 100644 index 9b86b3745c..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodel2.html +++ /dev/null @@ -1,30 +0,0 @@ - -
    -

    Hero Form

    -
    - - {{diagnostic}} -
    - - -
    - -
    - - -
    - -
    - - -
    - - - -
    -
    diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodel_ngfor.html b/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodel_ngfor.html deleted file mode 100644 index 111ac2403f..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodel_ngfor.html +++ /dev/null @@ -1,30 +0,0 @@ - -
    -

    Hero Form

    -
    -
    - - - - TODO: remove this: {{model.name}} - -
    - -
    - - -
    - - -
    - - -
    - - - -
    -
    diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodelchange.html b/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodelchange.html deleted file mode 100644 index c8ebb80386..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_ngmodelchange.html +++ /dev/null @@ -1,31 +0,0 @@ - -
    -

    Hero Form

    -
    -
    - - - - TODO: remove this: {{model.name}} - -
    - -
    - - -
    - -
    - - -
    - - -
    -
    diff --git a/public/docs/_examples/forms/dart/lib/hero_form_component_spy.html b/public/docs/_examples/forms/dart/lib/hero_form_component_spy.html deleted file mode 100644 index c1f331eed6..0000000000 --- a/public/docs/_examples/forms/dart/lib/hero_form_component_spy.html +++ /dev/null @@ -1,33 +0,0 @@ - -
    -

    Hero Form

    -
    -
    - - - - TODO: remove this: {{spy.className}} - -
    - -
    - - -
    - -
    - - -
    - - -
    -
    diff --git a/public/docs/_examples/forms/dart/pubspec.yaml b/public/docs/_examples/forms/dart/pubspec.yaml deleted file mode 100644 index 6d4e9825e5..0000000000 --- a/public/docs/_examples/forms/dart/pubspec.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# #docregion -name: hero_form -description: Form example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: - - 'package:angular2/common.dart#CORE_DIRECTIVES' - - 'package:angular2/common.dart#FORM_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/forms/dart/web/bootstrap.min.css b/public/docs/_examples/forms/dart/web/bootstrap.min.css deleted file mode 100644 index d65c66b1ba..0000000000 --- a/public/docs/_examples/forms/dart/web/bootstrap.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap v3.3.5 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/public/docs/_examples/forms/dart/web/index.html b/public/docs/_examples/forms/dart/web/index.html deleted file mode 100644 index e99d87d263..0000000000 --- a/public/docs/_examples/forms/dart/web/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - Hero Form - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/forms/dart/web/main.dart b/public/docs/_examples/forms/dart/web/main.dart deleted file mode 100644 index 24a30874e3..0000000000 --- a/public/docs/_examples/forms/dart/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:hero_form/hero_form_component.dart'; - -main() { - bootstrap(HeroFormComponent); -} diff --git a/public/docs/_examples/forms/e2e-spec.js b/public/docs/_examples/forms/e2e-spec.js deleted file mode 100644 index a90138b744..0000000000 --- a/public/docs/_examples/forms/e2e-spec.js +++ /dev/null @@ -1,62 +0,0 @@ -describeIf(browser.appIsTs || browser.appIsJs, 'Forms Tests', function () { - - beforeEach(function () { - browser.get(''); - }); - - it('should display correct title', function () { - expect(element.all(by.css('h1')).get(0).getText()).toEqual('Hero Form'); - }); - - - it('should not display message before submit', function () { - var ele = element(by.css('h2')); - expect(ele.isDisplayed()).toBe(false); - }); - - it('should hide form after submit', function () { - var ele = element.all(by.css('h1')).get(0); - expect(ele.isDisplayed()).toBe(true); - var b = element.all(by.css('button[type=submit]')).get(0); - b.click().then(function() { - expect(ele.isDisplayed()).toBe(false); - }); - }); - - it('should display message after submit', function () { - var b = element.all(by.css('button[type=submit]')).get(0); - b.click().then(function() { - expect(element(by.css('h2')).getText()).toContain('You submitted the following'); - }); - }); - - it('should hide form after submit', function () { - var alterEgoEle = element.all(by.css('input[ngcontrol=alterEgo]')).get(0); - expect(alterEgoEle.isDisplayed()).toBe(true); - var submitButtonEle = element.all(by.css('button[type=submit]')).get(0); - submitButtonEle.click().then(function() { - expect(alterEgoEle.isDisplayed()).toBe(false); - }) - }); - - it('should reflect submitted data after submit', function () { - var test = 'testing 1 2 3'; - var newValue; - var alterEgoEle = element.all(by.css('input[ngcontrol=alterEgo]')).get(0); - alterEgoEle.getAttribute('value').then(function(value) { - // alterEgoEle.sendKeys(test); - sendKeys(alterEgoEle, test); - newValue = value + test; - expect(alterEgoEle.getAttribute('value')).toEqual(newValue); - }).then(function() { - var b = element.all(by.css('button[type=submit]')).get(0); - return b.click(); - }).then(function() { - var alterEgoTextEle = element(by.cssContainingText('div', 'Alter Ego')); - expect(alterEgoTextEle.isPresent()).toBe(true, 'cannot locate "Alter Ego" label'); - var divEle = element(by.cssContainingText('div', newValue)); - expect(divEle.isPresent()).toBe(true, 'cannot locate div with this text: ' + newValue); - }); - }); -}); - diff --git a/public/docs/_examples/forms/e2e-spec.ts b/public/docs/_examples/forms/e2e-spec.ts new file mode 100644 index 0000000000..2afd370103 --- /dev/null +++ b/public/docs/_examples/forms/e2e-spec.ts @@ -0,0 +1,63 @@ +import { browser, element, by } from 'protractor'; +import { appLang, describeIf } from '../protractor-helpers'; + +describeIf(appLang.appIsTs || appLang.appIsJs, 'Forms Tests', function () { + + beforeEach(function () { + browser.get(''); + }); + + it('should display correct title', function () { + expect(element.all(by.css('h1')).get(0).getText()).toEqual('Hero Form'); + }); + + + it('should not display message before submit', function () { + let ele = element(by.css('h2')); + expect(ele.isDisplayed()).toBe(false); + }); + + it('should hide form after submit', function () { + let ele = element.all(by.css('h1')).get(0); + expect(ele.isDisplayed()).toBe(true); + let b = element.all(by.css('button[type=submit]')).get(0); + b.click().then(function() { + expect(ele.isDisplayed()).toBe(false); + }); + }); + + it('should display message after submit', function () { + let b = element.all(by.css('button[type=submit]')).get(0); + b.click().then(function() { + expect(element(by.css('h2')).getText()).toContain('You submitted the following'); + }); + }); + + it('should hide form after submit', function () { + let alterEgoEle = element.all(by.css('input[name=alterEgo]')).get(0); + expect(alterEgoEle.isDisplayed()).toBe(true); + let submitButtonEle = element.all(by.css('button[type=submit]')).get(0); + submitButtonEle.click().then(function() { + expect(alterEgoEle.isDisplayed()).toBe(false); + }); + }); + + it('should reflect submitted data after submit', function () { + let test = 'testing 1 2 3'; + let newValue: string; + let alterEgoEle = element.all(by.css('input[name=alterEgo]')).get(0); + alterEgoEle.getAttribute('value').then(function(value: string) { + alterEgoEle.sendKeys(test); + newValue = value + test; + expect(alterEgoEle.getAttribute('value')).toEqual(newValue); + let b = element.all(by.css('button[type=submit]')).get(0); + return b.click(); + }).then(function() { + let alterEgoTextEle = element(by.cssContainingText('div', 'Alter Ego')); + expect(alterEgoTextEle.isPresent()).toBe(true, 'cannot locate "Alter Ego" label'); + let divEle = element(by.cssContainingText('div', newValue)); + expect(divEle.isPresent()).toBe(true, 'cannot locate div with this text: ' + newValue); + }); + }); +}); + diff --git a/public/docs/_examples/forms/js/.gitignore b/public/docs/_examples/forms/js/.gitignore deleted file mode 100644 index 8b13789179..0000000000 --- a/public/docs/_examples/forms/js/.gitignore +++ /dev/null @@ -1 +0,0 @@ - diff --git a/public/docs/_examples/forms/js/app/app.component.js b/public/docs/_examples/forms/js/app/app.component.js deleted file mode 100644 index bb6b789938..0000000000 --- a/public/docs/_examples/forms/js/app/app.component.js +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -(function(app) { - app.AppComponent = ng.core - .Component({ - selector: 'my-app', - template: '', - directives: [app.HeroFormComponent] - }) - .Class({ - constructor: function() {} - }); -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms/js/app/hero-form.component.html b/public/docs/_examples/forms/js/app/hero-form.component.html deleted file mode 100644 index 2e20f638b7..0000000000 --- a/public/docs/_examples/forms/js/app/hero-form.component.html +++ /dev/null @@ -1,195 +0,0 @@ - - -
    - -
    -

    Hero Form

    - -
    - - -
    - - - -
    - Name is required -
    - -
    - -
    - - -
    - -
    - - -
    - Power is required -
    -
    - - - - -
    -
    - - -
    -

    You submitted the following:

    -
    -
    Name
    -
    {{ model.name }}
    -
    -
    -
    Alter Ego
    -
    {{ model.alterEgo }}
    -
    -
    -
    Power
    -
    {{ model.power }}
    -
    -
    - -
    - -
    - - - -
    -
    - - - - -
    -
    - - - -
    - -
    - -
    -

    Hero Form

    -
    -
    - - -
    - -
    - - -
    - - - -
    - - -
    - - - - -
    -
    - - - - -
    - -
    -

    Hero Form

    -
    - - {{diagnostic()}} -
    - - -
    - -
    - - -
    - -
    - - -
    - - - - -
    -
    - - - -
    - - - TODO: remove this: {{model.name}} - -
    - - - TODO: remove this: {{model.name}} - -
    -
    - - - -
    - - -
    TODO: remove this: {{spy.className}} - -
    - -
    -
    - Name via form.controls = {{showFormControls(heroForm)}} -
    - -
    diff --git a/public/docs/_examples/forms/js/app/main.js b/public/docs/_examples/forms/js/app/main.js deleted file mode 100644 index 56de1a0fdb..0000000000 --- a/public/docs/_examples/forms/js/app/main.js +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -(function(app) { - document.addEventListener('DOMContentLoaded', function() { - ng.platform.browser.bootstrap(app.AppComponent); - }); -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms/js/example-config.json b/public/docs/_examples/forms/js/example-config.json index e69de29bb2..81f31aaf0d 100644 --- a/public/docs/_examples/forms/js/example-config.json +++ b/public/docs/_examples/forms/js/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:babel" +} diff --git a/public/docs/_examples/forms/js/forms.css b/public/docs/_examples/forms/js/forms.css deleted file mode 100644 index d7e11405b1..0000000000 --- a/public/docs/_examples/forms/js/forms.css +++ /dev/null @@ -1,9 +0,0 @@ -/* #docregion */ -.ng-valid[required] { - border-left: 5px solid #42A948; /* green */ -} - -.ng-invalid { - border-left: 5px solid #a94442; /* red */ -} -/* #enddocregion */ \ No newline at end of file diff --git a/public/docs/_examples/forms/js/index.html b/public/docs/_examples/forms/js/index.html deleted file mode 100644 index 1ded44aab9..0000000000 --- a/public/docs/_examples/forms/js/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - Hero Form - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - diff --git a/public/docs/_examples/forms/js/plnkr.json b/public/docs/_examples/forms/js/plnkr.json index 0105283bd3..946cbb88f6 100644 --- a/public/docs/_examples/forms/js/plnkr.json +++ b/public/docs/_examples/forms/js/plnkr.json @@ -1,4 +1,5 @@ { "description": "Forms", + "basePath": "src/", "files":["app/**/*.js", "**/*.html", "**/*.css"] } diff --git a/public/docs/_examples/forms/js/src/app/app.component.js b/public/docs/_examples/forms/js/src/app/app.component.js new file mode 100644 index 0000000000..56bd982416 --- /dev/null +++ b/public/docs/_examples/forms/js/src/app/app.component.js @@ -0,0 +1,11 @@ +// #docregion +(function(app) { + app.AppComponent = ng.core + .Component({ + selector: 'my-app', + template: '' + }) + .Class({ + constructor: function() {} + }); +})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms/js/src/app/app.module.js b/public/docs/_examples/forms/js/src/app/app.module.js new file mode 100644 index 0000000000..92c7f8b9e5 --- /dev/null +++ b/public/docs/_examples/forms/js/src/app/app.module.js @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +(function(app) { + app.AppModule = + ng.core.NgModule({ + imports: [ + ng.platformBrowser.BrowserModule, + ng.forms.FormsModule + ], + declarations: [ + app.AppComponent, + app.HeroFormComponent + ], + bootstrap: [ app.AppComponent ] + }) + .Class({ + constructor: function() {} + }); +})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms/js/src/app/hero-form.component.html b/public/docs/_examples/forms/js/src/app/hero-form.component.html new file mode 100644 index 0000000000..279ded0866 --- /dev/null +++ b/public/docs/_examples/forms/js/src/app/hero-form.component.html @@ -0,0 +1,196 @@ + + +
    + +
    +

    Hero Form

    + +
    + + +
    + + + +
    + Name is required +
    + +
    + +
    + + +
    + +
    + + +
    + Power is required +
    +
    + + + + +
    +
    + + +
    +

    You submitted the following:

    +
    +
    Name
    +
    {{ model.name }}
    +
    +
    +
    Alter Ego
    +
    {{ model.alterEgo }}
    +
    +
    +
    Power
    +
    {{ model.power }}
    +
    +
    + +
    + +
    + + + +
    +
    + + + + +
    +
    + + + +
    + + +
    + +
    +

    Hero Form

    +
    +
    + + +
    + +
    + + +
    + + + +
    + + +
    + + + + +
    +
    + + + + +
    + +
    +

    Hero Form

    +
    + + {{diagnostic()}} +
    + + +
    + +
    + + +
    + +
    + + +
    + + + + +
    +
    + + + +
    + + + TODO: remove this: {{model.name}} + +
    + + + TODO: remove this: {{model.name}} + +
    +
    + + + +
    + + +
    TODO: remove this: {{spy.className}} + +
    + +
    +
    + Name via form.controls = {{showFormControls(heroForm)}} +
    + +
    diff --git a/public/docs/_examples/forms/js/app/hero-form.component.js b/public/docs/_examples/forms/js/src/app/hero-form.component.js similarity index 94% rename from public/docs/_examples/forms/js/app/hero-form.component.js rename to public/docs/_examples/forms/js/src/app/hero-form.component.js index 8988231189..505993a1fd 100644 --- a/public/docs/_examples/forms/js/app/hero-form.component.js +++ b/public/docs/_examples/forms/js/src/app/hero-form.component.js @@ -9,7 +9,7 @@ }) .Class({ // #docregion submitted - constructor: function() { + constructor: [function() { // #enddocregion submitted this.powers = ['Really Smart', 'Super Flexible', 'Super Hot', 'Weather Changer' @@ -20,7 +20,7 @@ // #docregion submitted this.submitted = false; - }, + }], onSubmit: function() { this.submitted = true; }, @@ -48,5 +48,5 @@ // #docregion first, final }); - // #enddocregion first, final })(window.app || (window.app = {})); +// #enddocregion first, final diff --git a/public/docs/_examples/forms/js/app/hero.js b/public/docs/_examples/forms/js/src/app/hero.js similarity index 100% rename from public/docs/_examples/forms/js/app/hero.js rename to public/docs/_examples/forms/js/src/app/hero.js diff --git a/public/docs/_examples/forms/dart/web/forms.css b/public/docs/_examples/forms/js/src/forms.css similarity index 100% rename from public/docs/_examples/forms/dart/web/forms.css rename to public/docs/_examples/forms/js/src/forms.css diff --git a/public/docs/_examples/forms/js/src/index.html b/public/docs/_examples/forms/js/src/index.html new file mode 100644 index 0000000000..3a41d74a3b --- /dev/null +++ b/public/docs/_examples/forms/js/src/index.html @@ -0,0 +1,47 @@ + + + + + + Hero Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/forms/js/src/main.js b/public/docs/_examples/forms/js/src/main.js new file mode 100644 index 0000000000..785823fa84 --- /dev/null +++ b/public/docs/_examples/forms/js/src/main.js @@ -0,0 +1,8 @@ +// #docregion +(function(app) { + document.addEventListener('DOMContentLoaded', function() { + ng.platformBrowserDynamic + .platformBrowserDynamic() + .bootstrapModule(app.AppModule); + }); +})(window.app || (window.app = {})); diff --git a/public/docs/_examples/forms/ts/.gitignore b/public/docs/_examples/forms/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/forms/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/forms/ts/app/app.component.ts b/public/docs/_examples/forms/ts/app/app.component.ts deleted file mode 100644 index 92f4ec5edd..0000000000 --- a/public/docs/_examples/forms/ts/app/app.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {HeroFormComponent} from './hero-form.component' - -@Component({ - selector: 'my-app', - template: '', - directives: [HeroFormComponent] -}) -export class AppComponent { } diff --git a/public/docs/_examples/forms/ts/app/hero-form.component.html b/public/docs/_examples/forms/ts/app/hero-form.component.html deleted file mode 100644 index 3412ceaff2..0000000000 --- a/public/docs/_examples/forms/ts/app/hero-form.component.html +++ /dev/null @@ -1,208 +0,0 @@ - - -
    - -
    -

    Hero Form

    - -
    - - -
    - - - - -
    - - Name is required -
    - -
    - -
    - - -
    - -
    - - -
    - Power is required -
    -
    - - - - - - - - - - - -
    -
    - Name via form.controls = {{showFormControls(heroForm)}} -
    - - -
    -
    - - -
    -

    You submitted the following:

    -
    -
    Name
    -
    {{ model.name }}
    -
    -
    -
    Alter Ego
    -
    {{ model.alterEgo }}
    -
    -
    -
    Power
    -
    {{ model.power }}
    -
    -
    - -
    - -
    - - - -
    -
    - - - - -
    -
    - - - -
    - -
    - -
    -

    Hero Form

    -
    -
    - - -
    - -
    - - -
    - - - -
    - - -
    - - - - - -
    -
    - - - - -
    - -
    -

    Hero Form

    -
    - - {{diagnostic}} -
    - - -
    - -
    - - -
    - -
    - - -
    - - - - -
    -
    - - - -
    - - - TODO: remove this: {{model.name}} - -
    - - - TODO: remove this: {{model.name}} - -
    - -
    - - - - - -
    - - -
    TODO: remove this: {{spy.className}} - -
    - -
    diff --git a/public/docs/_examples/forms/ts/app/hero-form.component.ts b/public/docs/_examples/forms/ts/app/hero-form.component.ts deleted file mode 100644 index 54f9c19151..0000000000 --- a/public/docs/_examples/forms/ts/app/hero-form.component.ts +++ /dev/null @@ -1,65 +0,0 @@ -// #docplaster -// #docregion -// #docregion first, final -import {Component} from 'angular2/core'; -import {NgForm} from 'angular2/common'; -import { Hero } from './hero'; - -@Component({ - selector: 'hero-form', - templateUrl: 'app/hero-form.component.html' -}) -export class HeroFormComponent { - - powers = ['Really Smart', 'Super Flexible', - 'Super Hot', 'Weather Changer']; - - model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet'); - - // #docregion submitted - submitted = false; - - onSubmit() { this.submitted = true; } - // #enddocregion submitted - - // #enddocregion final - // TODO: Remove this when we're done - get diagnostic() { return JSON.stringify(this.model); } - // #enddocregion first - - // #docregion final - // Reset the form with a new hero AND restore 'pristine' class state - // by toggling 'active' flag which causes the form - // to be removed/re-added in a tick via NgIf - // TODO: Workaround until NgForm has a reset method (#6822) - // #docregion new-hero - active = true; - - // #docregion new-hero-v1 - newHero() { - this.model = new Hero(42, '', ''); - // #enddocregion new-hero-v1 - this.active = false; - setTimeout(()=> this.active=true, 0); - // #docregion new-hero-v1 - } - // #enddocregion new-hero-v1 - // #enddocregion new-hero - // #enddocregion final - //////// NOT SHOWN IN DOCS //////// - - // Reveal in html: - // Name via form.controls = {{showFormControls(heroForm)}} - showFormControls(form:NgForm){ - - return form && form.controls['name'] && - // #docregion form-controls - form.controls['name'].value; // Dr. IQ - // #enddocregion form-controls - } - - ///////////////////////////// - - // #docregion first, final -} -// #enddocregion first, final diff --git a/public/docs/_examples/forms/ts/app/main.ts b/public/docs/_examples/forms/ts/app/main.ts deleted file mode 100644 index 3fe89a9b15..0000000000 --- a/public/docs/_examples/forms/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); diff --git a/public/docs/_examples/forms/ts/forms.css b/public/docs/_examples/forms/ts/forms.css deleted file mode 100644 index d7e11405b1..0000000000 --- a/public/docs/_examples/forms/ts/forms.css +++ /dev/null @@ -1,9 +0,0 @@ -/* #docregion */ -.ng-valid[required] { - border-left: 5px solid #42A948; /* green */ -} - -.ng-invalid { - border-left: 5px solid #a94442; /* red */ -} -/* #enddocregion */ \ No newline at end of file diff --git a/public/docs/_examples/forms/ts/index.html b/public/docs/_examples/forms/ts/index.html deleted file mode 100644 index b5b08869bc..0000000000 --- a/public/docs/_examples/forms/ts/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Hero Form - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/forms/ts/plnkr.json b/public/docs/_examples/forms/ts/plnkr.json index 60063d7d2c..3f0abbfc3d 100644 --- a/public/docs/_examples/forms/ts/plnkr.json +++ b/public/docs/_examples/forms/ts/plnkr.json @@ -1,7 +1,8 @@ { "description": "Forms", + "basePath": "src/", "files":[ - "!**/*.d.ts", + "!**/*.d.ts", "!**/*.js" ] -} \ No newline at end of file +} diff --git a/public/docs/_examples/forms/ts/src/app/app.component.ts b/public/docs/_examples/forms/ts/src/app/app.component.ts new file mode 100644 index 0000000000..454f7e03db --- /dev/null +++ b/public/docs/_examples/forms/ts/src/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/forms/ts/src/app/app.module.ts b/public/docs/_examples/forms/ts/src/app/app.module.ts new file mode 100644 index 0000000000..f214c02714 --- /dev/null +++ b/public/docs/_examples/forms/ts/src/app/app.module.ts @@ -0,0 +1,20 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { HeroFormComponent } from './hero-form.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + HeroFormComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/forms/ts/src/app/hero-form.component.html b/public/docs/_examples/forms/ts/src/app/hero-form.component.html new file mode 100644 index 0000000000..73b703f789 --- /dev/null +++ b/public/docs/_examples/forms/ts/src/app/hero-form.component.html @@ -0,0 +1,212 @@ + + +
    + +
    +

    Hero Form

    + +
    + +
    + + + + +
    + + Name is required +
    + +
    + +
    + + +
    + +
    + + +
    + Power is required +
    +
    + + + + + + + + + with reset + +    + + + + without reset + + +
    +
    + Name via form.controls = {{showFormControls(heroForm)}} +
    + + +
    +
    + + +
    +

    You submitted the following:

    +
    +
    Name
    +
    {{ model.name }}
    +
    +
    +
    Alter Ego
    +
    {{ model.alterEgo }}
    +
    +
    +
    Power
    +
    {{ model.power }}
    +
    +
    + +
    + +
    + + + +
    +
    + + + + +
    +
    + + + +
    + + +
    + +
    +

    Hero Form

    +
    +
    + + +
    + +
    + + +
    + + + +
    + + +
    + + + + + +
    +
    + + + + +
    + +
    +

    Hero Form

    + +
    + + + {{diagnostic}} +
    + + +
    + +
    + + +
    + +
    + + +
    + + + + +
    +
    + + + +
    + + + TODO: remove this: {{model.name}} + +
    + + + TODO: remove this: {{model.name}} + +
    + + +
    TODO: remove this: {{spy.className}} + + +
    diff --git a/public/docs/_examples/forms/ts/src/app/hero-form.component.ts b/public/docs/_examples/forms/ts/src/app/hero-form.component.ts new file mode 100644 index 0000000000..34be523a7f --- /dev/null +++ b/public/docs/_examples/forms/ts/src/app/hero-form.component.ts @@ -0,0 +1,59 @@ +// #docplaster +// #docregion , v1, final +import { Component } from '@angular/core'; + +import { Hero } from './hero'; + +@Component({ + selector: 'hero-form', + templateUrl: './hero-form.component.html' +}) +export class HeroFormComponent { + + powers = ['Really Smart', 'Super Flexible', + 'Super Hot', 'Weather Changer']; + + model = new Hero(18, 'Dr IQ', this.powers[0], 'Chuck Overstreet'); + + // #docregion submitted + submitted = false; + + onSubmit() { this.submitted = true; } + // #enddocregion submitted + + // #enddocregion final + // TODO: Remove this when we're done + get diagnostic() { return JSON.stringify(this.model); } + // #enddocregion v1 + + // #docregion final, new-hero + newHero() { + this.model = new Hero(42, '', ''); + } + // #enddocregion final, new-hero + + skyDog(): Hero { + // #docregion SkyDog + let myHero = new Hero(42, 'SkyDog', + 'Fetch any object at any distance', + 'Leslie Rollover'); + console.log('My hero is called ' + myHero.name); // "My hero is called SkyDog" + // #enddocregion SkyDog + return myHero; + } + + //////// NOT SHOWN IN DOCS //////// + + // Reveal in html: + // Name via form.controls = {{showFormControls(heroForm)}} + showFormControls(form: any) { + return form && form.controls['name'] && + // #docregion form-controls + form.controls['name'].value; // Dr. IQ + // #enddocregion form-controls + } + + ///////////////////////////// + + // #docregion v1, final +} diff --git a/public/docs/_examples/forms/ts/app/hero.ts b/public/docs/_examples/forms/ts/src/app/hero.ts similarity index 100% rename from public/docs/_examples/forms/ts/app/hero.ts rename to public/docs/_examples/forms/ts/src/app/hero.ts diff --git a/public/docs/_examples/forms/ts/src/forms.css b/public/docs/_examples/forms/ts/src/forms.css new file mode 100644 index 0000000000..13ffbe1203 --- /dev/null +++ b/public/docs/_examples/forms/ts/src/forms.css @@ -0,0 +1,9 @@ +/* #docregion */ +.ng-valid[required], .ng-valid.required { + border-left: 5px solid #42A948; /* green */ +} + +.ng-invalid:not(form) { + border-left: 5px solid #a94442; /* red */ +} +/* #enddocregion */ diff --git a/public/docs/_examples/forms/ts/src/index.html b/public/docs/_examples/forms/ts/src/index.html new file mode 100644 index 0000000000..032888ca3e --- /dev/null +++ b/public/docs/_examples/forms/ts/src/index.html @@ -0,0 +1,35 @@ + + + + + Hero Form + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/forms/ts/src/main.ts b/public/docs/_examples/forms/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/forms/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/edit_item.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/edit_item.dart deleted file mode 100644 index c5de35a9ed..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/edit_item.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -class EditItem { - bool editing = false; - T item; - EditItem(this.item); -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero.dart deleted file mode 100644 index 3a9ec96783..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero.dart +++ /dev/null @@ -1,14 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -class Hero { - String name; - String power; - - Hero clone() { - return new Hero() - ..name = name - ..power = power; - } -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero_card_component.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero_card_component.dart deleted file mode 100644 index bb4b2cfd1e..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero_card_component.dart +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; - -@Component( - selector: 'hero-card', - template: ''' -
    - Name: - {{hero.name}} -
    - ''') -class HeroCardComponent { - @Input() Hero hero; -} -// #docregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero_editor_component.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero_editor_component.dart deleted file mode 100644 index 3619d3ab0d..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/hero_editor_component.dart +++ /dev/null @@ -1,48 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; -import 'restore_service.dart'; - -@Component( - selector: 'hero-editor', - // #docregion providers - providers: const [RestoreService], - // #enddocregion providers - template: ''' -
    - Name: - -
    - - -
    -
    - ''') -class HeroEditorComponent { - @Output() final EventEmitter canceled = new EventEmitter(); - @Output() final EventEmitter saved = new EventEmitter(); - - RestoreService _restoreService; - - HeroEditorComponent(this._restoreService); - - @Input() - set hero(Hero hero) { - _restoreService.setItem(hero); - } - - Hero get hero { - return _restoreService.getItem(); - } - - onSaved() { - saved.add(_restoreService.getItem()); - } - - onCanceled() { - hero = _restoreService.restoreItem(); - canceled.add(hero); - } -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/heroes_list_component.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/heroes_list_component.dart deleted file mode 100644 index 90fbc8e2c4..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/heroes_list_component.dart +++ /dev/null @@ -1,54 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'edit_item.dart'; -import 'hero.dart'; -import 'hero_card_component.dart'; -import 'hero_editor_component.dart'; -import 'heroes_service.dart'; - -@Component( - selector: 'heroes-list', - template: ''' -
    -
      -
    • - - - - - -
    • -
    -
    - ''', - directives: const [HeroCardComponent, HeroEditorComponent]) -class HeroesListComponent { - List> heroes; - HeroesListComponent(HeroesService heroesService) { - heroes = heroesService - .getHeroes() - .map((Hero item) => new EditItem(item)) - .toList(); - } - - onCanceled(EditItem editItem) { - editItem.editing = false; - } - - onSaved(EditItem editItem, Hero updatedHero) { - editItem.item = updatedHero; - editItem.editing = false; - } -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/heroes_service.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/heroes_service.dart deleted file mode 100644 index adc97586ac..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/heroes_service.dart +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; - -@Injectable() -class HeroesService { - List _heroes = [ - new Hero() - ..name = "RubberMan" - ..power = 'Flexibility', - new Hero() - ..name = "Tornado" - ..power = 'Weather changer' - ]; - - List getHeroes() { - return _heroes; - } -} diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/restore_service.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/lib/restore_service.dart deleted file mode 100644 index a6d8c59d35..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/lib/restore_service.dart +++ /dev/null @@ -1,29 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -@Injectable() -class RestoreService { - T _originalItem; - T _currentItem; - - setItem(T item) { - print(item.runtimeType); - _originalItem = item; - _currentItem = clone(item); - } - - T getItem() { - return _currentItem; - } - - T restoreItem() { - _currentItem = _originalItem; - return getItem(); - } - - T clone(T item) { - // super poor clone implementation - return item.clone(); - } -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml b/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml deleted file mode 100644 index e07635bdc4..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# #docregion -name: 'hierarchical_di' -description: Hierarchical dependency injection example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/web/index.html b/public/docs/_examples/hierarchical-dependency-injection/dart/web/index.html deleted file mode 100644 index 598203b414..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/web/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - Hierarchical Injector - - - - - - - - loading... - - - - diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/web/main.dart b/public/docs/_examples/hierarchical-dependency-injection/dart/web/main.dart deleted file mode 100644 index a265c21e69..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/web/main.dart +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:hierarchical_di/heroes_list_component.dart'; -import 'package:hierarchical_di/heroes_service.dart'; - -void main() { - bootstrap(HeroesListComponent, [HeroesService]); -} - -/* Documentation artifact below -// #docregion bad-alternative -// Don't do this! -bootstrap(HeroesListComponent, [HeroesService, RestoreService]) -// #enddocregion bad-alternative -*/ diff --git a/public/docs/_examples/hierarchical-dependency-injection/e2e-spec.js b/public/docs/_examples/hierarchical-dependency-injection/e2e-spec.js deleted file mode 100644 index 2f63c32d52..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/e2e-spec.js +++ /dev/null @@ -1,56 +0,0 @@ -describe('Hierarchical dependency injection', function () { - - beforeEach(function () { - browser.get(''); - }); - - it('should open with a card view', function () { - expect(element.all(by.cssContainingText('button','edit')).get(0).isDisplayed()).toBe(true, - "edit button should be displayed"); - }); - - it('should have multiple heros listed', function () { - expect(element.all(by.css('heroes-list li')).count()).toBeGreaterThan(1); - }); - - it('should change to editor view after selection', function () { - var editButtonEle = element.all(by.cssContainingText('button','edit')).get(0); - editButtonEle.click().then(function() { - expect(editButtonEle.isDisplayed()).toBe(false, "edit button should be hidden after selection"); - }) - }); - - it('should be able to save editor change', function () { - testEdit(true); - }); - - it('should be able to cancel editor change', function () { - testEdit(false); - }); - - function testEdit(shouldSave) { - var inputEle; - // select 2nd ele - var heroEle = element.all(by.css('heroes-list li')).get(1); - // get the 2nd span which is the name of the hero - var heroNameEle = heroEle.all(by.css('hero-card span')).get(1); - var editButtonEle = heroEle.element(by.cssContainingText('button','edit')); - editButtonEle.click().then(function() { - inputEle = heroEle.element(by.css('hero-editor input')); - // return inputEle.sendKeys("foo"); - return sendKeys(inputEle, "foo"); - }).then(function() { - buttonName = shouldSave ? 'save' : 'cancel'; - var buttonEle = heroEle.element(by.cssContainingText('button', buttonName)); - return buttonEle.click(); - }).then(function() { - if (shouldSave) { - expect(heroNameEle.getText()).toContain('foo'); - } else { - expect(heroNameEle.getText()).not.toContain('foo'); - } - }) - } - - -}); diff --git a/public/docs/_examples/hierarchical-dependency-injection/e2e-spec.ts b/public/docs/_examples/hierarchical-dependency-injection/e2e-spec.ts new file mode 100644 index 0000000000..4630453f78 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/e2e-spec.ts @@ -0,0 +1,103 @@ +'use strict'; // necessary for es6 output in node + +import { browser, by, element } from 'protractor'; + +describe('Hierarchical dependency injection', () => { + + beforeAll(() => { + browser.get(''); + }); + + describe('Heroes Scenario', () => { + let page = { + heroName: '', + income: '', + + // queries + heroEl: element.all(by.css('heroes-list li')).get(0), // first hero + heroCardEl: element(by.css('heroes-list hero-tax-return')), // first hero tax-return + taxReturnNameEl: element.all(by.css('heroes-list hero-tax-return #name')).get(0), + incomeInputEl: element.all(by.css('heroes-list hero-tax-return input')).get(0), + cancelButtonEl: element(by.cssContainingText('heroes-list hero-tax-return button', 'Cancel')), + closeButtonEl: element(by.cssContainingText('heroes-list hero-tax-return button', 'Close')), + saveButtonEl: element(by.cssContainingText('heroes-list hero-tax-return button', 'Save')) + }; + + it('should list multiple heroes', () => { + expect(element.all(by.css('heroes-list li')).count()).toBeGreaterThan(1); + }); + + it('should show no hero tax-returns at the start', () => { + expect(element.all(by.css('heroes-list li hero-tax-return')).count()).toBe(0); + }); + + it('should open first hero in hero-tax-return view after click', () => { + page.heroEl.getText() + .then(val => { + page.heroName = val; + }) + .then(() => page.heroEl.click()) + .then(() => { + expect(page.heroCardEl.isDisplayed()).toBe(true); + }); + }); + + it('hero tax-return should have first hero\'s name', () => { + // Not `page.tax-returnNameInputEl.getAttribute('value')` although later that is essential + expect(page.taxReturnNameEl.getText()).toEqual(page.heroName); + }); + + it('should be able to cancel change', () => { + page.incomeInputEl.clear() + .then(() => page.incomeInputEl.sendKeys('777')) + .then(() => { + expect(page.incomeInputEl.getAttribute('value')).toBe('777', 'income should be 777'); + return page.cancelButtonEl.click(); + }) + .then(() => { + expect(page.incomeInputEl.getAttribute('value')).not.toBe('777', 'income should not be 777'); + }); + }); + + it('should be able to save change', () => { + page.incomeInputEl.clear() + .then(() => page.incomeInputEl.sendKeys('999')) + .then(() => { + expect(page.incomeInputEl.getAttribute('value')).toBe('999', 'income should be 999'); + return page.saveButtonEl.click(); + }) + .then(() => { + expect(page.incomeInputEl.getAttribute('value')).toBe('999', 'income should still be 999'); + }); + }); + + it('should be able to close tax-return', () => { + page.saveButtonEl.click() + .then(() => { + expect(element.all(by.css('heroes-list li hero-tax-return')).count()).toBe(0); + }); + }); + + }); + + describe('Villains Scenario', () => { + it('should list multiple villains', () => { + expect(element.all(by.css('villains-list li')).count()).toBeGreaterThan(1); + }); + }); + + describe('Cars Scenario', () => { + + it('A-component should use expected services', () => { + expect(element(by.css('a-car')).getText()).toContain('C1-E1-T1'); + }); + + it('B-component should use expected services', () => { + expect(element(by.css('b-car')).getText()).toContain('C2-E2-T1'); + }); + + it('C-component should use expected services', () => { + expect(element(by.css('c-car')).getText()).toContain('C3-E2-T1'); + }); + }); +}); diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/.gitignore b/public/docs/_examples/hierarchical-dependency-injection/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/edit-item.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/edit-item.ts deleted file mode 100644 index abbeabf2b0..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/edit-item.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export class EditItem { - editing: boolean - constructor (public item: T) {} -} -// #docregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-card.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-card.component.ts deleted file mode 100644 index 04d64ad19d..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-card.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {Component, Input} from 'angular2/core'; -import {Hero} from './hero'; - -@Component({ - selector: 'hero-card', - template: ` -
    - Name: - {{hero.name}} -
    ` -}) -export class HeroCardComponent { - @Input() hero: Hero; -} -// #docregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts deleted file mode 100644 index 1c19577cda..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero-editor.component.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docregion -import {Component, Input, Output, EventEmitter} from 'angular2/core'; -import {RestoreService} from './restore.service'; -import {Hero} from './hero'; - -@Component({ - selector: 'hero-editor', - // #docregion providers - providers: [RestoreService], - // #enddocregion providers - template: ` -
    - Name: - -
    - - -
    -
    ` -}) - -export class HeroEditorComponent { - @Output() canceled = new EventEmitter(); - @Output() saved = new EventEmitter(); - - constructor(private restoreService: RestoreService) {} - - @Input() - set hero (hero: Hero) { - this.restoreService.setItem(hero); - } - - get hero () { - return this.restoreService.getItem(); - } - - onSaved () { - this.saved.next(this.restoreService.getItem()); - } - - onCanceled () { - this.hero = this.restoreService.restoreItem(); - this.canceled.next(this.hero); - } -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero.ts deleted file mode 100644 index 76f808b1c5..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/hero.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export class Hero { - name: string; - power: string; -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/heroes-list.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/heroes-list.component.ts deleted file mode 100644 index a2d477710a..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/heroes-list.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {EditItem} from './edit-item'; -import {HeroesService} from './heroes.service'; -import {HeroCardComponent} from './hero-card.component'; -import {HeroEditorComponent} from './hero-editor.component'; -import {Hero} from './hero'; - -@Component({ - selector: 'heroes-list', - template: ` -
    -
      -
    • - - - - - -
    • -
    -
    `, - directives: [HeroCardComponent, HeroEditorComponent] -}) -export class HeroesListComponent { - heroes: Array>; - constructor(heroesService: HeroesService) { - this.heroes = heroesService.getHeroes() - .map(item => new EditItem(item)); - } - - onSaved (editItem: EditItem, updatedHero: Hero) { - editItem.item = updatedHero; - editItem.editing = false; - } - - onCanceled (editItem: EditItem) { - editItem.editing = false; - } -} - - -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/heroes.service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/heroes.service.ts deleted file mode 100644 index e4f9e2d213..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/heroes.service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Hero} from './hero'; - -export class HeroesService { - heroes: Array = [ - { name: "RubberMan", power: 'flexibility'}, - { name: "Tornado", power: 'Weather changer'} - ]; - - getHeroes () { - return this.heroes; - } -} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/main.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/main.ts deleted file mode 100644 index 7b3189eb3e..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/main.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {HeroesListComponent} from './heroes-list.component'; -import {HeroesService} from './heroes.service'; - -bootstrap(HeroesListComponent, [HeroesService]) - -/* Documentation artifact below -// #docregion bad-alternative -// Don't do this! -bootstrap(HeroesListComponent, [HeroesService, RestoreService]) -// #enddocregion bad-alternative -*/ \ No newline at end of file diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/app/restore.service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/app/restore.service.ts deleted file mode 100644 index c81786b2a3..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/app/restore.service.ts +++ /dev/null @@ -1,25 +0,0 @@ -// #docregion -export class RestoreService { - originalItem: T; - currentItem: T; - - setItem (item: T) { - this.originalItem = item; - this.currentItem = this.clone(item); - } - - getItem () :T { - return this.currentItem; - } - - restoreItem () :T { - this.currentItem = this.originalItem; - return this.getItem(); - } - - clone (item: T) :T { - // super poor clone implementation - return JSON.parse(JSON.stringify(item)); - } -} -// #enddocregion diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/index.html b/public/docs/_examples/hierarchical-dependency-injection/ts/index.html deleted file mode 100644 index e029217cee..0000000000 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - Hierarchical Injectors - - - - - - - - - - - - - - - - - - loading... - - - - diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/plnkr.json b/public/docs/_examples/hierarchical-dependency-injection/ts/plnkr.json index 84cd89d7ca..ca92b93b06 100644 --- a/public/docs/_examples/hierarchical-dependency-injection/ts/plnkr.json +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/plnkr.json @@ -1,5 +1,9 @@ { - "description": "Hierachical Injectors", - "files":["!**/*.d.ts", "!**/*.js"], + "description": "Hierachical Dependency Injection", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], "tags": ["dependency", "injection"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/app.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/app.component.ts new file mode 100644 index 0000000000..34b5dd0a5a --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/app.component.ts @@ -0,0 +1,21 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` + + + + +

    Hierarchical Dependency Injection

    + + + + + ` +}) +export class AppComponent { + showCars = true; + showHeroes = true; + showVillains = true; +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/app.module.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/app.module.ts new file mode 100644 index 0000000000..6ea18655af --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/app.module.ts @@ -0,0 +1,33 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { HeroTaxReturnComponent } from './hero-tax-return.component'; +import { HeroesListComponent } from './heroes-list.component'; +import { HeroesService } from './heroes.service'; +import { VillainsListComponent } from './villains-list.component'; + +import { carComponents, carServices } from './car.components'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + providers: [ + carServices, + HeroesService + ], + declarations: [ + AppComponent, + carComponents, + HeroesListComponent, + HeroTaxReturnComponent, + VillainsListComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } + diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/car.components.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/car.components.ts new file mode 100644 index 0000000000..5b4df19696 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/car.components.ts @@ -0,0 +1,74 @@ +import { Component } from '@angular/core'; + +import { + CarService, CarService2, CarService3, + EngineService, EngineService2, TiresService +} from './car.services'; + +////////// CCarComponent //////////// +@Component({ + selector: 'c-car', + template: `
    C: {{description}}
    `, + providers: [ + { provide: CarService, useClass: CarService3 } + ] +}) +export class CCarComponent { + description: string; + constructor(carService: CarService) { + this.description = `${carService.getCar().description} (${carService.name})`; + } +} + +////////// BCarComponent //////////// +@Component({ + selector: 'b-car', + template: ` +
    B: {{description}}
    + + `, + providers: [ + { provide: CarService, useClass: CarService2 }, + { provide: EngineService, useClass: EngineService2 } + ] +}) +export class BCarComponent { + description: string; + constructor(carService: CarService) { + this.description = `${carService.getCar().description} (${carService.name})`; + } +} + +////////// ACarComponent //////////// +@Component({ + selector: 'a-car', + template: ` +
    A: {{description}}
    + ` +}) +export class ACarComponent { + description: string; + constructor(carService: CarService) { + this.description = `${carService.getCar().description} (${carService.name})`; + } +} +////////// CarsComponent //////////// +@Component({ + selector: 'my-cars', + template: ` +

    Cars

    + ` +}) +export class CarsComponent { } + +//////////////// + +export const carComponents = [ + CarsComponent, + ACarComponent, BCarComponent, CCarComponent +]; + +// generic car-related services +export const carServices = [ + CarService, EngineService, TiresService +]; diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/car.services.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/car.services.ts new file mode 100644 index 0000000000..03c79270b0 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/car.services.ts @@ -0,0 +1,95 @@ +import { Injectable } from '@angular/core'; + +/// Model /// +export class Car { + name = 'Avocado Motors'; + constructor(public engine: Engine, public tires: Tires) { } + + get description() { + return `${this.name} car with ` + + `${this.engine.cylinders} cylinders and ${this.tires.make} tires.`; + } +} + +export class Engine { + cylinders = 4; +} + +export class Tires { + make = 'Flintstone'; + model = 'Square'; +} + +//// Engine services /// +@Injectable() +export class EngineService { + id = 'E1'; + getEngine() { return new Engine(); } +} + +@Injectable() +export class EngineService2 { + id = 'E2'; + getEngine() { + const eng = new Engine(); + eng.cylinders = 8; + return eng; + } +} + +//// Tire services /// +@Injectable() +export class TiresService { + id = 'T1'; + getTires() { return new Tires(); } +} + +/// Car Services /// +@Injectable() +export class CarService { + id = 'C1'; + constructor( + protected engineService: EngineService, + protected tiresService: TiresService) { } + + getCar() { + return new Car( + this.engineService.getEngine(), + this.tiresService.getTires()); + } + + get name() { + return `${this.id}-${this.engineService.id}-${this.tiresService.id}`; + } +} + +@Injectable() +export class CarService2 extends CarService { + id = 'C2'; + constructor( + protected engineService: EngineService, + protected tiresService: TiresService) { + super(engineService, tiresService); + } + getCar() { + const car = super.getCar(); + car.name = 'BamBam Motors, BroVan 2000'; + return car; + } +} + +@Injectable() +export class CarService3 extends CarService2 { + id = 'C3'; + constructor( + protected engineService: EngineService, + protected tiresService: TiresService) { + super(engineService, tiresService); + } + getCar() { + const car = super.getCar(); + car.name = 'Chizzamm Motors, Calico UltraMax Supreme'; + return car; + } +} + diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.css b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.css new file mode 100644 index 0000000000..1d29a1d168 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.css @@ -0,0 +1,22 @@ +.tax-return { border: thin dashed green; margin: 1em; padding: 1em; width: 18em; position: relative } +#name { font-weight: bold;} +#tid { float: right; } +input { font-size: 100%; padding-left: 2px; width: 6em; } +input.num { text-align: right; padding-left: 0; padding-right: 4px; width: 4em;} +fieldset { border: 0 none;} + +.msg { + color: white; + font-size: 150%; + position: absolute; + /*opacity: 0.3;*/ + left: 2px; + top: 3em; + width: 98%; + background-color: green; + text-align: center; +} +.msg.canceled { + color: white; + background-color: red; +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.html b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.html new file mode 100644 index 0000000000..ebf2dcbaaa --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.html @@ -0,0 +1,20 @@ +
    +
    {{message}}
    +
    + {{taxReturn.name}} + +
    +
    + +
    +
    + +
    +
    + + + +
    +
    diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts new file mode 100644 index 0000000000..ad8e0153d9 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.component.ts @@ -0,0 +1,44 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { HeroTaxReturn } from './hero'; +import { HeroTaxReturnService } from './hero-tax-return.service'; + +@Component({ + selector: 'hero-tax-return', + templateUrl: './hero-tax-return.component.html', + styleUrls: [ './hero-tax-return.component.css' ], + // #docregion providers + providers: [ HeroTaxReturnService ] + // #enddocregion providers +}) +export class HeroTaxReturnComponent { + message = ''; + @Output() close = new EventEmitter(); + + get taxReturn(): HeroTaxReturn { + return this.heroTaxReturnService.taxReturn; + } + @Input() + set taxReturn (htr: HeroTaxReturn) { + this.heroTaxReturnService.taxReturn = htr; + } + + constructor(private heroTaxReturnService: HeroTaxReturnService ) { } + + onCanceled() { + this.flashMessage('Canceled'); + this.heroTaxReturnService.restoreTaxReturn(); + }; + + onClose() { this.close.emit(); }; + + onSaved() { + this.flashMessage('Saved'); + this.heroTaxReturnService.saveTaxReturn(); + } + + flashMessage(msg: string) { + this.message = msg; + setTimeout(() => this.message = '', 500); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.service.ts new file mode 100644 index 0000000000..d6ff0f7fff --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero-tax-return.service.ts @@ -0,0 +1,30 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { HeroTaxReturn } from './hero'; +import { HeroesService } from './heroes.service'; + +@Injectable() +export class HeroTaxReturnService { + private currentTaxReturn: HeroTaxReturn; + private originalTaxReturn: HeroTaxReturn; + + constructor(private heroService: HeroesService) { } + + set taxReturn (htr: HeroTaxReturn) { + this.originalTaxReturn = htr; + this.currentTaxReturn = htr.clone(); + } + + get taxReturn (): HeroTaxReturn { + return this.currentTaxReturn; + } + + restoreTaxReturn() { + this.taxReturn = this.originalTaxReturn; + } + + saveTaxReturn() { + this.taxReturn = this.currentTaxReturn; + this.heroService.saveTaxReturn(this.currentTaxReturn).subscribe(); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero.ts new file mode 100644 index 0000000000..4ad6ccd8eb --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/hero.ts @@ -0,0 +1,31 @@ +// #docregion + +export class Hero { + id: number; + name: string; + tid: string; // tax id +} + +//// HeroTaxReturn //// +let nextId = 100; + +export class HeroTaxReturn { + constructor( + public id = nextId++, + public hero: Hero, + public income = 0 ) { + if (id === 0) { id = nextId++; } + } + + get name() { return this.hero.name; } + get tax() { return this.income ? .10 * this.income : 0; } + get tid() { return this.hero.tid; } + + toString() { + return `${this.hero.name}`; + } + + clone() { + return new HeroTaxReturn(this.id, this.hero, this.income); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts new file mode 100644 index 0000000000..36cb5ec1c3 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes-list.component.ts @@ -0,0 +1,48 @@ +// #docregion +import { Component } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + +import { Hero, HeroTaxReturn } from './hero'; +import { HeroesService } from './heroes.service'; + +@Component({ + selector: 'heroes-list', + template: ` +
    +

    Hero Tax Returns

    +
      +
    • {{hero.name}} +
    • +
    + + +
    + `, + styles: [ 'li {cursor: pointer;}' ] +}) +export class HeroesListComponent { + heroes: Observable; + selectedTaxReturns: HeroTaxReturn[] = []; + + constructor(private heroesService: HeroesService) { + this.heroes = heroesService.getHeroes(); + } + + showTaxReturn(hero: Hero) { + this.heroesService.getTaxReturn(hero) + .subscribe(htr => { + // show if not currently shown + if (!this.selectedTaxReturns.find(tr => tr.id === htr.id)) { + this.selectedTaxReturns.push(htr); + } + }); + } + + closeTaxReturn(ix: number) { + this.selectedTaxReturns.splice(ix, 1); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes.service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes.service.ts new file mode 100644 index 0000000000..85b33c89a0 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/heroes.service.ts @@ -0,0 +1,47 @@ +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import { Observer } from 'rxjs/Observer'; + +import { Hero, HeroTaxReturn } from './hero'; + +@Injectable() +export class HeroesService { + heroes: Hero[] = [ + { id: 1, name: 'RubberMan', tid: '082-27-5678'}, + { id: 2, name: 'Tornado', tid: '099-42-4321'} + ]; + + heroTaxReturns: HeroTaxReturn[] = [ + new HeroTaxReturn(10, this.heroes[0], 35000), + new HeroTaxReturn(20, this.heroes[1], 1250000) + ]; + + getHeroes(): Observable { + return new Observable((observer: Observer) => { + observer.next(this.heroes); + observer.complete(); + }); + } + + getTaxReturn(hero: Hero): Observable { + return new Observable((observer: Observer) => { + const htr = this.heroTaxReturns.find(t => t.hero.id === hero.id); + observer.next(htr || new HeroTaxReturn(0, hero)); + observer.complete(); + }); + } + + saveTaxReturn(heroTaxReturn: HeroTaxReturn): Observable { + return new Observable((observer: Observer) => { + const htr = this.heroTaxReturns.find(t => t.id === heroTaxReturn.id); + if (htr) { + heroTaxReturn = Object.assign(htr, heroTaxReturn); // demo: mutate + } else { + this.heroTaxReturns.push(heroTaxReturn); + } + observer.next(heroTaxReturn); + observer.complete(); + }); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains-list.component.html b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains-list.component.html new file mode 100644 index 0000000000..75e5ba3237 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains-list.component.html @@ -0,0 +1,6 @@ +
    +

    Villains

    +
      +
    • {{villain.name}}
    • +
    +
    diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains-list.component.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains-list.component.ts new file mode 100644 index 0000000000..5226d4f2a9 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains-list.component.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + +import { Villain, VillainsService } from './villains.service'; + +// #docregion metadata +@Component({ + selector: 'villains-list', + templateUrl: './villains-list.component.html', + providers: [ VillainsService ] +}) +// #enddocregion metadata +export class VillainsListComponent { + villains: Observable; + + constructor(private villainsService: VillainsService) { + this.villains = villainsService.getVillains(); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains.service.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains.service.ts new file mode 100644 index 0000000000..3d480c20af --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/app/villains.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@angular/core'; + +import { of } from 'rxjs/observable/of'; + +export interface Villain { id: number; name: string; } + +@Injectable() +export class VillainsService { + villains: Villain[] = [ + { id: 1, name: 'Dr. Evil'}, + { id: 2, name: 'Moriarty'} + ]; + + getVillains() { + return of(this.villains); + } +} diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/index.html b/public/docs/_examples/hierarchical-dependency-injection/ts/src/index.html new file mode 100644 index 0000000000..0ea32679e6 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/index.html @@ -0,0 +1,26 @@ + + + + Hierarchical Injectors + + + + + + + + + + + + + + + + + loading... + + + diff --git a/public/docs/_examples/hierarchical-dependency-injection/ts/src/main.ts b/public/docs/_examples/hierarchical-dependency-injection/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/hierarchical-dependency-injection/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/homepage-hello-world/e2e-spec.js b/public/docs/_examples/homepage-hello-world/e2e-spec.js deleted file mode 100644 index 4cccdfa4e3..0000000000 --- a/public/docs/_examples/homepage-hello-world/e2e-spec.js +++ /dev/null @@ -1,29 +0,0 @@ - -describe('Homepage Hello World', function () { - - beforeAll(function () { - browser.get(''); - }); - - // Does it even launch? - var expectedLabel = 'Name:'; - it('should display the label: ' + expectedLabel, function () { - expect(element(by.css('label')).getText()).toEqual(expectedLabel); - }); - - it('should display entered name', function () { - var testName = 'Bobby Joe'; - var newValue; - var nameEle = element.all(by.css('input')).get(0); - nameEle.getAttribute('value').then(function(value) { - // nameEle.sendKeys(testName); // should work but doesn't - sendKeys(nameEle, testName); // utility that does work - newValue = value + testName; // old input box value + new name - expect(nameEle.getAttribute('value')).toEqual(newValue); - }).then(function() { - // Check the interpolated message built from name - var helloEle = element.all(by.css('h1')).get(0); - expect(helloEle.getText()).toEqual('Hello ' + testName + '!'); - }); - }); -}); diff --git a/public/docs/_examples/homepage-hello-world/e2e-spec.ts b/public/docs/_examples/homepage-hello-world/e2e-spec.ts new file mode 100644 index 0000000000..c4c6464937 --- /dev/null +++ b/public/docs/_examples/homepage-hello-world/e2e-spec.ts @@ -0,0 +1,30 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Homepage Hello World', function () { + + beforeAll(function () { + browser.get(''); + }); + + // Does it even launch? + let expectedLabel = 'Name:'; + it(`should display the label: ${expectedLabel}`, function () { + expect(element(by.css('label')).getText()).toEqual(expectedLabel); + }); + + it('should display entered name', function () { + let testName = 'Bobby Joe'; + let nameEle = element.all(by.css('input')).get(0); + nameEle.getAttribute('value').then(function(value: string) { + nameEle.sendKeys(testName); + let newValue = value + testName; // old input box value + new name + expect(nameEle.getAttribute('value')).toEqual(newValue); + }).then(function() { + // Check the interpolated message built from name + let helloEle = element.all(by.css('h1')).get(0); + expect(helloEle.getText()).toEqual('Hello ' + testName + '!'); + }); + }); +}); diff --git a/public/docs/_examples/homepage-hello-world/ts/.gitignore b/public/docs/_examples/homepage-hello-world/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/homepage-hello-world/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/homepage-hello-world/ts/app/hello_world.ts b/public/docs/_examples/homepage-hello-world/ts/app/hello_world.ts deleted file mode 100644 index af08051387..0000000000 --- a/public/docs/_examples/homepage-hello-world/ts/app/hello_world.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - // Declare the tag name in index.html to where the component attaches - selector: 'hello-world', - - // Location of the template for this component - templateUrl: 'app/hello_world.html' -}) -export class HelloWorld { - - // Declaring the variable for binding with initial value - yourName: string = ''; -} diff --git a/public/docs/_examples/homepage-hello-world/ts/app/main.ts b/public/docs/_examples/homepage-hello-world/ts/app/main.ts deleted file mode 100644 index edafebcde5..0000000000 --- a/public/docs/_examples/homepage-hello-world/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {HelloWorld} from './hello_world'; - -bootstrap(HelloWorld); \ No newline at end of file diff --git a/public/docs/_examples/homepage-hello-world/ts/index.1.html b/public/docs/_examples/homepage-hello-world/ts/index.1.html deleted file mode 100644 index 74910a7a45..0000000000 --- a/public/docs/_examples/homepage-hello-world/ts/index.1.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Angular 2 Hello World - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/homepage-hello-world/ts/index.html b/public/docs/_examples/homepage-hello-world/ts/index.html deleted file mode 100644 index 997edd82d7..0000000000 --- a/public/docs/_examples/homepage-hello-world/ts/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - Angular 2 Hello World - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/homepage-hello-world/ts/plnkr.json b/public/docs/_examples/homepage-hello-world/ts/plnkr.json index 78f6fd979d..bfe6aecc8b 100644 --- a/public/docs/_examples/homepage-hello-world/ts/plnkr.json +++ b/public/docs/_examples/homepage-hello-world/ts/plnkr.json @@ -1,8 +1,9 @@ { "description": "Hello World", + "basePath": "src/", "files":[ - "!**/*.d.ts", + "!**/*.d.ts", "!**/*.js", "!**/*.[1].*" ] -} \ No newline at end of file +} diff --git a/public/docs/_examples/homepage-hello-world/ts/src/app/app.module.ts b/public/docs/_examples/homepage-hello-world/ts/src/app/app.module.ts new file mode 100644 index 0000000000..55a2ef3693 --- /dev/null +++ b/public/docs/_examples/homepage-hello-world/ts/src/app/app.module.ts @@ -0,0 +1,16 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { HelloWorldComponent } from './hello_world'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ HelloWorldComponent ], + bootstrap: [ HelloWorldComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/homepage-hello-world/ts/app/hello_world.html b/public/docs/_examples/homepage-hello-world/ts/src/app/hello_world.html similarity index 100% rename from public/docs/_examples/homepage-hello-world/ts/app/hello_world.html rename to public/docs/_examples/homepage-hello-world/ts/src/app/hello_world.html diff --git a/public/docs/_examples/homepage-hello-world/ts/src/app/hello_world.ts b/public/docs/_examples/homepage-hello-world/ts/src/app/hello_world.ts new file mode 100644 index 0000000000..145d22e1e9 --- /dev/null +++ b/public/docs/_examples/homepage-hello-world/ts/src/app/hello_world.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + // Declare the tag name in index.html to where the component attaches + selector: 'hello-world', + + // Location of the template for this component + templateUrl: './hello_world.html' +}) +export class HelloWorldComponent { + + // Declaring the variable for binding with initial value + yourName: string = ''; +} diff --git a/public/docs/_examples/homepage-hello-world/ts/src/index.1.html b/public/docs/_examples/homepage-hello-world/ts/src/index.1.html new file mode 100644 index 0000000000..37c1bf787c --- /dev/null +++ b/public/docs/_examples/homepage-hello-world/ts/src/index.1.html @@ -0,0 +1,32 @@ + + + + + Angular Hello World + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/homepage-hello-world/ts/src/index.html b/public/docs/_examples/homepage-hello-world/ts/src/index.html new file mode 100644 index 0000000000..9dab660d10 --- /dev/null +++ b/public/docs/_examples/homepage-hello-world/ts/src/index.html @@ -0,0 +1,28 @@ + + + + + Angular Hello World + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/homepage-hello-world/ts/src/main.ts b/public/docs/_examples/homepage-hello-world/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/homepage-hello-world/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/homepage-tabs/e2e-spec.js b/public/docs/_examples/homepage-tabs/e2e-spec.js deleted file mode 100644 index 12f4f4bf53..0000000000 --- a/public/docs/_examples/homepage-tabs/e2e-spec.js +++ /dev/null @@ -1,14 +0,0 @@ - -describe('Homepage Tabs', function () { - - beforeAll(function () { - browser.get(''); - }); - - // Does it even launch? - var expectedAppTitle = 'Tabs Demo'; - it('should display app title: ' + expectedAppTitle, function () { - expect(element(by.css('h4')).getText()).toEqual(expectedAppTitle); - }); - -}); diff --git a/public/docs/_examples/homepage-tabs/e2e-spec.ts b/public/docs/_examples/homepage-tabs/e2e-spec.ts new file mode 100644 index 0000000000..2131d75906 --- /dev/null +++ b/public/docs/_examples/homepage-tabs/e2e-spec.ts @@ -0,0 +1,17 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Homepage Tabs', function () { + + beforeAll(function () { + browser.get(''); + }); + + // Does it even launch? + let expectedAppTitle = 'Tabs Demo'; + it(`should display app title: ${expectedAppTitle}`, function () { + expect(element(by.css('h4')).getText()).toEqual(expectedAppTitle); + }); + +}); diff --git a/public/docs/_examples/homepage-tabs/ts/.gitignore b/public/docs/_examples/homepage-tabs/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/homepage-tabs/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/homepage-tabs/ts/app/di_demo.ts b/public/docs/_examples/homepage-tabs/ts/app/di_demo.ts deleted file mode 100644 index 96c4751771..0000000000 --- a/public/docs/_examples/homepage-tabs/ts/app/di_demo.ts +++ /dev/null @@ -1,47 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {UiTabs, UiPane} from './ui_tabs'; - -class Detail { - title: string; - text: string; -} - -@Component({ - selector: 'di-demo', - template: ` -

    Tabs Demo

    - - - - - -
    - - `, - directives: [UiTabs, UiPane] -}) -export class DiDemo { - details: Detail[] = []; - id: number = 0; - - addDetail() { - this.id++; - this.details.push({ - title: `Detail ${this.id}`, - text: `Some detail text for ${this.id}...` - }); - } - - removeDetail(detail:Detail) { - this.details = this.details.filter((d) => d !== detail); - } -} - diff --git a/public/docs/_examples/homepage-tabs/ts/app/main.ts b/public/docs/_examples/homepage-tabs/ts/app/main.ts deleted file mode 100644 index 35eaece68e..0000000000 --- a/public/docs/_examples/homepage-tabs/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {DiDemo} from './di_demo'; - -bootstrap(DiDemo); \ No newline at end of file diff --git a/public/docs/_examples/homepage-tabs/ts/app/ui_tabs.ts b/public/docs/_examples/homepage-tabs/ts/app/ui_tabs.ts deleted file mode 100644 index 63a3e87c54..0000000000 --- a/public/docs/_examples/homepage-tabs/ts/app/ui_tabs.ts +++ /dev/null @@ -1,51 +0,0 @@ -// #docregion -import {Component, Directive, Input, QueryList, - ViewContainerRef, TemplateRef, ContentChildren} from 'angular2/core'; - -@Directive({ - selector: '[ui-pane]' -}) -export class UiPane { - @Input() title: string; - private _active:boolean = false; - - constructor(public viewContainer: ViewContainerRef, - public templateRef: TemplateRef) { } - - @Input() set active(active: boolean) { - if (active == this._active) return; - this._active = active; - if (active) { - this.viewContainer.createEmbeddedView(this.templateRef); - } else { - this.viewContainer.remove(0); - } - } - - get active(): boolean { - return this._active; - } -} - -@Component({ - selector: 'ui-tabs', - template: ` - - - `, - styles:['a { cursor: pointer; cursor: hand; }'] -}) -export class UiTabs { - @ContentChildren(UiPane) panes: QueryList; - - select(pane: UiPane) { - this.panes.toArray().forEach((p: UiPane) => p.active = p == pane); - } -} - diff --git a/public/docs/_examples/homepage-tabs/ts/index.1.html b/public/docs/_examples/homepage-tabs/ts/index.1.html deleted file mode 100644 index 3878af0216..0000000000 --- a/public/docs/_examples/homepage-tabs/ts/index.1.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Angular 2 Tabs - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/homepage-tabs/ts/index.html b/public/docs/_examples/homepage-tabs/ts/index.html deleted file mode 100644 index 8cc7032da8..0000000000 --- a/public/docs/_examples/homepage-tabs/ts/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Angular 2 Tabs - - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/homepage-tabs/ts/plnkr.json b/public/docs/_examples/homepage-tabs/ts/plnkr.json index 05ee7a2b9d..c1a33dc8f0 100644 --- a/public/docs/_examples/homepage-tabs/ts/plnkr.json +++ b/public/docs/_examples/homepage-tabs/ts/plnkr.json @@ -1,8 +1,9 @@ { "description": "Tabs", + "basePath": "src/", "files":[ - "!**/*.d.ts", + "!**/*.d.ts", "!**/*.js", "!**/*.[1].*" ] -} \ No newline at end of file +} diff --git a/public/docs/_examples/homepage-tabs/ts/src/app/app.module.ts b/public/docs/_examples/homepage-tabs/ts/src/app/app.module.ts new file mode 100644 index 0000000000..bd2193755c --- /dev/null +++ b/public/docs/_examples/homepage-tabs/ts/src/app/app.module.ts @@ -0,0 +1,17 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { DiDemoComponent } from './di_demo'; +import { UiTabsComponent, UiPaneDirective } from './ui_tabs'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ + DiDemoComponent, + UiTabsComponent, + UiPaneDirective + ], + bootstrap: [ DiDemoComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/homepage-tabs/ts/src/app/di_demo.ts b/public/docs/_examples/homepage-tabs/ts/src/app/di_demo.ts new file mode 100644 index 0000000000..be72ae5c79 --- /dev/null +++ b/public/docs/_examples/homepage-tabs/ts/src/app/di_demo.ts @@ -0,0 +1,45 @@ +// #docregion +import { Component } from '@angular/core'; + +class Detail { + title: string; + text: string; +} + +@Component({ + selector: 'di-demo', + template: ` +

    Tabs Demo

    + + + + + +
    + + ` +}) +export class DiDemoComponent { + details: Detail[] = []; + id: number = 0; + + addDetail() { + this.id++; + this.details.push({ + title: `Detail ${this.id}`, + text: `Some detail text for ${this.id}...` + }); + } + + removeDetail(detail: Detail) { + this.details = this.details.filter((d) => d !== detail); + } +} + diff --git a/public/docs/_examples/homepage-tabs/ts/src/app/ui_tabs.ts b/public/docs/_examples/homepage-tabs/ts/src/app/ui_tabs.ts new file mode 100644 index 0000000000..5e2f47b140 --- /dev/null +++ b/public/docs/_examples/homepage-tabs/ts/src/app/ui_tabs.ts @@ -0,0 +1,51 @@ +// #docregion +import { Component, Directive, Input, QueryList, + ViewContainerRef, TemplateRef, ContentChildren } from '@angular/core'; + +@Directive({ + selector: '[uiPane]' +}) +export class UiPaneDirective { + @Input() title: string; + private _active: boolean = false; + + constructor(public viewContainer: ViewContainerRef, + public templateRef: TemplateRef) { } + + @Input() set active(active: boolean) { + if (active === this._active) { return; } + this._active = active; + if (active) { + this.viewContainer.createEmbeddedView(this.templateRef); + } else { + this.viewContainer.remove(0); + } + } + + get active(): boolean { + return this._active; + } +} + +@Component({ + selector: 'ui-tabs', + template: ` + + + `, + styles: ['a { cursor: pointer; cursor: hand; }'] +}) +export class UiTabsComponent { + @ContentChildren(UiPaneDirective) panes: QueryList; + + select(pane: UiPaneDirective) { + this.panes.toArray().forEach((p: UiPaneDirective) => p.active = p === pane); + } +} + diff --git a/public/docs/_examples/homepage-tabs/ts/src/index.1.html b/public/docs/_examples/homepage-tabs/ts/src/index.1.html new file mode 100644 index 0000000000..a25071b484 --- /dev/null +++ b/public/docs/_examples/homepage-tabs/ts/src/index.1.html @@ -0,0 +1,33 @@ + + + + + Angular Tabs + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/homepage-tabs/ts/src/index.html b/public/docs/_examples/homepage-tabs/ts/src/index.html new file mode 100644 index 0000000000..d38b36e033 --- /dev/null +++ b/public/docs/_examples/homepage-tabs/ts/src/index.html @@ -0,0 +1,29 @@ + + + + + Angular Tabs + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/homepage-tabs/ts/src/main.ts b/public/docs/_examples/homepage-tabs/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/homepage-tabs/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/homepage-todo/e2e-spec.js b/public/docs/_examples/homepage-todo/e2e-spec.js deleted file mode 100644 index 4bc9b5f6a6..0000000000 --- a/public/docs/_examples/homepage-todo/e2e-spec.js +++ /dev/null @@ -1,14 +0,0 @@ - -describe('Homepage Todo', function () { - - beforeAll(function () { - browser.get(''); - }); - - // Does it even launch? - var expectedAppTitle = 'Todo'; - it('should display app title: ' + expectedAppTitle, function () { - expect(element(by.css('h2')).getText()).toEqual(expectedAppTitle); - }); - -}); diff --git a/public/docs/_examples/homepage-todo/e2e-spec.ts b/public/docs/_examples/homepage-todo/e2e-spec.ts new file mode 100644 index 0000000000..fb74e4e70f --- /dev/null +++ b/public/docs/_examples/homepage-todo/e2e-spec.ts @@ -0,0 +1,17 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Homepage Todo', function () { + + beforeAll(function () { + browser.get(''); + }); + + // Does it even launch? + let expectedAppTitle = 'Todo'; + it(`should display app title: ${expectedAppTitle}`, function () { + expect(element(by.css('h2')).getText()).toEqual(expectedAppTitle); + }); + +}); diff --git a/public/docs/_examples/homepage-todo/ts/.gitignore b/public/docs/_examples/homepage-todo/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/homepage-todo/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/homepage-todo/ts/app/main.ts b/public/docs/_examples/homepage-todo/ts/app/main.ts deleted file mode 100644 index 717623acdc..0000000000 --- a/public/docs/_examples/homepage-todo/ts/app/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {TodoApp} from './todo_app'; - -bootstrap(TodoApp); \ No newline at end of file diff --git a/public/docs/_examples/homepage-todo/ts/app/todo.ts b/public/docs/_examples/homepage-todo/ts/app/todo.ts deleted file mode 100644 index 57070dc72c..0000000000 --- a/public/docs/_examples/homepage-todo/ts/app/todo.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -// Declare an interaface for type safety -export interface Todo { - text: string, - done: boolean -} diff --git a/public/docs/_examples/homepage-todo/ts/app/todo_app.ts b/public/docs/_examples/homepage-todo/ts/app/todo_app.ts deleted file mode 100644 index 5688868b73..0000000000 --- a/public/docs/_examples/homepage-todo/ts/app/todo_app.ts +++ /dev/null @@ -1,40 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {Todo} from './todo'; -import {TodoList} from './todo_list'; -import {TodoForm} from './todo_form'; - -@Component({ - selector: 'todo-app', - template: ` -

    Todo

    - {{remaining}} of {{todos.length}} remaining - [ archive ] - - - `, - styles:['a { cursor: pointer; cursor: hand; }'], - directives: [TodoList, TodoForm] -}) -export class TodoApp { - todos: Todo[] = [ - {text:'learn angular', done:true}, - {text:'build an angular app', done:false} - ]; - - get remaining() { - return this.todos.reduce((count: number, todo: Todo) => count + +!todo.done, 0); - } - - archive(): void { - var oldTodos = this.todos; - this.todos = []; - oldTodos.forEach((todo: Todo) => { - if (!todo.done) this.todos.push(todo); - }); - } - - addTask(task: Todo) { - this.todos.push(task); - } -} diff --git a/public/docs/_examples/homepage-todo/ts/app/todo_form.ts b/public/docs/_examples/homepage-todo/ts/app/todo_form.ts deleted file mode 100644 index 29117525ff..0000000000 --- a/public/docs/_examples/homepage-todo/ts/app/todo_form.ts +++ /dev/null @@ -1,25 +0,0 @@ -// #docregion -import {Component, Output, EventEmitter} from 'angular2/core'; -import {Todo} from './todo'; - -@Component({ - selector: 'todo-form', - template: ` -
    - - -
    ` -}) -export class TodoForm { - @Output() newTask = new EventEmitter(); - task: string = ''; - - addTodo() { - if (this.task) { - this.newTask.next({text:this.task, done:false}); - } - this.task = ''; - } -} - diff --git a/public/docs/_examples/homepage-todo/ts/app/todo_list.ts b/public/docs/_examples/homepage-todo/ts/app/todo_list.ts deleted file mode 100644 index f680832b23..0000000000 --- a/public/docs/_examples/homepage-todo/ts/app/todo_list.ts +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import {Component, Input} from 'angular2/core'; -import {Todo} from './todo'; - -@Component({ - selector: 'todo-list', - styles: [` - .done-true { - text-decoration: line-through; - color: grey; - }` - ], - template: ` -
      -
    • - - {{todo.text}} -
    • -
    ` -}) -export class TodoList { - @Input() todos: Todo[]; -} diff --git a/public/docs/_examples/homepage-todo/ts/index.1.html b/public/docs/_examples/homepage-todo/ts/index.1.html deleted file mode 100644 index 76cf01f802..0000000000 --- a/public/docs/_examples/homepage-todo/ts/index.1.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Angular 2 Todos - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/homepage-todo/ts/index.html b/public/docs/_examples/homepage-todo/ts/index.html deleted file mode 100644 index c0796e4ff2..0000000000 --- a/public/docs/_examples/homepage-todo/ts/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Angular 2 Todos - - - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/homepage-todo/ts/plnkr.json b/public/docs/_examples/homepage-todo/ts/plnkr.json index 7fecc539f7..8e69701221 100644 --- a/public/docs/_examples/homepage-todo/ts/plnkr.json +++ b/public/docs/_examples/homepage-todo/ts/plnkr.json @@ -1,8 +1,9 @@ { "description": "Todo", + "basePath": "src/", "files":[ - "!**/*.d.ts", + "!**/*.d.ts", "!**/*.js", "!**/*.[1].*" ] -} \ No newline at end of file +} diff --git a/public/docs/_examples/homepage-todo/ts/src/app/app.module.ts b/public/docs/_examples/homepage-todo/ts/src/app/app.module.ts new file mode 100644 index 0000000000..a77bb640ab --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/app/app.module.ts @@ -0,0 +1,22 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { TodoAppComponent } from './todo_app'; +import { TodoListComponent } from './todo_list'; +import { TodoFormComponent } from './todo_form'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + TodoAppComponent, + TodoListComponent, + TodoFormComponent + ], + bootstrap: [ TodoAppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/homepage-todo/ts/src/app/todo.ts b/public/docs/_examples/homepage-todo/ts/src/app/todo.ts new file mode 100644 index 0000000000..35faec9705 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/app/todo.ts @@ -0,0 +1,6 @@ +// #docregion +// Declare an interaface for type safety +export interface Todo { + text: string; + done: boolean; +} diff --git a/public/docs/_examples/homepage-todo/ts/src/app/todo_app.ts b/public/docs/_examples/homepage-todo/ts/src/app/todo_app.ts new file mode 100644 index 0000000000..e56bad95b6 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/app/todo_app.ts @@ -0,0 +1,38 @@ +// #docregion +import { Component } from '@angular/core'; + +import { Todo } from './todo'; + +@Component({ + selector: 'todo-app', + template: ` +

    Todo

    + {{remaining}} of {{todos.length}} remaining + [ archive ] + + + `, + styles: ['a { cursor: pointer; cursor: hand; }'] +}) +export class TodoAppComponent { + todos: Todo[] = [ + {text: 'learn angular', done: true}, + {text: 'build an angular app', done: false} + ]; + + get remaining() { + return this.todos.filter(todo => !todo.done).length; + } + + archive(): void { + let oldTodos = this.todos; + this.todos = []; + oldTodos.forEach(todo => { + if (!todo.done) { this.todos.push(todo); } + }); + } + + addTask(task: Todo) { + this.todos.push(task); + } +} diff --git a/public/docs/_examples/homepage-todo/ts/src/app/todo_form.ts b/public/docs/_examples/homepage-todo/ts/src/app/todo_form.ts new file mode 100644 index 0000000000..38e8d991a7 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/app/todo_form.ts @@ -0,0 +1,25 @@ +// #docregion +import { Component, Output, EventEmitter } from '@angular/core'; +import { Todo } from './todo'; + +@Component({ + selector: 'todo-form', + template: ` +
    + + +
    ` +}) +export class TodoFormComponent { + @Output() newTask = new EventEmitter(); + task: string = ''; + + addTodo() { + if (this.task) { + this.newTask.emit({text: this.task, done: false}); + } + this.task = ''; + } +} + diff --git a/public/docs/_examples/homepage-todo/ts/src/app/todo_list.ts b/public/docs/_examples/homepage-todo/ts/src/app/todo_list.ts new file mode 100644 index 0000000000..b6495f37c2 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/app/todo_list.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component, Input } from '@angular/core'; + +import { Todo } from './todo'; + +@Component({ + selector: 'todo-list', + styles: [` + .done-true { + text-decoration: line-through; + color: grey; + }` + ], + template: ` +
      +
    • + + {{todo.text}} +
    • +
    ` +}) +export class TodoListComponent { + @Input() todos: Todo[]; +} diff --git a/public/docs/_examples/homepage-todo/ts/src/index.1.html b/public/docs/_examples/homepage-todo/ts/src/index.1.html new file mode 100644 index 0000000000..4e8d034fd3 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/index.1.html @@ -0,0 +1,33 @@ + + + + + Angular Todos + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/homepage-todo/ts/src/index.html b/public/docs/_examples/homepage-todo/ts/src/index.html new file mode 100644 index 0000000000..e7a656a106 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/index.html @@ -0,0 +1,29 @@ + + + + + Angular Todos + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/homepage-todo/ts/src/main.ts b/public/docs/_examples/homepage-todo/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/homepage-todo/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/karma-test-shim.js b/public/docs/_examples/karma-test-shim.js deleted file mode 100644 index 8ccb27a727..0000000000 --- a/public/docs/_examples/karma-test-shim.js +++ /dev/null @@ -1,68 +0,0 @@ -// Tun on full stack traces in errors to help debugging -Error.stackTraceLimit=Infinity; - - -jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; - -// // Cancel Karma's synchronous start, -// // we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function() {}; - - -System.config({ - packages: { - 'base/app': { - defaultExtension: false, - // removed because of issues with raw .js files not being found. - // format: 'register', - map: Object.keys(window.__karma__.files). - filter(onlyAppFiles). - reduce(function createPathRecords(pathsMapping, appPath) { - // creates local module name mapping to global path with karma's fingerprint in path, e.g.: - // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' - var moduleName = appPath.replace(/^\/base\/app\//, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath] - return pathsMapping; - }, {}) - - } - } -}); - -// old code from angular 44 -// System.import('angular2/src/core/dom/browser_adapter').then(function(browser_adapter) { -// new path for angular 51 -System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) { - browser_adapter.BrowserDomAdapter.makeCurrent(); -}).then(function() { - return Promise.all( - Object.keys(window.__karma__.files) // All files served by Karma. - .filter(onlySpecFiles) - // .map(filePath2moduleName) // Normalize paths to module names. - .map(function(moduleName) { - // loads all spec files via their global module names (e.g. 'base/src/app/hero.service.spec') - return System.import(moduleName); - })); -}) -.then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); -}); - - -function filePath2moduleName(filePath) { - return filePath. - replace(/^\//, ''). // remove / prefix - replace(/\.\w+$/, ''); // remove suffix -} - - -function onlyAppFiles(filePath) { - return /^\/base\/app\/.*\.js$/.test(filePath) && !onlySpecFiles(filePath); -} - - -function onlySpecFiles(filePath) { - return /\.spec\.js$/.test(filePath); -} diff --git a/public/docs/_examples/karma.conf.js b/public/docs/_examples/karma.conf.js deleted file mode 100644 index 5b07bee380..0000000000 --- a/public/docs/_examples/karma.conf.js +++ /dev/null @@ -1,43 +0,0 @@ -module.exports = function(config) { - config.set({ - - basePath: '', - - frameworks: ['jasmine'], - - files: [ - // paths loaded by Karma - {pattern: 'node_modules/systemjs/dist/system.src.js', included: true, watched: true}, - {pattern: 'node_modules/angular2/bundles/angular2.js', included: true, watched: true}, - {pattern: 'node_modules/angular2/bundles/testing.js', included: true, watched: true}, - {pattern: 'karma-test-shim.js', included: true, watched: true}, - {pattern: 'app/test/*.js', included: true, watched: true}, - - // paths loaded via module imports - {pattern: 'app/**/*.js', included: false, watched: true}, - - // paths loaded via Angular's component compiler - // (these paths need to be rewritten, see proxies section) - {pattern: 'app/**/*.html', included: false, watched: true}, - {pattern: 'app/**/*.css', included: false, watched: true}, - - // paths to support debugging with source maps in dev tools - {pattern: 'app/**/*.ts', included: false, watched: false}, - {pattern: 'app/**/*.js.map', included: false, watched: false} - ], - - // proxied base paths - proxies: { - // required for component assests fetched by Angular's compiler - "/app/": "/base/app/" - }, - - reporters: ['progress'], - port: 9877, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: true - }) -} diff --git a/public/docs/_examples/karma.js.conf.js b/public/docs/_examples/karma.js.conf.js deleted file mode 100644 index e55127f0f0..0000000000 --- a/public/docs/_examples/karma.js.conf.js +++ /dev/null @@ -1,68 +0,0 @@ -// Karma configuration -// Generated on Mon Aug 10 2015 11:36:40 GMT-0700 (Pacific Daylight Time) - -module.exports = function(config) { - config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], - - - // list of files / patterns to load in the browser - files: [ - { pattern: 'https://code.angularjs.org/2.0.0-alpha.34/angular2.sfx.dev.js', watched: false }, - - '**/js/*.js', - ], - - - // list of files to exclude - exclude: [ - '**/*.e2e-spec.js' - ], - - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - }, - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], - - - // web server port - port: 9876, - - - // enable / disable colors in the output (reporters and logs) - colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Chrome'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false - }) -} diff --git a/public/docs/_examples/karma.ts.conf.js b/public/docs/_examples/karma.ts.conf.js deleted file mode 100644 index 5b2d176b56..0000000000 --- a/public/docs/_examples/karma.ts.conf.js +++ /dev/null @@ -1,70 +0,0 @@ -// Karma configuration -// Generated on Mon Aug 10 2015 11:36:40 GMT-0700 (Pacific Daylight Time) - -module.exports = function(config) { - config.set({ - - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', - - - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], - - - // list of files / patterns to load in the browser - files: [ - { pattern: 'https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.87/traceur-runtime.js', watched: false }, - { pattern: 'https://jspm.io/system@0.16.js', watched: false }, - { pattern: 'https://code.angularjs.org/2.0.0-alpha.34/angular2.dev.js', watched: false }, - - '**/ts/**/*.spec.js' - ], - - - // list of files to exclude - exclude: [ - '**/*.e2e-spec.js' - ], - - - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - }, - - - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], - - - // web server port - port: 9876, - - - // enable / disable colors in the output (reporters and logs) - colors: true, - - - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, - - - // enable / disable watching file and executing tests whenever any file changes - autoWatch: true, - - - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Chrome'], - - - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: false - }) -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/after_content_parent.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/after_content_parent.dart deleted file mode 100644 index bffea129ab..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/after_content_parent.dart +++ /dev/null @@ -1,95 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'child_component.dart'; -import 'logger_service.dart'; - -@Component( - selector: 'after-content', - template: ''' -
    -
    -- child content begins --
    - - - -
    -- child content ends --
    -
    - ''', - styles: const ['.after-content {background: LightCyan; padding: 8px;}']) -class AfterContentComponent - implements AfterContentChecked, AfterContentInit, AfterViewInit { - LoggerService _logger; - - // Query for a CONTENT child of type `ChildComponent` - @ContentChild(ChildComponent) ChildComponent contentChild; - - // Query for a VIEW child of type`ChildComponent` - // No such VIEW child exists! - // This component holds content but no view of that type. - @ViewChild(ChildComponent) ChildComponent viewChild; - - String _prevHero; - - AfterContentComponent(this._logger) { - _logger.log('AfterContent ctor: $message'); - } - - ///// Hooks - ngAfterContentInit() { - // contentChild is set after the content has been initialized - _logger.log('AfterContentInit: $message'); - } - - get hasViewChild => viewChild != null; - - ngAfterViewInit() { - _logger - .log('AfterViewInit: There is ${hasViewChild ? 'a' : 'no'} view child'); - } - - ngAfterContentChecked() { - // contentChild is updated after the content has been checked - // Called frequently; only report when the hero changes - if (!hasContentChild || _prevHero == contentChild.hero) return; - _prevHero = contentChild.hero; - _logger.log('AfterContentChecked: $message'); - } - - bool get hasContentChild => contentChild != null; - - String get message => hasContentChild - ? '"${contentChild.hero}" child content' - : 'no child content'; -} - -@Component( - selector: 'after-content-parent', - template: ''' -
    -

    AfterContent

    - - - - - - - - -

    -- Lifecycle Hook Log --

    -
    {{msg}}
    -
    - ''', - styles: const [ - '.parent {background: powderblue; padding: 8px; margin:100px 8px;}' - ], - directives: const [AfterContentComponent, ChildComponent], - providers: const [LoggerService]) -class AfterContentParentComponent { - List hookLog; - String hero = 'Magneta'; - bool showChild = true; - - AfterContentParentComponent(LoggerService logger) { - hookLog = logger.logs; - } -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/after_view_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/after_view_component.dart deleted file mode 100644 index 505571a679..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/after_view_component.dart +++ /dev/null @@ -1,77 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'child_component.dart'; -import 'logger_service.dart'; - -@Component( - selector: 'after-view-parent', - template: ''' -
    -

    AfterView

    - -
    - - - - -
    - -

    -- Lifecycle Hook Log --

    -
    {{msg}}
    -
    - ''', - styles: const [ - '.parent {background: burlywood; padding: 8px; margin:100px 8px;}' - ], - directives: const [ChildComponent], - providers: const [LoggerService]) -class AfterViewParentComponent - implements AfterContentInit, AfterViewChecked, AfterViewInit { - LoggerService _logger; - List hookLog; - String hero = 'Magneta'; - bool showChild = true; - - // Query for a CONTENT child of type `ChildComponent` - // No such CONTENT child exists! - // This component holds a view but no content of that type. - @ContentChild(ChildComponent) - ChildComponent contentChild; - - // Query for a VIEW child of type `ChildComponent` - @ViewChild(ChildComponent) - ChildComponent viewChild; - - String _prevHero; - - AfterViewParentComponent(this._logger) { - hookLog = _logger.logs; - _logger.log('AfterView ctor: $message'); - } - - bool get _hasContentChild => contentChild != null; - bool get _hasViewChild => viewChild != null; - - ///// Hooks - ngAfterContentInit() { - _logger.log( - 'AfterContentInit: There is ${ _hasContentChild ? 'a' : 'no'} content child'); - } - - ngAfterViewInit() { - // viewChild is set after the view has been initialized - _logger.log('AfterViewInit: $message'); - } - - ngAfterViewChecked() { - // viewChild is updated after the view has been checked - // Called frequently; only report when the hero changes - if (!_hasViewChild || _prevHero == viewChild.hero) return; - _prevHero = viewChild.hero; - _logger.log('AfterViewChecked: $message'); - } - - String get message => - _hasViewChild ? '"${viewChild.hero}" child view' : 'no child view'; -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/app_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/app_component.dart deleted file mode 100644 index dff8c59cf1..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/app_component.dart +++ /dev/null @@ -1,29 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'after_content_parent.dart'; -import 'after_view_component.dart'; -import 'counter_component.dart'; -import 'on_changes_component.dart'; -import 'peek_a_boo_parent_component.dart'; -import 'spy_component.dart'; - -@Component( - selector: 'my-app', - template: ''' - - - - - - - ''', - directives: const [ - PeekABooParentComponent, - OnChangesParentComponent, - AfterViewParentComponent, - AfterContentParentComponent, - SpyParentComponent, - CounterParentComponent - ]) -class AppComponent {} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/child_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/child_component.dart deleted file mode 100644 index dc43e899dc..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/child_component.dart +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -@Component( - selector: 'my-child', - template: ''' -
    -
    -- child view begins --
    -
    {{hero}} is my hero.
    -
    -- child view ends --
    -
    - ''', - styles: const [ - '.child {background: Yellow; padding: 8px; }', - '.my-child {background: LightYellow; padding: 8px; margin-top: 8px}' - ]) -class ChildComponent { - @Input() String hero; -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/counter_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/counter_component.dart deleted file mode 100644 index 0aaf2b155f..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/counter_component.dart +++ /dev/null @@ -1,77 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'logger_service.dart'; -import 'spy_directive.dart'; - -@Component( - selector: 'my-counter', - template: ''' -
    - Counter = {{counter}} - -
    -- Counter Change Log --
    -
    {{chg}}
    -
    - ''', - styles: const [ - '.counter {background: LightYellow; padding: 8px; margin-top: 8px}' - ], - directives: const [Spy]) -class MyCounter implements OnChanges { - @Input() num counter; - List changeLog = []; - - ngOnChanges(Map changes) { - // Empty the changeLog whenever counter goes to zero - // hint: this is a way to respond programmatically to external value changes. - if (this.counter == 0) { - changeLog.clear(); - } - - // A change to `counter` is the only change we care about - SimpleChange prop = changes['counter']; - var prev = prop.isFirstChange() ? "{}" : prop.previousValue; - changeLog.add( - 'counter: currentValue = ${prop.currentValue}, previousValue = $prev'); - } -} - -@Component( - selector: 'counter-parent', - template: ''' -
    -

    Counter Spy

    - - - - - - -

    -- Spy Lifecycle Hook Log --

    -
    {{msg}}
    -
    - ''', - styles: const [ - '.parent {background: gold; padding: 10px; margin:100px 8px;}' - ], - directives: const [MyCounter], - providers: const [LoggerService]) -class CounterParentComponent { - num value; - List spyLog = []; - - LoggerService _logger; - - CounterParentComponent(this._logger) { - spyLog = _logger.logs; - reset(); - } - - updateCounter() => value += 1; - - reset() { - _logger.log('-- reset --'); - value = 0; - } -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/logger_service.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/logger_service.dart deleted file mode 100644 index 51fe44cb39..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/logger_service.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'dart:async'; - -import 'package:angular2/angular2.dart'; - -@Injectable() -class LoggerService { - List logs = []; - - log(String msg, [bool noTick = false]) { - if (!noTick) { - tick(); - } - logs.add(msg); - } - - clear() => logs.clear(); - - tick() => new Future(() {}); -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/on_changes_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/on_changes_component.dart deleted file mode 100644 index 34389ddb2e..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/on_changes_component.dart +++ /dev/null @@ -1,81 +0,0 @@ -// #docregion -import 'dart:convert'; - -import 'package:angular2/angular2.dart'; - -class Hero { - String name; - Hero(this.name); - - Map toJson() => {'name': name}; -} - -@Component( - selector: 'my-hero', - template: ''' -
    -

    {{hero.name}} can {{power}}

    - -

    -- Change Log --

    -
    {{chg}}
    -
    - ''', - styles: const [ - '.hero {background: LightYellow; padding: 8px; margin-top: 8px}', - 'p {background: Yellow; padding: 8px; margin-top: 8px}' - ]) -class MyHeroComponent implements OnChanges { - @Input() Hero hero; - @Input() String power; - @Input() bool reset; - List changeLog = []; - - ngOnChanges(Map changes) { - // Empty the changeLog whenever 'reset' property changes - // hint: this is a way to respond programmatically to external value changes. - if (changes.containsKey('reset')) changeLog.clear(); - - changes.forEach((String key, SimpleChange change) { - String cur = JSON.encode(change.currentValue); - String prev = - change.isFirstChange() ? "{}" : JSON.encode(change.previousValue); - changeLog.add('$key: currentValue = ${cur}, previousValue = $prev'); - }); - } -} - -@Component( - selector: 'on-changes-parent', - template: ''' -
    -

    OnChanges

    - -
    Hero.name: does NOT trigger onChanges
    -
    Power: DOES trigger onChanges
    -
    triggers onChanges and clears the change log
    - - -
    - ''', - styles: const [ - '.parent {background: Lavender; padding: 10px; margin:100px 8px;}' - ], - directives: const [MyHeroComponent]) -class OnChangesParentComponent { - Hero hero; - String power; - bool resetTrigger = false; - - OnChangesParentComponent() { - reset(); - } - - reset() { - // new Hero object every time; triggers onChange - hero = new Hero('Windstorm'); - // setting power only triggers onChange if this value is different - power = 'sing'; - // always triggers onChange ... which is interpreted as a reset - resetTrigger = !resetTrigger; - } -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/peek_a_boo_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/peek_a_boo_component.dart deleted file mode 100644 index 5315e3cd44..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/peek_a_boo_component.dart +++ /dev/null @@ -1,78 +0,0 @@ -// #docregion -// #docregion lc-imports -import 'package:angular2/angular2.dart'; - -import 'logger_service.dart'; - -int nextId = 1; - -@Component( - selector: 'peek-a-boo', - template: '

    Now you see my hero, {{name}}

    ', - styles: const ['p {background: LightYellow; padding: 8px}']) -class PeekABooComponent - implements - OnChanges, - OnInit, - AfterContentInit, - AfterContentChecked, - AfterViewInit, - AfterViewChecked, - OnDestroy { - @Input() String name; - - int _afterContentCheckedCounter = 1; - int _afterViewCheckedCounter = 1; - int _id = nextId++; - LoggerService _logger; - int _onChangesCounter = 1; - String _verb = 'initialized'; - - PeekABooComponent(this._logger); - - // Only called if there is an @input variable set by parent. - ngOnChanges(Map changes) { - List messages = []; - changes.forEach((String propName, SimpleChange change) { - if (propName == 'name') { - var name = changes['name'].currentValue; - messages.add('name $_verb to "$name"'); - } else { - messages.add('$propName $_verb'); - } - }); - _logIt('onChanges (${_onChangesCounter++}): ${messages.join('; ')}'); - _verb = 'changed'; // Next time it will be a change - } - - ngOnInit() => _logIt('onInit'); - - ngAfterContentInit() => _logIt('afterContentInit'); - - // Called after every change detection check - // of the component (directive) CONTENT - // Beware! Called frequently! - ngAfterContentChecked() { - int counter = _afterContentCheckedCounter++; - _logIt('afterContentChecked (${counter})'); - } - - ngAfterViewInit() => _logIt('afterViewInit'); - - // Called after every change detection check - // of the component (directive) VIEW - // Beware! Called frequently! - ngAfterViewChecked() { - int counter = _afterViewCheckedCounter++; - _logIt('afterViewChecked ($counter)'); - } - - ngOnDestroy() => _logIt('onDestroy'); - - _logIt(String msg) { - // Don't tick or else - // the AfterContentChecked and AfterViewChecked recurse. - // Let parent call tick() - _logger.log("#$_id $msg", true); - } -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/peek_a_boo_parent_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/peek_a_boo_parent_component.dart deleted file mode 100644 index d9cdfa68bf..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/peek_a_boo_parent_component.dart +++ /dev/null @@ -1,54 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'logger_service.dart'; -import 'peek_a_boo_component.dart'; - -@Component( - selector: 'peek-a-boo-parent', - template: ''' -
    -

    Peek-A-Boo

    - - - - - - - -

    -- Lifecycle Hook Log --

    -
    {{msg}}
    -
    - ''', - styles: const [ - '.parent {background: moccasin; padding: 10px; margin:100px 8px}' - ], - directives: const [PeekABooComponent], - providers: const [LoggerService]) -class PeekABooParentComponent { - bool hasChild = false; - List hookLog; - - String heroName = 'Windstorm'; - LoggerService _logger; - - PeekABooParentComponent(this._logger) { - hookLog = _logger.logs; - } - - toggleChild() { - hasChild = !hasChild; - if (hasChild) { - heroName = 'Windstorm'; - _logger.clear(); // clear log on create - } - _logger.tick(); - } - - updateHero() { - heroName += '!'; - _logger.tick(); - } -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/spy_component.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/spy_component.dart deleted file mode 100644 index b5db1d0059..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/spy_component.dart +++ /dev/null @@ -1,53 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'logger_service.dart'; -import 'spy_directive.dart'; - -@Component( - selector: 'spy-parent', - template: ''' -
    -

    Spy Directive

    - - - - - -

    -
    - {{hero}} -
    - -

    -- Spy Lifecycle Hook Log --

    -
    {{msg}}
    -
    - ''', - styles: const [ - '.parent {background: khaki; padding: 10px; margin:100px 8px}', - '.heroes {background: LightYellow; padding: 0 8px}' - ], - directives: const [Spy], - providers: const [LoggerService]) -class SpyParentComponent { - String newName = 'Herbie'; - List heroes = ['Windstorm', 'Magneta']; - List spyLog; - LoggerService _logger; - - SpyParentComponent(this._logger) { - spyLog = _logger.logs; - } - - addHero() { - if (newName.trim().isNotEmpty) { - heroes.add(newName.trim()); - newName = ''; - } - } - - reset() { - _logger.log('-- reset --'); - heroes.clear(); - } -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/lib/spy_directive.dart b/public/docs/_examples/lifecycle-hooks/dart/lib/spy_directive.dart deleted file mode 100644 index 84e5937a56..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/lib/spy_directive.dart +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'logger_service.dart'; - -int nextId = 1; - -// Spy on any element to which it is applied. -// Usage:
    ...
    -@Directive(selector: '[mySpy]') -class Spy implements OnInit, OnDestroy { - int _id = nextId++; - LoggerService _logger; - - Spy(this._logger); - - ngOnInit() => _logIt('onInit'); - - ngOnDestroy() => _logIt('onDestroy'); - - _logIt(String msg) => _logger.log('Spy #$_id $msg'); -} diff --git a/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml b/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml deleted file mode 100644 index 2d60856b8c..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# #docregion -name: lifecycle_hooks -description: Lifecycle Hooks -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: - - 'package:angular2/common.dart#CORE_DIRECTIVES' - - 'package:angular2/common.dart#FORM_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/lifecycle-hooks/dart/web/index.html b/public/docs/_examples/lifecycle-hooks/dart/web/index.html deleted file mode 100644 index ae668dd2e9..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/web/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Angular 2 Lifecycle Hooks - - - - - - - Loading... - - - diff --git a/public/docs/_examples/lifecycle-hooks/dart/web/main.dart b/public/docs/_examples/lifecycle-hooks/dart/web/main.dart deleted file mode 100644 index 6fc83949b7..0000000000 --- a/public/docs/_examples/lifecycle-hooks/dart/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:lifecycle_hooks/app_component.dart'; - -main() { - bootstrap(AppComponent); -} diff --git a/public/docs/_examples/lifecycle-hooks/e2e-spec.js b/public/docs/_examples/lifecycle-hooks/e2e-spec.js deleted file mode 100644 index d201fd7bfb..0000000000 --- a/public/docs/_examples/lifecycle-hooks/e2e-spec.js +++ /dev/null @@ -1,144 +0,0 @@ -describe('Lifecycle hooks', function () { - - beforeAll(function () { - browser.get(''); - }); - - it('should open correctly', function () { - expect(element.all(by.css('h2')).get(0).getText()).toEqual('Peek-A-Boo'); - }); - - it('should be able to drive peek-a-boo button', function () { - var pabComp = element(by.css('peek-a-boo-parent peek-a-boo')); - expect(pabComp.isPresent()).toBe(false, "should not be able to find the 'peek-a-boo' component"); - var pabButton = element.all(by.css('peek-a-boo-parent button')).get(0); - var updateHeroButton = element.all(by.css('peek-a-boo-parent button')).get(1); - expect(pabButton.getText()).toContain('Create Peek'); - pabButton.click().then(function () { - expect(pabButton.getText()).toContain('Destroy Peek'); - expect(pabComp.isDisplayed()).toBe(true, "should be able to see the 'peek-a-boo' component"); - expect(pabComp.getText()).toContain('Windstorm'); - expect(pabComp.getText()).not.toContain('Windstorm!'); - expect(updateHeroButton.isPresent()).toBe(true, "should be able to see the update hero button"); - return updateHeroButton.click(); - }).then(function () { - expect(pabComp.getText()).toContain('Windstorm!'); - return pabButton.click(); - }).then(function () { - expect(pabComp.isPresent()).toBe(false, "should no longer be able to find the 'peek-a-boo' component"); - }); - }); - - it('should be able to trigger onChanges', function () { - var onChangesViewEle = element.all(by.css('on-changes-parent my-hero div')).get(0); - var inputEles = element.all(by.css('on-changes-parent input')); - var heroNameInputEle = inputEles.get(0); - var powerInputEle = inputEles.get(1); - var titleEle = onChangesViewEle.element(by.css('p')); - expect(titleEle.getText()).toContain('Windstorm can sing'); - var changeLogEles = onChangesViewEle.all(by.css('div')); - expect(changeLogEles.count()).toEqual(3, "should start with 3 messages"); - // heroNameInputEle.sendKeys('-foo-').then(function () { - sendKeys(heroNameInputEle, '-foo-').then(function () { - expect(titleEle.getText()).toContain('Windstorm-foo- can sing'); - expect(changeLogEles.count()).toEqual(3, "should still have 3 messages"); - // protractor bug with sendKeys means that line below does not work. - // return powerInputEle.sendKeys('-bar-'); - return sendKeys(powerInputEle, '-bar-'); - }).then(function () { - expect(titleEle.getText()).toContain('Windstorm-foo- can sing-bar-'); - // 8 == 3 previously + length of '-bar-' - expect(changeLogEles.count()).toEqual(8, "should have 8 messages now"); - }); - }); - - it('should support after-view hooks', function () { - var inputEle = element(by.css('after-view-parent input')); - var buttonEle = element(by.css('after-view-parent button')); - var logEles = element.all(by.css('after-view-parent h4 ~ div')); - var childViewTextEle = element(by.css('after-view-parent my-child .child')); - expect(childViewTextEle.getText()).toContain('Magneta is my hero'); - expect(logEles.count()).toBeGreaterThan(2); - var logCount; - logEles.count().then(function(count) { - logCount = count; - return sendKeys(inputEle, "-test-"); - }).then(function() { - expect(childViewTextEle.getText()).toContain('-test-'); - return logEles.count(); - }).then(function(count) { - expect(logCount + 6).toEqual(count, "6 additional log messages should have been added"); - logCount = count; - return buttonEle.click(); - }).then(function() { - expect(childViewTextEle.isPresent()).toBe(false,"child view should no longer be part of the DOM"); - sendKeys(inputEle, "-foo-"); - expect(logEles.count()).toEqual(logCount, "no additional log messages should have been added"); - }); - }); - - it('should support after-content hooks', function () { - var inputEle = element(by.css('after-content-parent input')); - var buttonEle = element(by.css('after-content-parent button')); - var logEles = element.all(by.css('after-content-parent h4 ~ div')); - var childViewTextEle = element(by.css('after-content-parent my-child .child')); - expect(childViewTextEle.getText()).toContain('Magneta is my hero'); - expect(logEles.count()).toBeGreaterThan(2); - var logCount; - logEles.count().then(function(count) { - logCount = count; - return sendKeys(inputEle, "-test-"); - }).then(function() { - expect(childViewTextEle.getText()).toContain('-test-'); - return logEles.count(); - }).then(function(count) { - expect(logCount + 6).toEqual(count, "6 additional log messages should have been added"); - logCount = count; - return buttonEle.click(); - }).then(function() { - expect(childViewTextEle.isPresent()).toBe(false,"child view should no longer be part of the DOM"); - sendKeys(inputEle, "-foo-"); - expect(logEles.count()).toEqual(logCount, "no additional log messages should have been added"); - }); - }); - - it('should support "spy" hooks', function () { - var inputEle = element(by.css('spy-parent input')); - var addHeroButtonEle = element(by.cssContainingText('spy-parent button','Add Hero')); - var resetHeroesButtonEle = element(by.cssContainingText('spy-parent button','Reset Heroes')); - var heroEles = element.all(by.css('spy-parent div[my-spy')); - var logEles = element.all(by.css('spy-parent h4 ~ div')); - expect(heroEles.count()).toBe(2, 'should have two heroes displayed'); - expect(logEles.count()).toBe(2, 'should have two log entries'); - sendKeys(inputEle, "-test-").then(function() { - return addHeroButtonEle.click(); - }).then(function() { - expect(heroEles.count()).toBe(3, 'should have added one hero'); - expect(heroEles.get(2).getText()).toContain('-test-'); - expect(logEles.count()).toBe(3, 'should now have 3 log entries'); - return resetHeroesButtonEle.click(); - }).then(function() { - expect(heroEles.count()).toBe(0, 'should no longer have any heroes'); - expect(logEles.count()).toBe(7, 'should now have 7 log entries - 3 orig + 1 reset + 3 removeall'); - }) - }); - - it('should support "spy counter" hooks', function () { - var updateCounterButtonEle = element(by.cssContainingText('counter-parent button','Update')); - var resetCounterButtonEle = element(by.cssContainingText('counter-parent button','Reset')); - var textEle = element(by.css('counter-parent my-counter > div')); - var logEles = element.all(by.css('counter-parent h4 ~ div')); - expect(textEle.getText()).toContain('Counter = 0'); - expect(logEles.count()).toBe(2, 'should start with two log entries'); - updateCounterButtonEle.click().then(function() { - expect(textEle.getText()).toContain('Counter = 1'); - expect(logEles.count()).toBe(3, 'should now have 3 log entries'); - return resetCounterButtonEle.click(); - }).then(function() { - expect(textEle.getText()).toContain('Counter = 0'); - expect(logEles.count()).toBe(7, 'should now have 7 log entries - 3 prev + 1 reset + 2 destroy + 1 init'); - }) - }); - - -}); diff --git a/public/docs/_examples/lifecycle-hooks/e2e-spec.ts b/public/docs/_examples/lifecycle-hooks/e2e-spec.ts new file mode 100644 index 0000000000..8e9acb1c76 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/e2e-spec.ts @@ -0,0 +1,178 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Lifecycle hooks', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should open correctly', function () { + expect(element.all(by.css('h2')).get(0).getText()).toEqual('Peek-A-Boo'); + }); + + it('should support peek-a-boo', function () { + let pabComp = element(by.css('peek-a-boo-parent peek-a-boo')); + expect(pabComp.isPresent()).toBe(false, 'should not be able to find the "peek-a-boo" component'); + let pabButton = element.all(by.css('peek-a-boo-parent button')).get(0); + let updateHeroButton = element.all(by.css('peek-a-boo-parent button')).get(1); + expect(pabButton.getText()).toContain('Create Peek'); + pabButton.click().then(function () { + expect(pabButton.getText()).toContain('Destroy Peek'); + expect(pabComp.isDisplayed()).toBe(true, 'should be able to see the "peek-a-boo" component'); + expect(pabComp.getText()).toContain('Windstorm'); + expect(pabComp.getText()).not.toContain('Windstorm!'); + expect(updateHeroButton.isPresent()).toBe(true, 'should be able to see the update hero button'); + return updateHeroButton.click(); + }).then(function () { + expect(pabComp.getText()).toContain('Windstorm!'); + return pabButton.click(); + }).then(function () { + expect(pabComp.isPresent()).toBe(false, 'should no longer be able to find the "peek-a-boo" component'); + }); + }); + + it('should support OnChanges hook', function () { + let onChangesViewEle = element.all(by.css('on-changes div')).get(0); + let inputEles = element.all(by.css('on-changes-parent input')); + let heroNameInputEle = inputEles.get(1); + let powerInputEle = inputEles.get(0); + let titleEle = onChangesViewEle.element(by.css('p')); + let changeLogEles = onChangesViewEle.all(by.css('div')); + + expect(titleEle.getText()).toContain('Windstorm can sing'); + expect(changeLogEles.count()).toEqual(2, 'should start with 2 messages'); + heroNameInputEle.sendKeys('-foo-'); + expect(titleEle.getText()).toContain('Windstorm-foo- can sing'); + expect(changeLogEles.count()).toEqual(2, 'should still have 2 messages'); + powerInputEle.sendKeys('-bar-'); + expect(titleEle.getText()).toContain('Windstorm-foo- can sing-bar-'); + // 7 == 2 previously + length of '-bar-' + expect(changeLogEles.count()).toEqual(7, 'should have 7 messages now'); + }); + + it('should support DoCheck hook', function () { + let doCheckViewEle = element.all(by.css('do-check div')).get(0); + let inputEles = element.all(by.css('do-check-parent input')); + let heroNameInputEle = inputEles.get(1); + let powerInputEle = inputEles.get(0); + let titleEle = doCheckViewEle.element(by.css('p')); + let changeLogEles = doCheckViewEle.all(by.css('div')); + let logCount: number; + + expect(titleEle.getText()).toContain('Windstorm can sing'); + changeLogEles.count().then(function(count: number) { + // 3 messages to start + expect(count).toEqual(3, 'should start with 3 messages'); + logCount = count; + return heroNameInputEle.sendKeys('-foo-'); + }).then(function () { + expect(titleEle.getText()).toContain('Windstorm-foo- can sing'); + return changeLogEles.count(); + }).then(function(count: number) { + // one more for each keystroke + expect(count).toEqual(logCount + 5, 'should add 5 more messages'); + logCount = count; + return powerInputEle.sendKeys('-bar-'); + }).then(function () { + expect(titleEle.getText()).toContain('Windstorm-foo- can sing-bar-'); + expect(changeLogEles.count()).toEqual(logCount + 6, 'should add 6 more messages'); + }); + }); + + it('should support AfterView hooks', function () { + let parentEle = element(by.tagName('after-view-parent')); + let buttonEle = parentEle.element(by.tagName('button')); // Reset + let commentEle = parentEle.element(by.className('comment')); + let logEles = parentEle.all(by.css('h4 ~ div')); + let childViewInputEle = parentEle.element(by.css('my-child-view input')); + let logCount: number; + + expect(childViewInputEle.getAttribute('value')).toContain('Magneta'); + expect(commentEle.isPresent()).toBe(false, 'comment should not be in DOM'); + + logEles.count().then(function(count: number) { + logCount = count; + return childViewInputEle.sendKeys('-test-'); + }).then(function() { + expect(childViewInputEle.getAttribute('value')).toContain('-test-'); + expect(commentEle.isPresent()).toBe(true, 'should have comment because >10 chars'); + expect(commentEle.getText()).toContain('long name'); + return logEles.count(); + }).then(function(count: number) { + expect(logCount + 7).toEqual(count, '7 additional log messages should have been added'); + logCount = count; + return buttonEle.click(); + }).then(function() { + expect(logEles.count()).toBeLessThan(logCount, 'log should shrink after reset'); + }); + }); + + + it('should support AfterContent hooks', function () { + let parentEle = element(by.tagName('after-content-parent')); + let buttonEle = parentEle.element(by.tagName('button')); // Reset + let commentEle = parentEle.element(by.className('comment')); + let logEles = parentEle.all(by.css('h4 ~ div')); + let childViewInputEle = parentEle.element(by.css('my-child input')); + let logCount: number; + + expect(childViewInputEle.getAttribute('value')).toContain('Magneta'); + expect(commentEle.isPresent()).toBe(false, 'comment should not be in DOM'); + + logEles.count().then(function(count: number) { + logCount = count; + return childViewInputEle.sendKeys('-test-'); + }).then(function() { + expect(childViewInputEle.getAttribute('value')).toContain('-test-'); + expect(commentEle.isPresent()).toBe(true, 'should have comment because >10 chars'); + expect(commentEle.getText()).toContain('long name'); + return logEles.count(); + }).then(function(count: number) { + expect(logCount + 5).toEqual(count, '5 additional log messages should have been added'); + logCount = count; + return buttonEle.click(); + }).then(function() { + expect(logEles.count()).toBeLessThan(logCount, 'log should shrink after reset'); + }); + }); + + it('should support spy\'s OnInit & OnDestroy hooks', function () { + let inputEle = element(by.css('spy-parent input')); + let addHeroButtonEle = element(by.cssContainingText('spy-parent button', 'Add Hero')); + let resetHeroesButtonEle = element(by.cssContainingText('spy-parent button', 'Reset Heroes')); + let heroEles = element.all(by.css('spy-parent div[mySpy')); + let logEles = element.all(by.css('spy-parent h4 ~ div')); + expect(heroEles.count()).toBe(2, 'should have two heroes displayed'); + expect(logEles.count()).toBe(2, 'should have two log entries'); + inputEle.sendKeys('-test-').then(function() { + return addHeroButtonEle.click(); + }).then(function() { + expect(heroEles.count()).toBe(3, 'should have added one hero'); + expect(heroEles.get(2).getText()).toContain('-test-'); + expect(logEles.count()).toBe(3, 'should now have 3 log entries'); + return resetHeroesButtonEle.click(); + }).then(function() { + expect(heroEles.count()).toBe(0, 'should no longer have any heroes'); + expect(logEles.count()).toBe(7, 'should now have 7 log entries - 3 orig + 1 reset + 3 removeall'); + }); + }); + + it('should support "spy counter"', function () { + let updateCounterButtonEle = element(by.cssContainingText('counter-parent button', 'Update')); + let resetCounterButtonEle = element(by.cssContainingText('counter-parent button', 'Reset')); + let textEle = element(by.css('counter-parent my-counter > div')); + let logEles = element.all(by.css('counter-parent h4 ~ div')); + expect(textEle.getText()).toContain('Counter = 0'); + expect(logEles.count()).toBe(2, 'should start with two log entries'); + updateCounterButtonEle.click().then(function() { + expect(textEle.getText()).toContain('Counter = 1'); + expect(logEles.count()).toBe(3, 'should now have 3 log entries'); + return resetCounterButtonEle.click(); + }).then(function() { + expect(textEle.getText()).toContain('Counter = 0'); + expect(logEles.count()).toBe(7, 'should now have 7 log entries - 3 prev + 1 reset + 2 destroy + 1 init'); + }); + }); +}); diff --git a/public/docs/_examples/lifecycle-hooks/ts/.gitignore b/public/docs/_examples/lifecycle-hooks/ts/.gitignore deleted file mode 100644 index cf44e148ba..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js \ No newline at end of file diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/after-content.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/after-content.component.ts deleted file mode 100644 index 1774470535..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/after-content.component.ts +++ /dev/null @@ -1,102 +0,0 @@ -// #docregion -import { - Component, Input, Output, - AfterContentChecked, AfterContentInit, ContentChild, - AfterViewInit, ViewChild -} from 'angular2/core'; - -import {ChildComponent} from './child.component'; -import {LoggerService} from './logger.service'; - -@Component({ - selector: 'after-content', - template: ` -
    -
    -- child content begins --
    - - - -
    -- child content ends --
    -
    - `, - styles: ['.after-content {background: LightCyan; padding: 8px;}'], - -}) -export class AfterContentComponent - implements AfterContentChecked, AfterContentInit, AfterViewInit { - - private _logger:LoggerService; - - constructor(logger:LoggerService){ - this._logger = logger; - logger.log('AfterContent ctor: ' + this._getMessage()); - } - - // Query for a CONTENT child of type `ChildComponent` - @ContentChild(ChildComponent) contentChild: ChildComponent; - - // Query for a VIEW child of type`ChildComponent` - // No such VIEW child exists! - // This component holds content but no view of that type. - @ViewChild(ChildComponent) viewChild: ChildComponent; - - - ///// Hooks - ngAfterContentInit() { - // contentChild is set after the content has been initialized - this._logger.log('AfterContentInit: ' + this._getMessage()); - } - - ngAfterViewInit() { - this._logger.log(`AfterViewInit: There is ${this.viewChild ? 'a' : 'no'} view child`); - } - - private _prevHero:string; - ngAfterContentChecked() { - // contentChild is updated after the content has been checked - // Called frequently; only report when the hero changes - if (!this.contentChild || this._prevHero === this.contentChild.hero) {return;} - this._prevHero = this.contentChild.hero; - this._logger.log('AfterContentChecked: ' + this._getMessage()); - } - - private _getMessage(): string { - let cmp = this.contentChild; - return cmp ? `"${cmp.hero}" child content` : 'no child content'; - } - -} - -/***************************************/ - -@Component({ - selector: 'after-content-parent', - template: ` -
    -

    AfterContent

    - - - - - - - - -

    -- Lifecycle Hook Log --

    -
    {{msg}}
    -
    - `, - styles: ['.parent {background: powderblue; padding: 8px; margin:100px 8px;}'], - directives: [AfterContentComponent, ChildComponent], - providers:[LoggerService] -}) -export class AfterContentParentComponent { - - hookLog:string[]; - hero = 'Magneta'; - showChild = true; - - constructor(logger:LoggerService){ - this.hookLog = logger.logs; - } -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/after-view.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/after-view.component.ts deleted file mode 100644 index 47f12b53ae..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/after-view.component.ts +++ /dev/null @@ -1,80 +0,0 @@ -// #docregion -import { - Component, Input, Output, - AfterContentInit, ContentChild, - AfterViewChecked, AfterViewInit, ViewChild -} from 'angular2/core'; - -import {ChildComponent} from './child.component'; -import {LoggerService} from './logger.service'; - -@Component({ - selector: 'after-view-parent', - template: ` -
    -

    AfterView

    - -
    - - - - -
    - -

    -- Lifecycle Hook Log --

    -
    {{msg}}
    -
    - `, - styles: ['.parent {background: burlywood; padding: 8px; margin:100px 8px;}'], - directives: [ChildComponent], - providers:[LoggerService] -}) -export class AfterViewParentComponent - implements AfterContentInit, AfterViewChecked, AfterViewInit { - - private _logger:LoggerService; - - constructor(logger:LoggerService){ - this._logger = logger; - this.hookLog = logger.logs; - logger.log('AfterView ctor: ' + this._getMessage()); - } - - hookLog:string[]; - hero = 'Magneta'; - showChild = true; - - // Query for a CONTENT child of type `ChildComponent` - // No such CONTENT child exists! - // This component holds a view but no content of that type. - @ContentChild(ChildComponent) contentChild: ChildComponent; - - // Query for a VIEW child of type `ChildComponent` - @ViewChild(ChildComponent) viewChild: ChildComponent; - - - ///// Hooks - ngAfterContentInit() { - this._logger.log(`AfterContentInit: There is ${this.contentChild ? 'a' : 'no'} content child`); - } - - ngAfterViewInit() { - // viewChild is set after the view has been initialized - this._logger.log('AfterViewInit: ' + this._getMessage()); - } - - private _prevHero:string; - ngAfterViewChecked() { - // viewChild is updated after the view has been checked - // Called frequently; only report when the hero changes - if (!this.viewChild || this._prevHero === this.viewChild.hero) {return;} - this._prevHero = this.viewChild.hero; - this._logger.log('AfterViewChecked: ' + this._getMessage()); - } - - private _getMessage(): string { - let cmp = this.viewChild; - return cmp ? `"${cmp.hero}" child view` : 'no child view'; - } - -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/app.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/app.component.ts deleted file mode 100644 index 14f1bdab24..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/app.component.ts +++ /dev/null @@ -1,43 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -import {AfterContentParentComponent} from './after-content.component'; -import {AfterViewParentComponent} from './after-view.component'; -import {CounterParentComponent} from './counter.component'; -import {OnChangesParentComponent} from './on-changes.component'; -import {PeekABooParentComponent} from './peek-a-boo-parent.component'; -import {SpyParentComponent} from './spy.component'; - -/***************************************/ -/* - template: ` - - - - - - - `, - */ - -@Component({ - selector: 'my-app', - template: ` - - - - - - - `, - directives: [ - AfterContentParentComponent, - AfterViewParentComponent, - OnChangesParentComponent, - PeekABooParentComponent, - SpyParentComponent, - CounterParentComponent - ] -}) -export class AppComponent { -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/child.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/child.component.ts deleted file mode 100644 index a027d9180c..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/child.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import {Component, Input} from 'angular2/core'; - -@Component({ - selector: 'my-child', - template: ` -
    -
    -- child view begins --
    -
    {{hero}} is my hero.
    -
    -- child view ends --
    -
    - `, - styles: [ - '.child {background: Yellow; padding: 8px; }', - '.my-child {background: LightYellow; padding: 8px; margin-top: 8px}' - ] -}) -export class ChildComponent { - @Input() hero: string; -} \ No newline at end of file diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/counter.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/counter.component.ts deleted file mode 100644 index 7a502a25b0..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/counter.component.ts +++ /dev/null @@ -1,86 +0,0 @@ -// #docregion -import { - Component, Input, Output, - OnChanges, SimpleChange, -} from 'angular2/core'; - -import {Spy} from './spy.directive'; -import {LoggerService} from './logger.service'; - -@Component({ - selector: 'my-counter', - template: ` -
    - Counter = {{counter}} - -
    -- Counter Change Log --
    -
    {{chg}}
    -
    - `, - styles: ['.counter {background: LightYellow; padding: 8px; margin-top: 8px}'], - directives:[Spy] -}) -export class MyCounter implements OnChanges { - @Input() counter: number; - changeLog:string[] = []; - - ngOnChanges(changes: {[propertyName: string]: SimpleChange}) { - - // Empty the changeLog whenever counter goes to zero - // hint: this is a way to respond programmatically to external value changes. - if (this.counter === 0) { - this.changeLog.length = 0; - } - - // A change to `counter` is the only change we care about - let prop = changes['counter']; - let cur = prop.currentValue; - let prev = JSON.stringify(prop.previousValue); // first time is {}; after is integer - this.changeLog.push(`counter: currentValue = ${cur}, previousValue = ${prev}`); - } - -} - -/***************************************/ - -@Component({ - selector: 'counter-parent', - template: ` -
    -

    Counter Spy

    - - - - - - -

    -- Spy Lifecycle Hook Log --

    -
    {{msg}}
    -
    - `, - styles: ['.parent {background: gold; padding: 10px; margin:100px 8px;}'], - directives: [MyCounter], - providers: [LoggerService] -}) -export class CounterParentComponent { - value: number; - spyLog:string[] = []; - - private _logger:LoggerService; - - constructor(logger:LoggerService){ - this._logger = logger; - this.spyLog = logger.logs; - this.reset(); - } - - updateCounter() { - this.value += 1; - } - - reset(){ - this._logger.log('-- reset --'); - this.value=0; - } -} - diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/logger.service.ts b/public/docs/_examples/lifecycle-hooks/ts/app/logger.service.ts deleted file mode 100644 index 209bd6a2a5..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/logger.service.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {Injectable} from 'angular2/core'; - -@Injectable() -export class LoggerService { - logs:string[] = []; - - log(msg:string, noTick:boolean = false) { - if (!noTick) { this.tick(); } - this.logs.push(msg); - } - - clear() {this.logs.length = 0;} - - tick() { - setTimeout(() => { - // console.log('tick') - }, 0); - } -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/main.ts b/public/docs/_examples/lifecycle-hooks/ts/app/main.ts deleted file mode 100644 index 4651bd780a..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent).catch(err => console.error(err)); \ No newline at end of file diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/on-changes.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/on-changes.component.ts deleted file mode 100644 index 32a2185aba..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/on-changes.component.ts +++ /dev/null @@ -1,84 +0,0 @@ -// #docregion -import { - Component, Input, Output, - OnChanges, SimpleChange, -} from 'angular2/core'; - - -export class Hero { - constructor(public name:string){} -} - -@Component({ - selector: 'my-hero', - template: ` -
    -

    {{hero.name}} can {{power}}

    - -

    -- Change Log --

    -
    {{chg}}
    -
    - `, - styles: [ - '.hero {background: LightYellow; padding: 8px; margin-top: 8px}', - 'p {background: Yellow; padding: 8px; margin-top: 8px}' - ] -}) -export class MyHeroComponent implements OnChanges { - @Input() hero: Hero; - @Input() power: string; - @Input() reset: {}; - - changeLog:string[] = []; - - ngOnChanges(changes: {[propertyName: string]: SimpleChange}) { - - // Empty the changeLog whenever 'reset' property changes - // hint: this is a way to respond programmatically to external value changes. - if (changes['reset']) { this.changeLog.length = 0; } - - for (let propName in changes) { - let prop = changes[propName]; - let cur = JSON.stringify(prop.currentValue) - let prev = JSON.stringify(prop.previousValue); // first time is {}; after is integer - this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`); - } - } -} - -/***************************************/ - -@Component({ - selector: 'on-changes-parent', - template: ` -
    -

    OnChanges

    - -
    Hero.name: does NOT trigger onChanges
    -
    Power: DOES trigger onChanges
    -
    triggers onChanges and clears the change log
    - - -
    - `, - styles: ['.parent {background: Lavender; padding: 10px; margin:100px 8px;}'], - directives: [MyHeroComponent] -}) -export class OnChangesParentComponent { - hero:Hero; - power:string; - resetTrigger = false; - - constructor() { - this.reset(); - } - - reset(){ - // new Hero object every time; triggers onChange - this.hero = new Hero('Windstorm'); - // setting power only triggers onChange if this value is different - this.power = 'sing'; - // always triggers onChange ... which is interpreted as a reset - this.resetTrigger = !this.resetTrigger; - } -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/peek-a-boo-parent.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/peek-a-boo-parent.component.ts deleted file mode 100644 index 57e4754866..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/peek-a-boo-parent.component.ts +++ /dev/null @@ -1,54 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {PeekABooComponent} from './peek-a-boo.component' -import {LoggerService} from './logger.service'; - -@Component({ - selector: 'peek-a-boo-parent', - template: ` -
    -

    Peek-A-Boo

    - - - - - - - -

    -- Lifecycle Hook Log --

    -
    {{msg}}
    -
    - `, - styles: ['.parent {background: moccasin; padding: 10px; margin:100px 8px}'], - directives: [PeekABooComponent], - providers: [LoggerService] -}) -export class PeekABooParentComponent { - - hasChild = false; - hookLog:string[]; - - heroName = 'Windstorm'; - private _logger:LoggerService; - - constructor(logger:LoggerService){ - this._logger = logger; - this.hookLog = logger.logs; - } - - toggleChild() { - this.hasChild = !this.hasChild; - if (this.hasChild) { - this.heroName = 'Windstorm'; - this._logger.clear(); // clear log on create - } - this._logger.tick(); - } - - updateHero() { - this.heroName += '!'; - this._logger.tick(); - } -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/peek-a-boo.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/peek-a-boo.component.ts deleted file mode 100644 index 5800554cf4..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/peek-a-boo.component.ts +++ /dev/null @@ -1,98 +0,0 @@ -// #docregion -// #docregion lc-imports -import { - OnChanges, SimpleChange, - OnInit, - // DoCheck, // not demonstrated - AfterContentInit, - AfterContentChecked, - AfterViewInit, - AfterViewChecked, - OnDestroy -} from 'angular2/core'; -// #docregion lc-imports -import {Component, Input, Output} from 'angular2/core'; -import {LoggerService} from './logger.service'; - -let nextId = 1; - -@Component({ - selector: 'peek-a-boo', - template: '

    Now you see my hero, {{name}}

    ', - styles: ['p {background: LightYellow; padding: 8px}'] -}) -// Don't HAVE to mention the Lifecycle Hook interfaces -// unless we want typing and tool support. -export class PeekABooComponent - implements OnChanges, OnInit,AfterContentInit,AfterContentChecked, - AfterViewInit, AfterViewChecked, OnDestroy { - @Input() name:string; - - private _afterContentCheckedCounter = 1; - private _afterViewCheckedCounter = 1; - private _id = nextId++; - private _logger:LoggerService; - private _onChangesCounter = 1; - private _verb = 'initialized'; - - constructor(logger:LoggerService){ - this._logger = logger; - } - - // only called if there is an @input variable set by parent. - ngOnChanges(changes: {[propertyName: string]: SimpleChange}){ - let changesMsgs:string[] = [] - for (let propName in changes) { - if (propName === 'name') { - let name = changes['name'].currentValue; - changesMsgs.push(`name ${this._verb} to "${name}"`); - } else { - changesMsgs.push(propName + ' ' + this._verb); - } - } - this._logIt(`onChanges (${this._onChangesCounter++}): ${changesMsgs.join('; ')}`); - this._verb = 'changed'; // next time it will be a change - } - - ngOnInit() { - this._logIt(`onInit`); - } - - ngAfterContentInit(){ - this._logIt(`afterContentInit`); - } - - // Called after every change detection check - // of the component (directive) CONTENT - // Beware! Called frequently! - ngAfterContentChecked(){ - let counter = this._afterContentCheckedCounter++; - let msg = `afterContentChecked (${counter})`; - this._logIt(msg); - } - - ngAfterViewInit(){ - this._logIt(`afterViewInit`); - } - - // Called after every change detection check - // of the component (directive) VIEW - // Beware! Called frequently! - - ngAfterViewChecked(){ - let counter = this._afterViewCheckedCounter++; - let msg = `afterViewChecked (${counter})`; - this._logIt(msg); - } - - ngOnDestroy() { - this._logIt(`onDestroy`); - } - - private _logIt(msg:string){ - // Don't tick or else - // the AfterContentChecked and AfterViewChecked recurse. - // Let parent call tick() - this._logger.log(`#${this._id } ${msg}`, true); - } -} \ No newline at end of file diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/spy.component.ts b/public/docs/_examples/lifecycle-hooks/ts/app/spy.component.ts deleted file mode 100644 index 9a82b2faa8..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/spy.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {LoggerService} from './logger.service'; -import {Spy} from './spy.directive'; - -@Component({ - selector: 'spy-parent', - template: ` -
    -

    Spy Directive

    - - - - - -

    -
    - {{hero}} -
    - -

    -- Spy Lifecycle Hook Log --

    -
    {{msg}}
    -
    - `, - styles: [ - '.parent {background: khaki; padding: 10px; margin:100px 8px}', - '.heroes {background: LightYellow; padding: 0 8px}' - ], - directives: [Spy], - providers: [LoggerService] -}) -export class SpyParentComponent { - newName = 'Herbie'; - heroes:string[] = ['Windstorm', 'Magneta']; - spyLog:string[]; - - private _logger:LoggerService; - - constructor(logger:LoggerService){ - this._logger = logger; - this.spyLog = logger.logs; - } - - addHero() { - if (this.newName.trim()) { - this.heroes.push(this.newName.trim()); - this.newName = ''; - } - } - - reset(){ - this._logger.log('-- reset --'); - this.heroes.length = 0; - } -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/app/spy.directive.ts b/public/docs/_examples/lifecycle-hooks/ts/app/spy.directive.ts deleted file mode 100644 index 31c54ba9bc..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/app/spy.directive.ts +++ /dev/null @@ -1,33 +0,0 @@ -// #docregion -import {Directive, Input, - OnInit, OnDestroy} from 'angular2/core'; - -import {LoggerService} from './logger.service'; - -/***************************************/ -let nextId = 1; - -// Spy on any element to which it is applied. -// Usage:
    ...
    -@Directive({selector: '[my-spy]'}) -export class Spy implements OnInit, OnDestroy { - - private _id = nextId++; - private _logger:LoggerService; - - constructor(logger:LoggerService){ - this._logger = logger; - } - - ngOnInit() { - this._logIt(`onInit`); - } - - ngOnDestroy() { - this._logIt(`onDestroy`); - } - - private _logIt(msg:string){ - this._logger.log(`Spy #${this._id } ${msg}`); - } -} diff --git a/public/docs/_examples/lifecycle-hooks/ts/index.html b/public/docs/_examples/lifecycle-hooks/ts/index.html deleted file mode 100644 index a55cab995a..0000000000 --- a/public/docs/_examples/lifecycle-hooks/ts/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Angular 2 Lifecycle Hooks - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/lifecycle-hooks/ts/plnkr.json b/public/docs/_examples/lifecycle-hooks/ts/plnkr.json index 366b8325ce..49290aa804 100644 --- a/public/docs/_examples/lifecycle-hooks/ts/plnkr.json +++ b/public/docs/_examples/lifecycle-hooks/ts/plnkr.json @@ -1,7 +1,9 @@ { "description": "Lifecycle Hooks", + "basePath": "src/", "files":["!**/*.d.ts", "!**/*.js"], - "tags": ["lifecycle", "hooks", - "onInit", "onDestroy", "onChange", - "ngOnInit", "ngOnDestroy", "ngOnChange"] -} \ No newline at end of file + "tags": ["lifecycle", "hooks", + "OnInit", "OnDestroy", "OnChange", "DoCheck", + "AfterContentInit", "AfterContentChecked", + "AfterViewInit", "AfterViewChecked"] +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/after-content.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/after-content.component.ts new file mode 100644 index 0000000000..dfd2b80d24 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/after-content.component.ts @@ -0,0 +1,116 @@ +// #docplaster +// #docregion +import { AfterContentChecked, AfterContentInit, Component, ContentChild } from '@angular/core'; + +import { LoggerService } from './logger.service'; + +////////////////// +@Component({ + selector: 'my-child', + template: '' +}) +export class ChildComponent { + hero = 'Magneta'; +} + +////////////////////// +@Component({ + selector: 'after-content', +// #docregion template + template: ` +
    -- projected content begins --
    + +
    -- projected content ends --
    ` +// #enddocregion template + + ` +

    + {{comment}} +

    + ` +}) +// #docregion hooks +export class AfterContentComponent implements AfterContentChecked, AfterContentInit { + private prevHero = ''; + comment = ''; + + // Query for a CONTENT child of type `ChildComponent` + @ContentChild(ChildComponent) contentChild: ChildComponent; + +// #enddocregion hooks + constructor(private logger: LoggerService) { + this.logIt('AfterContent constructor'); + } + +// #docregion hooks + ngAfterContentInit() { + // contentChild is set after the content has been initialized + this.logIt('AfterContentInit'); + this.doSomething(); + } + + ngAfterContentChecked() { + // contentChild is updated after the content has been checked + if (this.prevHero === this.contentChild.hero) { + this.logIt('AfterContentChecked (no change)'); + } else { + this.prevHero = this.contentChild.hero; + this.logIt('AfterContentChecked'); + this.doSomething(); + } + } +// #enddocregion hooks +// #docregion do-something + + // This surrogate for real business logic sets the `comment` + private doSomething() { + this.comment = this.contentChild.hero.length > 10 ? `That's a long name` : ''; + } + + private logIt(method: string) { + let child = this.contentChild; + let message = `${method}: ${child ? child.hero : 'no'} child content`; + this.logger.log(message); + } +// #docregion hooks + // ... +} +// #enddocregion hooks + +////////////// +@Component({ + selector: 'after-content-parent', + template: ` +
    +

    AfterContent

    + +
    ` + +// #docregion parent-template + ` + + ` +// #enddocregion parent-template ++ `
    + +

    -- AfterContent Logs --

    +

    +
    {{msg}}
    +
    + `, + styles: ['.parent {background: burlywood}'], + providers: [LoggerService] +}) +export class AfterContentParentComponent { + logs: string[]; + show = true; + + constructor(private logger: LoggerService) { + this.logs = logger.logs; + } + + reset() { + this.logs.length = 0; + // quickly remove and reload AfterContentComponent which recreates it + this.show = false; + this.logger.tick_then(() => this.show = true); + } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/after-view.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/after-view.component.ts new file mode 100644 index 0000000000..71310e4530 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/after-view.component.ts @@ -0,0 +1,118 @@ +// #docplaster +// #docregion +import { AfterViewChecked, AfterViewInit, Component, ViewChild } from '@angular/core'; + +import { LoggerService } from './logger.service'; + +////////////////// +// #docregion child-view +@Component({ + selector: 'my-child-view', + template: '' +}) +export class ChildViewComponent { + hero = 'Magneta'; +} +// #enddocregion child-view + +////////////////////// +@Component({ + selector: 'after-view', +// #docregion template + template: ` +
    -- child view begins --
    + +
    -- child view ends --
    ` +// #enddocregion template + + ` +

    + {{comment}} +

    + ` +}) +// #docregion hooks +export class AfterViewComponent implements AfterViewChecked, AfterViewInit { + private prevHero = ''; + + // Query for a VIEW child of type `ChildViewComponent` + @ViewChild(ChildViewComponent) viewChild: ChildViewComponent; + +// #enddocregion hooks + constructor(private logger: LoggerService) { + this.logIt('AfterView constructor'); + } + +// #docregion hooks + ngAfterViewInit() { + // viewChild is set after the view has been initialized + this.logIt('AfterViewInit'); + this.doSomething(); + } + + ngAfterViewChecked() { + // viewChild is updated after the view has been checked + if (this.prevHero === this.viewChild.hero) { + this.logIt('AfterViewChecked (no change)'); + } else { + this.prevHero = this.viewChild.hero; + this.logIt('AfterViewChecked'); + this.doSomething(); + } + } +// #enddocregion hooks + + comment = ''; + +// #docregion do-something + // This surrogate for real business logic sets the `comment` + private doSomething() { + let c = this.viewChild.hero.length > 10 ? `That's a long name` : ''; + if (c !== this.comment) { + // Wait a tick because the component's view has already been checked + this.logger.tick_then(() => this.comment = c); + } + } +// #enddocregion do-something + + private logIt(method: string) { + let child = this.viewChild; + let message = `${method}: ${child ? child.hero : 'no'} child view`; + this.logger.log(message); + } +// #docregion hooks + // ... +} +// #enddocregion hooks + +////////////// +@Component({ + selector: 'after-view-parent', + template: ` +
    +

    AfterView

    + + + +

    -- AfterView Logs --

    +

    +
    {{msg}}
    +
    + `, + styles: ['.parent {background: burlywood}'], + providers: [LoggerService] +}) +export class AfterViewParentComponent { + logs: string[]; + show = true; + + constructor(private logger: LoggerService) { + this.logs = logger.logs; + } + + reset() { + this.logs.length = 0; + // quickly remove and reload AfterViewComponent which recreates it + this.show = false; + this.logger.tick_then(() => this.show = true); + } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/app.component.html b/public/docs/_examples/lifecycle-hooks/ts/src/app/app.component.html new file mode 100644 index 0000000000..d0692e28ac --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/app.component.html @@ -0,0 +1,37 @@ + +

    Component Lifecycle Hooks

    +Peek-a-boo: (most) lifecycle hooks
    +OnChanges
    +DoCheck
    +AfterViewInit & AfterViewChecked
    +AfterContentInit & AfterContentChecked
    +Spy: directive with OnInit & OnDestroy
    +Counter: OnChanges + Spy directive
    + + + +back to top + + + +back to top + + + +back to top + + + +back to top + + + +back to top + + + +back to top + + + +back to top diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/app.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/app.component.ts new file mode 100644 index 0000000000..5bd535a113 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/app.component.ts @@ -0,0 +1,7 @@ +// #docregion +import { Component } from '@angular/core'; +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/app.module.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/app.module.ts new file mode 100644 index 0000000000..4d9cabf218 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/app.module.ts @@ -0,0 +1,67 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; + +import { + AfterContentParentComponent, + AfterContentComponent, + ChildComponent +} from './after-content.component'; + +import { + AfterViewParentComponent, + AfterViewComponent, + ChildViewComponent +} from './after-view.component'; + +import { + CounterParentComponent, + MyCounterComponent +} from './counter.component'; + +import { + DoCheckParentComponent, + DoCheckComponent +} from './do-check.component'; + +import { + OnChangesParentComponent, + OnChangesComponent +} from './on-changes.component'; + +import { PeekABooParentComponent } from './peek-a-boo-parent.component'; +import { PeekABooComponent } from './peek-a-boo.component'; + +import { SpyParentComponent } from './spy.component'; +import { SpyDirective } from './spy.directive'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + AfterContentParentComponent, + AfterContentComponent, + ChildComponent, + AfterViewParentComponent, + AfterViewComponent, + ChildViewComponent, + CounterParentComponent, + MyCounterComponent, + DoCheckParentComponent, + DoCheckComponent, + OnChangesParentComponent, + OnChangesComponent, + PeekABooParentComponent, + PeekABooComponent, + SpyParentComponent, + SpyDirective + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/counter.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/counter.component.ts new file mode 100644 index 0000000000..8efd1fbd52 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/counter.component.ts @@ -0,0 +1,84 @@ +// #docregion +import { + Component, Input, + OnChanges, SimpleChanges, +} from '@angular/core'; + +import { LoggerService } from './logger.service'; + +@Component({ + selector: 'my-counter', + template: ` +
    + Counter = {{counter}} + +
    -- Counter Change Log --
    +
    {{chg}}
    +
    + `, + styles: ['.counter {background: LightYellow; padding: 8px; margin-top: 8px}'] +}) +export class MyCounterComponent implements OnChanges { + @Input() counter: number; + changeLog: string[] = []; + + ngOnChanges(changes: SimpleChanges) { + + // Empty the changeLog whenever counter goes to zero + // hint: this is a way to respond programmatically to external value changes. + if (this.counter === 0) { + this.changeLog.length = 0; + } + + // A change to `counter` is the only change we care about + let chng = changes['counter']; + let cur = chng.currentValue; + let prev = JSON.stringify(chng.previousValue); // first time is {}; after is integer + this.changeLog.push(`counter: currentValue = ${cur}, previousValue = ${prev}`); + } +} + +/***************************************/ + +@Component({ + selector: 'counter-parent', + template: ` +
    +

    Counter Spy

    + + + + + + +

    -- Spy Lifecycle Hook Log --

    +
    {{msg}}
    +
    + `, + styles: ['.parent {background: gold;}'], + providers: [LoggerService] +}) +export class CounterParentComponent { + value: number; + spyLog: string[] = []; + + private logger: LoggerService; + + constructor(logger: LoggerService) { + this.logger = logger; + this.spyLog = logger.logs; + this.reset(); + } + + updateCounter() { + this.value += 1; + this.logger.tick(); + } + + reset() { + this.logger.log('-- reset --'); + this.value = 0; + this.logger.tick(); + } +} + diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/do-check-parent.component.html b/public/docs/_examples/lifecycle-hooks/ts/src/app/do-check-parent.component.html new file mode 100644 index 0000000000..cf7c2b91ce --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/do-check-parent.component.html @@ -0,0 +1,13 @@ +
    +

    {{title}}

    + + + + +
    Power:
    Hero.name:
    +

    + + + + +
    diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/do-check.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/do-check.component.ts new file mode 100644 index 0000000000..6196dd8edd --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/do-check.component.ts @@ -0,0 +1,95 @@ +/* tslint:disable:forin */ +// #docregion +import { Component, DoCheck, Input, ViewChild } from '@angular/core'; + +class Hero { + constructor(public name: string) {} +} + +@Component({ + selector: 'do-check', + template: ` +
    +

    {{hero.name}} can {{power}}

    + +

    -- Change Log --

    +
    {{chg}}
    +
    + `, + styles: [ + '.hero {background: LightYellow; padding: 8px; margin-top: 8px}', + 'p {background: Yellow; padding: 8px; margin-top: 8px}' + ] +}) +export class DoCheckComponent implements DoCheck { + @Input() hero: Hero; + @Input() power: string; + + changeDetected = false; + changeLog: string[] = []; + oldHeroName = ''; + oldPower = ''; + oldLogLength = 0; + noChangeCount = 0; + + // #docregion ng-do-check + ngDoCheck() { + + if (this.hero.name !== this.oldHeroName) { + this.changeDetected = true; + this.changeLog.push(`DoCheck: Hero name changed to "${this.hero.name}" from "${this.oldHeroName}"`); + this.oldHeroName = this.hero.name; + } + + if (this.power !== this.oldPower) { + this.changeDetected = true; + this.changeLog.push(`DoCheck: Power changed to "${this.power}" from "${this.oldPower}"`); + this.oldPower = this.power; + } + + if (this.changeDetected) { + this.noChangeCount = 0; + } else { + // log that hook was called when there was no relevant change. + let count = this.noChangeCount += 1; + let noChangeMsg = `DoCheck called ${count}x when no change to hero or power`; + if (count === 1) { + // add new "no change" message + this.changeLog.push(noChangeMsg); + } else { + // update last "no change" message + this.changeLog[this.changeLog.length - 1] = noChangeMsg; + } + } + + this.changeDetected = false; + } + // #enddocregion ng-do-check + + reset() { + this.changeDetected = true; + this.changeLog.length = 0; + } +} + +/***************************************/ + +@Component({ + selector: 'do-check-parent', + templateUrl: './do-check-parent.component.html', + styles: ['.parent {background: Lavender}'] +}) +export class DoCheckParentComponent { + hero: Hero; + power: string; + title = 'DoCheck'; + @ViewChild(DoCheckComponent) childView: DoCheckComponent; + + constructor() { this.reset(); } + + reset() { + this.hero = new Hero('Windstorm'); + this.power = 'sing'; + if (this.childView) { this.childView.reset(); } + } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/logger.service.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/logger.service.ts new file mode 100644 index 0000000000..56ddaf9063 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/logger.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class LoggerService { + logs: string[] = []; + prevMsg = ''; + prevMsgCount = 1; + + log(msg: string) { + if (msg === this.prevMsg) { + // Repeat message; update last log entry with count. + this.logs[this.logs.length - 1] = msg + ` (${this.prevMsgCount += 1}x)`; + } else { + // New message; log it. + this.prevMsg = msg; + this.prevMsgCount = 1; + this.logs.push(msg); + } + } + + clear() { this.logs.length = 0; } + + // schedules a view refresh to ensure display catches up + tick() { this.tick_then(() => { }); } + tick_then(fn: () => any) { setTimeout(fn, 0); } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/on-changes-parent.component.html b/public/docs/_examples/lifecycle-hooks/ts/src/app/on-changes-parent.component.html new file mode 100644 index 0000000000..a0fd404931 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/on-changes-parent.component.html @@ -0,0 +1,13 @@ +
    +

    {{title}}

    + + + + +
    Power:
    Hero.name:
    +

    + + + + +
    diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/on-changes.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/on-changes.component.ts new file mode 100644 index 0000000000..a5a49a61e9 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/on-changes.component.ts @@ -0,0 +1,73 @@ +/* tslint:disable:forin */ +// #docregion +import { + Component, Input, OnChanges, + SimpleChanges, ViewChild +} from '@angular/core'; + +class Hero { + constructor(public name: string) {} +} + +@Component({ + selector: 'on-changes', + template: ` +
    +

    {{hero.name}} can {{power}}

    + +

    -- Change Log --

    +
    {{chg}}
    +
    + `, + styles: [ + '.hero {background: LightYellow; padding: 8px; margin-top: 8px}', + 'p {background: Yellow; padding: 8px; margin-top: 8px}' + ] +}) +export class OnChangesComponent implements OnChanges { +// #docregion inputs + @Input() hero: Hero; + @Input() power: string; +// #enddocregion inputs + + changeLog: string[] = []; + + // #docregion ng-on-changes + ngOnChanges(changes: SimpleChanges) { + for (let propName in changes) { + let chng = changes[propName]; + let cur = JSON.stringify(chng.currentValue); + let prev = JSON.stringify(chng.previousValue); + this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`); + } + } + // #enddocregion ng-on-changes + + reset() { this.changeLog.length = 0; } +} + +/***************************************/ + +@Component({ + selector: 'on-changes-parent', + templateUrl: './on-changes-parent.component.html', + styles: ['.parent {background: Lavender;}'] +}) +export class OnChangesParentComponent { + hero: Hero; + power: string; + title = 'OnChanges'; + @ViewChild(OnChangesComponent) childView: OnChangesComponent; + + constructor() { + this.reset(); + } + + reset() { + // new Hero object every time; triggers onChanges + this.hero = new Hero('Windstorm'); + // setting power only triggers onChanges if this value is different + this.power = 'sing'; + if (this.childView) { this.childView.reset(); } + } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/peek-a-boo-parent.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/peek-a-boo-parent.component.ts new file mode 100644 index 0000000000..3f2bd8585d --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/peek-a-boo-parent.component.ts @@ -0,0 +1,53 @@ +// #docregion +import { Component } from '@angular/core'; + +import { LoggerService } from './logger.service'; + +@Component({ + selector: 'peek-a-boo-parent', + template: ` +
    +

    Peek-A-Boo

    + + + + + + + +

    -- Lifecycle Hook Log --

    +
    {{msg}}
    +
    + `, + styles: ['.parent {background: moccasin}'], + providers: [ LoggerService ] +}) +export class PeekABooParentComponent { + + hasChild = false; + hookLog: string[]; + + heroName = 'Windstorm'; + private logger: LoggerService; + + constructor(logger: LoggerService) { + this.logger = logger; + this.hookLog = logger.logs; + } + + toggleChild() { + this.hasChild = !this.hasChild; + if (this.hasChild) { + this.heroName = 'Windstorm'; + this.logger.clear(); // clear log on create + } + this.logger.tick(); + } + + updateHero() { + this.heroName += '!'; + this.logger.tick(); + } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/peek-a-boo.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/peek-a-boo.component.ts new file mode 100644 index 0000000000..dcee428753 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/peek-a-boo.component.ts @@ -0,0 +1,85 @@ +import { + AfterContentChecked, + AfterContentInit, + AfterViewChecked, + AfterViewInit, + DoCheck, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges +} from '@angular/core'; +import { Component, Input } from '@angular/core'; +import { LoggerService } from './logger.service'; + +let nextId = 1; + +// #docregion ngOnInit +export class PeekABoo implements OnInit { + constructor(private logger: LoggerService) { } + + // implement OnInit's `ngOnInit` method + ngOnInit() { this.logIt(`OnInit`); } + + logIt(msg: string) { + this.logger.log(`#${nextId++} ${msg}`); + } +} +// #enddocregion ngOnInit + +@Component({ + selector: 'peek-a-boo', + template: '

    Now you see my hero, {{name}}

    ', + styles: ['p {background: LightYellow; padding: 8px}'] +}) +// Don't HAVE to mention the Lifecycle Hook interfaces +// unless we want typing and tool support. +export class PeekABooComponent extends PeekABoo implements + OnChanges, OnInit, DoCheck, + AfterContentInit, AfterContentChecked, + AfterViewInit, AfterViewChecked, + OnDestroy { + @Input() name: string; + + private verb = 'initialized'; + + constructor(logger: LoggerService) { + super(logger); + + let is = this.name ? 'is' : 'is not'; + this.logIt(`name ${is} known at construction`); + } + + // only called for/if there is an @input variable set by parent. + ngOnChanges(changes: SimpleChanges) { + let changesMsgs: string[] = []; + for (let propName in changes) { + if (propName === 'name') { + let name = changes['name'].currentValue; + changesMsgs.push(`name ${this.verb} to "${name}"`); + } else { + changesMsgs.push(propName + ' ' + this.verb); + } + } + this.logIt(`OnChanges: ${changesMsgs.join('; ')}`); + this.verb = 'changed'; // next time it will be a change + } + + // Beware! Called frequently! + // Called in every change detection cycle anywhere on the page + ngDoCheck() { this.logIt(`DoCheck`); } + + ngAfterContentInit() { this.logIt(`AfterContentInit`); } + + // Beware! Called frequently! + // Called in every change detection cycle anywhere on the page + ngAfterContentChecked() { this.logIt(`AfterContentChecked`); } + + ngAfterViewInit() { this.logIt(`AfterViewInit`); } + + // Beware! Called frequently! + // Called in every change detection cycle anywhere on the page + ngAfterViewChecked() { this.logIt(`AfterViewChecked`); } + + ngOnDestroy() { this.logIt(`OnDestroy`); } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.component.html b/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.component.html new file mode 100644 index 0000000000..782435b961 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.component.html @@ -0,0 +1,16 @@ +
    +

    Spy Directive

    + + + + + +

    + +
    + {{hero}} +
    + +

    -- Spy Lifecycle Hook Log --

    +
    {{msg}}
    +
    diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.component.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.component.ts new file mode 100644 index 0000000000..0f3b0d35f1 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.component.ts @@ -0,0 +1,40 @@ +// #docregion +import { Component } from '@angular/core'; + +import { LoggerService } from './logger.service'; + +@Component({ + selector: 'spy-parent', + templateUrl: './spy.component.html', + styles: [ + '.parent {background: khaki;}', + '.heroes {background: LightYellow; padding: 0 8px}' + ], + providers: [LoggerService] +}) +export class SpyParentComponent { + newName = 'Herbie'; + heroes: string[] = ['Windstorm', 'Magneta']; + spyLog: string[]; + + constructor(private logger: LoggerService) { + this.spyLog = logger.logs; + } + + addHero() { + if (this.newName.trim()) { + this.heroes.push(this.newName.trim()); + this.newName = ''; + this.logger.tick(); + } + } + removeHero(hero: string) { + this.heroes.splice(this.heroes.indexOf(hero), 1); + this.logger.tick(); + } + reset() { + this.logger.log('-- reset --'); + this.heroes.length = 0; + this.logger.tick(); + } +} diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.directive.ts b/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.directive.ts new file mode 100644 index 0000000000..01f3f95880 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/app/spy.directive.ts @@ -0,0 +1,24 @@ +// #docregion +import { Directive, OnInit, OnDestroy } from '@angular/core'; + +import { LoggerService } from './logger.service'; + +let nextId = 1; + +// #docregion spy-directive +// Spy on any element to which it is applied. +// Usage:
    ...
    +@Directive({selector: '[mySpy]'}) +export class SpyDirective implements OnInit, OnDestroy { + + constructor(private logger: LoggerService) { } + + ngOnInit() { this.logIt(`onInit`); } + + ngOnDestroy() { this.logIt(`onDestroy`); } + + private logIt(msg: string) { + this.logger.log(`Spy #${nextId++} ${msg}`); + } +} +// #enddocregion spy-directive diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/index.html b/public/docs/_examples/lifecycle-hooks/ts/src/index.html new file mode 100644 index 0000000000..cf7059f780 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/index.html @@ -0,0 +1,28 @@ + + + + + Angular Lifecycle Hooks + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/main.ts b/public/docs/_examples/lifecycle-hooks/ts/src/main.ts new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/main.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/lifecycle-hooks/ts/src/sample.css b/public/docs/_examples/lifecycle-hooks/ts/src/sample.css new file mode 100644 index 0000000000..df17c897c6 --- /dev/null +++ b/public/docs/_examples/lifecycle-hooks/ts/src/sample.css @@ -0,0 +1,13 @@ +.parent { + color: #666; + margin: 14px 0; + padding: 8px; +} +input { + margin: 4px; + padding: 4px; +} +.comment { + color: red; + font-style: italic; +} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/.gitkeep b/public/docs/_examples/ngcontainer/ts/example-config.json similarity index 100% rename from public/docs/_examples/upgrade/ts/typescript-conversion/app/img/.gitkeep rename to public/docs/_examples/ngcontainer/ts/example-config.json diff --git a/public/docs/_examples/ngcontainer/ts/plnkr.json b/public/docs/_examples/ngcontainer/ts/plnkr.json new file mode 100644 index 0000000000..a6cdc4ba1a --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/plnkr.json @@ -0,0 +1,11 @@ +{ + "description": "", + "basePath": "src/", + "files": [ + "!**/*.d.ts", + "!**/*.js" + ], + "tags": [ + "ngcontainer", "structural", "directives" + ] +} diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.component.css b/public/docs/_examples/ngcontainer/ts/src/app/app.component.css new file mode 100644 index 0000000000..953ed3c39d --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.component.css @@ -0,0 +1,34 @@ +/* #docregion */ +button { + min-width: 100px; + font-size: 100%; +} + +code, .code { + background-color: #eee; + color: black; + font-family: Courier, sans-serif; + font-size: 85%; +} + +div.code { + width: 400px; +} + +.heroic { + font-size: 150%; + font-weight: bold; +} + +hr { + margin: 40px 0 +} + +td, th { + text-align: left; + vertical-align: top; +} + +/* #docregion p-span */ +p span { color: red; font-size: 70%; } +/* #enddocregion p-span */ diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.component.html b/public/docs/_examples/ngcontainer/ts/src/app/app.component.html new file mode 100644 index 0000000000..afd0b00f36 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.component.html @@ -0,0 +1,279 @@ + + +

    <ng-container>

    + + +
    {{hero.name}}
    + + +
    + +

    <ng-container> and CSS

    +

    Examples demonstrating issues with rigid CSS styles.

    + + + +

    #1 <ng-container> and <p>

    + +

    + I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

    + + +

    + I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

    + + +

    #2 <ng-container> and <p>

    + +
    + +

    + {{hero.name}} is + + , + and + {{trait}} + . +

    + + + +

    + {{hero.name}} is + + , + and + {{trait}} + . +

    + + +
    + +

    #3 <ng-container> and <p>

    + +

    + +

    + + +
    + The hero.id in the <span> + is caught by the p-span CSS: + +

    + + Id: ({{hero.id}}) + + Name: {{hero.name}} +

    + +
    + +
    + The hero.id in the <ng-container> + is unaffected by the p-span CSS: +

    + + Id: ({{hero.id}}) + + Name: {{hero.name}} +

    +
    + +
    + The hero.id in the <template *ngIf> disappears: +

    + + Name: {{hero.name}} +

    +
    + +
    + The hero.id in the <template [ngIf]> + is unaffected by the p-span CSS: +

    + + Name: {{hero.name}} +

    +
    + +
    + +
    + +

    <ng-container> and layout-sensitive elements

    +

    + Examples demonstrating issues with layout-sensitive elements + such as <select> and <table>. +

    + +

    #1 <ng-container> and <options>

    + +

    <select> with <span>

    +
    + Pick your favorite hero + () +
    + + + + +

    <select> with <ng-container>

    +
    + Pick your favorite hero + () +
    + + + + +



    + +

    #2 <ng-container> and <options>

    +

    + +

    + +

    Options with <ng-container>

    + + + + +

    Options with <span>

    + + + + +
    + +

    <ng-container> and <table>

    +

    + + + +

    + + + + + + + + + + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveTypeDescription
    NgClassAAdd or remove multiple CSS classes.
    xxxSdiv with *ngIf formats crazy.
    yyySdiv with *ngIf formats crazy.
    NgForSRepeat the template for each item in a list.
    NgIfSAdd or remove DOM elements.
    NgStyleAAdd or remove multiple style attributes.
    NgSwitchSInclude in DOM if case matches the switch value.
    + +
    + +

    Do not confuse <ng-container> with <ng-content>

    + +

    <ng-container>Inside ng-container</ng-container>

    + +Inside ng-container + + +

    <ng-content>this is an Angular parse error</ng-content>

    + + + +
    Template parse errors:
    +<ng-content> element cannot have content.
    + +

    Demo of </ng-content>

    + + + Projected content + + diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.component.ts b/public/docs/_examples/ngcontainer/ts/src/app/app.component.ts new file mode 100644 index 0000000000..65c511acd2 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.component.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component } from '@angular/core'; + +import { heroes } from './hero'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] +}) +export class AppComponent { + heroes = heroes; + hero = this.heroes[0]; + heroTraits = [ 'honest', 'brave', 'considerate' ]; + + // flags for the table + attrDirs = true; + strucDirs = true; + divNgIf = false; + + showId = true; + showDefaultTraits = true; + showSad = true; +} diff --git a/public/docs/_examples/ngcontainer/ts/src/app/app.module.ts b/public/docs/_examples/ngcontainer/ts/src/app/app.module.ts new file mode 100644 index 0000000000..57ac92f518 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/app.module.ts @@ -0,0 +1,19 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ContentComponent } from './content.component'; +import { heroComponents } from './hero.components'; + +@NgModule({ + imports: [ BrowserModule, FormsModule ], + declarations: [ + AppComponent, + ContentComponent, + heroComponents + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/ngcontainer/ts/src/app/content.component.ts b/public/docs/_examples/ngcontainer/ts/src/app/content.component.ts new file mode 100644 index 0000000000..63c5646f99 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/content.component.ts @@ -0,0 +1,16 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'content-comp', + // #docregion template + template: + `
    + +
    `, + // #enddocregion template + styles: [ ` + div { border: medium dashed green; padding: 1em; width: 150px; text-align: center} + `] +}) +export class ContentComponent { } diff --git a/public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts b/public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts new file mode 100644 index 0000000000..43e400ed8e --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/hero.components.ts @@ -0,0 +1,43 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'happy-hero', + template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.` +}) +export class HappyHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'sad-hero', + template: `You like {{hero.name}}? Such a sad hero. Are you sad too?` +}) +export class SadHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'confused-hero', + template: `Are you as confused as {{hero.name}}?` +}) +export class ConfusedHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'unknown-hero', + template: `{{message}}` +}) +export class UnknownHeroComponent { + @Input() hero: Hero; + get message() { + return this.hero && this.hero.name ? + `${this.hero.name} is strange and mysterious.` : + 'Are you feeling indecisive?'; + } +} + +export const heroComponents = + [ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ]; diff --git a/public/docs/_examples/ngcontainer/ts/src/app/hero.ts b/public/docs/_examples/ngcontainer/ts/src/app/hero.ts new file mode 100644 index 0000000000..a1de3b3b82 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/app/hero.ts @@ -0,0 +1,13 @@ +// #docregion +export class Hero { + id: number; + name: string; + emotion?: string; +} + +export const heroes: Hero[] = [ + { id: 1, name: 'Mr. Nice', emotion: 'happy'}, + { id: 2, name: 'Narco', emotion: 'sad' }, + { id: 3, name: 'Windstorm', emotion: 'confused' }, + { id: 4, name: 'Magneta'} +]; diff --git a/public/docs/_examples/ngcontainer/ts/src/index.html b/public/docs/_examples/ngcontainer/ts/src/index.html new file mode 100644 index 0000000000..fc5ff417c3 --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + Angular <ng-container> + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/ngcontainer/ts/src/main.ts b/public/docs/_examples/ngcontainer/ts/src/main.ts new file mode 100644 index 0000000000..105b06712d --- /dev/null +++ b/public/docs/_examples/ngcontainer/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); + diff --git a/public/docs/_examples/ngmodule/e2e-spec.ts b/public/docs/_examples/ngmodule/e2e-spec.ts new file mode 100644 index 0000000000..0fbce1213d --- /dev/null +++ b/public/docs/_examples/ngmodule/e2e-spec.ts @@ -0,0 +1,223 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('NgModule', function () { + + // helpers + const gold = 'rgba(255, 215, 0, 1)'; + const powderblue = 'rgba(176, 224, 230, 1)'; + const lightgray = 'rgba(211, 211, 211, 1)'; + const white = 'rgba(0, 0, 0, 0)'; + + function getCommonsSectionStruct() { + const buttons = element.all(by.css('nav a')); + + return { + title: element.all(by.tagName('h1')).get(0), + subtitle: element.all(by.css('app-title p i')).get(0), + contactButton: buttons.get(0), + crisisButton: buttons.get(1), + heroesButton: buttons.get(2) + }; + } + + function getContactSectionStruct() { + const buttons = element.all(by.css('app-contact form button')); + + return { + header: element.all(by.css('app-contact h2')).get(0), + popupMessage: element.all(by.css('app-contact div')).get(0), + contactNameHeader: element.all(by.css('app-contact form h3')).get(0), + input: element.all(by.css('app-contact form input')).get(0), + validationError: element.all(by.css('app-contact form .alert')).get(0), + saveButton: buttons.get(0), // can't be tested + nextContactButton: buttons.get(1), + newContactButton: buttons.get(2) + }; + } + + function getCrisisSectionStruct() { + return { + title: element.all(by.css('ng-component h3')).get(0), + items: element.all(by.css('ng-component a')), + itemId: element.all(by.css('ng-component div')).get(0), + listLink: element.all(by.css('ng-component a')).get(0), + }; + } + + function getHeroesSectionStruct() { + return { + header: element.all(by.css('ng-component h2')).get(0), + title: element.all(by.css('ng-component h3')).get(0), + items: element.all(by.css('ng-component a')), + itemId: element.all(by.css('ng-component ng-component div div')).get(0), + itemInput: element.all(by.css('ng-component ng-component input')).get(0), + listLink: element.all(by.css('ng-component ng-component a')).get(0), + }; + } + + // tests + function appTitleTests(color: string, name?: string) { + return function() { + it('should have a gray header', function() { + const commons = getCommonsSectionStruct(); + expect(commons.title.getCssValue('backgroundColor')).toBe(color); + }); + + it('should welcome us', function () { + const commons = getCommonsSectionStruct(); + expect(commons.subtitle.getText()).toBe('Welcome, ' + (name || 'Sherlock Holmes')); + }); + }; + } + + function contactTests(color: string, name?: string) { + return function() { + it('shows the contact\'s owner', function() { + const contacts = getContactSectionStruct(); + expect(contacts.header.getText()).toBe('Contact of ' + (name || 'Sherlock Holmes')); + }); + + it('can cycle between contacts', function () { + const contacts = getContactSectionStruct(); + const nextButton = contacts.nextContactButton; + expect(contacts.contactNameHeader.getText()).toBe('Awesome Sam Spade'); + expect(contacts.contactNameHeader.getCssValue('backgroundColor')).toBe(color); + nextButton.click().then(function () { + expect(contacts.contactNameHeader.getText()).toBe('Awesome Nick Danger'); + return nextButton.click(); + }).then(function () { + expect(contacts.contactNameHeader.getText()).toBe('Awesome Nancy Drew'); + }); + }); + + it('can change an existing contact', function () { + const contacts = getContactSectionStruct(); + contacts.input.sendKeys('a'); + expect(contacts.input.getCssValue('backgroundColor')).toBe(color); + expect(contacts.contactNameHeader.getText()).toBe('Awesome Sam Spadea'); + }); + + it('can create a new contact', function () { + const contacts = getContactSectionStruct(); + const newContactButton = contacts.newContactButton; + newContactButton.click().then(function () { + expect(contacts.validationError.getText()).toBe('Name is required'); + contacts.input.sendKeys('John Doe'); + expect(contacts.contactNameHeader.getText()).toBe('Awesome John Doe'); + expect(contacts.validationError.getText()).toBe(''); + }); + }); + }; + } + + describe('index.html', function () { + beforeEach(function () { + browser.get(''); + }); + + describe('app-title', appTitleTests(white, 'Miss Marple')); + + describe('contact', contactTests(lightgray, 'Miss Marple')); + + describe('crisis center', function () { + beforeEach(function () { + getCommonsSectionStruct().crisisButton.click(); + }); + + it('shows a list of crisis', function () { + const crisis = getCrisisSectionStruct(); + expect(crisis.title.getText()).toBe('Crisis List'); + expect(crisis.items.count()).toBe(4); + expect(crisis.items.get(0).getText()).toBe('1 - Dragon Burning Cities'); + }); + + it('can navigate to one crisis details', function () { + const crisis = getCrisisSectionStruct(); + crisis.items.get(0).click().then(function() { + expect(crisis.itemId.getText()).toBe('Crisis id: 1'); + return crisis.listLink.click(); + }).then(function () { + // We are back to the list + expect(crisis.items.count()).toBe(4); + }); + }); + }); + + describe('heroes', function () { + beforeEach(function () { + getCommonsSectionStruct().heroesButton.click(); + }); + + it('shows a list of heroes', function() { + const heroes = getHeroesSectionStruct(); + expect(heroes.header.getText()).toBe('Heroes of Miss Marple'); + expect(heroes.title.getText()).toBe('Hero List'); + expect(heroes.items.count()).toBe(6); + expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice'); + }); + + it('can navigate and edit one hero details', function () { + const heroes = getHeroesSectionStruct(); + heroes.items.get(0).click().then(function () { + expect(heroes.itemId.getText()).toBe('Id: 11'); + heroes.itemInput.sendKeys(' try'); + return heroes.listLink.click(); + }).then(function () { + // We are back to the list + expect(heroes.items.count()).toBe(6); + expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice try'); + }); + }); + }); + }); + + describe('index.0.html', function() { + beforeEach(function () { + browser.get('index.0.html'); + }); + + it('has a title', function () { + const title = element.all(by.tagName('h1')).get(0); + expect(title.getText()).toBe('Minimal NgModule'); + }); + }); + + describe('index.1.html', function () { + beforeEach(function () { + browser.get('index.1.html'); + }); + + describe('app-title', appTitleTests(powderblue)); + }); + + describe('index.1b.html', function () { + beforeEach(function () { + browser.get('index.1b.html'); + }); + + describe('app-title', appTitleTests(powderblue)); + + describe('contact', contactTests(powderblue)); + }); + + describe('index.2.html', function () { + beforeEach(function () { + browser.get('index.2.html'); + }); + + describe('app-title', appTitleTests(gold)); + + describe('contact', contactTests(powderblue)); + }); + + describe('index.3.html', function () { + beforeEach(function () { + browser.get('index.3.html'); + }); + + describe('app-title', appTitleTests(gold)); + }); + +}); diff --git a/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json b/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json new file mode 100644 index 0000000000..0f61c91f75 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/contact.1b.plnkr.json @@ -0,0 +1,25 @@ +{ + "description": "Contact NgModule v.1", + "basePath": "src/", + "files": [ + "app/app.component.1b.ts", + "app/app.module.1b.ts", + "app/highlight.directive.ts", + "app/title.component.html", + "app/title.component.ts", + "app/user.service.ts", + + "app/contact/awesome.pipe.ts", + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.component.3.ts", + "app/contact/contact.service.ts", + "app/contact/highlight.directive.ts", + + "main.1b.ts", + "styles.css", + "index.1b.html" + ], + "main": "index.1b.html", + "tags": ["NgModule"] +} diff --git a/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json b/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json new file mode 100644 index 0000000000..6555b76dcd --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/contact.2.plnkr.json @@ -0,0 +1,27 @@ +{ + "description": "Contact NgModule v.2", + "basePath": "src/", + "files": [ + "app/app.component.2.ts", + "app/app.module.2.ts", + "app/highlight.directive.ts", + "app/title.component.html", + "app/title.component.ts", + "app/user.service.ts", + + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.service.ts", + + "app/contact/awesome.pipe.ts", + "app/contact/contact.component.3.ts", + "app/contact/contact.module.2.ts", + "app/contact/highlight.directive.ts", + + "main.2.ts", + "styles.css", + "index.2.html" + ], + "main": "index.2.html", + "tags": ["NgModule"] +} diff --git a/public/docs/_examples/ngmodule/ts/example-config.json b/public/docs/_examples/ngmodule/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/ngmodule/ts/minimal.0.plnkr.json b/public/docs/_examples/ngmodule/ts/minimal.0.plnkr.json new file mode 100644 index 0000000000..e5e37ac4ee --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/minimal.0.plnkr.json @@ -0,0 +1,13 @@ +{ + "description": "Minimal NgModule", + "basePath": "src/", + "files": [ + "app/app.component.0.ts", + "app/app.module.0.ts", + "main.0.ts", + "styles.css", + "index.0.html" + ], + "main": "index.0.html", + "tags": ["NgModule"] +} diff --git a/public/docs/_examples/ngmodule/ts/plnkr.json b/public/docs/_examples/ngmodule/ts/plnkr.json new file mode 100644 index 0000000000..4d9d2ec20b --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/plnkr.json @@ -0,0 +1,41 @@ +{ + "description": "NgModule Final", + "basePath": "src/", + "files": [ + "app/app.component.ts", + "app/app.module.ts", + "app/app-routing.module.ts", + + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.service.ts", + + "app/contact/contact.component.ts", + "app/contact/contact.module.ts", + "app/contact/contact-routing.module.ts", + + "app/crisis/*.ts", + + "app/hero/hero-detail.component.ts", + "app/hero/hero-list.component.ts", + "app/hero/hero.service.ts", + + "app/hero/hero.component.ts", + "app/hero/hero.module.ts", + "app/hero/hero-routing.module.ts", + + "app/core/*.css", + "app/core/*.html", + "app/core/*.ts", + + "app/shared/*.css", + "app/shared/*.html", + "app/shared/*.ts", + + "main.ts", + "styles.css", + "index.html" + ], + "main": "index.html", + "tags": ["NgModule"] +} diff --git a/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json b/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json new file mode 100644 index 0000000000..9747801604 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/pre-shared.3.plnkr.json @@ -0,0 +1,41 @@ +{ + "description": "NgModule v.3", + "basePath": "src/", + "files": [ + "app/app.component.3.ts", + "app/app.module.3.ts", + "app/app-routing.module.3.ts", + + "app/highlight.directive.ts", + "app/title.component.html", + "app/title.component.ts", + "app/user.service.ts", + + "app/contact/contact.component.css", + "app/contact/contact.component.html", + "app/contact/contact.service.ts", + + "app/contact/awesome.pipe.ts", + "app/contact/contact.component.3.ts", + "app/contact/contact.module.3.ts", + "app/contact/contact-routing.module.3.ts", + "app/contact/highlight.directive.ts", + + "app/crisis/*.ts", + + "app/hero/hero-detail.component.ts", + "app/hero/hero-list.component.ts", + "app/hero/hero.service.ts", + + "app/hero/hero.component.3.ts", + "app/hero/hero.module.3.ts", + "app/hero/hero-routing.module.3.ts", + "app/hero/highlight.directive.ts", + + "main.3.ts", + "styles.css", + "index.3.html" + ], + "main": "index.3.html", + "tags": ["NgModule"] +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app-routing.module.3.ts b/public/docs/_examples/ngmodule/ts/src/app/app-routing.module.3.ts new file mode 100644 index 0000000000..1d53b708f8 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app-routing.module.3.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +export const routes: Routes = [ + { path: '', redirectTo: 'contact', pathMatch: 'full'}, + { path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' }, + { path: 'heroes', loadChildren: 'app/hero/hero.module.3#HeroModule' } +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app-routing.module.ts b/public/docs/_examples/ngmodule/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..c753dcd488 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app-routing.module.ts @@ -0,0 +1,19 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; + +export const routes: Routes = [ + { path: '', redirectTo: 'contact', pathMatch: 'full'}, +// #docregion lazy-routes + { path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' }, + { path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule' } +// #enddocregion lazy-routes +]; + +// #docregion forRoot +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule {} +// #enddocregion forRoot diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.component.0.ts b/public/docs/_examples/ngmodule/ts/src/app/app.component.0.ts new file mode 100644 index 0000000000..4977890c3b --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.component.0.ts @@ -0,0 +1,10 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: '

    {{title}}

    ', +}) +export class AppComponent { + title = 'Minimal NgModule'; +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.component.1.ts b/public/docs/_examples/ngmodule/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..ccf44d4416 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.component.1.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', +// #enddocregion + /* + // #docregion template + template: '

    {{title}}

    ' + // #enddocregion template + */ +// #docregion + template: '' +}) +export class AppComponent { + subtitle = '(v1)'; +} +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.component.1b.ts b/public/docs/_examples/ngmodule/ts/src/app/app.component.1b.ts new file mode 100644 index 0000000000..291bf0ac6b --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.component.1b.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` + + + ` + // #enddocregion template +}) +export class AppComponent { + subtitle = '(v1)'; +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.component.2.ts b/public/docs/_examples/ngmodule/ts/src/app/app.component.2.ts new file mode 100644 index 0000000000..a68b7d337d --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.component.2.ts @@ -0,0 +1,12 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` + + + ` +}) +export class AppComponent { + subtitle = '(v2)'; +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.component.3.ts b/public/docs/_examples/ngmodule/ts/src/app/app.component.3.ts new file mode 100644 index 0000000000..6d69a56f70 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.component.3.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` + + + + ` + // #enddocregion template +}) +export class AppComponent { + subtitle = '(v3)'; +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.component.ts b/public/docs/_examples/ngmodule/ts/src/app/app.component.ts new file mode 100644 index 0000000000..67336c8b08 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` + + + + ` +}) +export class AppComponent { + subtitle = '(Final)'; +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.module.0.ts b/public/docs/_examples/ngmodule/ts/src/app/app.module.0.ts new file mode 100644 index 0000000000..144ad7bb50 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.module.0.ts @@ -0,0 +1,23 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import +// #enddocregion + { AppComponent } from './app.component.0'; +/* +// #docregion + { AppComponent } from './app.component'; +// #enddocregion +*/ +// #docregion + +@NgModule({ +// #docregion imports + imports: [ BrowserModule ], +// #enddocregion imports + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.module.1.ts b/public/docs/_examples/ngmodule/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..f9f50e18d0 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.module.1.ts @@ -0,0 +1,54 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import +// #enddocregion + { AppComponent } from './app.component.1'; +/* +// #docregion + { AppComponent } from './app.component'; +// #enddocregion +*/ +// #docregion +import { HighlightDirective } from './highlight.directive'; +import { TitleComponent } from './title.component'; +import { UserService } from './user.service'; + +/* Contact Related Imports */ +import { FormsModule } from '@angular/forms'; + +import { AwesomePipe } from './contact/awesome.pipe'; +import { ContactComponent } from './contact/contact.component.3'; + +// #docregion import-contact-directive +import { + HighlightDirective as ContactHighlightDirective +} from './contact/highlight.directive'; +// #enddocregion import-contact-directive + +@NgModule({ +// #docregion imports + imports: [ BrowserModule, FormsModule ], +// #enddocregion imports +// #docregion declarations, directive, component + declarations: [ + AppComponent, + HighlightDirective, +// #enddocregion directive + TitleComponent, +// #enddocregion component + + AwesomePipe, + ContactComponent, + ContactHighlightDirective +// #docregion directive, component + ], +// #enddocregion declarations, directive, component +// #docregion providers + providers: [ UserService ], +// #enddocregion providers + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.module.1b.ts b/public/docs/_examples/ngmodule/ts/src/app/app.module.1b.ts new file mode 100644 index 0000000000..ae04326239 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.module.1b.ts @@ -0,0 +1,53 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +/* App Root */ +import +// #enddocregion + { AppComponent } from './app.component.1b'; +/* +// #docregion + { AppComponent } from './app.component'; +// #enddocregion +*/ +// #docregion +import { HighlightDirective } from './highlight.directive'; +import { TitleComponent } from './title.component'; +import { UserService } from './user.service'; + +/* Contact Imports */ +import +// #enddocregion + { ContactComponent } from './contact/contact.component.3'; +/* +// #docregion + { ContactComponent } from './contact/contact.component'; +// #enddocregion +*/ +// #docregion +import { ContactService } from './contact/contact.service'; +import { AwesomePipe } from './contact/awesome.pipe'; + +// #docregion import-alias +import { + HighlightDirective as ContactHighlightDirective +} from './contact/highlight.directive'; +// #enddocregion import-alias + +import { FormsModule } from '@angular/forms'; + +@NgModule({ + imports: [ BrowserModule, FormsModule ], +// #docregion declarations + declarations: [ + AppComponent, HighlightDirective, TitleComponent, + AwesomePipe, ContactComponent, ContactHighlightDirective + ], +// #docregion providers + providers: [ ContactService, UserService ], +// #enddocregion providers + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.module.2.ts b/public/docs/_examples/ngmodule/ts/src/app/app.module.2.ts new file mode 100644 index 0000000000..f00e9b5d27 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.module.2.ts @@ -0,0 +1,37 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +/* App Root */ +import +// #enddocregion + { AppComponent } from './app.component.2'; +/* +// #docregion + { AppComponent } from './app.component'; +// #enddocregion +*/ +// #docregion +import { HighlightDirective } from './highlight.directive'; +import { TitleComponent } from './title.component'; +import { UserService } from './user.service'; + +/* Contact Imports */ +import +// #enddocregion + { ContactModule } from './contact/contact.module.2'; +/* +// #docregion + { ContactModule } from './contact/contact.module'; +// #enddocregion +*/ +// #docregion + +@NgModule({ + imports: [ BrowserModule, ContactModule ], + declarations: [ AppComponent, HighlightDirective, TitleComponent ], + providers: [ UserService ], + bootstrap: [ AppComponent ], +}) +export class AppModule { } diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.module.3.ts b/public/docs/_examples/ngmodule/ts/src/app/app.module.3.ts new file mode 100644 index 0000000000..8ca0a46d9a --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.module.3.ts @@ -0,0 +1,30 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +/* App Root */ +import { AppComponent } from './app.component.3'; +import { HighlightDirective } from './highlight.directive'; +import { TitleComponent } from './title.component'; +import { UserService } from './user.service'; + +/* Feature Modules */ +import { ContactModule } from './contact/contact.module.3'; + +/* Routing Module */ +import { AppRoutingModule } from './app-routing.module.3'; + +@NgModule({ +// #docregion imports + imports: [ + BrowserModule, + ContactModule, + AppRoutingModule + ], +// #enddocregion imports + providers: [ UserService ], + declarations: [ AppComponent, HighlightDirective, TitleComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/ngmodule/ts/src/app/app.module.ts b/public/docs/_examples/ngmodule/ts/src/app/app.module.ts new file mode 100644 index 0000000000..da03420804 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/app.module.ts @@ -0,0 +1,40 @@ +// #docplaster +// #docregion +// #docregion v4 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +/* App Root */ +import { AppComponent } from './app.component'; + +/* Feature Modules */ +import { ContactModule } from './contact/contact.module'; +import { CoreModule } from './core/core.module'; + +/* Routing Module */ +import { AppRoutingModule } from './app-routing.module'; + +@NgModule({ + // #docregion import-for-root + imports: [ + BrowserModule, + ContactModule, +// #enddocregion v4 +// #enddocregion import-for-root +/* +// #docregion v4 + CoreModule, +// #enddocregion v4 +*/ +// #docregion import-for-root + CoreModule.forRoot({userName: 'Miss Marple'}), +// #docregion v4 + AppRoutingModule + ], + // #enddocregion import-for-root + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion v4 +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/awesome.pipe.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/awesome.pipe.ts new file mode 100644 index 0000000000..d6dce99901 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/awesome.pipe.ts @@ -0,0 +1,10 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'awesome' }) +/** Precede the input string with the word "Awesome " */ +export class AwesomePipe implements PipeTransform { + transform(phrase: string) { + return phrase ? 'Awesome ' + phrase : ''; + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact-routing.module.3.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact-routing.module.3.ts new file mode 100644 index 0000000000..27dfc232b7 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact-routing.module.3.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { ContactComponent } from './contact.component.3'; + +@NgModule({ + imports: [RouterModule.forChild([ + { path: 'contact', component: ContactComponent} + ])], + exports: [RouterModule] +}) +export class ContactRoutingModule {} diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact-routing.module.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact-routing.module.ts new file mode 100644 index 0000000000..2fa81af5a9 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact-routing.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { ContactComponent } from './contact.component'; + +// #docregion routing +@NgModule({ + imports: [RouterModule.forChild([ + { path: 'contact', component: ContactComponent } + ])], + exports: [RouterModule] +}) +export class ContactRoutingModule {} +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.3.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.3.ts new file mode 100644 index 0000000000..ea6e9868ba --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.3.ts @@ -0,0 +1,53 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Contact, ContactService } from './contact.service'; +import { UserService } from '../user.service'; + +@Component({ + selector: 'app-contact', + templateUrl: './contact.component.html', + styleUrls: [ './contact.component.css' ] +}) +export class ContactComponent implements OnInit { + contact: Contact; + contacts: Contact[]; + + msg = 'Loading contacts ...'; + userName = ''; + + constructor(private contactService: ContactService, userService: UserService) { + this.userName = userService.userName; + } + + ngOnInit() { + this.contactService.getContacts().then(contacts => { + this.msg = ''; + this.contacts = contacts; + this.contact = contacts[0]; + }); + } + + next() { + let ix = 1 + this.contacts.indexOf(this.contact); + if (ix >= this.contacts.length) { ix = 0; } + this.contact = this.contacts[ix]; + } + + onSubmit() { + // POST-DEMO TODO: do something like save it + this.displayMessage('Saved ' + this.contact.name); + } + + newContact() { + this.displayMessage('New contact'); + this.contact = {id: 42, name: ''}; + this.contacts.push(this.contact); + } + + /** Display a message briefly, then remove it. */ + displayMessage(msg: string) { + this.msg = msg; + setTimeout(() => this.msg = '', 1500); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.css b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.css new file mode 100644 index 0000000000..45e8f6e76d --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +.ng-valid[required] { + border-left: 5px solid #42A948; /* green */ +} + +.ng-invalid { + border-left: 5px solid #a94442; /* red */ +} + +.alert { + padding: 15px; + margin: 8px 0; + border: 1px solid transparent; + border-radius: 4px; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} + +.msg { + color: blue; + background-color: whitesmoke; + border: 1px solid transparent; + border-radius: 4px; + margin-bottom: 20px; +} + diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.html b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.html new file mode 100644 index 0000000000..483480571e --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.html @@ -0,0 +1,23 @@ + +

    Contact of {{userName}}

    +
    {{msg}}
    + +
    + +

    {{ contact.name | awesome }}

    + +
    + + +
    + Name is required +
    +
    +
    + + + +
    + diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.ts new file mode 100644 index 0000000000..d6dcbbc53f --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.component.ts @@ -0,0 +1,54 @@ +// Exact copy except import UserService from core +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Contact, ContactService } from './contact.service'; +import { UserService } from '../core/user.service'; + +@Component({ + selector: 'app-contact', + templateUrl: './contact.component.html', + styleUrls: [ './contact.component.css' ] +}) +export class ContactComponent implements OnInit { + contact: Contact; + contacts: Contact[]; + + msg = 'Loading contacts ...'; + userName = ''; + + constructor(private contactService: ContactService, userService: UserService) { + this.userName = userService.userName; + } + + ngOnInit() { + this.contactService.getContacts().then(contacts => { + this.msg = ''; + this.contacts = contacts; + this.contact = contacts[0]; + }); + } + + next() { + let ix = 1 + this.contacts.indexOf(this.contact); + if (ix >= this.contacts.length) { ix = 0; } + this.contact = this.contacts[ix]; + } + + onSubmit() { + // POST-DEMO TODO: do something like save it + this.displayMessage('Saved ' + this.contact.name); + } + + newContact() { + this.displayMessage('New contact'); + this.contact = {id: 42, name: ''}; + this.contacts.push(this.contact); + } + + /** Display a message briefly, then remove it. */ + displayMessage(msg: string) { + this.msg = msg; + setTimeout(() => this.msg = '', 1500); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.2.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.2.ts new file mode 100644 index 0000000000..f347bd3b51 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.2.ts @@ -0,0 +1,30 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { AwesomePipe } from './awesome.pipe'; + +import +// #enddocregion + { ContactComponent } from './contact.component.3'; +/* +// #docregion + { ContactComponent } from './contact.component'; +// #enddocregion +*/ +// #docregion +import { ContactService } from './contact.service'; +import { HighlightDirective } from './highlight.directive'; + +// #docregion class +@NgModule({ + imports: [ CommonModule, FormsModule ], + declarations: [ ContactComponent, HighlightDirective, AwesomePipe ], + exports: [ ContactComponent ], + providers: [ ContactService ] +}) +export class ContactModule { } +// #enddocregion class +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.3.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.3.ts new file mode 100644 index 0000000000..ff70721b2f --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.3.ts @@ -0,0 +1,22 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { AwesomePipe } from './awesome.pipe'; + +import { ContactComponent } from './contact.component.3'; +import { ContactService } from './contact.service'; +import { HighlightDirective } from './highlight.directive'; + +import { ContactRoutingModule } from './contact-routing.module.3'; + +// #docregion class +@NgModule({ + imports: [ CommonModule, FormsModule, ContactRoutingModule ], + declarations: [ ContactComponent, HighlightDirective, AwesomePipe ], + providers: [ ContactService ] +}) +export class ContactModule { } +// #enddocregion class +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.ts new file mode 100644 index 0000000000..9456de7654 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.module.ts @@ -0,0 +1,16 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { SharedModule } from '../shared/shared.module'; + +import { ContactComponent } from './contact.component'; +import { ContactService } from './contact.service'; +import { ContactRoutingModule } from './contact-routing.module'; + +// #docregion class +@NgModule({ + imports: [ SharedModule, ContactRoutingModule ], + declarations: [ ContactComponent ], + providers: [ ContactService ] +}) +export class ContactModule { } +// #enddocregion class diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/contact.service.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.service.ts new file mode 100644 index 0000000000..28b18bd84a --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/contact.service.ts @@ -0,0 +1,29 @@ +// #docregion +import { Injectable } from '@angular/core'; + +export class Contact { + constructor(public id: number, public name: string) { } +} + +const CONTACTS: Contact[] = [ + new Contact(21, 'Sam Spade'), + new Contact(22, 'Nick Danger'), + new Contact(23, 'Nancy Drew') +]; + +const FETCH_LATENCY = 500; + +@Injectable() +export class ContactService { + + getContacts() { + return new Promise(resolve => { + setTimeout(() => { resolve(CONTACTS); }, FETCH_LATENCY); + }); + } + + getContact(id: number | string) { + return this.getContacts() + .then(heroes => heroes.find(hero => hero.id === +id)); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/contact/highlight.directive.ts b/public/docs/_examples/ngmodule/ts/src/app/contact/highlight.directive.ts new file mode 100644 index 0000000000..64338b1377 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/contact/highlight.directive.ts @@ -0,0 +1,18 @@ +/* tslint:disable */ +// Same directive name and selector as +// HighlightDirective in parent AppModule +// It selects for both input boxes and 'highlight' attr +// and it highlights in blue instead of gold + +// #docregion +import { Directive, ElementRef } from '@angular/core'; + +@Directive({ selector: '[highlight], input' }) +/** Highlight the attached element or an InputElement in blue */ +export class HighlightDirective { + constructor(el: ElementRef) { + el.nativeElement.style.backgroundColor = 'powderblue'; + console.log( + `* Contact highlight called for ${el.nativeElement.tagName}`); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/core/core.module.ts b/public/docs/_examples/ngmodule/ts/src/app/core/core.module.ts new file mode 100644 index 0000000000..27cb9a2193 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/core/core.module.ts @@ -0,0 +1,48 @@ +/* tslint:disable:member-ordering no-unused-variable */ +// #docplaster +// #docregion +// #docregion v4 +import { + ModuleWithProviders, NgModule, + Optional, SkipSelf } from '@angular/core'; + +import { CommonModule } from '@angular/common'; + +import { TitleComponent } from './title.component'; +import { UserService } from './user.service'; +// #enddocregion +import { UserServiceConfig } from './user.service'; + +// #docregion v4 +@NgModule({ + imports: [ CommonModule ], + declarations: [ TitleComponent ], + exports: [ TitleComponent ], + providers: [ UserService ] +}) +export class CoreModule { +// #enddocregion v4 + + // #docregion ctor + constructor (@Optional() @SkipSelf() parentModule: CoreModule) { + if (parentModule) { + throw new Error( + 'CoreModule is already loaded. Import it in the AppModule only'); + } + } + // #enddocregion ctor + + // #docregion for-root + static forRoot(config: UserServiceConfig): ModuleWithProviders { + return { + ngModule: CoreModule, + providers: [ + {provide: UserServiceConfig, useValue: config } + ] + }; + } + // #enddocregion for-root +// #docregion v4 +} +// #enddocregion v4 +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/core/title.component.html b/public/docs/_examples/ngmodule/ts/src/app/core/title.component.html new file mode 100644 index 0000000000..8ebd08ae43 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/core/title.component.html @@ -0,0 +1,6 @@ + +

    {{title}} {{subtitle}}

    +

    + Welcome, {{user}} +

    + diff --git a/public/docs/_examples/ngmodule/ts/src/app/core/title.component.ts b/public/docs/_examples/ngmodule/ts/src/app/core/title.component.ts new file mode 100644 index 0000000000..b52a57aa13 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/core/title.component.ts @@ -0,0 +1,17 @@ +// Exact copy of app/title.component.ts except import UserService from shared +import { Component, Input } from '@angular/core'; +import { UserService } from '../core/user.service'; + +@Component({ + selector: 'app-title', + templateUrl: './title.component.html', +}) +export class TitleComponent { + @Input() subtitle = ''; + title = 'Angular Modules'; + user = ''; + + constructor(userService: UserService) { + this.user = userService.userName; + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/core/user.service.ts b/public/docs/_examples/ngmodule/ts/src/app/core/user.service.ts new file mode 100644 index 0000000000..8fe839075e --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/core/user.service.ts @@ -0,0 +1,32 @@ +// Crazy copy of the app/user.service +// Proves that UserService is an app-wide singleton and only instantiated once +// IFF shared.module follows the `forRoot` pattern +// +// If it didn't, a new instance of UserService would be created +// after each lazy load and the userName would double up. + +import { Injectable, Optional } from '@angular/core'; + +let nextId = 1; + +export class UserServiceConfig { + userName = 'Philip Marlowe'; +} + +@Injectable() +export class UserService { + id = nextId++; + private _userName = 'Sherlock Holmes'; + + // #docregion ctor + constructor(@Optional() config: UserServiceConfig) { + if (config) { this._userName = config.userName; } + } + // #enddocregion ctor + + get userName() { + // Demo: add a suffix if this service has been created more than once + const suffix = this.id > 1 ? ` times ${this.id}` : ''; + return this._userName + suffix; + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-detail.component.ts b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-detail.component.ts new file mode 100644 index 0000000000..9749029d62 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-detail.component.ts @@ -0,0 +1,19 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + template: ` +

    Crisis Detail

    +
    Crisis id: {{id}}
    +
    + Crisis List + ` +}) +export class CrisisDetailComponent implements OnInit { + id: number; + constructor(private route: ActivatedRoute) { } + + ngOnInit() { + this.id = parseInt(this.route.snapshot.params['id'], 10); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-list.component.ts b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-list.component.ts new file mode 100644 index 0000000000..ae459cdf1b --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-list.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit } from '@angular/core'; + +import { Crisis, + CrisisService } from './crisis.service'; + +@Component({ + template: ` +

    Crisis List

    + + ` +}) +export class CrisisListComponent implements OnInit { + crisises: Promise; + + constructor(private crisisService: CrisisService) { } + + ngOnInit() { + this.crisises = this.crisisService.getCrises(); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-routing.module.ts b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-routing.module.ts new file mode 100644 index 0000000000..c60efa8cb4 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis-routing.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { Routes, + RouterModule } from '@angular/router'; + +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: 'list', pathMatch: 'full'}, + { path: 'list', component: CrisisListComponent }, + { path: ':id', component: CrisisDetailComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class CrisisRoutingModule {} diff --git a/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis.module.ts b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis.module.ts new file mode 100644 index 0000000000..f557bd6423 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; +import { CrisisService } from './crisis.service'; +import { CrisisRoutingModule } from './crisis-routing.module'; + +@NgModule({ + imports: [ CommonModule, CrisisRoutingModule ], + declarations: [ CrisisDetailComponent, CrisisListComponent ], + providers: [ CrisisService ] +}) +export class CrisisModule {} diff --git a/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis.service.ts b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis.service.ts new file mode 100644 index 0000000000..419ee19b36 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/crisis/crisis.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; + +export class Crisis { + constructor(public id: number, public name: string) { } +} + +const CRISES: Crisis[] = [ + new Crisis(1, 'Dragon Burning Cities'), + new Crisis(2, 'Sky Rains Great White Sharks'), + new Crisis(3, 'Giant Asteroid Heading For Earth'), + new Crisis(4, 'Procrastinators Meeting Delayed Again'), +]; + +const FETCH_LATENCY = 500; + +@Injectable() +export class CrisisService { + + getCrises() { + return new Promise(resolve => { + setTimeout(() => { resolve(CRISES); }, FETCH_LATENCY); + }); + } + + getCrisis(id: number | string) { + return this.getCrises() + .then(heroes => heroes.find(hero => hero.id === +id)); + } + +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero-detail.component.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-detail.component.ts new file mode 100644 index 0000000000..1478ad350c --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-detail.component.ts @@ -0,0 +1,31 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { Hero, + HeroService } from './hero.service'; + +@Component({ + template: ` +

    Hero Detail

    +
    +
    Id: {{hero.id}}

    + +
    +
    + Hero List + ` +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + constructor( + private route: ActivatedRoute, + private heroService: HeroService) { } + + ngOnInit() { + let id = parseInt(this.route.snapshot.params['id'], 10); + this.heroService.getHero(id).then(hero => this.hero = hero); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero-list.component.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-list.component.ts new file mode 100644 index 0000000000..5a4e9ef0c4 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-list.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero, + HeroService } from './hero.service'; + +@Component({ + template: ` +

    Hero List

    + + ` +}) +export class HeroListComponent implements OnInit { + heroes: Promise; + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.heroes = this.heroService.getHeroes(); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero-routing.module.3.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-routing.module.3.ts new file mode 100644 index 0000000000..588ffd94be --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-routing.module.3.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { Routes, + RouterModule } from '@angular/router'; + +import { HeroComponent } from './hero.component.3'; +import { HeroListComponent } from './hero-list.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', + component: HeroComponent, + children: [ + { path: '', component: HeroListComponent }, + { path: ':id', component: HeroDetailComponent } + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class HeroRoutingModule {} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero-routing.module.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-routing.module.ts new file mode 100644 index 0000000000..d97aab3beb --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero-routing.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { Routes, + RouterModule } from '@angular/router'; + +import { HeroComponent } from './hero.component'; +import { HeroListComponent } from './hero-list.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', + component: HeroComponent, + children: [ + { path: '', component: HeroListComponent }, + { path: ':id', component: HeroDetailComponent } + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class HeroRoutingModule {} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero.component.3.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.component.3.ts new file mode 100644 index 0000000000..d52bc253df --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.component.3.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; + +import { HeroService } from './hero.service'; +import { UserService } from '../user.service'; + +@Component({ + template: ` +

    Heroes of {{userName}}

    + + `, + providers: [ HeroService ] +}) +export class HeroComponent { + userName = ''; + constructor(userService: UserService) { + this.userName = userService.userName; + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero.component.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.component.ts new file mode 100644 index 0000000000..86338fb0ae --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.component.ts @@ -0,0 +1,19 @@ +// Exact copy except import UserService from core +import { Component } from '@angular/core'; + +import { HeroService } from './hero.service'; +import { UserService } from '../core/user.service'; + +@Component({ + template: ` +

    Heroes of {{userName}}

    + + `, + providers: [ HeroService ] +}) +export class HeroComponent { + userName = ''; + constructor(userService: UserService) { + this.userName = userService.userName; + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero.module.3.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.module.3.ts new file mode 100644 index 0000000000..c00f4eedd5 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.module.3.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { HeroComponent } from './hero.component.3'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroListComponent } from './hero-list.component'; +import { HighlightDirective } from './highlight.directive'; +import { HeroRoutingModule } from './hero-routing.module.3'; + +// #docregion class +@NgModule({ + imports: [ CommonModule, FormsModule, HeroRoutingModule ], + declarations: [ + HeroComponent, HeroDetailComponent, HeroListComponent, + HighlightDirective + ] +}) +export class HeroModule { } +// #enddocregion class diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero.module.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.module.ts new file mode 100644 index 0000000000..98d7b76b00 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; + +import { SharedModule } from '../shared/shared.module'; + +import { HeroComponent } from './hero.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroListComponent } from './hero-list.component'; +import { HeroRoutingModule } from './hero-routing.module'; + +@NgModule({ + imports: [ SharedModule, HeroRoutingModule ], + declarations: [ + HeroComponent, HeroDetailComponent, HeroListComponent, + ] +}) +export class HeroModule { } diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/hero.service.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.service.ts new file mode 100644 index 0000000000..bb7ff5fa5c --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/hero.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; + +export class Hero { + constructor(public id: number, public name: string) { } +} + +const HEROES: Hero[] = [ + new Hero(11, 'Mr. Nice'), + new Hero(12, 'Narco'), + new Hero(13, 'Bombasto'), + new Hero(14, 'Celeritas'), + new Hero(15, 'Magneta'), + new Hero(16, 'RubberMan') +]; + +const FETCH_LATENCY = 500; + +@Injectable() +export class HeroService { + + getHeroes() { + return new Promise(resolve => { + setTimeout(() => { resolve(HEROES); }, FETCH_LATENCY); + }); + } + + getHero(id: number | string) { + return this.getHeroes() + .then(heroes => heroes.find(hero => hero.id === +id)); + } + +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/hero/highlight.directive.ts b/public/docs/_examples/ngmodule/ts/src/app/hero/highlight.directive.ts new file mode 100644 index 0000000000..d7e39afd05 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/hero/highlight.directive.ts @@ -0,0 +1,14 @@ +// #docregion +import { Directive, ElementRef } from '@angular/core'; + +// Same directive name and selector as +// HighlightDirective in parent AppRootModule +// It selects for both input boxes and 'highlight' attr +// and it highlights in beige instead of yellow +@Directive({ selector: '[highlight]' }) +export class HighlightDirective { + constructor(el: ElementRef) { + el.nativeElement.style.backgroundColor = 'beige'; + console.log(`* Hero highlight called for ${el.nativeElement.tagName}`); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/highlight.directive.ts b/public/docs/_examples/ngmodule/ts/src/app/highlight.directive.ts new file mode 100644 index 0000000000..df67a3ae89 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/highlight.directive.ts @@ -0,0 +1,12 @@ +// #docregion +import { Directive, ElementRef } from '@angular/core'; + +@Directive({ selector: '[highlight]' }) +/** Highlight the attached element in gold */ +export class HighlightDirective { + constructor(el: ElementRef) { + el.nativeElement.style.backgroundColor = 'gold'; + console.log( + `* AppRoot highlight called for ${el.nativeElement.tagName}`); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/shared/awesome.pipe.ts b/public/docs/_examples/ngmodule/ts/src/app/shared/awesome.pipe.ts new file mode 100644 index 0000000000..a1a0001d24 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/shared/awesome.pipe.ts @@ -0,0 +1,10 @@ +// Exact copy of contact.awesome.pipe +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'awesome' }) +/** Precede the input string with the word "Awesome " */ +export class AwesomePipe implements PipeTransform { + transform(phrase: string) { + return phrase ? 'Awesome ' + phrase : ''; + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/shared/highlight.directive.ts b/public/docs/_examples/ngmodule/ts/src/app/shared/highlight.directive.ts new file mode 100644 index 0000000000..63fbd4e488 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/shared/highlight.directive.ts @@ -0,0 +1,13 @@ +/* tslint:disable */ +// Exact copy of contact/highlight.directive except for color and message +import { Directive, ElementRef } from '@angular/core'; + +@Directive({ selector: '[highlight], input' }) +/** Highlight the attached element or an InputElement in gray */ +export class HighlightDirective { + constructor(el: ElementRef) { + el.nativeElement.style.backgroundColor = 'lightgray'; + console.log( + `* Shared highlight called for ${el.nativeElement.tagName}`); + } +} diff --git a/public/docs/_examples/ngmodule/ts/src/app/shared/shared.module.ts b/public/docs/_examples/ngmodule/ts/src/app/shared/shared.module.ts new file mode 100644 index 0000000000..2da7d7b2a5 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/shared/shared.module.ts @@ -0,0 +1,18 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { AwesomePipe } from './awesome.pipe'; +import { HighlightDirective } from './highlight.directive'; + +// #docregion module +@NgModule({ + imports: [ CommonModule ], + declarations: [ AwesomePipe, HighlightDirective ], + exports: [ AwesomePipe, HighlightDirective, + CommonModule, FormsModule ] +}) +export class SharedModule { } +// #enddocregion module +// #enddocregion diff --git a/public/docs/_examples/ngmodule/ts/src/app/title.component.html b/public/docs/_examples/ngmodule/ts/src/app/title.component.html new file mode 100644 index 0000000000..3db364cd4b --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/title.component.html @@ -0,0 +1,10 @@ + + +

    {{title}} {{subtitle}}

    + + +

    + Welcome, {{user}} +

    + + diff --git a/public/docs/_examples/ngmodule/ts/src/app/title.component.ts b/public/docs/_examples/ngmodule/ts/src/app/title.component.ts new file mode 100644 index 0000000000..9a2ef1c4b8 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/title.component.ts @@ -0,0 +1,24 @@ +// #docplaster +// #docregion +// #docregion v1 +import { Component, Input } from '@angular/core'; +// #enddocregion v1 +import { UserService } from './user.service'; +// #docregion v1 + +@Component({ + selector: 'app-title', + templateUrl: './title.component.html', +}) +export class TitleComponent { + @Input() subtitle = ''; + title = 'Angular Modules'; +// #enddocregion v1 + user = ''; + + constructor(userService: UserService) { + this.user = userService.userName; + } +// #docregion v1 +} +// #enddocregion v1 diff --git a/public/docs/_examples/ngmodule/ts/src/app/user.service.ts b/public/docs/_examples/ngmodule/ts/src/app/user.service.ts new file mode 100644 index 0000000000..7d996b26fa --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/app/user.service.ts @@ -0,0 +1,8 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +/** Dummy version of an authenticated user service */ +export class UserService { + userName = 'Sherlock Holmes'; +} diff --git a/public/docs/_examples/ngmodule/ts/src/index.0.html b/public/docs/_examples/ngmodule/ts/src/index.0.html new file mode 100644 index 0000000000..2281b9fecb --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/index.0.html @@ -0,0 +1,24 @@ + + + + + NgModule Minimal + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/ngmodule/ts/src/index.1.html b/public/docs/_examples/ngmodule/ts/src/index.1.html new file mode 100644 index 0000000000..65f7991a26 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/index.1.html @@ -0,0 +1,24 @@ + + + + + NgModule - Contact + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/ngmodule/ts/src/index.1b.html b/public/docs/_examples/ngmodule/ts/src/index.1b.html new file mode 100644 index 0000000000..b4a89d6549 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/index.1b.html @@ -0,0 +1,24 @@ + + + + + NgModule - Contact + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/ngmodule/ts/src/index.2.html b/public/docs/_examples/ngmodule/ts/src/index.2.html new file mode 100644 index 0000000000..72c545f1f3 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/index.2.html @@ -0,0 +1,24 @@ + + + + + NgModule - Contact + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/ngmodule/ts/src/index.3.html b/public/docs/_examples/ngmodule/ts/src/index.3.html new file mode 100644 index 0000000000..ec55dd984e --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/index.3.html @@ -0,0 +1,24 @@ + + + + + NgModule - Contact + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/ngmodule/ts/src/index.html b/public/docs/_examples/ngmodule/ts/src/index.html new file mode 100644 index 0000000000..9fc50c02a5 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/index.html @@ -0,0 +1,25 @@ + + + + + NgModule Deluxe + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/ngmodule/ts/src/main-static.ts b/public/docs/_examples/ngmodule/ts/src/main-static.ts new file mode 100644 index 0000000000..a1bcf466d2 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main-static.ts @@ -0,0 +1,13 @@ +// #docplaster +/* +// #docregion +// The browser platform without a compiler +import { platformBrowser } from '@angular/platform-browser'; + +// The app module factory produced by the static offline compiler +import { AppModuleNgFactory } from './app/app.module.ngfactory'; + +// Launch with the app module factory. +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); +// #enddocregion +*/ diff --git a/public/docs/_examples/ngmodule/ts/src/main.0.ts b/public/docs/_examples/ngmodule/ts/src/main.0.ts new file mode 100644 index 0000000000..6d1d712f07 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main.0.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module.0'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/ngmodule/ts/src/main.1.ts b/public/docs/_examples/ngmodule/ts/src/main.1.ts new file mode 100644 index 0000000000..48129f4cc9 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main.1.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module.1'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/ngmodule/ts/src/main.1b.ts b/public/docs/_examples/ngmodule/ts/src/main.1b.ts new file mode 100644 index 0000000000..7a7bfae22f --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main.1b.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module.1b'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/ngmodule/ts/src/main.2.ts b/public/docs/_examples/ngmodule/ts/src/main.2.ts new file mode 100644 index 0000000000..c535e2e775 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main.2.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module.2'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/ngmodule/ts/src/main.3.ts b/public/docs/_examples/ngmodule/ts/src/main.3.ts new file mode 100644 index 0000000000..72f21dd142 --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main.3.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module.3'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/ngmodule/ts/src/main.ts b/public/docs/_examples/ngmodule/ts/src/main.ts new file mode 100644 index 0000000000..c8424d8c4c --- /dev/null +++ b/public/docs/_examples/ngmodule/ts/src/main.ts @@ -0,0 +1,9 @@ +// #docregion +// The browser platform with a compiler +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +// The app module +import { AppModule } from './app/app.module'; + +// Compile and launch the module +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 6bdf07a74e..41dc5e5b56 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -1,50 +1,89 @@ { - "name": "angular2-examples-master", + "name": "angular-examples-master", "version": "1.0.0", - "description": "Master package.json, the superset of all dependencies for all of the _example package.json files.", - "main": "index.js", + "private": true, + "description": "Master package.json, the superset of all dependencies for all of the _example package.json files. See _boilerplate/package.json for example npm scripts.", "scripts": { - "start": "concurrently \"npm run tsc:w\" \"npm run lite\" ", - "tsc": "tsc", - "tsc:w": "tsc -w", - "lite": "lite-server", - "live": "live-server", - "test": "karma start karma.conf.js", - "build-and-test": "npm run tsc && npm run test", - "http-server": "tsc && http-server", - "typings": "typings", - "postinstall": "typings install" + "http-server": "http-server", + "protractor": "protractor", + "webdriver:update": "webdriver-manager update --standalone false --gecko false" }, "keywords": [], "author": "", - "license": "ISC", + "license": "MIT", "dependencies": { - "angular2": "2.0.0-beta.8", - "systemjs": "0.19.23", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "zone.js": "0.5.15", - - "a2-in-memory-web-api": "^0.1.8", - "bootstrap": "^3.3.6" - + "@angular/animations": "~4.0.0", + "@angular/common": "~4.0.0", + "@angular/compiler": "~4.0.0", + "@angular/compiler-cli": "~4.0.0", + "@angular/core": "~4.0.0", + "@angular/forms": "~4.0.0", + "@angular/http": "~4.0.0", + "@angular/platform-browser": "~4.0.0", + "@angular/platform-browser-dynamic": "~4.0.0", + "@angular/platform-server": "~4.0.0", + "@angular/router": "~4.0.0", + "@angular/tsc-wrapped": "~4.0.0", + "@angular/upgrade": "~4.0.0", + "angular-in-memory-web-api": "~0.3.1", + "core-js": "^2.4.1", + "rxjs": "5.0.1", + "systemjs": "0.19.39", + "zone.js": "^0.8.4" }, "devDependencies": { - "concurrently": "^2.0.0", + "@angular/cli": "^1.0.0", + "@types/angular": "^1.5.16", + "@types/angular-animate": "^1.5.5", + "@types/angular-cookies": "^1.4.2", + "@types/angular-mocks": "^1.5.5", + "@types/angular-resource": "^1.5.6", + "@types/angular-route": "^1.3.2", + "@types/angular-sanitize": "^1.3.3", + "@types/jasmine": "2.5.36", + "@types/node": "^6.0.45", + "angular2-template-loader": "^0.6.0", + "awesome-typescript-loader": "^3.0.4", + "babel-cli": "^6.16.0", + "babel-preset-angular2": "^0.0.2", + "babel-preset-es2015": "^6.16.0", + "canonical-path": "0.0.2", + "concurrently": "^3.0.0", + "css-loader": "^0.26.1", + "extract-text-webpack-plugin": "2.0.0-beta.5", + "file-loader": "^0.9.0", + "html-loader": "^0.4.3", + "html-webpack-plugin": "^2.16.1", "http-server": "^0.9.0", + "jasmine": "~2.4.1", "jasmine-core": "~2.4.1", - "karma": "^0.13.21", - "karma-chrome-launcher": "^0.2.2", - "karma-cli": "^0.1.2", - "karma-jasmine": "^0.3.7", - "lite-server": "^2.1.0", - "live-server": "^0.9.2", - "protractor": "^3.1.1", - "rimraf": "^2.5.2", - "typescript": "^1.8.7", - "typings": "0.6.9" + "karma": "^1.3.0", + "karma-chrome-launcher": "^2.0.0", + "karma-cli": "^1.0.1", + "karma-jasmine": "^1.0.2", + "karma-jasmine-html-reporter": "^0.2.2", + "karma-phantomjs-launcher": "^1.0.2", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^2.0.1", + "lite-server": "^2.2.2", + "lodash": "^4.16.2", + "null-loader": "^0.1.1", + "phantomjs-prebuilt": "^2.1.7", + "protractor": "~4.0.14", + "raw-loader": "^0.5.1", + "rimraf": "^2.5.4", + "rollup": "^0.41.6", + "rollup-plugin-commonjs": "^8.0.2", + "rollup-plugin-node-resolve": "2.0.0", + "rollup-plugin-uglify": "^1.0.1", + "source-map-explorer": "^1.3.2", + "style-loader": "^0.13.1", + "ts-node": "^1.3.0", + "tslint": "^3.15.1", + "typescript": "~2.2.0", + "webpack": "2.2.1", + "webpack-dev-server": "2.4.1", + "webpack-merge": "^3.0.0" }, - "repository": { } + "repository": {} } diff --git a/public/docs/_examples/pipes/dart/lib/app_component.dart b/public/docs/_examples/pipes/dart/lib/app_component.dart deleted file mode 100644 index 1edd92c0f4..0000000000 --- a/public/docs/_examples/pipes/dart/lib/app_component.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:angular2/angular2.dart'; - -import 'hero_async_message_component.dart'; -import 'hero_birthday2_component.dart'; -import 'hero_list_component.dart'; -import 'power_booster.dart'; -import 'power_boost_calculator.dart'; - -@Component( - selector: 'my-app', - templateUrl: 'app_component.html', - directives: const [ - HeroAsyncMessageComponent, - HeroBirthday, - HeroListComponent, - PowerBooster, - PowerBoostCalculator - ]) -class AppComponent { - DateTime birthday = new DateTime(1988, 4, 15); // April 15, 1988 -} diff --git a/public/docs/_examples/pipes/dart/lib/app_component.html b/public/docs/_examples/pipes/dart/lib/app_component.html deleted file mode 100644 index feed0f1908..0000000000 --- a/public/docs/_examples/pipes/dart/lib/app_component.html +++ /dev/null @@ -1,36 +0,0 @@ -


    - - - -
    - - -
    -

    The hero's birthday is {{ birthday | date }}

    - -

    The hero's birthday is {{ birthday | date:"MM/dd/yy" }}

    - -
    -

    Hero Birthday v.2

    -loading... -
    - - -

    - The chained hero's birthday is - {{ birthday | date | uppercase}} -

    - -

    - The chained hero's birthday is - {{ birthday | date:'fullDate' | uppercase}} -

    -

    - The chained hero's birthday is - {{ ( birthday | date:'fullDate' ) | uppercase}} -

    -
    -loading... - -
    -loading .. diff --git a/public/docs/_examples/pipes/dart/lib/exponential_strength_pipe.dart b/public/docs/_examples/pipes/dart/lib/exponential_strength_pipe.dart deleted file mode 100644 index b84297950c..0000000000 --- a/public/docs/_examples/pipes/dart/lib/exponential_strength_pipe.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'dart:math' as math; - -import 'package:angular2/angular2.dart'; - -/* -* Raise the value exponentially -* Takes a value that defaults to 0 and an exponent argument that defaults to 1. -* Checks for value to be a string or number. -* Usage: -* value | exponentialStrength:exponent -* Example: -* {{ 2 | exponentialStrength:10}} -* formats to: 1024 -*/ - -@Pipe(name: 'exponentialStrength') -@Injectable() -class ExponentialStrengthPipe extends PipeTransform { - transform(dynamic value, [List args]) { - var v = int.parse(value.toString(), onError: (source) => 0); - var p = args.isEmpty - ? 1 - : int.parse(args.first.toString(), onError: (source) => 1); - return math.pow(v, p); - } -} diff --git a/public/docs/_examples/pipes/dart/lib/fetch_json_pipe.dart b/public/docs/_examples/pipes/dart/lib/fetch_json_pipe.dart deleted file mode 100644 index e07f58ff53..0000000000 --- a/public/docs/_examples/pipes/dart/lib/fetch_json_pipe.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'dart:html'; -import 'dart:async'; -import 'dart:convert'; - -import 'package:angular2/angular2.dart'; - -@Pipe(name: 'fetch', pure: false) -@Injectable() -class FetchJsonPipe extends PipeTransform { - dynamic _fetchedValue; - Future _fetchPromise; - transform(dynamic value, [List args]) { - if (_fetchPromise == null) { - _fetchPromise = new Future(() async { - _fetchedValue = JSON.decode(await HttpRequest.getString(value)); - }); - } - return _fetchedValue; - } -} diff --git a/public/docs/_examples/pipes/dart/lib/hero_async_message_component.dart b/public/docs/_examples/pipes/dart/lib/hero_async_message_component.dart deleted file mode 100644 index 52d1851a86..0000000000 --- a/public/docs/_examples/pipes/dart/lib/hero_async_message_component.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'dart:async'; - -import 'package:angular2/angular2.dart'; - -@Component( - selector: 'hero-message', template: 'Message: {{delayedMessage | async}}') -class HeroAsyncMessageComponent { - Future delayedMessage = - new Future.delayed(new Duration(milliseconds: 500), () { - return 'You are my Hero!'; - }); -} diff --git a/public/docs/_examples/pipes/dart/lib/hero_birthday1_component.dart b/public/docs/_examples/pipes/dart/lib/hero_birthday1_component.dart deleted file mode 100644 index 4b8f3a33f2..0000000000 --- a/public/docs/_examples/pipes/dart/lib/hero_birthday1_component.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:angular2/angular2.dart'; - -@Component( - selector: 'hero-birthday', - template: ''' -

    The hero's birthday is {{ birthday | date }}

    - ''') -class HeroBirthday { - DateTime birthday = new DateTime(1988, 4, 15); // April 15, 1988 -} diff --git a/public/docs/_examples/pipes/dart/lib/hero_birthday2_component.dart b/public/docs/_examples/pipes/dart/lib/hero_birthday2_component.dart deleted file mode 100644 index 032888080e..0000000000 --- a/public/docs/_examples/pipes/dart/lib/hero_birthday2_component.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:angular2/angular2.dart'; - -@Component( - selector: 'hero-birthday', - template: ''' -

    The hero's birthday is {{ birthday | date:format }}

    - - ''') -class HeroBirthday { - DateTime birthday = new DateTime(1988, 4, 15); // April 15, 1988 - - bool toggle = true; - - get format => toggle ? 'shortDate' : 'fullDate'; - - void toggleFormat() { - toggle = !toggle; - } -} diff --git a/public/docs/_examples/pipes/dart/lib/hero_list_component.dart b/public/docs/_examples/pipes/dart/lib/hero_list_component.dart deleted file mode 100644 index 50ae1a5bf1..0000000000 --- a/public/docs/_examples/pipes/dart/lib/hero_list_component.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:angular2/angular2.dart'; - -import 'fetch_json_pipe.dart'; - -@Component( - selector: 'hero-list', - template: ''' -

    Heroes from JSON File

    - -
    - {{hero['name']}} -
    - -

    Heroes as JSON: - {{'heroes.json' | fetch | json}} -

    -''', - pipes: const [FetchJsonPipe]) -class HeroListComponent {} diff --git a/public/docs/_examples/pipes/dart/lib/power_boost_calculator.dart b/public/docs/_examples/pipes/dart/lib/power_boost_calculator.dart deleted file mode 100644 index 1d7f9558cd..0000000000 --- a/public/docs/_examples/pipes/dart/lib/power_boost_calculator.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:angular2/angular2.dart'; - -import 'exponential_strength_pipe.dart'; - -@Component( - selector: 'power-boost-calculator', - template: ''' -

    Power Boost Calculator

    -
    Normal power:
    -
    Boost factor:
    -

    - Super Hero Power: {{power | exponentialStrength: factor}} -

    -''', - pipes: const [ExponentialStrengthPipe], - directives: const [COMMON_DIRECTIVES]) -class PowerBoostCalculator { - // XXX: These should be ints, but that causes exceptions in checked mode. - String power = '5'; - String factor = '1'; -} diff --git a/public/docs/_examples/pipes/dart/lib/power_booster.dart b/public/docs/_examples/pipes/dart/lib/power_booster.dart deleted file mode 100644 index 194abe1b0c..0000000000 --- a/public/docs/_examples/pipes/dart/lib/power_booster.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:angular2/angular2.dart'; -import 'exponential_strength_pipe.dart'; - -@Component( - selector: 'power-booster', - template: ''' -

    Power Booster

    -

    - Super power boost: {{2 | exponentialStrength: 10}} -

    -''', - pipes: const [ExponentialStrengthPipe]) -class PowerBooster {} diff --git a/public/docs/_examples/pipes/dart/pubspec.yaml b/public/docs/_examples/pipes/dart/pubspec.yaml deleted file mode 100644 index a0f3ba82ed..0000000000 --- a/public/docs/_examples/pipes/dart/pubspec.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# #docregion -name: pipe_examples -description: Pipes Example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES' - platform_pipes: 'package:angular2/common.dart#COMMON_PIPES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/pipes/dart/web/heroes.json b/public/docs/_examples/pipes/dart/web/heroes.json deleted file mode 100644 index 436b220d53..0000000000 --- a/public/docs/_examples/pipes/dart/web/heroes.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - {"name": "Windstorm"}, - {"name": "Bombasto"}, - {"name": "Magneto"}, - {"name": "Tornado"} -] diff --git a/public/docs/_examples/pipes/dart/web/index.html b/public/docs/_examples/pipes/dart/web/index.html deleted file mode 100644 index 483b9537ba..0000000000 --- a/public/docs/_examples/pipes/dart/web/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - Pipes Example - - - - - - -

    Hero Birthday v.1

    - hero-birthday loading... - - my-app loading ... - - - diff --git a/public/docs/_examples/pipes/dart/web/main.dart b/public/docs/_examples/pipes/dart/web/main.dart deleted file mode 100644 index 72e510805c..0000000000 --- a/public/docs/_examples/pipes/dart/web/main.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:angular2/bootstrap.dart'; -import 'package:pipe_examples/app_component.dart'; -import 'package:pipe_examples/hero_birthday1_component.dart'; - -main() { - bootstrap(AppComponent); - bootstrap(HeroBirthday); -} diff --git a/public/docs/_examples/pipes/e2e-spec.js b/public/docs/_examples/pipes/e2e-spec.js deleted file mode 100644 index a8637947d0..0000000000 --- a/public/docs/_examples/pipes/e2e-spec.js +++ /dev/null @@ -1,70 +0,0 @@ -describe('Pipes', function () { - - beforeAll(function () { - browser.get(''); - }); - - it('should open correctly', function () { - expect(element.all(by.css('h4')).get(0).getText()).toEqual('Hero Birthday v.1'); - expect(element(by.css('body > hero-birthday p')).getText()).toEqual("The hero's birthday is Apr 15, 1988"); - }); - - it('should show delayed message', function () { - expect(element.all(by.css('hero-message')).get(0).getText()).toEqual('Message: You are my Hero!'); - }); - - it('should show 4 heroes', function () { - expect(element.all(by.css('hero-list div')).count()).toEqual(4); - }); - - it('should show 4 heroes in json', function () { - expect(element(by.cssContainingText('hero-list p', 'Heroes as JSON')).getText()).toContain('Bombasto'); - }); - - it('should show alternate birthday formats', function () { - expect(element(by.cssContainingText('my-app > p', "The hero's birthday is Apr 15, 1988")).isDisplayed()).toBe(true); - expect(element(by.cssContainingText('my-app > p', "The hero's birthday is 04/15/88")).isDisplayed()).toBe(true); - }); - - it('should be able to toggle birthday formats', function () { - var birthDayEle = element(by.css('my-app > hero-birthday > p')); - expect(birthDayEle.getText()).toEqual("The hero's birthday is 4/15/1988"); - var buttonEle = element(by.cssContainingText('my-app > hero-birthday > button', "Toggle Format")); - expect(buttonEle.isDisplayed()).toBe(true); - buttonEle.click().then(function() { - expect(birthDayEle.getText()).toEqual("The hero's birthday is Friday, April 15, 1988"); - }); - }); - - it('should be able to chain and compose pipes', function () { - var chainedPipeEles = element.all(by.cssContainingText('my-app p', "The chained hero's")); - expect(chainedPipeEles.count()).toBe(3, "should have 3 chained pipe examples"); - expect(chainedPipeEles.get(0).getText()).toContain('APR 15, 1988'); - expect(chainedPipeEles.get(1).getText()).toContain('FRIDAY, APRIL 15, 1988'); - expect(chainedPipeEles.get(2).getText()).toContain('FRIDAY, APRIL 15, 1988'); - }); - - it('should be able to use ExponentialStrengthPipe pipe', function () { - var ele = element(by.css('power-booster p')); - expect(ele.getText()).toContain('Super power boost: 1024'); - }); - - it('should be able to use the exponential calculator', function () { - var eles = element.all(by.css('power-boost-calculator input')); - var baseInputEle = eles.get(0); - var factorInputEle = eles.get(1); - var outputEle = element(by.css('power-boost-calculator p')); - baseInputEle.clear().then(function() { - return sendKeys(baseInputEle, "7"); - }).then(function() { - return factorInputEle.clear(); - }).then(function() { - return sendKeys(factorInputEle, "3"); - }).then(function() { - expect(outputEle.getText()).toContain("343"); - }); - }); - - - -}); diff --git a/public/docs/_examples/pipes/e2e-spec.ts b/public/docs/_examples/pipes/e2e-spec.ts new file mode 100644 index 0000000000..00277e3657 --- /dev/null +++ b/public/docs/_examples/pipes/e2e-spec.ts @@ -0,0 +1,111 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Pipes', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should open correctly', function () { + expect(element.all(by.tagName('h1')).get(0).getText()).toEqual('Pipes'); + expect(element(by.css('hero-birthday p')).getText()).toEqual(`The hero's birthday is Apr 15, 1988`); + }); + + it('should show 4 heroes', function () { + expect(element.all(by.css('hero-list div')).count()).toEqual(4); + }); + + it('should show a familiar hero in json', function () { + expect(element(by.cssContainingText('hero-list p', 'Heroes as JSON')).getText()).toContain('Bombasto'); + }); + + it('should show alternate birthday formats', function () { + expect(element(by.cssContainingText('my-app > p', `The hero's birthday is Apr 15, 1988`)).isDisplayed()).toBe(true); + expect(element(by.cssContainingText('my-app > p', `The hero's birthday is 04/15/88`)).isDisplayed()).toBe(true); + }); + + it('should be able to toggle birthday formats', function () { + let birthDayEle = element(by.css('hero-birthday2 > p')); + expect(birthDayEle.getText()).toEqual(`The hero's birthday is 4/15/1988`); + let buttonEle = element(by.cssContainingText('hero-birthday2 > button', 'Toggle Format')); + expect(buttonEle.isDisplayed()).toBe(true); + buttonEle.click().then(function() { + expect(birthDayEle.getText()).toEqual(`The hero's birthday is Friday, April 15, 1988`); + }); + }); + + it('should be able to chain and compose pipes', function () { + let chainedPipeEles = element.all(by.cssContainingText('my-app p', `The chained hero's`)); + expect(chainedPipeEles.count()).toBe(3, 'should have 3 chained pipe examples'); + expect(chainedPipeEles.get(0).getText()).toContain('APR 15, 1988'); + expect(chainedPipeEles.get(1).getText()).toContain('FRIDAY, APRIL 15, 1988'); + expect(chainedPipeEles.get(2).getText()).toContain('FRIDAY, APRIL 15, 1988'); + }); + + it('should be able to use ExponentialStrengthPipe pipe', function () { + let ele = element(by.css('power-booster p')); + expect(ele.getText()).toContain('Super power boost: 1024'); + }); + + it('should be able to use the exponential calculator', function () { + let eles = element.all(by.css('power-boost-calculator input')); + let baseInputEle = eles.get(0); + let factorInputEle = eles.get(1); + let outputEle = element(by.css('power-boost-calculator p')); + baseInputEle.clear().then(function() { + baseInputEle.sendKeys('7'); + return factorInputEle.clear(); + }).then(function() { + factorInputEle.sendKeys('3'); + expect(outputEle.getText()).toContain('343'); + }); + }); + + + it('should support flying heroes (pure) ', function () { + let nameEle = element(by.css('flying-heroes input[type="text"]')); + let canFlyCheckEle = element(by.css('flying-heroes #can-fly')); + let mutateCheckEle = element(by.css('flying-heroes #mutate')); + let resetEle = element(by.css('flying-heroes button')); + let flyingHeroesEle = element.all(by.css('flying-heroes #flyers div')); + + expect(canFlyCheckEle.getAttribute('checked')).toEqual('true', 'should default to "can fly"'); + expect(mutateCheckEle.getAttribute('checked')).toEqual('true', 'should default to mutating array'); + expect(flyingHeroesEle.count()).toEqual(2, 'only two of the original heroes can fly'); + + nameEle.sendKeys('test1\n'); + expect(flyingHeroesEle.count()).toEqual(2, 'no change while mutating array'); + mutateCheckEle.click().then(function() { + nameEle.sendKeys('test2\n'); + expect(flyingHeroesEle.count()).toEqual(4, 'not mutating; should see both adds'); + expect(flyingHeroesEle.get(2).getText()).toContain('test1'); + expect(flyingHeroesEle.get(3).getText()).toContain('test2'); + return resetEle.click(); + }) + .then(function() { + expect(flyingHeroesEle.count()).toEqual(2, 'reset should restore orginal flying heroes'); + }); + }); + + + it('should support flying heroes (impure) ', function () { + let nameEle = element(by.css('flying-heroes-impure input[type="text"]')); + let canFlyCheckEle = element(by.css('flying-heroes-impure #can-fly')); + let mutateCheckEle = element(by.css('flying-heroes-impure #mutate')); + let flyingHeroesEle = element.all(by.css('flying-heroes-impure #flyers div')); + + expect(canFlyCheckEle.getAttribute('checked')).toEqual('true', 'should default to "can fly"'); + expect(mutateCheckEle.getAttribute('checked')).toEqual('true', 'should default to mutating array'); + expect(flyingHeroesEle.count()).toEqual(2, 'only two of the original heroes can fly'); + + nameEle.sendKeys('test1\n'); + expect(flyingHeroesEle.count()).toEqual(3, 'new flying hero should show in mutating array'); + }); + + it('should show an async hero message', function () { + expect(element.all(by.tagName('hero-message')).get(0).getText()).toContain('hero'); + }); + +}); diff --git a/public/docs/_examples/pipes/ts/.gitignore b/public/docs/_examples/pipes/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/pipes/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/pipes/ts/app/app.component.html b/public/docs/_examples/pipes/ts/app/app.component.html deleted file mode 100644 index 7cbc969c84..0000000000 --- a/public/docs/_examples/pipes/ts/app/app.component.html +++ /dev/null @@ -1,47 +0,0 @@ -
    - - - -
    - - -
    - -

    The hero's birthday is {{ birthday | date }}

    - - - -

    The hero's birthday is {{ birthday | date:"MM/dd/yy" }}

    - - -
    -

    Hero Birthday v.2

    -loading... -
    - - - -

    - The chained hero's birthday is - {{ birthday | date | uppercase}} -

    - - - -

    - The chained hero's birthday is - {{ birthday | date:'fullDate' | uppercase}} -

    - - -

    - The chained hero's birthday is - {{ ( birthday | date:'fullDate' ) | uppercase}} -

    - -
    -loading... - -
    -loading .. - diff --git a/public/docs/_examples/pipes/ts/app/app.component.ts b/public/docs/_examples/pipes/ts/app/app.component.ts deleted file mode 100644 index db6a0c7a81..0000000000 --- a/public/docs/_examples/pipes/ts/app/app.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {HeroAsyncMessageComponent} from './hero-async-message.component'; -import {HeroBirthday} from './hero-birthday2.component'; -import {HeroListComponent} from './hero-list.component'; -import {PowerBooster} from './power-booster.component'; -import {PowerBoostCalculator} from './power-boost-calculator.component'; - -@Component({ - selector: 'my-app', - templateUrl: 'app/app.component.html', - directives:[ - HeroAsyncMessageComponent, - HeroBirthday, - HeroListComponent, - PowerBooster, PowerBoostCalculator - ] -}) -export class AppComponent { - birthday = new Date(1988,3,15); // April 15, 1988 -} diff --git a/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts b/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts deleted file mode 100644 index 2907cd00dd..0000000000 --- a/public/docs/_examples/pipes/ts/app/exponential-strength.pipe.ts +++ /dev/null @@ -1,18 +0,0 @@ -// #docregion -import {Pipe, PipeTransform} from 'angular2/core'; -/* - * Raise the value exponentially - * Takes an exponent argument that defaults to 1. - * Usage: - * value | exponentialStrength:exponent - * Example: - * {{ 2 | exponentialStrength:10}} - * formats to: 1024 -*/ -@Pipe({name: 'exponentialStrength'}) -export class ExponentialStrengthPipe implements PipeTransform { - - transform(value:number, args:string[]) : any { - return Math.pow(value, parseInt(args[0] || '1', 10)); - } -} diff --git a/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts b/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts deleted file mode 100644 index 9383ce0990..0000000000 --- a/public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts +++ /dev/null @@ -1,24 +0,0 @@ -/// -// #docregion -import {Pipe, PipeTransform} from 'angular2/core'; - -// #docregion pipe-metadata -@Pipe({ - name: 'fetch', - pure: false -}) -// #enddocregion pipe-metadata -export class FetchJsonPipe implements PipeTransform{ - private fetchedValue:any; - private fetchPromise:Promise; - - transform(value:string, args:string[]):any { - if (!this.fetchPromise) { - this.fetchPromise = window.fetch(value) - .then((result:any) => result.json()) - .then((json:any) => this.fetchedValue = json); - } - - return this.fetchedValue; - } -} \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts b/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts deleted file mode 100644 index 9303932d41..0000000000 --- a/public/docs/_examples/pipes/ts/app/hero-async-message.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -// Initial view: "Message: " -// After 500ms: Message: You are my Hero!" - -@Component({ - selector: 'hero-message', - template: 'Message: {{delayedMessage | async}}', -}) -export class HeroAsyncMessageComponent { - delayedMessage:Promise = new Promise((resolve, reject) => { - setTimeout(() => resolve('You are my Hero!'), 500); - }); -} diff --git a/public/docs/_examples/pipes/ts/app/hero-birthday1.component.ts b/public/docs/_examples/pipes/ts/app/hero-birthday1.component.ts deleted file mode 100644 index e8ef259381..0000000000 --- a/public/docs/_examples/pipes/ts/app/hero-birthday1.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Version #1 -// #docregion -import {Component} from 'angular2/core' - -@Component({ - selector: 'hero-birthday', - // #docregion hero-birthday-template - template: `

    The hero's birthday is {{ birthday | date }}

    ` - // #enddocregion hero-birthday-template -}) -export class HeroBirthday { - birthday = new Date(1988,3,15); // April 15, 1988 -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts b/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts deleted file mode 100644 index e0b357c7f4..0000000000 --- a/public/docs/_examples/pipes/ts/app/hero-birthday2.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Version #2 -// #docregion -import {Component} from 'angular2/core' - -@Component({ - selector: 'hero-birthday', -// #docregion template - template: ` -

    The hero's birthday is {{ birthday | date:format }}

    - - ` -// #enddocregion template -}) -// #docregion class -export class HeroBirthday { - birthday = new Date(1988,3,15); // April 15, 1988 - - toggle = true; // start with true == shortDate - - get format() { return this.toggle ? 'shortDate' : 'fullDate'} - - toggleFormat() { this.toggle = !this.toggle; } -} -// #enddocregion class diff --git a/public/docs/_examples/pipes/ts/app/hero-list.component.ts b/public/docs/_examples/pipes/ts/app/hero-list.component.ts deleted file mode 100644 index 169767eac1..0000000000 --- a/public/docs/_examples/pipes/ts/app/hero-list.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {FetchJsonPipe} from './fetch-json.pipe'; - -@Component({ - selector: 'hero-list', - // #docregion template - template: ` -

    Heroes from JSON File

    - -
    - {{hero.name}} -
    - -

    Heroes as JSON: - {{'heroes.json' | fetch | json}} -

    - `, - // #enddocregion template - pipes: [FetchJsonPipe] -}) -export class HeroListComponent { - /* I've got nothing to do ;-) */ -} diff --git a/public/docs/_examples/pipes/ts/app/main.ts b/public/docs/_examples/pipes/ts/app/main.ts deleted file mode 100644 index 597ab3aa7c..0000000000 --- a/public/docs/_examples/pipes/ts/app/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; -import {HeroBirthday} from './hero-birthday1.component'; - -bootstrap(AppComponent); -bootstrap(HeroBirthday); // v.1 \ No newline at end of file diff --git a/public/docs/_examples/pipes/ts/app/power-boost-calculator.component.ts b/public/docs/_examples/pipes/ts/app/power-boost-calculator.component.ts deleted file mode 100644 index 73151d5362..0000000000 --- a/public/docs/_examples/pipes/ts/app/power-boost-calculator.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {ExponentialStrengthPipe} from './exponential-strength.pipe'; - -@Component({ - selector: 'power-boost-calculator', - template: ` -

    Power Boost Calculator

    -
    Normal power:
    -
    Boost factor:
    -

    - Super Hero Power: {{power | exponentialStrength: factor}} -

    - `, - pipes: [ExponentialStrengthPipe] -}) -export class PowerBoostCalculator { - power = 5; - factor = 1; -} diff --git a/public/docs/_examples/pipes/ts/app/power-booster.component.ts b/public/docs/_examples/pipes/ts/app/power-booster.component.ts deleted file mode 100644 index 73d5c25ca0..0000000000 --- a/public/docs/_examples/pipes/ts/app/power-booster.component.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {ExponentialStrengthPipe} from './exponential-strength.pipe'; - -@Component({ - selector: 'power-booster', - template: ` -

    Power Booster

    -

    - Super power boost: {{2 | exponentialStrength: 10}} -

    - `, - pipes: [ExponentialStrengthPipe] -}) -export class PowerBooster { } diff --git a/public/docs/_examples/pipes/ts/app/window.extension.d.ts b/public/docs/_examples/pipes/ts/app/window.extension.d.ts deleted file mode 100644 index 0a5a71bbf6..0000000000 --- a/public/docs/_examples/pipes/ts/app/window.extension.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -interface Window { - fetch(url: string, options? : {}) : Promise -} diff --git a/public/docs/_examples/pipes/ts/heroes.json b/public/docs/_examples/pipes/ts/heroes.json deleted file mode 100644 index 436b220d53..0000000000 --- a/public/docs/_examples/pipes/ts/heroes.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - {"name": "Windstorm"}, - {"name": "Bombasto"}, - {"name": "Magneto"}, - {"name": "Tornado"} -] diff --git a/public/docs/_examples/pipes/ts/index.html b/public/docs/_examples/pipes/ts/index.html deleted file mode 100644 index f11eba1c67..0000000000 --- a/public/docs/_examples/pipes/ts/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - Pipes - - - - - - - - - - - - - - - - -

    Hero Birthday v.1

    - hero-birthday loading... - - my-app loading ... - - - diff --git a/public/docs/_examples/pipes/ts/plnkr.json b/public/docs/_examples/pipes/ts/plnkr.json index cc19097a4a..3c07266109 100644 --- a/public/docs/_examples/pipes/ts/plnkr.json +++ b/public/docs/_examples/pipes/ts/plnkr.json @@ -1,8 +1,8 @@ { "description": "Pipes", + "basePath": "src/", "files":[ "!**/*.d.ts", - "!**/*.js", - "!**/*.d.ts"], + "!**/*.js"], "tags": ["pipe"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/pipes/ts/src/app/app.component.html b/public/docs/_examples/pipes/ts/src/app/app.component.html new file mode 100644 index 0000000000..a27d587fcd --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/app.component.html @@ -0,0 +1,83 @@ + +

    Pipes

    +Happy Birthday v1
    +Birthday DatePipe
    +Happy Birthday v2
    +Birthday Pipe Chaining
    +Power Booster custom pipe
    +Power Boost Calculator custom pipe with params
    +Flying Heroes filter pipe (pure)
    +Flying Heroes filter pipe (impure)
    +Async Hero Message and AsyncPipe
    +Hero List with caching FetchJsonPipe
    + + +
    + +

    Hero Birthday v1

    + + +
    + +

    Birthday DatePipe

    + +

    The hero's birthday is {{ birthday | date }}

    + + + +

    The hero's birthday is {{ birthday | date:"MM/dd/yy" }}

    + + +
    + +

    Hero Birthday v2

    + + +
    + +

    Birthday Pipe Chaining

    +

    + + The chained hero's birthday is + {{ birthday | date | uppercase}} + +

    + +

    + + The chained hero's birthday is + {{ birthday | date:'fullDate' | uppercase}} + +

    +

    + + The chained hero's birthday is + {{ ( birthday | date:'fullDate' ) | uppercase}} + +

    +
    + + + +
    + +loading + +
    + + + +
    + + + +
    + + + + +
    + + + +
    diff --git a/public/docs/_examples/pipes/ts/src/app/app.component.ts b/public/docs/_examples/pipes/ts/src/app/app.component.ts new file mode 100644 index 0000000000..090eae7766 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/app.component.ts @@ -0,0 +1,10 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { + birthday = new Date(1988, 3, 15); // April 15, 1988 +} diff --git a/public/docs/_examples/pipes/ts/src/app/app.module.ts b/public/docs/_examples/pipes/ts/src/app/app.module.ts new file mode 100644 index 0000000000..89a3a29505 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/app.module.ts @@ -0,0 +1,48 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppComponent } from './app.component'; +import { + FlyingHeroesComponent, + FlyingHeroesImpureComponent +} from './flying-heroes.component'; +import { HeroAsyncMessageComponent } from './hero-async-message.component'; +import { HeroBirthdayComponent } from './hero-birthday1.component'; +import { HeroBirthday2Component } from './hero-birthday2.component'; +import { HeroListComponent } from './hero-list.component'; +import { PowerBoosterComponent } from './power-booster.component'; +import { PowerBoostCalculatorComponent } from './power-boost-calculator.component'; +import { + FlyingHeroesPipe, + FlyingHeroesImpurePipe +} from './flying-heroes.pipe'; +import { FetchJsonPipe } from './fetch-json.pipe'; +import { ExponentialStrengthPipe } from './exponential-strength.pipe'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule + ], + declarations: [ + AppComponent, + FlyingHeroesComponent, + FlyingHeroesImpureComponent, + HeroAsyncMessageComponent, + HeroBirthdayComponent, + HeroBirthday2Component, + HeroListComponent, + PowerBoosterComponent, + PowerBoostCalculatorComponent, + FlyingHeroesPipe, + FlyingHeroesImpurePipe, + FetchJsonPipe, + ExponentialStrengthPipe + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/pipes/ts/src/app/exponential-strength.pipe.ts b/public/docs/_examples/pipes/ts/src/app/exponential-strength.pipe.ts new file mode 100644 index 0000000000..0a703d7016 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/exponential-strength.pipe.ts @@ -0,0 +1,18 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; +/* + * Raise the value exponentially + * Takes an exponent argument that defaults to 1. + * Usage: + * value | exponentialStrength:exponent + * Example: + * {{ 2 | exponentialStrength:10}} + * formats to: 1024 +*/ +@Pipe({name: 'exponentialStrength'}) +export class ExponentialStrengthPipe implements PipeTransform { + transform(value: number, exponent: string): number { + let exp = parseFloat(exponent); + return Math.pow(value, isNaN(exp) ? 1 : exp); + } +} diff --git a/public/docs/_examples/pipes/ts/src/app/fetch-json.pipe.ts b/public/docs/_examples/pipes/ts/src/app/fetch-json.pipe.ts new file mode 100644 index 0000000000..4d56e865f3 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/fetch-json.pipe.ts @@ -0,0 +1,30 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; +import { Http } from '@angular/http'; + +import 'rxjs/add/operator/map'; + +// #docregion pipe-metadata +@Pipe({ + name: 'fetch', + pure: false +}) +// #enddocregion pipe-metadata +export class FetchJsonPipe implements PipeTransform { + private cachedData: any = null; + private cachedUrl = ''; + + constructor(private http: Http) { } + + transform(url: string): any { + if (url !== this.cachedUrl) { + this.cachedData = null; + this.cachedUrl = url; + this.http.get(url) + .map( result => result.json() ) + .subscribe( result => this.cachedData = result ); + } + + return this.cachedData; + } +} diff --git a/public/docs/_examples/pipes/ts/src/app/flying-heroes-impure.component.html b/public/docs/_examples/pipes/ts/src/app/flying-heroes-impure.component.html new file mode 100644 index 0000000000..66bd86f81c --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/flying-heroes-impure.component.html @@ -0,0 +1,38 @@ + + +

    {{title}}

    +

    + +New hero: + + + can fly +

    +

    + Mutate array + + + +

    + +

    Heroes who fly (piped)

    +
    + +
    + {{hero.name}} +
    + +
    + +

    All Heroes (no pipe)

    +
    + + +
    + {{hero.name}} +
    + + +
    diff --git a/public/docs/_examples/pipes/ts/src/app/flying-heroes.component.html b/public/docs/_examples/pipes/ts/src/app/flying-heroes.component.html new file mode 100644 index 0000000000..93e635b662 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/flying-heroes.component.html @@ -0,0 +1,38 @@ + + +

    {{title}}

    +

    + +New hero: + + + can fly +

    +

    + Mutate array + + + +

    + +

    Heroes who fly (piped)

    +
    + +
    + {{hero.name}} +
    + +
    + +

    All Heroes (no pipe)

    +
    + + +
    + {{hero.name}} +
    + + +
    diff --git a/public/docs/_examples/pipes/ts/src/app/flying-heroes.component.ts b/public/docs/_examples/pipes/ts/src/app/flying-heroes.component.ts new file mode 100644 index 0000000000..e4abb09a2f --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/flying-heroes.component.ts @@ -0,0 +1,61 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +import { HEROES } from './heroes'; + +@Component({ + selector: 'flying-heroes', + templateUrl: './flying-heroes.component.html', + styles: ['#flyers, #all {font-style: italic}'] +}) +// #docregion v1 +export class FlyingHeroesComponent { + heroes: any[] = []; + canFly = true; +// #enddocregion v1 + mutate = true; + title = 'Flying Heroes (pure pipe)'; + +// #docregion v1 + constructor() { this.reset(); } + + addHero(name: string) { + name = name.trim(); + if (!name) { return; } + let hero = {name, canFly: this.canFly}; +// #enddocregion v1 + if (this.mutate) { + // Pure pipe won't update display because heroes array reference is unchanged + // Impure pipe will display +// #docregion v1 +// #docregion push + this.heroes.push(hero); +// #enddocregion push +// #enddocregion v1 + } else { + // Pipe updates display because heroes array is a new object +// #docregion concat + this.heroes = this.heroes.concat(hero); +// #enddocregion concat + } +// #docregion v1 + } + + reset() { this.heroes = HEROES.slice(); } +} +// #enddocregion v1 + +////// Identical except for impure pipe ////// +// #docregion impure-component +@Component({ + selector: 'flying-heroes-impure', + templateUrl: './flying-heroes-impure.component.html', +// #enddocregion impure-component + styles: ['.flyers, .all {font-style: italic}'], +// #docregion impure-component +}) +export class FlyingHeroesImpureComponent extends FlyingHeroesComponent { + title = 'Flying Heroes (impure pipe)'; +} +// #enddocregion impure-component diff --git a/public/docs/_examples/pipes/ts/src/app/flying-heroes.pipe.ts b/public/docs/_examples/pipes/ts/src/app/flying-heroes.pipe.ts new file mode 100644 index 0000000000..87db9c277e --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/flying-heroes.pipe.ts @@ -0,0 +1,27 @@ +/* tslint:disable use-pipe-transform-interface */ +// #docregion +// #docregion pure +import { Pipe, PipeTransform } from '@angular/core'; + +import { Flyer } from './heroes'; + +@Pipe({ name: 'flyingHeroes' }) +export class FlyingHeroesPipe implements PipeTransform { + transform(allHeroes: Flyer[]) { + // #docregion filter + return allHeroes.filter(hero => hero.canFly); + // #enddocregion filter + } +} +// #enddocregion pure + +/////// Identical except for the pure flag +// #docregion impure +// #docregion pipe-decorator +@Pipe({ + name: 'flyingHeroesImpure', + pure: false +}) +// #enddocregion pipe-decorator +export class FlyingHeroesImpurePipe extends FlyingHeroesPipe {} +// #enddocregion impure diff --git a/public/docs/_examples/pipes/ts/src/app/hero-async-message.component.ts b/public/docs/_examples/pipes/ts/src/app/hero-async-message.component.ts new file mode 100644 index 0000000000..d5bbd9fb0e --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/hero-async-message.component.ts @@ -0,0 +1,38 @@ +// #docregion +import { Component } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/interval'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/take'; + +@Component({ + selector: 'hero-message', + template: ` +

    Async Hero Message and AsyncPipe

    +

    Message: {{ message$ | async }}

    + `, +}) +export class HeroAsyncMessageComponent { + message$: Observable; + + private messages = [ + 'You are my hero!', + 'You are the best hero!', + 'Will you be my hero?' + ]; + + constructor() { this.resend(); } + + resend() { + this.message$ = Observable.interval(500) + .map(i => this.messages[i]) + .take(this.messages.length); + } +} +// #enddocregion + +// Alternative message$ formula: +// this.message$ = Observable.fromArray(this.messages) +// .map(message => Observable.timer(500).map(() => message)) +// .concatAll(); diff --git a/public/docs/_examples/pipes/ts/src/app/hero-birthday1.component.ts b/public/docs/_examples/pipes/ts/src/app/hero-birthday1.component.ts new file mode 100644 index 0000000000..a670a807a8 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/hero-birthday1.component.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-birthday', + // #docregion hero-birthday-template + template: `

    The hero's birthday is {{ birthday | date }}

    ` + // #enddocregion hero-birthday-template +}) +export class HeroBirthdayComponent { + birthday = new Date(1988, 3, 15); // April 15, 1988 +} diff --git a/public/docs/_examples/pipes/ts/src/app/hero-birthday2.component.ts b/public/docs/_examples/pipes/ts/src/app/hero-birthday2.component.ts new file mode 100644 index 0000000000..87481aa121 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/hero-birthday2.component.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-birthday2', + // #docregion template + template: ` +

    The hero's birthday is {{ birthday | date:format }}

    + + ` + // #enddocregion template +}) +// #docregion class +export class HeroBirthday2Component { + birthday = new Date(1988, 3, 15); // April 15, 1988 + toggle = true; // start with true == shortDate + + get format() { return this.toggle ? 'shortDate' : 'fullDate'; } + toggleFormat() { this.toggle = !this.toggle; } +} diff --git a/public/docs/_examples/pipes/ts/src/app/hero-list.component.ts b/public/docs/_examples/pipes/ts/src/app/hero-list.component.ts new file mode 100644 index 0000000000..df231120ce --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/hero-list.component.ts @@ -0,0 +1,17 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-list', + template: ` +

    Heroes from JSON File

    + +
    + {{hero.name}} +
    + +

    Heroes as JSON: + {{'heroes.json' | fetch | json}} +

    ` +}) +export class HeroListComponent { } diff --git a/public/docs/_examples/pipes/ts/src/app/heroes.ts b/public/docs/_examples/pipes/ts/src/app/heroes.ts new file mode 100644 index 0000000000..b2edabe0da --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/heroes.ts @@ -0,0 +1,7 @@ +export interface Flyer { canFly: boolean; } +export const HEROES = [ + {name: 'Windstorm', canFly: true}, + {name: 'Bombasto', canFly: false}, + {name: 'Magneto', canFly: false}, + {name: 'Tornado', canFly: true} +]; diff --git a/public/docs/_examples/pipes/ts/src/app/power-boost-calculator.component.ts b/public/docs/_examples/pipes/ts/src/app/power-boost-calculator.component.ts new file mode 100644 index 0000000000..e65e29ad4c --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/power-boost-calculator.component.ts @@ -0,0 +1,18 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'power-boost-calculator', + template: ` +

    Power Boost Calculator

    +
    Normal power:
    +
    Boost factor:
    +

    + Super Hero Power: {{power | exponentialStrength: factor}} +

    + ` +}) +export class PowerBoostCalculatorComponent { + power = 5; + factor = 1; +} diff --git a/public/docs/_examples/pipes/ts/src/app/power-booster.component.ts b/public/docs/_examples/pipes/ts/src/app/power-booster.component.ts new file mode 100644 index 0000000000..08e3e24c7b --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/app/power-booster.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'power-booster', + template: ` +

    Power Booster

    +

    Super power boost: {{2 | exponentialStrength: 10}}

    + ` +}) +export class PowerBoosterComponent { } diff --git a/public/docs/_examples/pipes/ts/src/heroes.json b/public/docs/_examples/pipes/ts/src/heroes.json new file mode 100644 index 0000000000..e5f0b77262 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/heroes.json @@ -0,0 +1,6 @@ +[ + {"name": "Windstorm", "canFly": true}, + {"name": "Bombasto", "canFly": false}, + {"name": "Magneto", "canFly": false}, + {"name": "Tornado", "canFly": true} +] diff --git a/public/docs/_examples/pipes/ts/src/index.html b/public/docs/_examples/pipes/ts/src/index.html new file mode 100644 index 0000000000..fedb5c2e5e --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/index.html @@ -0,0 +1,26 @@ + + + + Pipes + + + + + + + + + + + + + + + + + my-app loading ... + + + diff --git a/public/docs/_examples/pipes/ts/src/main.ts b/public/docs/_examples/pipes/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/pipes/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/protractor-conf.old.js b/public/docs/_examples/protractor-conf.old.js deleted file mode 100644 index 12dd89ab9f..0000000000 --- a/public/docs/_examples/protractor-conf.old.js +++ /dev/null @@ -1,24 +0,0 @@ -exports.config = { - onPrepare: function() { - patchProtractorWait(browser); - }, - seleniumAddress: 'http://localhost:4444/wd/hub', - baseUrl: 'http://localhost:8080/', - specs: [ - '**/*e2e-spec.js' - ] -}; - -// Disable waiting for Angular as we don't have an integration layer yet... -// TODO(tbosch): Implement a proper debugging API for Ng2.0, remove this here -// and the sleeps in all tests. -function patchProtractorWait(browser) { - browser.ignoreSynchronization = true; - var _get = browser.get; - var sleepInterval = process.env.TRAVIS || process.env.JENKINS_URL ? 14000 : 8000; - browser.get = function() { - var result = _get.apply(this, arguments); - browser.sleep(sleepInterval); - return result; - } -} diff --git a/public/docs/_examples/protractor-helpers.ts b/public/docs/_examples/protractor-helpers.ts new file mode 100644 index 0000000000..61af74ba30 --- /dev/null +++ b/public/docs/_examples/protractor-helpers.ts @@ -0,0 +1,35 @@ +import { browser } from 'protractor'; + +export var appLang = { + appIsTs: false, + appIsJs: false, + appIsDart: false, + appIsUnknown: false +}; + +export function describeIf(cond: boolean, name: string, func: () => void): void { + if (cond) { + describe(name, func); + } else { + xdescribe(name, func); + } +} + +export function itIf(cond: boolean, name: string, func: (done: DoneFn) => void): void { + if (cond) { + it(name, func); + } else { + xit(name, func); + } +} + +// protractor.config.js is set to ng2 mode by default, so we must manually +// change it for upgradeAdapter tests +export function setProtractorToNg1Mode(): void { + browser.rootEl = 'body'; +} + +export function setProtractorToHybridMode() { + setProtractorToNg1Mode(); + browser.ng12Hybrid = true; +} diff --git a/public/docs/_examples/protractor.config.js b/public/docs/_examples/protractor.config.js index 1a128f4ca9..92b5e1fda5 100644 --- a/public/docs/_examples/protractor.config.js +++ b/public/docs/_examples/protractor.config.js @@ -1,9 +1,14 @@ -// TO RUN THE TESTS -// -// The first time, run: +// FIRST TIME ONLY- run: // ./node_modules/.bin/webdriver-manager update -// Make sure the test server is running. Then do. -// ./node_modules/.bin/protractor protractor.config.js +// +// Try: `npm run webdriver:update` +// +// AND THEN EVERYTIME ... +// 1. Compile with `tsc` +// 2. Make sure the test server (e.g., http-server: localhost:8080) is running. +// 3. ./node_modules/.bin/protractor protractor.config.js +// +// To do all steps, try: `npm run e2e` var fs = require('fs'); var path = require('canonical-path'); @@ -21,18 +26,15 @@ exports.config = { // Framework to use. Jasmine is recommended. framework: 'jasmine', - // Spec patterns are relative to this config file - specs: ['**/*e2e-spec.js' ], - - - // For angular2 tests + // For angular tests useAllAngular2AppRoots: true, + // Base URL for application server baseUrl: 'http://localhost:8080', // doesn't seem to work. // resultJsonOutputFile: "foo.json", - + onPrepare: function() { //// SpecReporter //var SpecReporter = require('jasmine-spec-reporter'); @@ -41,25 +43,23 @@ exports.config = { // debugging // console.log('browser.params:' + JSON.stringify(browser.params)); + var protractorHelpers = require('./protractor-helpers.ts'); var appDir = browser.params.appDir; if (appDir) { if (appDir.match('/ts') != null) { - browser.appIsTs = true; + protractorHelpers.appLang.appIsTs = true; } else if (appDir.match('/js') != null) { - browser.appIsJs = true; + protractorHelpers.appLang.appIsJs = true; } else if (appDir.match('/dart') != null) { - browser.appIsDart = true; + protractorHelpers.appLang.appIsDart = true; } else { - browser.appIsUnknown = true; + protractorHelpers.appLang.appIsUnknown = true; } } else { - browser.appIsUnknown = true; + protractorHelpers.appLang.appIsUnknown = true; } - jasmine.getEnv().addReporter(new Reporter( browser.params )) ; - global.describeIf = describeIf; - global.itIf = itIf; - global.sendKeys = sendKeys; + jasmine.getEnv().addReporter(new Reporter( browser.params )); }, jasmineNodeOpts: { @@ -67,38 +67,19 @@ exports.config = { defaultTimeoutInterval: 10000, showTiming: true, print: function() {} - } -}; - -function describeIf(cond, name, func) { - if (cond) { - describe(name, func); - } else { - xdescribe(name, func); - } -} - -function itIf(cond, name, func) { - if (cond) { - it(name, func); - } else { - xit(name, func); - } -} + }, -// Hack - because of bug with send keys -function sendKeys(element, str) { - return str.split('').reduce(function (promise, char) { - return promise.then(function () { - return element.sendKeys(char); + beforeLaunch: function() { + // add TS support for specs + require('ts-node').register({ + project: './tsconfig.json' }); - }, element.getAttribute('value')); - // better to create a resolved promise here but ... don't know how with protractor; -} - + } +}; +// See http://jasmine.github.io/2.1/custom_reporter.html function Reporter(options) { - var _defaultOutputFile = path.resolve(process.cwd(), "../../", 'protractor-results.txt'); + var _defaultOutputFile = path.resolve(process.cwd(), "../../../", 'protractor-results.txt'); options.outputFile = options.outputFile || _defaultOutputFile; var _root = { appDir: options.appDir, suites: [] }; @@ -136,6 +117,11 @@ function Reporter(options) { _currentSuite.specs.push(currentSpec); log(spec.status + ' - ' + spec.description); + if (spec.status === 'failed') { + spec.failedExpectations.forEach(function(err) { + log(err.message); + }); + } }; this.jasmineDone = function() { @@ -187,4 +173,3 @@ function Reporter(options) { } } - diff --git a/public/docs/_examples/quickstart/dart/ex1/pubspec.yaml b/public/docs/_examples/quickstart/dart/ex1/pubspec.yaml deleted file mode 100644 index c1be565dad..0000000000 --- a/public/docs/_examples/quickstart/dart/ex1/pubspec.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# #docregion -name: angular2_getting_started -description: QuickStart -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 -transformers: -- angular2: - entry_points: web/main.dart diff --git a/public/docs/_examples/quickstart/dart/ex1/web/index.html b/public/docs/_examples/quickstart/dart/ex1/web/index.html deleted file mode 100644 index a1e925b8fb..0000000000 --- a/public/docs/_examples/quickstart/dart/ex1/web/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Getting Started - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/quickstart/dart/ex1/web/main.dart b/public/docs/_examples/quickstart/dart/ex1/web/main.dart deleted file mode 100644 index e6836148a3..0000000000 --- a/public/docs/_examples/quickstart/dart/ex1/web/main.dart +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; -import 'package:angular2/bootstrap.dart'; - -@Component(selector: 'my-app', template: '

    My First Angular 2 App

    ') -class AppComponent {} - -main() { - bootstrap(AppComponent); -} diff --git a/public/docs/_examples/quickstart/dart/ex2/pubspec.yaml b/public/docs/_examples/quickstart/dart/ex2/pubspec.yaml deleted file mode 100644 index ce8c66ece3..0000000000 --- a/public/docs/_examples/quickstart/dart/ex2/pubspec.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# #docregion -name: angular2_getting_started -description: QuickStart -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/quickstart/dart/ex2/web/index.html b/public/docs/_examples/quickstart/dart/ex2/web/index.html deleted file mode 100644 index a1e925b8fb..0000000000 --- a/public/docs/_examples/quickstart/dart/ex2/web/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - Getting Started - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/quickstart/dart/ex2/web/main.dart b/public/docs/_examples/quickstart/dart/ex2/web/main.dart deleted file mode 100644 index e6836148a3..0000000000 --- a/public/docs/_examples/quickstart/dart/ex2/web/main.dart +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; -import 'package:angular2/bootstrap.dart'; - -@Component(selector: 'my-app', template: '

    My First Angular 2 App

    ') -class AppComponent {} - -main() { - bootstrap(AppComponent); -} diff --git a/public/docs/_examples/quickstart/e2e-spec.js b/public/docs/_examples/quickstart/e2e-spec.js deleted file mode 100644 index 52bb8ec7af..0000000000 --- a/public/docs/_examples/quickstart/e2e-spec.js +++ /dev/null @@ -1,15 +0,0 @@ - -describe('QuickStart E2E Tests', function () { - - var expectedMsg = 'My First Angular 2 App'; - - - beforeEach(function () { - browser.get(''); - }); - - it('should display: ' + expectedMsg, function () { - expect(element(by.css('h1')).getText()).toEqual(expectedMsg); - }); - -}); diff --git a/public/docs/_examples/quickstart/e2e-spec.ts b/public/docs/_examples/quickstart/e2e-spec.ts new file mode 100644 index 0000000000..73921707ee --- /dev/null +++ b/public/docs/_examples/quickstart/e2e-spec.ts @@ -0,0 +1,17 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('QuickStart E2E Tests', function () { + + let expectedMsg = 'Hello Angular'; + + beforeEach(function () { + browser.get(''); + }); + + it(`should display: ${expectedMsg}`, function () { + expect(element(by.css('h1')).getText()).toEqual(expectedMsg); + }); + +}); diff --git a/public/docs/_examples/quickstart/js/app/app.component.js b/public/docs/_examples/quickstart/js/app/app.component.js deleted file mode 100644 index f86b3bde46..0000000000 --- a/public/docs/_examples/quickstart/js/app/app.component.js +++ /dev/null @@ -1,27 +0,0 @@ -// #docplaster -// #docregion -// #docregion iife -(function(app) { - // #enddocregion iife - // #docregion ng-namespace-funcs, export - app.AppComponent = - // #enddocregion export - // #docregion component - ng.core.Component({ - // #enddocregion ng-namespace-funcs - selector: 'my-app', - template: '

    My First Angular 2 App

    ' - // #docregion ng-namespace-funcs - }) - // #enddocregion component - // #docregion class - .Class({ - // #enddocregion ng-namespace-funcs - constructor: function() {} - // #docregion ng-namespace-funcs - }); - // #enddocregion class - // #enddocregion ng-namespace-funcs -// #docregion iife -})(window.app || (window.app = {})); -// #enddocregion iife diff --git a/public/docs/_examples/quickstart/js/app/main.js b/public/docs/_examples/quickstart/js/app/main.js deleted file mode 100644 index d003119574..0000000000 --- a/public/docs/_examples/quickstart/js/app/main.js +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -(function(app) { - document.addEventListener('DOMContentLoaded', function() { - // #docregion import - ng.platform.browser.bootstrap(app.AppComponent); - // #enddocregion import - }); -})(window.app || (window.app = {})); diff --git a/public/docs/_examples/quickstart/js/bs-config.1.json b/public/docs/_examples/quickstart/js/bs-config.1.json new file mode 100644 index 0000000000..4e58595267 --- /dev/null +++ b/public/docs/_examples/quickstart/js/bs-config.1.json @@ -0,0 +1,8 @@ +{ + "server": { + "baseDir": "src", + "routes": { + "/node_modules": "node_modules" + } + } +} diff --git a/public/docs/_examples/quickstart/js/example-config.json b/public/docs/_examples/quickstart/js/example-config.json index e69de29bb2..81f31aaf0d 100644 --- a/public/docs/_examples/quickstart/js/example-config.json +++ b/public/docs/_examples/quickstart/js/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:babel" +} diff --git a/public/docs/_examples/quickstart/js/index.html b/public/docs/_examples/quickstart/js/index.html deleted file mode 100644 index 1e66047c46..0000000000 --- a/public/docs/_examples/quickstart/js/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Angular 2 QuickStart - - - - - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - - diff --git a/public/docs/_examples/quickstart/js/package.1.json b/public/docs/_examples/quickstart/js/package.1.json index c41de3b0a9..28aee2b92e 100644 --- a/public/docs/_examples/quickstart/js/package.1.json +++ b/public/docs/_examples/quickstart/js/package.1.json @@ -1,21 +1,29 @@ { - "name": "angular2-quickstart", + "name": "angular-quickstart", "version": "1.0.0", "scripts": { "start": "npm run lite", "lite": "lite-server" }, - "license": "ISC", + "license": "MIT", "dependencies": { - "angular2": "2.0.0-beta.8", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "zone.js": "0.5.15" + "@angular/common": "~2.4.0", + "@angular/compiler": "~2.4.0", + "@angular/core": "~2.4.0", + "@angular/forms": "~2.4.0", + "@angular/http": "~2.4.0", + "@angular/platform-browser": "~2.4.0", + "@angular/platform-browser-dynamic": "~2.4.0", + "@angular/router": "~3.4.0", + "@angular/upgrade": "~2.4.0", + + "angular-in-memory-web-api": "~0.3.1", + "core-js": "^2.4.1", + "rxjs": "5.0.1", + "zone.js": "^0.8.4" }, "devDependencies": { - "concurrently": "^2.0.0", - "lite-server": "^2.1.0" + "concurrently": "^3.0.0", + "lite-server": "^2.2.2" } } diff --git a/public/docs/_examples/quickstart/js/plnkr.json b/public/docs/_examples/quickstart/js/plnkr.json index 16a1c9a6c0..5e24ad9790 100644 --- a/public/docs/_examples/quickstart/js/plnkr.json +++ b/public/docs/_examples/quickstart/js/plnkr.json @@ -1,5 +1,6 @@ { "description": "QuickStart", + "basePath": "src/", "files": [ "!**/*.[1].*" ], diff --git a/public/docs/_examples/quickstart/js/spec.js b/public/docs/_examples/quickstart/js/spec.js deleted file mode 100644 index 83f3eaea94..0000000000 --- a/public/docs/_examples/quickstart/js/spec.js +++ /dev/null @@ -1,9 +0,0 @@ -describe("Jasmine sample test", function() { - - it("1+1 should be 2", function() { - - var result = 1 + 1; - - expect(result).toBe(2); - }); -}); \ No newline at end of file diff --git a/public/docs/_examples/quickstart/js/src/app/app.component.js b/public/docs/_examples/quickstart/js/src/app/app.component.js new file mode 100644 index 0000000000..26ba116efe --- /dev/null +++ b/public/docs/_examples/quickstart/js/src/app/app.component.js @@ -0,0 +1,27 @@ +// #docplaster +// #docregion +// #docregion iife +(function(app) { + // #enddocregion iife + // #docregion ng-namespace-funcs, export + app.AppComponent = + // #enddocregion export + // #docregion component + ng.core.Component({ + // #enddocregion ng-namespace-funcs + selector: 'my-app', + template: '

    Hello Angular

    ' + // #docregion ng-namespace-funcs + }) + // #enddocregion component + // #docregion class + .Class({ + // #enddocregion ng-namespace-funcs + constructor: function() {} + // #docregion ng-namespace-funcs + }); + // #enddocregion class + // #enddocregion ng-namespace-funcs +// #docregion iife +})(window.app || (window.app = {})); +// #enddocregion iife diff --git a/public/docs/_examples/quickstart/js/src/app/app.module.js b/public/docs/_examples/quickstart/js/src/app/app.module.js new file mode 100644 index 0000000000..0f3d5f82cf --- /dev/null +++ b/public/docs/_examples/quickstart/js/src/app/app.module.js @@ -0,0 +1,15 @@ +// #docplaster +// #docregion +(function(app) { + app.AppModule = + ng.core.NgModule({ + imports: [ ng.platformBrowser.BrowserModule ], + // #docregion import + declarations: [ app.AppComponent ], + // #enddocregion import + bootstrap: [ app.AppComponent ] + }) + .Class({ + constructor: function() {} + }); +})(window.app || (window.app = {})); diff --git a/public/docs/_examples/quickstart/js/src/index.html b/public/docs/_examples/quickstart/js/src/index.html new file mode 100644 index 0000000000..43d63e9c83 --- /dev/null +++ b/public/docs/_examples/quickstart/js/src/index.html @@ -0,0 +1,42 @@ + + + + + Angular QuickStart JS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + + diff --git a/public/docs/_examples/quickstart/js/src/main.js b/public/docs/_examples/quickstart/js/src/main.js new file mode 100644 index 0000000000..785823fa84 --- /dev/null +++ b/public/docs/_examples/quickstart/js/src/main.js @@ -0,0 +1,8 @@ +// #docregion +(function(app) { + document.addEventListener('DOMContentLoaded', function() { + ng.platformBrowserDynamic + .platformBrowserDynamic() + .bootstrapModule(app.AppModule); + }); +})(window.app || (window.app = {})); diff --git a/public/docs/_examples/quickstart/js/src/styles.1.css b/public/docs/_examples/quickstart/js/src/styles.1.css new file mode 100644 index 0000000000..fbc30e2c9e --- /dev/null +++ b/public/docs/_examples/quickstart/js/src/styles.1.css @@ -0,0 +1,14 @@ +/* #docregion */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +body { + margin: 2em; +} + + /* + * See https://github.com/angular/angular.io/blob/master/public/docs/_examples/styles.css + * for the full set of master styles used by the documentation samples + */ diff --git a/public/docs/_examples/quickstart/ts/.gitignore b/public/docs/_examples/quickstart/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/quickstart/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/quickstart/ts/app/app.component.ts b/public/docs/_examples/quickstart/ts/app/app.component.ts deleted file mode 100644 index 0d6e66d2aa..0000000000 --- a/public/docs/_examples/quickstart/ts/app/app.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -// #docregion -// #docregion import -import {Component} from 'angular2/core'; -// #enddocregion import - -// #docregion metadata -@Component({ - selector: 'my-app', - template: '

    My First Angular 2 App

    ' -}) -// #enddocregion metadata -// #docregion export -export class AppComponent { } -// #enddocregion export \ No newline at end of file diff --git a/public/docs/_examples/quickstart/ts/app/main.ts b/public/docs/_examples/quickstart/ts/app/main.ts deleted file mode 100644 index effe7c896f..0000000000 --- a/public/docs/_examples/quickstart/ts/app/main.ts +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser' -// #docregion app-component -import {AppComponent} from './app.component' -// #enddocregion app-component - -bootstrap(AppComponent); diff --git a/public/docs/_examples/quickstart/ts/bs-config.1.json b/public/docs/_examples/quickstart/ts/bs-config.1.json new file mode 100644 index 0000000000..4e58595267 --- /dev/null +++ b/public/docs/_examples/quickstart/ts/bs-config.1.json @@ -0,0 +1,8 @@ +{ + "server": { + "baseDir": "src", + "routes": { + "/node_modules": "node_modules" + } + } +} diff --git a/public/docs/_examples/quickstart/ts/index.html b/public/docs/_examples/quickstart/ts/index.html deleted file mode 100644 index 21b3a60713..0000000000 --- a/public/docs/_examples/quickstart/ts/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Angular 2 QuickStart - - - - - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - - diff --git a/public/docs/_examples/quickstart/ts/package.1.json b/public/docs/_examples/quickstart/ts/package.1.json deleted file mode 100644 index 5160703dcf..0000000000 --- a/public/docs/_examples/quickstart/ts/package.1.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "angular2-quickstart", - "version": "1.0.0", - "scripts": { - "start": "concurrently \"npm run tsc:w\" \"npm run lite\" ", - "tsc": "tsc", - "tsc:w": "tsc -w", - "lite": "lite-server", - "typings": "typings", - "postinstall": "typings install" - }, - "license": "ISC", - "dependencies": { - "angular2": "2.0.0-beta.8", - "systemjs": "0.19.22", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "zone.js": "0.5.15" - }, - "devDependencies": { - "concurrently": "^2.0.0", - "lite-server": "^2.1.0", - "typescript": "^1.8.2", - "typings":"^0.6.8" - } -} diff --git a/public/docs/_examples/quickstart/ts/plnkr.json b/public/docs/_examples/quickstart/ts/plnkr.json index a4449b444f..8edf7c25ea 100644 --- a/public/docs/_examples/quickstart/ts/plnkr.json +++ b/public/docs/_examples/quickstart/ts/plnkr.json @@ -1,9 +1,12 @@ { "description": "QuickStart", + "basePath": "src/", "files": [ - "!**/*.d.ts", - "!**/*.js", - "!**/*.[1].*" + "app/app.component.ts", + "app/app.module.ts", + "main.ts", + "index.html" ], + "open": "app/app.component.ts", "tags": ["quickstart"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/quickstart/ts/src/app/app.component.ts b/public/docs/_examples/quickstart/ts/src/app/app.component.ts new file mode 100644 index 0000000000..1ef28fc5c4 --- /dev/null +++ b/public/docs/_examples/quickstart/ts/src/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: `

    Hello {{name}}

    ` +}) +export class AppComponent { name = 'Angular'; } diff --git a/public/docs/_examples/quickstart/ts/src/app/app.module.ts b/public/docs/_examples/quickstart/ts/src/app/app.module.ts new file mode 100644 index 0000000000..50a0e6eb47 --- /dev/null +++ b/public/docs/_examples/quickstart/ts/src/app/app.module.ts @@ -0,0 +1,11 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/quickstart/ts/src/index.html b/public/docs/_examples/quickstart/ts/src/index.html new file mode 100644 index 0000000000..21fb56edb9 --- /dev/null +++ b/public/docs/_examples/quickstart/ts/src/index.html @@ -0,0 +1,31 @@ + + + + Angular Quickstart + + + + + + + + + + + + + + + + + + + Loading AppComponent content here ... + + + + diff --git a/public/docs/_examples/quickstart/ts/src/main.ts b/public/docs/_examples/quickstart/ts/src/main.ts new file mode 100644 index 0000000000..311c44b76d --- /dev/null +++ b/public/docs/_examples/quickstart/ts/src/main.ts @@ -0,0 +1,5 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/quickstart/ts/src/tsconfig.1.json b/public/docs/_examples/quickstart/ts/src/tsconfig.1.json new file mode 100644 index 0000000000..2c7260d1bc --- /dev/null +++ b/public/docs/_examples/quickstart/ts/src/tsconfig.1.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + } +} diff --git a/public/docs/_examples/quickstart/ts/tsconfig.1.json b/public/docs/_examples/quickstart/ts/tsconfig.1.json deleted file mode 100644 index 9be71e4c6e..0000000000 --- a/public/docs/_examples/quickstart/ts/tsconfig.1.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "system", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "removeComments": false, - "noImplicitAny": false - }, - "exclude": [ - "node_modules", - "typings/main", - "typings/main.d.ts" - ] -} diff --git a/public/docs/_examples/quickstart/ts/typings.1.json b/public/docs/_examples/quickstart/ts/typings.1.json deleted file mode 100644 index f10b7c5416..0000000000 --- a/public/docs/_examples/quickstart/ts/typings.1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ambientDependencies": { - "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#bc92442c075929849ec41d28ab618892ba493504" - } -} diff --git a/public/docs/_examples/reactive-forms/e2e-spec.ts b/public/docs/_examples/reactive-forms/e2e-spec.ts new file mode 100644 index 0000000000..bb788397ef --- /dev/null +++ b/public/docs/_examples/reactive-forms/e2e-spec.ts @@ -0,0 +1,1020 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +function finalDemoAddressForm(element: any, index: number) { + let form = { + street: element.all(by.css('input[formcontrolname=street]')).get(index).getAttribute('value'), + city: element.all(by.css('input[formcontrolname=city]')).get(index).getAttribute('value'), + state: element.all(by.css('select[formcontrolname=state]')).get(index).getAttribute('value'), + zip: element.all(by.css('input[formcontrolname=zip]')).get(index).getAttribute('value') + }; + return form; +} + +describe('Reactive forms', function() { + let select: any; + + beforeEach(function() { + browser.get(''); + select = element(by.css('.container > h4 > select')); + }); + + describe('navigation', function() { + it('should display the title', function() { + let title = element(by.css('.container > h1')); + expect(title.getText()).toBe('Reactive Forms'); + }); + + it('should contain a dropdown with each example', function() { + expect(select.isDisplayed()).toBe(true); + }); + + it('should have 9 options for different demos', function() { + let options = select.all(by.tagName('option')); + expect(options.count()).toBe(9); + }); + + it('should start with Final Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('Final Demo'); + }); + }); + }); + +// *************Begin Final Demo test******************************* + + describe('final demo', function() { + it('does not select any hero by default', function() { + let heroSection = element(by.css('hero-list > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + it('refreshes the page upon button click', function() { + // We move to another page... + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + let refresh = element(by.css('button')); + refresh.click(); + let heroSection = element(by.css('hero-list > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + describe('Whirlwind form', function() { + beforeEach(function() { + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Whirlwind'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Whirlwind'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe('123 Main'); + expect(address1.state).toBe('CA'); + expect(address1.zip).toBe('94801'); + expect(address1.city).toBe('Anywhere'); + let address2 = finalDemoAddressForm(element, 1); + expect(address2.street).toBe('456 Maple'); + expect(address2.state).toBe('VA'); + expect(address2.zip).toBe('23226'); + expect(address2.city).toBe('Somewhere'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail > p')); + expect(json.getText()).toContain('Whirlwind'); + expect(json.getText()).toContain('Anywhere'); + expect(json.getText()).toContain('Somewhere'); + expect(json.getText()).toContain('VA'); + }); + + it('has two disabled buttons by default', function() { + let buttons = element.all(by.css('hero-detail > form > div > button')); + expect(buttons.get(0).getAttribute('disabled')).toBe('true'); + expect(buttons.get(1).getAttribute('disabled')).toBe('true'); + }); + + it('enables the buttons after we edit the form', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let buttons = element.all(by.css('hero-detail > form > div > button')); + expect(buttons.get(0).getAttribute('disabled')).toBeNull(); + expect(buttons.get(1).getAttribute('disabled')).toBeNull(); + }); + + it('saves the changes when the save button is clicked', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let save = element.all(by.css('hero-detail > form > div > button')).get(0); + save.click(); + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Whirlwinda'); + }); + + it('reverts the changes when the revert button is clicked', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let revert = element.all(by.css('hero-detail > form > div > button')).get(1); + revert.click(); + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Whirlwind'); + expect(nameInput.getAttribute('value')).toBe('Whirlwind'); + }); + + it('is able to add a new empty address', function() { + let newLairButton = element.all(by.css('button')).get(3); + newLairButton.click(); + let address3 = finalDemoAddressForm(element, 2); + expect(address3.street).toBe(''); + expect(address3.state).toBe(''); + expect(address3.zip).toBe(''); + expect(address3.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + }); + + describe('Bombastic form', function() { + beforeEach(function() { + let bombastaButton = element.all(by.css('nav a')).get(1); + bombastaButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Bombastic'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Bombastic'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe('789 Elm'); + // expect(address1.state).toBe('OH'); + expect(address1.zip).toBe('04501'); + expect(address1.city).toBe('Smallville'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail > p')); + expect(json.getText()).toContain('Bombastic'); + expect(json.getText()).toContain('Smallville'); + expect(json.getText()).toContain('OH'); + expect(json.getText()).toContain('04501'); + }); + + it('has two disabled buttons by default', function() { + let buttons = element.all(by.css('hero-detail > form > div > button')); + expect(buttons.get(0).getAttribute('disabled')).toBe('true'); + expect(buttons.get(1).getAttribute('disabled')).toBe('true'); + }); + + it('enables the buttons after we edit the form', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let buttons = element.all(by.css('hero-detail > form > div > button')); + expect(buttons.get(0).getAttribute('disabled')).toBeNull(); + expect(buttons.get(1).getAttribute('disabled')).toBeNull(); + }); + + it('saves the changes when the save button is clicked', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let save = element.all(by.css('hero-detail > form > div > button')).get(0); + save.click(); + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Bombastica'); + }); + + it('reverts the changes when the revert button is clicked', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let revert = element.all(by.css('hero-detail > form > div > button')).get(1); + revert.click(); + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Bombastic'); + expect(nameInput.getAttribute('value')).toBe('Bombastic'); + }); + + it('is able to add a new empty address', function() { + let newLairButton = element.all(by.css('button')).get(3); + newLairButton.click(); + let address2 = finalDemoAddressForm(element, 1); + expect(address2.street).toBe(''); + expect(address2.state).toBe(''); + expect(address2.zip).toBe(''); + expect(address2.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + }); + + describe('Magneta form', function() { + + beforeEach(function() { + let magnetaButton = element.all(by.css('nav a')).get(2); + magnetaButton.click(); + }); + + it('should show hero information when the button is clicked', function() { + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Magneta'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Magneta'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail > p')); + expect(json.getText()).toContain('Magneta'); + }); + + it('has two disabled buttons by default', function() { + let buttons = element.all(by.css('hero-detail > form > div > button')); + expect(buttons.get(0).getAttribute('disabled')).toBe('true'); + expect(buttons.get(1).getAttribute('disabled')).toBe('true'); + }); + + it('enables the buttons after we edit the form', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let buttons = element.all(by.css('hero-detail > form > div > button')); + expect(buttons.get(0).getAttribute('disabled')).toBeNull(); + expect(buttons.get(1).getAttribute('disabled')).toBeNull(); + }); + + it('saves the changes when the save button is clicked', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let save = element.all(by.css('hero-detail > form > div > button')).get(0); + save.click(); + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Magnetaa'); + }); + + it('reverts the changes when the revert button is clicked', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + nameInput.sendKeys('a'); + let revert = element.all(by.css('hero-detail > form > div > button')).get(1); + revert.click(); + let editMessage = element(by.css('hero-list > div > h3')); + expect(editMessage.getText()).toBe('Editing: Magneta'); + expect(nameInput.getAttribute('value')).toBe('Magneta'); + }); + + it('is able to add a new empty address', function() { + let newLairButton = element.all(by.css('button')).get(3); + newLairButton.click(); + let address = finalDemoAddressForm(element, 0); + expect(address.street).toBe(''); + expect(address.state).toBe(''); + expect(address.zip).toBe(''); + expect(address.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + }); + }); // final demo + +// *************Begin FormArray Demo test******************************* + + + describe('formArray demo', function() { + beforeEach(function() { + let FormArrayOption = element.all(by.css('select option')).get(7); + FormArrayOption.click(); + }); + + it('should show FormArray Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('FormArray Demo'); + }); + }); + + it('does not select any hero by default', function() { + let heroSection = element(by.css('hero-list > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + it('refreshes the page upon button click', function() { + // We move to another page... + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + let refresh = element(by.css('button')); + refresh.click(); + let heroSection = element(by.css('hero-list > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + describe('Whirlwind form', function() { + beforeEach(function() { + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + }); + + it('should show hero information when the button is clicked', function() { + let editMessage = element(by.css('div.demo > div > div > h3')); + expect(editMessage.getText()).toBe('Editing: Whirlwind'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Whirlwind'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe('123 Main'); + expect(address1.state).toBe('CA'); + expect(address1.zip).toBe('94801'); + expect(address1.city).toBe('Anywhere'); + let address2 = finalDemoAddressForm(element, 1); + expect(address2.street).toBe('456 Maple'); + expect(address2.state).toBe('VA'); + expect(address2.zip).toBe('23226'); + expect(address2.city).toBe('Somewhere'); + }); + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-8 > p')); + expect(json.getText()).toContain('Whirlwind'); + expect(json.getText()).toContain('Anywhere'); + expect(json.getText()).toContain('Somewhere'); + expect(json.getText()).toContain('VA'); + }); + + it('is able to add a new empty address', function() { + let newLairButton = element.all(by.css('button')).get(1); + newLairButton.click(); + let address2 = finalDemoAddressForm(element, 2); + expect(address2.street).toBe(''); + expect(address2.state).toBe(''); + expect(address2.zip).toBe(''); + expect(address2.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + }); // Whirlwind form + + describe('Bombastic FormArray form', function() { + beforeEach(function() { + let bombasticButton = element.all(by.css('nav a')).get(1); + bombasticButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('div.demo > div > div > h3')); + expect(editMessage.getText()).toBe('Editing: Bombastic'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + // nameInput.getAttribute('value').then(function(name: string) { + // expect(name).toBe('Whirlwind'); + // }); + expect(nameInput.getAttribute('value')).toBe('Bombastic'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe('789 Elm'); + // expect(address1.state).toBe('OH'); + // This select should be OH not CA, which it shows in the UI, the JSON shows OH. + expect(address1.zip).toBe('04501'); + expect(address1.city).toBe('Smallville'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-8 > p')); + expect(json.getText()).toContain('Bombastic'); + expect(json.getText()).toContain('Smallville'); + expect(json.getText()).toContain('04501'); + expect(json.getText()).toContain('789 Elm'); + }); + + it('is able to add a new empty address', function() { + let newLairButton = element.all(by.css('button')).get(1); + newLairButton.click(); + let address1 = finalDemoAddressForm(element, 1); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + }); // Bombastic FormArray form + + describe('Magneta FormArray form', function() { + beforeEach(function() { + let magnetaButton = element.all(by.css('nav a')).get(2); + magnetaButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('div.demo > div > div > h3')); + expect(editMessage.getText()).toBe('Editing: Magneta'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Magneta'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-8 > p')); + expect(json.getText()).toContain('Magneta'); + }); + + it('is able to add a new empty address', function() { + let newLairButton = element.all(by.css('button')).get(1); + newLairButton.click(); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + }); // Magneta FormArray form + + }); // formArray demo + + +// *************Begin SetValue Demo test******************************* + + describe('SetValue demo', function() { + beforeEach(function() { + let SetValueOption = element.all(by.css('select option')).get(6); + SetValueOption.click(); + }); + + it('should show SetValue Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('SetValue Demo'); + }); + }); + + it('does not select any hero by default', function() { + let heroSection = element(by.css('hero-list > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + it('refreshes the page upon button click', function() { + // We move to another page... + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + let refresh = element(by.css('button')); + refresh.click(); + let heroSection = element(by.css('hero-list > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + describe('Whirlwind setValue form', function() { + beforeEach(function() { + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('.demo > div > div > h3')); + expect(editMessage.getText()).toBe('Editing: Whirlwind'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Whirlwind'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe('123 Main'); + expect(address1.state).toBe('CA'); + expect(address1.zip).toBe('94801'); + expect(address1.city).toBe('Anywhere'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-7 > p')); + expect(json.getText()).toContain('Whirlwind'); + expect(json.getText()).toContain('Anywhere'); + let nameOutput = element(by.css('hero-detail-7 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value: Whirlwind'); + let streetOutput = element(by.css('hero-detail-7 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value: 123 Main'); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + }); // Whirlwind setValue form + + describe('Bombastic setValue form', function() { + beforeEach(function() { + let bombasticButton = element.all(by.css('nav a')).get(1); + bombasticButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('.demo > div > div > h3')); + expect(editMessage.getText()).toBe('Editing: Bombastic'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Bombastic'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe('789 Elm'); + expect(address1.state).toBe('OH'); + expect(address1.zip).toBe('04501'); + expect(address1.city).toBe('Smallville'); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-7 > p')); + expect(json.getText()).toContain('Bombastic'); + expect(json.getText()).toContain('Smallville'); + expect(json.getText()).toContain('04501'); + expect(json.getText()).toContain('789 Elm'); + let nameOutput = element(by.css('hero-detail-7 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value: Bombastic'); + let streetOutput = element(by.css('hero-detail-7 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value: 789 Elm'); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + }); // Bombastic setValue form + + describe('Magneta setValue form', function() { + beforeEach(function() { + let magnetaButton = element.all(by.css('nav a')).get(2); + magnetaButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('.demo > div > div > h3')); + expect(editMessage.getText()).toBe('Editing: Magneta'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Magneta'); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-7 > p')); + expect(json.getText()).toContain('Magneta'); + let nameOutput = element(by.css('hero-detail-7 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value: Magneta'); + let streetOutput = element(by.css('hero-detail-7 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value:'); + }); + + }); // Magneta setValue form + }); // SetValue demo + +// *************Begin patchValue Demo test******************************* + + describe('patchValue demo', function() { + beforeEach(function() { + let SetValueOption = element.all(by.css('select option')).get(5); + SetValueOption.click(); + }); + + it('should show patchValue Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('PatchValue Demo'); + }); + }); + + it('does not select any hero by default', function() { + let heroSection = element(by.css('.demo > div > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + it('refreshes the page upon button click', function() { + // We move to another page... + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + let refresh = element(by.css('button')); + refresh.click(); + let heroSection = element(by.css('.demo > div > div')); + expect(heroSection.isPresent()).toBe(false); + }); + + describe('Whirlwind patchValue form', function() { + beforeEach(function() { + let whirlwindButton = element.all(by.css('nav a')).get(0); + whirlwindButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('h2 ~ h3')); + expect(editMessage.getText()).toBe('Editing: Whirlwind'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Whirlwind'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-6 > p')); + expect(json.getText()).toContain('Whirlwind'); + let nameOutput = element(by.css('hero-detail-6 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value: Whirlwind'); + let streetOutput = element(by.css('hero-detail-6 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value:'); + }); + + + }); // Bombastic patchValue form + describe('Bombastic patchValue form', function() { + beforeEach(function() { + let bombasticButton = element.all(by.css('nav a')).get(1); + bombasticButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('h2 ~ h3')); + expect(editMessage.getText()).toBe('Editing: Bombastic'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Bombastic'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-6 > p')); + expect(json.getText()).toContain('Bombastic'); + let nameOutput = element(by.css('hero-detail-6 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value: Bombastic'); + let streetOutput = element(by.css('hero-detail-6 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value:'); + }); + }); // Bombastic patchValue form + + describe('Magneta patchValue form', function() { + beforeEach(function() { + let magnetaButton = element.all(by.css('nav a')).get(2); + magnetaButton.click(); + }); + + it('should show a hero information when the button is clicked', function() { + let editMessage = element(by.css('h2 ~ h3')); + expect(editMessage.getText()).toBe('Editing: Magneta'); + }); + + it('should show a form with the selected hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe('Magneta'); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-6 > p')); + expect(json.getText()).toContain('Magneta'); + let nameOutput = element(by.css('hero-detail-6 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value: Magneta'); + let streetOutput = element(by.css('hero-detail-6 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value:'); + }); + + }); // Magneta patchValue form + }); // PatchValue demo + + + +// *************Begin Nested FormBuilder Demo test******************************* + + describe('Nested FormBuilder demo', function() { + beforeEach(function() { + let NestedFormBuilderOption = element.all(by.css('select option')).get(4); + NestedFormBuilderOption.click(); + }); + + it('should show Nested FormBuilder Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('Nested FormBuilder group Demo'); + }); + }); + + it('should show a form for hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe(''); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-5 > p')); + expect(json.getText()).toContain('address'); + let nameOutput = element(by.css('hero-detail-5 > p ~ p')); + expect(nameOutput.getText()).toContain('Name value:'); + let streetOutput = element(by.css('hero-detail-5 > p ~ p ~ p')); + expect(streetOutput.getText()).toContain('Street value:'); + }); + + }); // Nested FormBuilder demo + +// *************Begin Group with multiple controls Demo test******************************* + + describe('Group with multiple controls demo', function() { + beforeEach(function() { + let NestedFormBuilderOption = element.all(by.css('select option')).get(3); + NestedFormBuilderOption.click(); + }); + + it('should show Group with multiple controls Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('Group with multiple controls Demo'); + }); + }); + + it('should show header', function() { + let header = element(by.css('hero-detail-4 > h3')); + expect(header.getText()).toBe('A FormGroup with multiple FormControls'); + }); + + it('should show a form for hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe(''); + let address1 = finalDemoAddressForm(element, 0); + expect(address1.street).toBe(''); + expect(address1.state).toBe(''); + expect(address1.zip).toBe(''); + expect(address1.city).toBe(''); + }); + + it('should show three radio buttons', function() { + let radioButtons = element.all(by.css('input[formcontrolname=power]')); + expect(radioButtons.get(0).getAttribute('value')).toBe('flight'); + expect(radioButtons.get(1).getAttribute('value')).toBe('x-ray vision'); + expect(radioButtons.get(2).getAttribute('value')).toBe('strength'); + }); + it('should show a checkbox', function() { + let checkbox = element(by.css('input[formcontrolname=sidekick]')); + expect(checkbox.getAttribute('checked')).toBe(null); + }); + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-4 > p')); + expect(json.getText()).toContain('power'); + }); + +}); // Group with multiple controls demo + + + +// *************Begin Group with multiple controls Demo test******************************* + + describe('Simple FormBuilder Group demo', function() { + beforeEach(function() { + let SimpleFormBuilderOption = element.all(by.css('select option')).get(2); + SimpleFormBuilderOption.click(); + }); + + it('should show Simple FormBuilder group Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('Simple FormBuilder group Demo'); + }); + }); + + it('should show header', function() { + let header = element(by.css('hero-detail-3 > h3')); + expect(header.getText()).toBe('A FormGroup with a single FormControl using FormBuilder'); + }); + + it('should show a form for hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe(''); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-3 > p')); + expect(json.getText()).toContain('name'); + let validStatus = element(by.css('hero-detail-3 > p ~ p')); + expect(validStatus.getText()).toContain('INVALID'); + }); + +}); // Group with multiple controls demo + + +// *************Begin FormControl in a FormGroup Demo test******************************* + + describe('FormControl in a FormGroup demo', function() { + beforeEach(function() { + let SimpleFormBuilderOption = element.all(by.css('select option')).get(1); + SimpleFormBuilderOption.click(); + }); + + it('should show FormControl in a FormGroup Demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('FormControl in a FormGroup Demo'); + }); + }); + + it('should show header', function() { + let header = element(by.css('hero-detail-2 > h3')); + expect(header.getText()).toBe('FormControl in a FormGroup'); + }); + + it('should show a form for hero information', function() { + let nameInput = element(by.css('input[formcontrolname=name]')); + expect(nameInput.getAttribute('value')).toBe(''); + }); + + it('shows a json output from the form', function() { + let json = element(by.css('hero-detail-2 > p')); + expect(json.getText()).toContain('name'); + }); + +}); // Group with multiple controls demo + +// *************Begin Just A FormControl Demo test******************************* + + describe('Just a FormControl demo', function() { + beforeEach(function() { + let FormControlOption = element.all(by.css('select option')).get(0); + FormControlOption.click(); + }); + + it('should show Just a FormControl demo', function() { + select.getAttribute('value').then(function(demo: string) { + expect(demo).toBe('Just a FormControl Demo'); + }); + }); + + it('should show header', function() { + let header = element(by.css('hero-detail-1 > h3')); + expect(header.getText()).toBe('Just a FormControl'); + }); + + it('should show a form for hero information', function() { + let nameInput = element(by.css('input')); + expect(nameInput.getAttribute('value')).toBe(''); + }); + + }); // Just a FormControl demo test + + +}); // reactive forms diff --git a/public/docs/_examples/reactive-forms/ts/example-config.json b/public/docs/_examples/reactive-forms/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/reactive-forms/ts/final.plnkr.json b/public/docs/_examples/reactive-forms/ts/final.plnkr.json new file mode 100644 index 0000000000..41481acc99 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/final.plnkr.json @@ -0,0 +1,21 @@ +{ + "description": "Angular Reactive Forms (final)", + "basePath": "src/", + "files":[ + "styles.css", + + "app/app.component.ts", + "app/app.module.ts", + "app/data-model.ts", + "app/hero.service.ts", + "app/hero-detail.component.html", + "app/hero-detail.component.ts", + "app/hero-list.component.html", + "app/hero-list.component.ts", + + "main-final.ts", + "index-final.html" + ], + "main": "index-final.html", + "tags": ["reactive", "forms"] +} diff --git a/public/docs/_examples/reactive-forms/ts/plnkr.json b/public/docs/_examples/reactive-forms/ts/plnkr.json new file mode 100644 index 0000000000..f0daeb4aad --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/plnkr.json @@ -0,0 +1,15 @@ +{ + "description": "Angular Reactive Forms (Demo runner)", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + + "!app/app.component.1.ts", + "!app/hero-list.component.1.html", + + "!app/main-final.ts", + "!index-final.html" + ], + "tags": ["reactive", "forms"] +} diff --git a/public/docs/_examples/reactive-forms/ts/src/app/app.component.1.ts b/public/docs/_examples/reactive-forms/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..3023618334 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/app.component.1.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +
    +

    Reactive Forms

    + +
    ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/reactive-forms/ts/src/app/app.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/app.component.ts new file mode 100644 index 0000000000..d30a38e979 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/app.component.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +
    +

    Reactive Forms

    + +
    ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/reactive-forms/ts/src/app/app.module.ts b/public/docs/_examples/reactive-forms/ts/src/app/app.module.ts new file mode 100644 index 0000000000..b9f2ea8f99 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/app.module.ts @@ -0,0 +1,39 @@ +// #docplaster +// #docregion +// #docregion v1 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { ReactiveFormsModule } from '@angular/forms'; // <-- #1 import module + +import { AppComponent } from './app.component'; +import { HeroDetailComponent } from './hero-detail.component'; // <-- #1 import component +// #enddocregion v1 +import { HeroListComponent } from './hero-list.component'; + +import { HeroService } from './hero.service'; // <-- #1 import service +// #docregion v1 + +@NgModule({ + imports: [ + BrowserModule, + ReactiveFormsModule // <-- #2 add to Angular module imports + ], + declarations: [ + AppComponent, + HeroDetailComponent, // <-- #3 declare app component +// #enddocregion v1 + HeroListComponent +// #docregion v1 + ], +// #enddocregion v1 + exports: [ // export for the DemoModule + AppComponent, + HeroDetailComponent, + HeroListComponent + ], + providers: [ HeroService ], // <-- #4 provide HeroService +// #docregion v1 + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion v1 diff --git a/public/docs/_examples/reactive-forms/ts/src/app/data-model.ts b/public/docs/_examples/reactive-forms/ts/src/app/data-model.ts new file mode 100644 index 0000000000..ad01ddee56 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/data-model.ts @@ -0,0 +1,40 @@ +// #docregion +// #docregion model-classes +export class Hero { + id = 0; + name = ''; + addresses: Address[]; +} + +export class Address { + street = ''; + city = ''; + state = ''; + zip = ''; +} +// #enddocregion model-classes + +export const heroes: Hero[] = [ + { + id: 1, + name: 'Whirlwind', + addresses: [ + {street: '123 Main', city: 'Anywhere', state: 'CA', zip: '94801'}, + {street: '456 Maple', city: 'Somewhere', state: 'VA', zip: '23226'}, + ] + }, + { + id: 2, + name: 'Bombastic', + addresses: [ + {street: '789 Elm', city: 'Smallville', state: 'OH', zip: '04501'}, + ] + }, + { + id: 3, + name: 'Magneta', + addresses: [ ] + }, +]; + +export const states = ['CA', 'MD', 'OH', 'VA']; diff --git a/public/docs/_examples/reactive-forms/ts/src/app/demo.component.html b/public/docs/_examples/reactive-forms/ts/src/app/demo.component.html new file mode 100644 index 0000000000..1caae127af --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/demo.component.html @@ -0,0 +1,40 @@ +
    +

    Reactive Forms

    +

    Pick a demo: + +

    + +
    + +
    + + + + + + + +
    + +

    Loading heroes ...

    +

    Select a hero:

    + + + +
    +
    +

    Hero Detail

    +

    Editing: {{selectedHero.name}}

    + + + + +
    +
    +
    +
    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/demo.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/demo.component.ts new file mode 100644 index 0000000000..181726eb66 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/demo.component.ts @@ -0,0 +1,47 @@ +/* tslint:disable:member-ordering */ +import { Component } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + +import { Hero } from './data-model'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-app', + templateUrl: './demo.component.html' +}) +export class DemoComponent { + + demos: string[] = [ + 'Just a FormControl', + 'FormControl in a FormGroup', + 'Simple FormBuilder group', + 'Group with multiple controls', + 'Nested FormBuilder group', + 'PatchValue', + 'SetValue', + 'FormArray', + 'Final'].map(n => n + ' Demo'); + + final = this.demos.length; + demo = this.final; // current demo + + heroes: Observable; + isLoading = false; + selectedHero: Hero; + + constructor(private heroService: HeroService) { } + + getHeroes() { + this.isLoading = true; + this.heroes = this.heroService.getHeroes() + .finally(() => this.isLoading = false); + this.selectedHero = undefined; + } + + select(hero: Hero) { this.selectedHero = hero; } + + selectDemo(demo: number) { + this.demo = demo + 1; + this.getHeroes(); + } +} diff --git a/public/docs/_examples/reactive-forms/ts/src/app/demo.module.ts b/public/docs/_examples/reactive-forms/ts/src/app/demo.module.ts new file mode 100644 index 0000000000..dac9145ca9 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/demo.module.ts @@ -0,0 +1,33 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { ReactiveFormsModule } from '@angular/forms'; + +import { AppModule } from './app.module'; +import { DemoComponent } from './demo.component'; +import { HeroDetailComponent1 } from './hero-detail-1.component'; +import { HeroDetailComponent2 } from './hero-detail-2.component'; +import { HeroDetailComponent3 } from './hero-detail-3.component'; +import { HeroDetailComponent4 } from './hero-detail-4.component'; +import { HeroDetailComponent5 } from './hero-detail-5.component'; +import { HeroDetailComponent6 } from './hero-detail-6.component'; +import { HeroDetailComponent7 } from './hero-detail-7.component'; +import { HeroDetailComponent8 } from './hero-detail-8.component'; + +@NgModule({ + imports: [ + BrowserModule, + ReactiveFormsModule, + AppModule, + ], + declarations: [ DemoComponent, + HeroDetailComponent1, + HeroDetailComponent2, + HeroDetailComponent3, + HeroDetailComponent4, + HeroDetailComponent5, + HeroDetailComponent6, + HeroDetailComponent7, + HeroDetailComponent8], + bootstrap: [ DemoComponent ] +}) +export class DemoModule { } diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-1.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-1.component.html new file mode 100644 index 0000000000..7217708d22 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-1.component.html @@ -0,0 +1,8 @@ + +

    Hero Detail

    +

    Just a FormControl

    + + + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-1.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-1.component.ts new file mode 100644 index 0000000000..318dfff145 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-1.component.ts @@ -0,0 +1,14 @@ +/* tslint:disable:component-class-suffix */ +// #docregion imports +import { Component } from '@angular/core'; +import { FormControl } from '@angular/forms'; +// #enddocregion + +@Component({ + selector: 'hero-detail-1', + templateUrl: './hero-detail-1.component.html' +}) +// #docregion v1 +export class HeroDetailComponent1 { + name = new FormControl(); +} diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-2.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-2.component.html new file mode 100644 index 0000000000..1e98354842 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-2.component.html @@ -0,0 +1,18 @@ + +

    Hero Detail

    +

    FormControl in a FormGroup

    +
    +
    + +
    +
    + + + +

    Form value: {{ heroForm.value | json }}

    + + + + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-2.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-2.component.ts new file mode 100644 index 0000000000..6aa3c1ed3a --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-2.component.ts @@ -0,0 +1,17 @@ +/* tslint:disable:component-class-suffix */ +// #docregion imports +import { Component } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +// #enddocregion imports + +@Component({ + selector: 'hero-detail-2', + templateUrl: './hero-detail-2.component.html' +}) +// #docregion v2 +export class HeroDetailComponent2 { + heroForm = new FormGroup ({ + name: new FormControl() + }); +} +// #enddocregion v2 diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3.component.html new file mode 100644 index 0000000000..8edc544dd4 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3.component.html @@ -0,0 +1,16 @@ + +

    Hero Detail

    +

    A FormGroup with a single FormControl using FormBuilder

    +
    +
    + +
    +
    + + + +

    Form value: {{ heroForm.value | json }}

    +

    Form status: {{ heroForm.status | json }}

    + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3.component.ts new file mode 100644 index 0000000000..54a4e93361 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3.component.ts @@ -0,0 +1,27 @@ +/* tslint:disable:component-class-suffix */ +// #docregion imports +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +// #enddocregion imports + +@Component({ + selector: 'hero-detail-3', + templateUrl: './hero-detail-3.component.html' +}) +// #docregion v3 +export class HeroDetailComponent3 { + heroForm: FormGroup; // <--- heroForm is of type FormGroup + + constructor(private fb: FormBuilder) { // <--- inject FormBuilder + this.createForm(); + } + + createForm() { + // #docregion required + this.heroForm = this.fb.group({ + name: ['', Validators.required ], + }); + // #enddocregion required + } +} +// #enddocregion v3 diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3a.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3a.component.ts new file mode 100644 index 0000000000..2347869967 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-3a.component.ts @@ -0,0 +1,25 @@ +/* tslint:disable:component-class-suffix */ +// #docregion imports +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +// #enddocregion imports + +@Component({ + selector: 'hero-detail-3', + templateUrl: './hero-detail-3.component.html' +}) +// #docregion v3a +export class HeroDetailComponent3 { + heroForm: FormGroup; // <--- heroForm is of type FormGroup + + constructor(private fb: FormBuilder) { // <--- inject FormBuilder + this.createForm(); + } + + createForm() { + this.heroForm = this.fb.group({ + name: '', // <--- the FormControl called "name" + }); + } +} +// #enddocregion v3a diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-4.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-4.component.html new file mode 100644 index 0000000000..30529868e9 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-4.component.html @@ -0,0 +1,46 @@ + +

    Hero Detail

    +

    A FormGroup with multiple FormControls

    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Super power:

    + + + +
    +
    + +
    +
    + + +

    Form value: {{ heroForm.value | json }}

    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-4.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-4.component.ts new file mode 100644 index 0000000000..d2f1ea2f96 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-4.component.ts @@ -0,0 +1,34 @@ +/* tslint:disable:component-class-suffix */ +// #docregion imports +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +import { states } from './data-model'; +// #enddocregion imports + +@Component({ + selector: 'hero-detail-4', + templateUrl: './hero-detail-4.component.html' +}) +// #docregion v4 +export class HeroDetailComponent4 { + heroForm: FormGroup; + states = states; + + constructor(private fb: FormBuilder) { + this.createForm(); + } + + createForm() { + this.heroForm = this.fb.group({ + name: ['', Validators.required ], + street: '', + city: '', + state: '', + zip: '', + power: '', + sidekick: '' + }); + } +} +// #enddocregion v4 diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-5.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-5.component.html new file mode 100644 index 0000000000..2a41b4f2f9 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-5.component.html @@ -0,0 +1,56 @@ + +
    +
    + +
    + +
    +

    Secret Lair

    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +

    Super power:

    + + + +
    +
    + +
    +
    + +

    heroForm value: {{ heroForm.value | json}}

    +

    Extra info for the curious:

    + +

    Name value: {{ heroForm.get('name').value }}

    + + + +

    Street value: {{ heroForm.get('address.street').value}}

    + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-5.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-5.component.ts new file mode 100644 index 0000000000..f4be33389f --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-5.component.ts @@ -0,0 +1,35 @@ +/* tslint:disable:component-class-suffix */ +import { Component } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +import { states } from './data-model'; + +@Component({ + selector: 'hero-detail-5', + templateUrl: './hero-detail-5.component.html' +}) +// #docregion v5 +export class HeroDetailComponent5 { + heroForm: FormGroup; + states = states; + + constructor(private fb: FormBuilder) { + this.createForm(); + } + + createForm() { + this.heroForm = this.fb.group({ // <-- the parent FormGroup + name: ['', Validators.required ], + address: this.fb.group({ // <-- the child FormGroup + street: '', + city: '', + state: '', + zip: '' + }), + power: '', + sidekick: '' + }); + } +} +// #enddocregion v5 + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-6.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-6.component.html new file mode 100644 index 0000000000..4c8b5c9e05 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-6.component.html @@ -0,0 +1,46 @@ + +

    Hero Detail

    +

    PatchValue to initialize a value

    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Super power:

    + + + +
    +
    + +
    +
    + + +

    Form value: {{ heroForm.value | json }}

    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-6.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-6.component.ts new file mode 100644 index 0000000000..d5136822d1 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-6.component.ts @@ -0,0 +1,58 @@ +/* tslint:disable:component-class-suffix */ +// #docregion import-input +import { Component, Input, OnChanges } from '@angular/core'; +// #enddocregion import-input +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +// #docregion import-hero +import { Hero, states } from './data-model'; +// #enddocregion import-hero + +////////// 6 //////////////////// + +@Component({ + selector: 'hero-detail-6', + templateUrl: './hero-detail-5.component.html' +}) +// #docregion v6 +export class HeroDetailComponent6 implements OnChanges { + // #docregion hero + @Input() hero: Hero; + // #enddocregion hero + + heroForm: FormGroup; + states = states; + + constructor(private fb: FormBuilder) { + this.createForm(); + } + + createForm() { + // #docregion hero-form-model + this.heroForm = this.fb.group({ + name: ['', Validators.required ], + address: this.fb.group({ + street: '', + city: '', + state: '', + zip: '' + }), + power: '', + sidekick: '' + }); + // #enddocregion hero-form-model + } + + // #docregion patch-value-on-changes + ngOnChanges() { // <-- wrap patchValue in ngOnChanges + this.heroForm.reset(); + // #docregion patch-value + this.heroForm.patchValue({ + name: this.hero.name + }); + // #enddocregion patch-value + } + // #enddocregion patch-value-on-changes +} + +// #enddocregion v6 diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-7.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-7.component.html new file mode 100644 index 0000000000..6d68b49b4d --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-7.component.html @@ -0,0 +1,46 @@ + +

    Hero Detail

    +

    A FormGroup with multiple FormControls

    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Super power:

    + + + +
    +
    + +
    +
    + + +

    Form value: {{ heroForm.value | json }}

    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-7.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-7.component.ts new file mode 100644 index 0000000000..497c7f6a56 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-7.component.ts @@ -0,0 +1,69 @@ +/* tslint:disable:component-class-suffix */ +// #docplaster +// #docregion imports +import { Component, Input, OnChanges } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +// #docregion import-address +import { Address, Hero, states } from './data-model'; +// #enddocregion import-address + +// #enddocregion imports + +@Component({ + selector: 'hero-detail-7', + templateUrl: './hero-detail-5.component.html' +}) +// #docregion v7 +export class HeroDetailComponent7 implements OnChanges { + @Input() hero: Hero; + + heroForm: FormGroup; + states = states; + + constructor(private fb: FormBuilder) { + this.createForm(); + } + + createForm() { + // #docregion address-form-group + this.heroForm = this.fb.group({ + name: ['', Validators.required ], + address: this.fb.group(new Address()), // <-- a FormGroup with a new address + power: '', + sidekick: '' + }); + // #enddocregion address-form-group + } + + // #docregion ngOnChanges + ngOnChanges() { + this.heroForm.reset({ + name: this.hero.name, + address: this.hero.addresses[0] || new Address() + }); + } + // #enddocregion ngOnChanges + + /* First version of ngOnChanges + // #docregion ngOnChanges-1 + ngOnChanges() + // #enddocregion ngOnChanges-1 + */ + ngOnChanges1() { + // #docregion reset + this.heroForm.reset(); + // #enddocregion reset + // #docregion ngOnChanges-1 + // #docregion set-value + this.heroForm.setValue({ + name: this.hero.name, + // #docregion set-value-address + address: this.hero.addresses[0] || new Address() + // #enddocregion set-value-address + }); + // #enddocregion set-value + } + // #enddocregion ngOnChanges-1 +} + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-8.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-8.component.html new file mode 100644 index 0000000000..d8e47ae798 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-8.component.html @@ -0,0 +1,70 @@ + +

    Using FormArray to add groups

    + +
    +

    Form Changed: {{ heroForm.dirty }}

    + +
    + +
    + + +
    +
    + + +

    Address #{{i + 1}}

    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + + +
    + + + + + + + +
    + + +
    +

    Super power:

    + + + +
    +
    + +
    +
    + +

    heroForm value: {{ heroForm.value | json}}

    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-8.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-8.component.ts new file mode 100644 index 0000000000..1141c836a7 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail-8.component.ts @@ -0,0 +1,68 @@ +/* tslint:disable:component-class-suffix */ +// #docregion imports +import { Component, Input, OnChanges } from '@angular/core'; +import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; + +import { Address, Hero, states } from './data-model'; +// #enddocregion imports + +@Component({ + selector: 'hero-detail-8', + templateUrl: './hero-detail-8.component.html' +}) +// #docregion v8 +export class HeroDetailComponent8 implements OnChanges { + @Input() hero: Hero; + + heroForm: FormGroup; + states = states; + + // #docregion ctor + constructor(private fb: FormBuilder) { + this.createForm(); + this.logNameChange(); + } + // #enddocregion ctor + + createForm() { + // #docregion secretLairs-form-array + this.heroForm = this.fb.group({ + name: ['', Validators.required ], + secretLairs: this.fb.array([]), // <-- secretLairs as an empty FormArray + power: '', + sidekick: '' + }); + // #enddocregion secretLairs-form-array + } + + logNameChange() {/* Coming soon */} + + // #docregion onchanges + ngOnChanges() { + this.heroForm.reset({ + name: this.hero.name + }); + this.setAddresses(this.hero.addresses); + } + // #enddocregion onchanges + + // #docregion get-secret-lairs + get secretLairs(): FormArray { + return this.heroForm.get('secretLairs') as FormArray; + }; + // #enddocregion get-secret-lairs + + // #docregion set-addresses + setAddresses(addresses: Address[]) { + const addressFGs = addresses.map(address => this.fb.group(address)); + const addressFormArray = this.fb.array(addressFGs); + this.heroForm.setControl('secretLairs', addressFormArray); + } + // #enddocregion set-addresses + + // #docregion add-lair + addLair() { + this.secretLairs.push(this.fb.group(new Address())); + } + // #enddocregion add-lair +} diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..8f5b8bf2c8 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail.component.html @@ -0,0 +1,73 @@ + + + +
    +
    +   + +
    + + + +
    + +
    + +
    +
    + +

    Address #{{i + 1}}

    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + +
    + +
    + +
    +

    Super power:

    + + + +
    +
    + +
    +
    + + +

    heroForm value: {{ heroForm.value | json}}

    + + +

    Name change log

    +
    {{name}}
    + diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-detail.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..4cb69aaedf --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-detail.component.ts @@ -0,0 +1,107 @@ +// #docplaster +// #docregion +import { Component, Input, OnChanges } from '@angular/core'; +import { FormArray, FormBuilder, FormGroup } from '@angular/forms'; + +import { Address, Hero, states } from './data-model'; +// #docregion import-service +import { HeroService } from './hero.service'; +// #enddocregion import-service + +// #docregion metadata +@Component({ + selector: 'hero-detail', + templateUrl: './hero-detail.component.html' +}) +// #enddocregion metadata +export class HeroDetailComponent implements OnChanges { + @Input() hero: Hero; + + heroForm: FormGroup; + // #docregion log-name-change + nameChangeLog: string[] = []; + // #enddocregion log-name-change + states = states; + + // #docregion ctor + constructor( + private fb: FormBuilder, + private heroService: HeroService) { + + this.createForm(); + this.logNameChange(); + } + // #enddocregion ctor + + createForm() { + this.heroForm = this.fb.group({ + name: '', + secretLairs: this.fb.array([]), + power: '', + sidekick: '' + }); + } + + ngOnChanges() { + this.heroForm.reset({ + name: this.hero.name + }); + this.setAddresses(this.hero.addresses); + } + + get secretLairs(): FormArray { + return this.heroForm.get('secretLairs') as FormArray; + }; + + setAddresses(addresses: Address[]) { + const addressFGs = addresses.map(address => this.fb.group(address)); + const addressFormArray = this.fb.array(addressFGs); + this.heroForm.setControl('secretLairs', addressFormArray); + } + + addLair() { + this.secretLairs.push(this.fb.group(new Address())); + } + + // #docregion on-submit + onSubmit() { + this.hero = this.prepareSaveHero(); + this.heroService.updateHero(this.hero).subscribe(/* error handling */); + this.ngOnChanges(); + } + // #enddocregion on-submit + + // #docregion prepare-save-hero + prepareSaveHero(): Hero { + const formModel = this.heroForm.value; + + // deep copy of form model lairs + const secretLairsDeepCopy: Address[] = formModel.secretLairs.map( + (address: Address) => Object.assign({}, address) + ); + + // return new `Hero` object containing a combination of original hero value(s) + // and deep copies of changed form model values + const saveHero: Hero = { + id: this.hero.id, + name: formModel.name as string, + // addresses: formModel.secretLairs // <-- bad! + addresses: secretLairsDeepCopy + }; + return saveHero; + } + // #enddocregion prepare-save-hero + + // #docregion revert + revert() { this.ngOnChanges(); } + // #enddocregion revert + + // #docregion log-name-change + logNameChange() { + const nameControl = this.heroForm.get('name'); + nameControl.valueChanges.forEach( + (value: string) => this.nameChangeLog.push(value) + ); + } + // #enddocregion log-name-change +} diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.1.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.1.html new file mode 100644 index 0000000000..fa76c84f54 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.1.html @@ -0,0 +1,8 @@ + + + +
    + +
    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.html b/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.html new file mode 100644 index 0000000000..d0fb2ee920 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.html @@ -0,0 +1,17 @@ + +

    Loading heroes ...

    +

    Select a hero:

    + + + +
    +
    +

    Hero Detail

    +

    Editing: {{selectedHero.name}}

    + + + +
    diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.ts new file mode 100644 index 0000000000..98092adcdb --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero-list.component.ts @@ -0,0 +1,31 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/finally'; + +import { Hero } from './data-model'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'hero-list', + templateUrl: './hero-list.component.html' +}) +export class HeroListComponent implements OnInit { + heroes: Observable; + isLoading = false; + selectedHero: Hero; + + constructor(private heroService: HeroService) { } + + ngOnInit() { this.getHeroes(); } + + getHeroes() { + this.isLoading = true; + this.heroes = this.heroService.getHeroes() + // Todo: error handling + .finally(() => this.isLoading = false); + this.selectedHero = undefined; + } + + select(hero: Hero) { this.selectedHero = hero; } +} diff --git a/public/docs/_examples/reactive-forms/ts/src/app/hero.service.ts b/public/docs/_examples/reactive-forms/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..6600586de7 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/app/hero.service.ts @@ -0,0 +1,26 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import { of } from 'rxjs/observable/of'; +import 'rxjs/add/operator/delay'; + +import { Hero, heroes } from './data-model'; + +@Injectable() +export class HeroService { + + delayMs = 500; + + // Fake server get; assume nothing can go wrong + getHeroes(): Observable { + return of(heroes).delay(this.delayMs); // simulate latency with delay + } + + // Fake server update; assume nothing can go wrong + updateHero(hero: Hero): Observable { + const oldHero = heroes.find(h => h.id === hero.id); + const newHero = Object.assign(oldHero, hero); // Demo: mutate cached hero + return of(newHero).delay(this.delayMs); // simulate latency with delay + } +} diff --git a/public/docs/_examples/reactive-forms/ts/src/index-final.html b/public/docs/_examples/reactive-forms/ts/src/index-final.html new file mode 100644 index 0000000000..9ef0a379e0 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/index-final.html @@ -0,0 +1,31 @@ + + + + + Hero Form + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/reactive-forms/ts/src/index.html b/public/docs/_examples/reactive-forms/ts/src/index.html new file mode 100644 index 0000000000..802d12f211 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/index.html @@ -0,0 +1,31 @@ + + + + + Hero Form + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/reactive-forms/ts/src/main-final.ts b/public/docs/_examples/reactive-forms/ts/src/main-final.ts new file mode 100644 index 0000000000..7572d1f1d3 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/main-final.ts @@ -0,0 +1,5 @@ +// tslint:disable:no-unused-variable +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/reactive-forms/ts/src/main.ts b/public/docs/_examples/reactive-forms/ts/src/main.ts new file mode 100644 index 0000000000..f415a71708 --- /dev/null +++ b/public/docs/_examples/reactive-forms/ts/src/main.ts @@ -0,0 +1,6 @@ +// tslint:disable:no-unused-variable +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; // just the final version +import { DemoModule } from './app/demo.module'; // demo picker + +platformBrowserDynamic().bootstrapModule(DemoModule); // (AppModule); diff --git a/public/docs/_examples/router/e2e-spec.js b/public/docs/_examples/router/e2e-spec.js deleted file mode 100644 index 0cea6a73fb..0000000000 --- a/public/docs/_examples/router/e2e-spec.js +++ /dev/null @@ -1,128 +0,0 @@ -describe('Router', function () { - - beforeAll(function () { - browser.get(''); - }); - - function getPageStruct() { - hrefEles = element.all(by.css('my-app a')); - - return { - hrefs: hrefEles, - routerParent: element(by.css('my-app > undefined')), - routerTitle: element(by.css('my-app > undefined > h2')), - - crisisHref: hrefEles.get(0), - crisisList: element.all(by.css('my-app > undefined > undefined li')), - crisisDetail: element(by.css('my-app > undefined > undefined > div')), - crisisDetailTitle: element(by.css('my-app > undefined > undefined > div > h3')), - - heroesHref: hrefEles.get(1), - heroesList: element.all(by.css('my-app > undefined li')), - heroDetail: element(by.css('my-app > undefined > div')), - heroDetailTitle: element(by.css('my-app > undefined > div > h3')), - - } - } - - it('should be able to see the start screen', function () { - var page = getPageStruct(); - expect(page.hrefs.count()).toEqual(2, 'should be two dashboard choices'); - expect(page.crisisHref.getText()).toEqual("Crisis Center"); - expect(page.heroesHref.getText()).toEqual("Heroes"); - }); - - // assumes that jasmine runs tests in order that they appear. - // (don't move this test later in this file because it will fail first 'expect'). - it('should be able to see crises center items', function () { - var page = getPageStruct(); - expect(page.crisisList.count()).toBe(0, "should be no crisis center entries on startup"); - page.crisisHref.click().then(function() { - expect(page.routerTitle.getText()).toContain('CRISIS CENTER'); - expect(page.crisisList.count()).toBe(4, "should be 4 crisis center entries"); - }); - }); - - it('should be able to see hero items', function () { - var page = getPageStruct(); - page.heroesHref.click().then(function() { - expect(page.routerTitle.getText()).toContain('HEROES'); - expect(page.heroesList.count()).toBe(6, "should be 6 heroes"); - }); - }); - - it('should be able to toggle the views', function () { - var page = getPageStruct(); - page.crisisHref.click().then(function() { - expect(page.crisisList.count()).toBe(4, "should be 4 crisis center entries"); - return page.heroesHref.click(); - }).then(function() { - expect(page.heroesList.count()).toBe(6, "should be 6 heroes"); - }); - }); - - it('should be able to edit and save details from the crisis center view', function () { - crisisCenterEdit(2, true); - }); - - it('should be able to edit and cancel details from the crisis center view', function () { - crisisCenterEdit(3, false); - }); - - it('should be able to edit and save details from the heroes view', function () { - var page = getPageStruct(); - var heroEle, heroText; - page.heroesHref.click().then(function() { - heroEle = page.heroesList.get(4); - return heroEle.getText(); - }).then(function(text) { - expect(text.length).toBeGreaterThan(0, 'should have some text'); - // remove leading id from text - heroText = text.substr(text.indexOf(' ')).trim(); - return heroEle.click(); - }).then(function() { - expect(page.heroesList.count()).toBe(0, "should no longer see crisis center entries"); - expect(page.heroDetail.isPresent()).toBe(true, 'should be able to see crisis detail'); - expect(page.heroDetailTitle.getText()).toContain(heroText); - var inputEle = page.heroDetail.element(by.css('input')); - return sendKeys(inputEle, '-foo'); - }).then(function() { - expect(page.heroDetailTitle.getText()).toContain(heroText + '-foo'); - var buttonEle = page.heroDetail.element(by.css('button')); - return buttonEle.click(); - }).then(function() { - expect(heroEle.getText()).toContain(heroText + '-foo'); - }) - }); - - function crisisCenterEdit(index, shouldSave) { - var page = getPageStruct(); - var crisisEle, crisisText; - page.crisisHref.click().then(function () { - crisisEle = page.crisisList.get(index); - return crisisEle.getText(); - }).then(function (text) { - expect(text.length).toBeGreaterThan(0, 'should have some text'); - // remove leading id from text - crisisText = text.substr(text.indexOf(' ')).trim(); - return crisisEle.click(); - }).then(function () { - expect(page.crisisList.count()).toBe(0, "should no longer see crisis center entries"); - expect(page.crisisDetail.isPresent()).toBe(true, 'should be able to see crisis detail'); - expect(page.crisisDetailTitle.getText()).toContain(crisisText); - var inputEle = page.crisisDetail.element(by.css('input')); - return sendKeys(inputEle, '-foo'); - }).then(function () { - expect(page.crisisDetailTitle.getText()).toContain(crisisText + '-foo'); - var buttonEle = page.crisisDetail.element(by.cssContainingText('button', shouldSave ? 'Save' : 'Cancel')); - return buttonEle.click(); - }).then(function () { - if (shouldSave) { - expect(crisisEle.getText()).toContain(crisisText + '-foo'); - } else { - expect(crisisEle.getText()).not.toContain(crisisText + '-foo'); - } - }); - } - -}); diff --git a/public/docs/_examples/router/e2e-spec.ts b/public/docs/_examples/router/e2e-spec.ts new file mode 100644 index 0000000000..2e9c6bafeb --- /dev/null +++ b/public/docs/_examples/router/e2e-spec.ts @@ -0,0 +1,162 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ExpectedConditions } from 'protractor'; + +const numDashboardTabs = 5; +const numCrises = 4; +const numHeroes = 6; +const EC = ExpectedConditions; + +describe('Router', () => { + + beforeAll(() => browser.get('')); + + function getPageStruct() { + const hrefEles = element.all(by.css('my-app a')); + const crisisDetail = element.all(by.css('my-app > ng-component > ng-component > ng-component > div')).first(); + const heroDetail = element(by.css('my-app > ng-component > div')); + + return { + hrefs: hrefEles, + activeHref: element(by.css('my-app a.active')), + + crisisHref: hrefEles.get(0), + crisisList: element.all(by.css('my-app > ng-component > ng-component li')), + crisisDetail: crisisDetail, + crisisDetailTitle: crisisDetail.element(by.xpath('*[1]')), + + heroesHref: hrefEles.get(1), + heroesList: element.all(by.css('my-app > ng-component li')), + heroDetail: heroDetail, + heroDetailTitle: heroDetail.element(by.xpath('*[1]')), + + adminHref: hrefEles.get(2), + adminPreloadList: element.all(by.css('my-app > ng-component > ng-component > ul > li')), + + loginHref: hrefEles.get(3), + loginButton: element.all(by.css('my-app > ng-component > p > button')), + + contactHref: hrefEles.get(4), + contactCancelButton: element.all(by.buttonText('Cancel')), + + outletComponents: element.all(by.css('my-app > ng-component')) + }; + } + + it('has expected dashboard tabs', () => { + const page = getPageStruct(); + expect(page.hrefs.count()).toEqual(numDashboardTabs, 'dashboard tab count'); + expect(page.crisisHref.getText()).toEqual('Crisis Center'); + expect(page.heroesHref.getText()).toEqual('Heroes'); + expect(page.adminHref.getText()).toEqual('Admin'); + expect(page.loginHref.getText()).toEqual('Login'); + expect(page.contactHref.getText()).toEqual('Contact'); + }); + + it('has heroes selected as opening tab', () => { + const page = getPageStruct(); + expect(page.activeHref.getText()).toEqual('Heroes'); + }); + + it('has crises center items', async () => { + const page = getPageStruct(); + await page.crisisHref.click(); + expect(page.activeHref.getText()).toEqual('Crisis Center'); + expect(page.crisisList.count()).toBe(numCrises, 'crisis list count'); + }); + + it('has hero items', async () => { + const page = getPageStruct(); + await page.heroesHref.click(); + expect(page.activeHref.getText()).toEqual('Heroes'); + expect(page.heroesList.count()).toBe(numHeroes, 'hero list count'); + }); + + it('toggles views', async () => { + const page = getPageStruct(); + await page.crisisHref.click(); + expect(page.activeHref.getText()).toEqual('Crisis Center'); + expect(page.crisisList.count()).toBe(numCrises, 'crisis list count'); + await page.heroesHref.click(); + expect(page.activeHref.getText()).toEqual('Heroes'); + expect(page.heroesList.count()).toBe(numHeroes, 'hero list count'); + }); + + it('saves changed crisis details', async () => { + const page = getPageStruct(); + await page.crisisHref.click(); + await crisisCenterEdit(2, true); + }); + + it('can cancel changed crisis details', async () => { + const page = getPageStruct(); + await page.crisisHref.click(); + await crisisCenterEdit(3, false); + }); + + it('saves changed hero details', async () => { + const page = getPageStruct(); + await page.heroesHref.click(); + const heroEle = page.heroesList.get(4); + let text = await heroEle.getText(); + expect(text.length).toBeGreaterThan(0, 'hero item text length'); + // remove leading id from text + const heroText = text.substr(text.indexOf(' ')).trim(); + + await heroEle.click(); + expect(page.heroesList.count()).toBe(0, 'hero list count'); + expect(page.heroDetail.isPresent()).toBe(true, 'hero detail'); + expect(page.heroDetailTitle.getText()).toContain(heroText); + let inputEle = page.heroDetail.element(by.css('input')); + await inputEle.sendKeys('-foo'); + expect(page.heroDetailTitle.getText()).toContain(heroText + '-foo'); + + let buttonEle = page.heroDetail.element(by.css('button')); + await buttonEle.click(); + expect(heroEle.getText()).toContain(heroText + '-foo'); + }); + + it('sees preloaded modules', async () => { + const page = getPageStruct(); + await page.loginHref.click(); + await page.loginButton.click(); + const list = page.adminPreloadList; + expect(list.count()).toBe(1, 'preloaded module'); + expect(await list.first().getText()).toBe('crisis-center', 'first preloaded module'); + }); + + it('sees the secondary route', async () => { + const page = getPageStruct(); + await page.heroesHref.click(); + await page.contactHref.click(); + expect(page.outletComponents.count()).toBe(2, 'route count'); + }); + + async function crisisCenterEdit(index: number, save: boolean) { + const page = getPageStruct(); + await page.crisisHref.click(); + let crisisEle = page.crisisList.get(index); + let text = await crisisEle.getText(); + expect(text.length).toBeGreaterThan(0, 'crisis item text length'); + // remove leading id from text + const crisisText = text.substr(text.indexOf(' ')).trim(); + + await crisisEle.click(); + expect(page.crisisDetail.isPresent()).toBe(true, 'crisis detail present'); + expect(page.crisisDetailTitle.getText()).toContain(crisisText); + let inputEle = page.crisisDetail.element(by.css('input')); + await inputEle.sendKeys('-foo'); + + let buttonEle = page.crisisDetail.element(by.buttonText(save ? 'Save' : 'Cancel')); + await buttonEle.click(); + crisisEle = page.crisisList.get(index); + if (save) { + expect(crisisEle.getText()).toEqual(crisisText + '-foo'); + } else { + await browser.wait(EC.alertIsPresent(), 4000); + await browser.switchTo().alert().accept(); + expect(crisisEle.getText()).toEqual(crisisText); + } + } + +}); diff --git a/public/docs/_examples/router/ts/.gitignore b/public/docs/_examples/router/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/router/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/router/ts/app/app.component.1.ts b/public/docs/_examples/router/ts/app/app.component.1.ts deleted file mode 100644 index 3caad41fe8..0000000000 --- a/public/docs/_examples/router/ts/app/app.component.1.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* First version */ -// #docplaster - -// #docregion -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; - -import {CrisisListComponent} from './crisis-list.component'; -import {HeroListComponent} from './hero-list.component'; - -@Component({ - selector: 'my-app', -// #docregion template - template: ` -

    Component Router

    - - - `, -// #enddocregion template - directives: [ROUTER_DIRECTIVES] -}) -// #enddocregion -/* -// #docregion route-config -@Component({ ... }) -// #enddocregion route-config -*/ -// #docregion -// #docregion route-config -@RouteConfig([ -// #docregion route-defs - {path:'/crisis-center', name: 'CrisisCenter', component: CrisisListComponent}, - {path:'/heroes', name: 'Heroes', component: HeroListComponent} -// #enddocregion route-defs -]) -export class AppComponent { } -// #enddocregion route-config -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/app.component.2.ts b/public/docs/_examples/router/ts/app/app.component.2.ts deleted file mode 100644 index ce4f3c1c53..0000000000 --- a/public/docs/_examples/router/ts/app/app.component.2.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* Second Heroes version */ -// #docplaster - -// #docregion -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; - -import {CrisisListComponent} from './crisis-list.component'; -// #enddocregion -/* -// Apparent Milestone 2 imports -// #docregion -// #docregion hero-import -import {HeroListComponent} from './heroes/hero-list.component'; -import {HeroDetailComponent} from './heroes/hero-detail.component'; -import {HeroService} from './heroes/hero.service'; -// #enddocregion hero-import -// #enddocregion -*/ -// Actual Milestone 2 imports -import {HeroListComponent} from './heroes/hero-list.component.1'; -import {HeroDetailComponent} from './heroes/hero-detail.component.1'; -import {HeroService} from './heroes/hero.service'; -// #docregion - -@Component({ - selector: 'my-app', - template: ` -

    Component Router

    - - - `, - providers: [HeroService], - directives: [ROUTER_DIRECTIVES] -}) -// #enddocregion -/* -// #docregion route-config -@Component({ ... }) -// #enddocregion route-config -*/ -// #docregion -// #docregion route-config -@RouteConfig([ -// #docregion route-defs - {path:'/crisis-center', name: 'CrisisCenter', component: CrisisListComponent}, - {path:'/heroes', name: 'Heroes', component: HeroListComponent}, - // #docregion hero-detail-route - {path:'/hero/:id', name: 'HeroDetail', component: HeroDetailComponent} - // #enddocregion hero-detail-route -// #enddocregion route-defs -]) -export class AppComponent { } -// #enddocregion route-config -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/app.component.3.ts b/public/docs/_examples/router/ts/app/app.component.3.ts deleted file mode 100644 index a16defa8af..0000000000 --- a/public/docs/_examples/router/ts/app/app.component.3.ts +++ /dev/null @@ -1,55 +0,0 @@ -// #docplaster -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; - -import {CrisisCenterComponent} from './crisis-center/crisis-center.component.1'; -import {HeroListComponent} from './heroes/hero-list.component.1'; -import {HeroDetailComponent} from './heroes/hero-detail.component.1'; - -import {DialogService} from './dialog.service'; -import {HeroService} from './heroes/hero.service'; - -@Component({ - selector: 'my-app', -// #enddocregion - /* Typical link - // #docregion h-anchor - Heroes - // #enddocregion h-anchor - */ - /* Incomplete Crisis Center link when CC lacks a default - // #docregion cc-anchor-fail - // The link now fails with a "non-terminal link" error - // #docregion cc-anchor-w-default - Crisis Center - // #enddocregion cc-anchor-w-default - // #enddocregion cc-anchor-fail - */ - /* Crisis Center link when CC lacks a default - // #docregion cc-anchor-no-default - Crisis Center - // #enddocregion cc-anchor-no-default - */ - /* Crisis Center Detail link - // #docregion Dragon-anchor - Dragon Crisis - // #enddocregion Dragon-anchor - */ -// #docregion template - template: ` -

    Component Router

    - - - `, -// #enddocregion template - providers: [DialogService, HeroService], - directives: [ROUTER_DIRECTIVES] -}) -@RouteConfig([ - {path: '/crisis-center/...', name: 'CrisisCenter', component: CrisisCenterComponent}, -]) -export class AppComponent { } diff --git a/public/docs/_examples/router/ts/app/app.component.ts b/public/docs/_examples/router/ts/app/app.component.ts deleted file mode 100644 index d2ca8c0c4c..0000000000 --- a/public/docs/_examples/router/ts/app/app.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -// #docplaster -// #docregion -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; - -import {CrisisCenterComponent} from './crisis-center/crisis-center.component'; -import {HeroListComponent} from './heroes/hero-list.component'; -import {HeroDetailComponent} from './heroes/hero-detail.component'; - -import {DialogService} from './dialog.service'; -import {HeroService} from './heroes/hero.service'; - -@Component({ - selector: 'my-app', -// #docregion template - template: ` -

    Component Router

    - - - `, -// #enddocregion template - providers: [DialogService, HeroService], - directives: [ROUTER_DIRECTIVES] -}) -// #docregion route-config -@RouteConfig([ - - // #docregion route-config-cc - { // Crisis Center child route - path: '/crisis-center/...', - name: 'CrisisCenter', - component: CrisisCenterComponent, - useAsDefault: true - }, - // #enddocregion route-config-cc - - {path: '/heroes', name: 'Heroes', component: HeroListComponent}, - {path: '/hero/:id', name: 'HeroDetail', component: HeroDetailComponent}, - // #enddocregion route-config - // #docregion asteroid-route - {path: '/disaster', name: 'Asteroid', redirectTo: ['CrisisCenter', 'CrisisDetail', {id:3}]} - // #enddocregion asteroid-route - // #docregion route-config -]) -// #enddocregion route-config -export class AppComponent { } diff --git a/public/docs/_examples/router/ts/app/crisis-center/add-crisis.component.ts b/public/docs/_examples/router/ts/app/crisis-center/add-crisis.component.ts deleted file mode 100644 index c9e2550eab..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/add-crisis.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {Component} from 'angular2/core'; -import {Crisis, CrisisService} from './crisis.service'; -import {DialogService} from '../dialog.service'; -import {CanDeactivate, ComponentInstruction, Router} from 'angular2/router'; - -@Component({ - template: ` -

    "{{editName}}"

    -
    - - -
    - - - `, - styles: ['input {width: 20em}'] -}) -export class AddCrisisComponent implements CanDeactivate { - editName: string; - - constructor( - private _service: CrisisService, - private _router: Router, - private _dialog: DialogService) { } - - routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { - return !!this.editName.trim() || - this._dialog.confirm('Discard changes?'); - } - - cancel() { this.gotoCrises(); } - - save() { - this._service.addCrisis(this.editName); - this.gotoCrises(); - } - - gotoCrises() { - this._router.navigate(['CrisisCenter']); - } -} \ No newline at end of file diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.1.ts deleted file mode 100644 index 1cb8250f34..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.1.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Component} from 'angular2/core'; -import {RouteConfig, RouterOutlet} from 'angular2/router'; - -import {CrisisListComponent} from './crisis-list.component.1'; -import {CrisisDetailComponent} from './crisis-detail.component.1'; -import {CrisisService} from './crisis.service'; - -// #docregion minus-imports -@Component({ - template: ` -

    CRISIS CENTER

    - - `, - directives: [RouterOutlet], -// #docregion providers - providers: [CrisisService] -// #enddocregion providers -}) -// #docregion route-config -@RouteConfig([ - // #docregion default-route - {path:'/', name: 'CrisisList', component: CrisisListComponent, useAsDefault: true}, - // #enddocregion default-route - {path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent} -]) -// #enddocregion route-config -export class CrisisCenterComponent { } -// #enddocregion minus-imports diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts deleted file mode 100644 index 37fb4bf2dd..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-center.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {RouteConfig, RouterOutlet} from 'angular2/router'; - -import {CrisisListComponent} from './crisis-list.component'; -import {CrisisDetailComponent} from './crisis-detail.component'; -import {CrisisService} from './crisis.service'; - -@Component({ - template: ` -

    CRISIS CENTER

    - - `, - directives: [RouterOutlet], - providers: [CrisisService] -}) -@RouteConfig([ - {path:'/', name: 'CrisisList', component: CrisisListComponent, useAsDefault: true}, - {path:'/:id', name: 'CrisisDetail', component: CrisisDetailComponent} -]) -export class CrisisCenterComponent { } -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts deleted file mode 100644 index ed3994eaf8..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-detail.component.1.ts +++ /dev/null @@ -1,94 +0,0 @@ -// #docplaster - -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Crisis, CrisisService} from './crisis.service'; -import {RouteParams, Router} from 'angular2/router'; -// #docregion routerCanDeactivate -import {CanDeactivate, ComponentInstruction} from 'angular2/router'; -import {DialogService} from '../dialog.service'; - -// #enddocregion routerCanDeactivate - -@Component({ - // #docregion template - template: ` -
    -

    "{{editName}}"

    -
    - {{crisis.id}}
    -
    - - -
    -

    - - -

    -
    - `, - // #enddocregion template - styles: ['input {width: 20em}'] -}) -// #docregion routerCanDeactivate, cancel-save -export class CrisisDetailComponent implements OnInit, CanDeactivate { - - crisis: Crisis; - editName: string; - -// #enddocregion routerCanDeactivate, cancel-save - constructor( - private _service: CrisisService, - private _router: Router, - private _routeParams: RouteParams, - private _dialog: DialogService - ) { } - - // #docregion ngOnInit - ngOnInit() { - let id = +this._routeParams.get('id'); - this._service.getCrisis(id).then(crisis => { - if (crisis) { - this.editName = crisis.name; - this.crisis = crisis; - } else { // id not found - this.gotoCrises(); - } - }); - } - // #enddocregion ngOnInit - - // #docregion routerCanDeactivate - routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : any { - // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged. - if (!this.crisis || this.crisis.name === this.editName) { - return true; - } - // Otherwise ask the user with the dialog service and return its - // promise which resolves to true or false when the user decides - return this._dialog.confirm('Discard changes?'); - } - // #enddocregion routerCanDeactivate - - // #docregion cancel-save - cancel() { - this.editName = this.crisis.name; - this.gotoCrises(); - } - - save() { - this.crisis.name = this.editName; - this.gotoCrises(); - } - // #enddocregion cancel-save - - // #docregion gotoCrises - gotoCrises() { - // Like Crisis Center -

    "{{editName}}"

    -
    - {{crisis.id}}
    -
    - - -
    -

    - - -

    -
    - `, - styles: ['input {width: 20em}'] -}) - -export class CrisisDetailComponent implements OnInit, CanDeactivate { - - crisis: Crisis; - editName: string; - - constructor( - private _service: CrisisService, - private _router: Router, - private _routeParams: RouteParams, - private _dialog: DialogService - ) { } - - ngOnInit() { - let id = +this._routeParams.get('id'); - this._service.getCrisis(id).then(crisis => { - if (crisis) { - this.editName = crisis.name; - this.crisis = crisis; - } else { // id not found - this.gotoCrises(); - } - }); - } - - routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) : any { - // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged. - if (!this.crisis || this.crisis.name === this.editName) { - return true; - } - // Otherwise ask the user with the dialog service and return its - // promise which resolves to true or false when the user decides - return this._dialog.confirm('Discard changes?'); - } - - cancel() { - this.editName = this.crisis.name; - this.gotoCrises(); - } - - save() { - this.crisis.name = this.editName; - this.gotoCrises(); - } - - // #docregion gotoCrises - gotoCrises() { - let crisisId = this.crisis ? this.crisis.id : null; - // Pass along the hero id if available - // so that the CrisisListComponent can select that hero. - // Add a totally useless `foo` parameter for kicks. - // #docregion gotoCrises-navigate - this._router.navigate(['CrisisList', {id: crisisId, foo: 'foo'} ]); - // #enddocregion gotoCrises-navigate - } - // #enddocregion gotoCrises -} diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts deleted file mode 100644 index 96854b910c..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.1.ts +++ /dev/null @@ -1,36 +0,0 @@ -// #docplaster - -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Crisis, CrisisService} from './crisis.service'; -import {Router} from 'angular2/router'; - -@Component({ - // #docregion template - template: ` -
      -
    • - {{crisis.id}} {{crisis.name}} -
    • -
    - `, - // #enddocregion template -}) -export class CrisisListComponent implements OnInit { - crises: Crisis[]; - - constructor( - private _service: CrisisService, - private _router: Router) {} - - ngOnInit() { - this._service.getCrises().then(crises => this.crises = crises); - } - - // #docregion select - onSelect(crisis: Crisis) { - this._router.navigate(['CrisisDetail', { id: crisis.id }] ); - } - // #enddocregion select -} diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts deleted file mode 100644 index 8d6dcfca16..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis-list.component.ts +++ /dev/null @@ -1,40 +0,0 @@ -// #docplaster - -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Crisis, CrisisService} from './crisis.service'; -import {Router, RouteParams} from 'angular2/router'; - -@Component({ - template: ` -
      -
    • - {{crisis.id}} {{crisis.name}} -
    • -
    - `, -}) -export class CrisisListComponent implements OnInit { - crises: Crisis[]; - - private _selectedId: number; - - constructor( - private _service: CrisisService, - private _router: Router, - routeParams: RouteParams) { - this._selectedId = +routeParams.get('id'); - } - - isSelected(crisis: Crisis) { return crisis.id === this._selectedId; } - - ngOnInit() { - this._service.getCrises().then(crises => this.crises = crises); - } - - onSelect(crisis: Crisis) { - this._router.navigate( ['CrisisDetail', { id: crisis.id }] ); - } -} diff --git a/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts b/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts deleted file mode 100644 index 2f3fd761ec..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-center/crisis.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -// #docplaster - -// #docregion -import {Injectable} from 'angular2/core'; - -export class Crisis { - constructor(public id: number, public name: string) { } -} - -@Injectable() -export class CrisisService { - getCrises() { return crisesPromise; } - - getCrisis(id: number | string) { - return crisesPromise - .then(crises => crises.filter(c => c.id === +id)[0]); - } - -// #enddocregion - - static nextCrisisId = 100; - - addCrisis(name:string) { - name = name.trim(); - if (name){ - let crisis = new Crisis(CrisisService.nextCrisisId++, name); - crisesPromise.then(crises => crises.push(crisis)); - } - } -// #docregion -} - -var crises = [ - new Crisis(1, 'Dragon Burning Cities'), - new Crisis(2, 'Sky Rains Great White Sharks'), - new Crisis(3, 'Giant Asteroid Heading For Earth'), - new Crisis(4, 'Procrastinators Meeting Delayed Again'), -]; - -var crisesPromise = Promise.resolve(crises); -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/crisis-list.component.ts b/public/docs/_examples/router/ts/app/crisis-list.component.ts deleted file mode 100644 index b712137d05..0000000000 --- a/public/docs/_examples/router/ts/app/crisis-list.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Initial empty version -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - template: ` -

    CRISIS CENTER

    -

    Get your crisis here

    ` -}) -export class CrisisListComponent { } diff --git a/public/docs/_examples/router/ts/app/dialog.service.ts b/public/docs/_examples/router/ts/app/dialog.service.ts deleted file mode 100644 index a25f9c68d2..0000000000 --- a/public/docs/_examples/router/ts/app/dialog.service.ts +++ /dev/null @@ -1,18 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; -/** - * Async modal dialog service - * DialogService makes this app easier to test by faking this service. - * TODO: better modal implemenation that doesn't use window.confirm - */ -@Injectable() -export class DialogService { - /** - * Ask user to confirm an action. `message` explains the action and choices. - * Returns promise resolving to `true`=confirm or `false`=cancel - */ - confirm(message?:string) { - return new Promise((resolve, reject) => - resolve(window.confirm(message || 'Is it OK?'))); - }; -} diff --git a/public/docs/_examples/router/ts/app/hero-list.component.ts b/public/docs/_examples/router/ts/app/hero-list.component.ts deleted file mode 100644 index d1abf925de..0000000000 --- a/public/docs/_examples/router/ts/app/hero-list.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// Initial empty version -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - template: ` -

    HEROES

    -

    Get your heroes here

    ` -}) -export class HeroListComponent { } diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts deleted file mode 100644 index bf189d7e1c..0000000000 --- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.1.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Hero, HeroService} from './hero.service'; -import {RouteParams, Router} from 'angular2/router'; - -@Component({ - template: ` -

    HEROES

    -
    -

    "{{hero.name}}"

    -
    - {{hero.id}}
    -
    - - -
    -

    - -

    -
    - `, -}) -export class HeroDetailComponent implements OnInit { - hero: Hero; - - // #docregion ctor - constructor( - private _router:Router, - private _routeParams:RouteParams, - private _service:HeroService){} - // #enddocregion ctor - - // #docregion ngOnInit - ngOnInit() { - let id = this._routeParams.get('id'); - this._service.getHero(id).then(hero => this.hero = hero); - } - // #enddocregion ngOnInit - - // #docregion gotoHeroes - gotoHeroes() { - // Like Heroes - this._router.navigate(['Heroes']); - } - // #enddocregion gotoHeroes -} diff --git a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts deleted file mode 100644 index b13c15c8d8..0000000000 --- a/public/docs/_examples/router/ts/app/heroes/hero-detail.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Hero, HeroService} from './hero.service'; -import {RouteParams, Router} from 'angular2/router'; - -@Component({ - template: ` -

    HEROES

    -
    -

    "{{hero.name}}"

    -
    - {{hero.id}}
    -
    - - -
    -

    - -

    -
    - `, -}) -export class HeroDetailComponent implements OnInit { - hero: Hero; - - // #docregion ctor - constructor( - private _router:Router, - private _routeParams:RouteParams, - private _service:HeroService){} - // #enddocregion ctor - - // #docregion ngOnInit - ngOnInit() { - let id = this._routeParams.get('id'); - this._service.getHero(id).then(hero => this.hero = hero); - } - // #enddocregion ngOnInit - - // #docregion gotoHeroes - gotoHeroes() { - let heroId = this.hero ? this.hero.id : null; - // Pass along the hero id if available - // so that the HeroList component can select that hero. - // Add a totally useless `foo` parameter for kicks. - // #docregion gotoHeroes-navigate - this._router.navigate(['Heroes', {id: heroId, foo: 'foo'} ]); - // #enddocregion gotoHeroes-navigate - } - // #enddocregion gotoHeroes -} diff --git a/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts b/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts deleted file mode 100644 index 05ca2ded3e..0000000000 --- a/public/docs/_examples/router/ts/app/heroes/hero-list.component.1.ts +++ /dev/null @@ -1,49 +0,0 @@ -// #docplaster - -// #docregion -// TODO SOMEDAY: Feature Componetized like HeroCenter -import {Component, OnInit} from 'angular2/core'; -import {Hero, HeroService} from './hero.service'; -import {Router} from 'angular2/router'; - -@Component({ - // #docregion template - template: ` -

    HEROES

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - ` - // #enddocregion template -}) -export class HeroListComponent implements OnInit { - heroes: Hero[]; - - // #docregion ctor - constructor( - private _router: Router, - private _service: HeroService) { } - // #enddocregion ctor - - ngOnInit() { - this._service.getHeroes().then(heroes => this.heroes = heroes) - } - - // #docregion select - onSelect(hero: Hero) { - // #docregion nav-to-detail - this._router.navigate( ['HeroDetail', { id: hero.id }] ); - // #enddocregion nav-to-detail - } - // #enddocregion select -} -// #enddocregion - -/* A link parameters array -// #docregion link-parameters-array -['HeroDetail', { id: hero.id }] // {id: 15} -// #enddocregion link-parameters-array -*/ \ No newline at end of file diff --git a/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts b/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts deleted file mode 100644 index 83f628704c..0000000000 --- a/public/docs/_examples/router/ts/app/heroes/hero-list.component.ts +++ /dev/null @@ -1,53 +0,0 @@ -// #docplaster - -// TODO SOMEDAY: Feature Componetized like CrisisCenter -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Hero, HeroService} from './hero.service'; -// #docregion import-route-params -import {Router, RouteParams} from 'angular2/router'; -// #enddocregion import-route-params - -@Component({ - // #docregion template - template: ` -

    HEROES

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - ` - // #enddocregion template -}) -export class HeroListComponent implements OnInit { - heroes: Hero[]; - - // #docregion ctor - private _selectedId: number; - - constructor( - private _service: HeroService, - private _router: Router, - routeParams: RouteParams) { - this._selectedId = +routeParams.get('id'); - } - // #enddocregion ctor - - // #docregion isSelected - isSelected(hero: Hero) { return hero.id === this._selectedId; } - // #enddocregion isSelected - - // #docregion select - onSelect(hero: Hero) { - this._router.navigate( ['HeroDetail', { id: hero.id }] ); - } - // #enddocregion select - - ngOnInit() { - this._service.getHeroes().then(heroes => this.heroes = heroes) - } -} -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/heroes/hero.service.ts b/public/docs/_examples/router/ts/app/heroes/hero.service.ts deleted file mode 100644 index f85d353d2d..0000000000 --- a/public/docs/_examples/router/ts/app/heroes/hero.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; - -export class Hero { - constructor(public id: number, public name: string) { } -} - -@Injectable() -export class HeroService { - getHeroes() { return heroesPromise; } - - getHero(id: number | string) { - return heroesPromise - .then(heroes => heroes.filter(h => h.id === +id)[0]); - } -} - -var HEROES = [ - new Hero(11, 'Mr. Nice'), - new Hero(12, 'Narco'), - new Hero(13, 'Bombasto'), - new Hero(14, 'Celeritas'), - new Hero(15, 'Magneta'), - new Hero(16, 'RubberMan') -]; - -var heroesPromise = Promise.resolve(HEROES); diff --git a/public/docs/_examples/router/ts/app/main.1.ts b/public/docs/_examples/router/ts/app/main.1.ts deleted file mode 100644 index 8dfbeb39eb..0000000000 --- a/public/docs/_examples/router/ts/app/main.1.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* First version */ -// #docplaster - -// #docregion all -import {AppComponent} from './app.component'; -import {bootstrap} from 'angular2/platform/browser'; -import {ROUTER_PROVIDERS} from 'angular2/router'; - -// #enddocregion all - -/* Can't use AppComponent ... but display as if we can -// #docregion all -bootstrap(AppComponent, [ -// #enddocregion all -*/ - -// Actually use the v.1 component -import {AppComponent as ac} from './app.component.1'; -bootstrap(ac, [ -// #docregion all - ROUTER_PROVIDERS -]); -// #enddocregion all \ No newline at end of file diff --git a/public/docs/_examples/router/ts/app/main.2.ts b/public/docs/_examples/router/ts/app/main.2.ts deleted file mode 100644 index 244050a36a..0000000000 --- a/public/docs/_examples/router/ts/app/main.2.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* Second version */ -// For Milestone #2 -// Also includes digression on HashPathStrategy (not used in the final app) -// #docplaster - -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {ROUTER_PROVIDERS} from 'angular2/router'; -import {AppComponent} from './app.component'; - -// Add these symbols to override the `LocationStrategy` -import {provide} from 'angular2/core'; -import {LocationStrategy, - HashLocationStrategy} from 'angular2/router'; -// #enddocregion -/* Can't use AppComponent ... but display as if we can -// #docregion - -bootstrap(AppComponent, [ -// #enddocregion -*/ - -// Actually use the v.2 component -import {AppComponent as ac} from './app.component.2'; - -bootstrap(ac, [ -// #docregion - ROUTER_PROVIDERS, - provide(LocationStrategy, - {useClass: HashLocationStrategy}) // .../#/crisis-center/ -]); -// #enddocregion diff --git a/public/docs/_examples/router/ts/app/main.3.ts b/public/docs/_examples/router/ts/app/main.3.ts deleted file mode 100644 index d895aff5e9..0000000000 --- a/public/docs/_examples/router/ts/app/main.3.ts +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {ROUTER_PROVIDERS} from 'angular2/router'; - -import {AppComponent} from './app.component.3'; - -bootstrap(AppComponent, [ROUTER_PROVIDERS]); diff --git a/public/docs/_examples/router/ts/app/main.ts b/public/docs/_examples/router/ts/app/main.ts deleted file mode 100644 index 6805a24f60..0000000000 --- a/public/docs/_examples/router/ts/app/main.ts +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import {bootstrap} from 'angular2/platform/browser'; -import {ROUTER_PROVIDERS} from 'angular2/router'; - -import {AppComponent} from './app.component'; - -bootstrap(AppComponent, [ROUTER_PROVIDERS]); diff --git a/public/docs/_examples/router/ts/index.1.html b/public/docs/_examples/router/ts/index.1.html deleted file mode 100644 index f6a027f1de..0000000000 --- a/public/docs/_examples/router/ts/index.1.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - Router Sample - - - - - - - - - - - - - - - - - - - - - -

    Milestone 1

    - loading... - - - - diff --git a/public/docs/_examples/router/ts/index.2.html b/public/docs/_examples/router/ts/index.2.html deleted file mode 100644 index 9fa6328a22..0000000000 --- a/public/docs/_examples/router/ts/index.2.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - Router Sample - - - - - - - - - - - - - - - - - - - -

    Milestone 2

    - loading... - - - - diff --git a/public/docs/_examples/router/ts/index.3.html b/public/docs/_examples/router/ts/index.3.html deleted file mode 100644 index 8b66281cc9..0000000000 --- a/public/docs/_examples/router/ts/index.3.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - Router Sample - - - - - - - - - - - - - - - - - - - -

    Milestone 3

    - loading... - - - - diff --git a/public/docs/_examples/router/ts/index.html b/public/docs/_examples/router/ts/index.html deleted file mode 100644 index dae130f8aa..0000000000 --- a/public/docs/_examples/router/ts/index.html +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - Router Sample - - - - - - - - - - - - - - - - - - - - - - - - - loading... - - - - diff --git a/public/docs/_examples/router/ts/plnkr.json b/public/docs/_examples/router/ts/plnkr.json index 741f87caa6..23ed1a1606 100644 --- a/public/docs/_examples/router/ts/plnkr.json +++ b/public/docs/_examples/router/ts/plnkr.json @@ -1,12 +1,12 @@ { "description": "Router", + "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!**/*.[1,2,3].*", + "!**/*.[0-9].*", "!app/crisis-list.component.ts", - "!app/hero-list.component.ts", - "!app/crisis-center/add-crisis.component.ts" + "!app/hero-list.component.ts" ], "tags": ["router"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.1.ts b/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.1.ts new file mode 100644 index 0000000000..ffa3e3cb8f --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.1.ts @@ -0,0 +1,9 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    Dashboard

    + ` +}) +export class AdminDashboardComponent { } diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.2.ts b/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.2.ts new file mode 100644 index 0000000000..8c8e481643 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.2.ts @@ -0,0 +1,33 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +@Component({ + template: ` +

    Dashboard

    + +

    Session ID: {{ sessionId | async }}

    + +

    Token: {{ token | async }}

    + ` +}) +export class AdminDashboardComponent implements OnInit { + sessionId: Observable; + token: Observable; + + constructor(private route: ActivatedRoute) {} + + ngOnInit() { + // Capture the session ID if available + this.sessionId = this.route + .queryParams + .map(params => params['session_id'] || 'None'); + + // Capture the fragment if available + this.token = this.route + .fragment + .map(fragment => fragment || 'None'); + } +} diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.ts b/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.ts new file mode 100644 index 0000000000..b3fc839616 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-dashboard.component.ts @@ -0,0 +1,47 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; + +import { SelectivePreloadingStrategy } from '../selective-preloading-strategy'; + +import 'rxjs/add/operator/map'; + +@Component({ + template: ` +

    Dashboard

    + +

    Session ID: {{ sessionId | async }}

    + +

    Token: {{ token | async }}

    + + Preloaded Modules +
      +
    • {{ module }}
    • +
    + ` +}) +export class AdminDashboardComponent implements OnInit { + sessionId: Observable; + token: Observable; + modules: string[]; + + constructor( + private route: ActivatedRoute, + private preloadStrategy: SelectivePreloadingStrategy + ) { + this.modules = preloadStrategy.preloadedModules; + } + + ngOnInit() { + // Capture the session ID if available + this.sessionId = this.route + .queryParams + .map(params => params['session_id'] || 'None'); + + // Capture the fragment if available + this.token = this.route + .fragment + .map(fragment => fragment || 'None'); + } +} diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.1.ts b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.1.ts new file mode 100644 index 0000000000..e7d83f113f --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.1.ts @@ -0,0 +1,39 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { AdminComponent } from './admin.component'; +import { AdminDashboardComponent } from './admin-dashboard.component'; +import { ManageCrisesComponent } from './manage-crises.component'; +import { ManageHeroesComponent } from './manage-heroes.component'; + +// #docregion admin-routes +const adminRoutes: Routes = [ + { + path: 'admin', + component: AdminComponent, + children: [ + { + path: '', + children: [ + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } + ] + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AdminRoutingModule {} +// #enddocregion admin-routes +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.2.ts b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.2.ts new file mode 100644 index 0000000000..d945201afe --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.2.ts @@ -0,0 +1,44 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { AdminComponent } from './admin.component'; +import { AdminDashboardComponent } from './admin-dashboard.component'; +import { ManageCrisesComponent } from './manage-crises.component'; +import { ManageHeroesComponent } from './manage-heroes.component'; + +// #docregion admin-route +import { AuthGuard } from '../auth-guard.service'; + +const adminRoutes: Routes = [ + { + path: 'admin', + component: AdminComponent, + canActivate: [AuthGuard], + children: [ + { + path: '', + children: [ + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } + ], + // #enddocregion admin-route + canActivateChild: [AuthGuard] + // #docregion admin-route + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AdminRoutingModule {} +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.3.ts b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.3.ts new file mode 100644 index 0000000000..63f1c9aaf4 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.3.ts @@ -0,0 +1,43 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { AdminComponent } from './admin.component'; +import { AdminDashboardComponent } from './admin-dashboard.component'; +import { ManageCrisesComponent } from './manage-crises.component'; +import { ManageHeroesComponent } from './manage-heroes.component'; + +// #docregion admin-route +import { AuthGuard } from '../auth-guard.service'; + +// #docregion can-activate-child +const adminRoutes: Routes = [ + { + path: 'admin', + component: AdminComponent, + canActivate: [AuthGuard], + children: [ + { + path: '', + canActivateChild: [AuthGuard], + children: [ + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } + ] + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AdminRoutingModule {} +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.ts b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.ts new file mode 100644 index 0000000000..2b1048d110 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin-routing.module.ts @@ -0,0 +1,41 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { AdminComponent } from './admin.component'; +import { AdminDashboardComponent } from './admin-dashboard.component'; +import { ManageCrisesComponent } from './manage-crises.component'; +import { ManageHeroesComponent } from './manage-heroes.component'; + +import { AuthGuard } from '../auth-guard.service'; + +const adminRoutes: Routes = [ + { + path: '', + component: AdminComponent, + canActivate: [AuthGuard], + children: [ + { + path: '', + canActivateChild: [AuthGuard], + children: [ + { path: 'crises', component: ManageCrisesComponent }, + { path: 'heroes', component: ManageHeroesComponent }, + { path: '', component: AdminDashboardComponent } + ] + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(adminRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AdminRoutingModule {} +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/admin/admin.component.ts b/public/docs/_examples/router/ts/src/app/admin/admin.component.ts new file mode 100644 index 0000000000..30abfa4524 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin.component.ts @@ -0,0 +1,17 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    ADMIN

    + + + ` +}) +export class AdminComponent { +} diff --git a/public/docs/_examples/router/ts/src/app/admin/admin.module.ts b/public/docs/_examples/router/ts/src/app/admin/admin.module.ts new file mode 100644 index 0000000000..2736f00e1d --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/admin.module.ts @@ -0,0 +1,24 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { AdminComponent } from './admin.component'; +import { AdminDashboardComponent } from './admin-dashboard.component'; +import { ManageCrisesComponent } from './manage-crises.component'; +import { ManageHeroesComponent } from './manage-heroes.component'; + +import { AdminRoutingModule } from './admin-routing.module'; + +@NgModule({ + imports: [ + CommonModule, + AdminRoutingModule + ], + declarations: [ + AdminComponent, + AdminDashboardComponent, + ManageCrisesComponent, + ManageHeroesComponent + ] +}) +export class AdminModule {} diff --git a/public/docs/_examples/router/ts/src/app/admin/manage-crises.component.ts b/public/docs/_examples/router/ts/src/app/admin/manage-crises.component.ts new file mode 100644 index 0000000000..d3176563eb --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/manage-crises.component.ts @@ -0,0 +1,9 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    Manage your crises here

    + ` +}) +export class ManageCrisesComponent { } diff --git a/public/docs/_examples/router/ts/src/app/admin/manage-heroes.component.ts b/public/docs/_examples/router/ts/src/app/admin/manage-heroes.component.ts new file mode 100644 index 0000000000..7f3a39893d --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/admin/manage-heroes.component.ts @@ -0,0 +1,9 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    Manage your heroes here

    + ` +}) +export class ManageHeroesComponent { } diff --git a/public/docs/_examples/router/ts/src/app/animations.ts b/public/docs/_examples/router/ts/src/app/animations.ts new file mode 100644 index 0000000000..d7a55d721f --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/animations.ts @@ -0,0 +1,26 @@ +// #docregion +import { animate, AnimationEntryMetadata, state, style, transition, trigger } from '@angular/core'; + +// Component transition animations +export const slideInDownAnimation: AnimationEntryMetadata = + trigger('routeAnimation', [ + state('*', + style({ + opacity: 1, + transform: 'translateX(0)' + }) + ), + transition(':enter', [ + style({ + opacity: 0, + transform: 'translateX(-100%)' + }), + animate('0.2s ease-in') + ]), + transition(':leave', [ + animate('0.5s ease-out', style({ + opacity: 0, + transform: 'translateY(100%)' + })) + ]) + ]); diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.1.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.1.ts new file mode 100644 index 0000000000..8146e54671 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.1.ts @@ -0,0 +1,26 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisListComponent } from './crisis-list.component'; +import { HeroListComponent } from './hero-list.component'; +import { PageNotFoundComponent } from './not-found.component'; + +// #docregion appRoutes +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'heroes', component: HeroListComponent }, + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; +// #enddocregion appRoutes + +@NgModule({ + imports: [ + RouterModule.forRoot(appRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.2.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.2.ts new file mode 100644 index 0000000000..42ac84a481 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.2.ts @@ -0,0 +1,24 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisListComponent } from './crisis-list.component'; +// import { HeroListComponent } from './hero-list.component'; // <-- delete this line +import { PageNotFoundComponent } from './not-found.component'; + +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + // { path: 'heroes', component: HeroListComponent }, // <-- delete this line + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(appRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.3.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.3.ts new file mode 100644 index 0000000000..538ff9aafc --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.3.ts @@ -0,0 +1,31 @@ +// #docplaster +// #docregion , v3 +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { ComposeMessageComponent } from './compose-message.component'; +import { PageNotFoundComponent } from './not-found.component'; + +const appRoutes: Routes = [ +// #enddocregion v3 +// #docregion compose + { + path: 'compose', + component: ComposeMessageComponent, + outlet: 'popup' + }, +// #enddocregion compose +// #docregion v3 + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(appRoutes) + ], + exports: [ + RouterModule + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.4.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.4.ts new file mode 100644 index 0000000000..6835d24a85 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.4.ts @@ -0,0 +1,30 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { ComposeMessageComponent } from './compose-message.component'; +import { CanDeactivateGuard } from './can-deactivate-guard.service'; +import { PageNotFoundComponent } from './not-found.component'; + +const appRoutes: Routes = [ + { + path: 'compose', + component: ComposeMessageComponent, + outlet: 'popup' + }, + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(appRoutes) + ], + exports: [ + RouterModule + ], + providers: [ + CanDeactivateGuard + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.5.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.5.ts new file mode 100644 index 0000000000..2badf7f593 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.5.ts @@ -0,0 +1,45 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +// #docregion import-router +import { RouterModule, Routes } from '@angular/router'; +// #enddocregion import-router + +import { ComposeMessageComponent } from './compose-message.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { CanDeactivateGuard } from './can-deactivate-guard.service'; +import { AuthGuard } from './auth-guard.service'; + + +const appRoutes: Routes = [ + { + path: 'compose', + component: ComposeMessageComponent, + outlet: 'popup' + }, +// #docregion admin, admin-1 + { + path: 'admin', + loadChildren: 'app/admin/admin.module#AdminModule', +// #enddocregion admin-1 + canLoad: [AuthGuard] +// #docregion admin-1 + }, +// #enddocregion admin, admin-1 + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(appRoutes) + ], + exports: [ + RouterModule + ], + providers: [ + CanDeactivateGuard + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.6.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.6.ts new file mode 100644 index 0000000000..df2c8c097d --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.6.ts @@ -0,0 +1,54 @@ +// #docplaster +// #docregion, preload-v1 +import { NgModule } from '@angular/core'; +import { + RouterModule, Routes, +// #enddocregion preload-v1 + PreloadAllModules +// #docregion preload-v1 +} from '@angular/router'; + +import { ComposeMessageComponent } from './compose-message.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { CanDeactivateGuard } from './can-deactivate-guard.service'; +import { AuthGuard } from './auth-guard.service'; + +const appRoutes: Routes = [ + { + path: 'compose', + component: ComposeMessageComponent, + outlet: 'popup' + }, + { + path: 'admin', + loadChildren: 'app/admin/admin.module#AdminModule', + canLoad: [AuthGuard] + }, + { + path: 'crisis-center', + loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule' + }, + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + // #docregion forRoot + RouterModule.forRoot( + appRoutes + // #enddocregion preload-v1 + , { preloadingStrategy: PreloadAllModules } + // #docregion preload-v1 + ) + // #enddocregion forRoot + ], + exports: [ + RouterModule + ], + providers: [ + CanDeactivateGuard + ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/app-routing.module.ts b/public/docs/_examples/router/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..cc01ced890 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app-routing.module.ts @@ -0,0 +1,50 @@ +// #docplaster +// #docregion, preload-v1 +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { ComposeMessageComponent } from './compose-message.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { CanDeactivateGuard } from './can-deactivate-guard.service'; +import { AuthGuard } from './auth-guard.service'; +import { SelectivePreloadingStrategy } from './selective-preloading-strategy'; + +const appRoutes: Routes = [ + { + path: 'compose', + component: ComposeMessageComponent, + outlet: 'popup' + }, + { + path: 'admin', + loadChildren: 'app/admin/admin.module#AdminModule', + canLoad: [AuthGuard] + }, + // #docregion preload-v2 + { + path: 'crisis-center', + loadChildren: 'app/crisis-center/crisis-center.module#CrisisCenterModule', + data: { preload: true } + }, + // #enddocregion preload-v2 + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot( + appRoutes, + { preloadingStrategy: SelectivePreloadingStrategy } + ) + ], + exports: [ + RouterModule + ], + providers: [ + CanDeactivateGuard, + SelectivePreloadingStrategy + ] +}) +export class AppRoutingModule { } diff --git a/public/docs/_examples/router/ts/src/app/app.component.1.ts b/public/docs/_examples/router/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..21e9aa417d --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.component.1.ts @@ -0,0 +1,18 @@ +/* First version */ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    Angular Router

    + + + ` + // #enddocregion template +}) +export class AppComponent { } diff --git a/public/docs/_examples/router/ts/src/app/app.component.2.ts b/public/docs/_examples/router/ts/src/app/app.component.2.ts new file mode 100644 index 0000000000..ffd4d8dfae --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.component.2.ts @@ -0,0 +1,16 @@ +/* Second Heroes version */ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Angular Router

    + + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/router/ts/src/app/app.component.3.ts b/public/docs/_examples/router/ts/src/app/app.component.3.ts new file mode 100644 index 0000000000..6013df6321 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.component.3.ts @@ -0,0 +1,48 @@ +/* tslint:disable:no-unused-variable */ +// #docplaster +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'my-app', + /* Typical link + // #docregion h-anchor + Heroes + // #enddocregion h-anchor + */ + /* Incomplete Crisis Center link when CC lacks a default + // #docregion cc-anchor-fail + // The link now fails with a "non-terminal link" error + // #docregion cc-anchor-w-default + Crisis Center + // #enddocregion cc-anchor-w-default + // #enddocregion cc-anchor-fail + */ + /* Crisis Center link when CC lacks a default + // #docregion cc-anchor-no-default + Crisis Center + // #enddocregion cc-anchor-no-default + */ + /* Crisis Center Detail link + // #docregion Dragon-anchor + Dragon Crisis + // #enddocregion Dragon-anchor + */ + /* Crisis Center link with optional query params + // #docregion cc-query-params + Crisis Center + // #enddocregion cc-query-params + */ +// #docregion template + template: ` +

    Angular Router

    + + + ` +// #enddocregion template +}) +export class AppComponent { } diff --git a/public/docs/_examples/router/ts/src/app/app.component.4.ts b/public/docs/_examples/router/ts/src/app/app.component.4.ts new file mode 100644 index 0000000000..a630703c28 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.component.4.ts @@ -0,0 +1,23 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    Angular Router

    + + // #docregion outlets + + + // #enddocregion outlets + ` + // #enddocregion template +}) +export class AppComponent { } diff --git a/public/docs/_examples/router/ts/src/app/app.component.5.ts b/public/docs/_examples/router/ts/src/app/app.component.5.ts new file mode 100644 index 0000000000..24162c6136 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.component.5.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    Angular Router

    + + + + ` + // #enddocregion template +}) +export class AppComponent { } diff --git a/public/docs/_examples/router/ts/src/app/app.component.ts b/public/docs/_examples/router/ts/src/app/app.component.ts new file mode 100644 index 0000000000..a479680cbe --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.component.ts @@ -0,0 +1,23 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    Angular Router

    + + + + ` + // #enddocregion template +}) +export class AppComponent { +} diff --git a/public/docs/_examples/router/ts/src/app/app.module.0.ts b/public/docs/_examples/router/ts/src/app/app.module.0.ts new file mode 100644 index 0000000000..a195dbdd7a --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.0.ts @@ -0,0 +1,41 @@ +// NEVER USED. For docs only. Should compile though +// #docplaster +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { HeroListComponent } from './hero-list.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { PageNotFoundComponent } from './not-found.component'; +import { PageNotFoundComponent as HeroDetailComponent } from './not-found.component'; + +// #docregion +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'hero/:id', component: HeroDetailComponent }, + { + path: 'heroes', + component: HeroListComponent, + data: { title: 'Heroes List' } + }, + { path: '', + redirectTo: '/heroes', + pathMatch: 'full' + }, + { path: '**', component: PageNotFoundComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(appRoutes) + // other imports here + ], +// #enddocregion +/* +// #docregion + ... +}) +export class AppModule { } +// #enddocregion +*/ +}) +export class AppModule0 { } diff --git a/public/docs/_examples/router/ts/src/app/app.module.1.ts b/public/docs/_examples/router/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..32f93b8f79 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.1.ts @@ -0,0 +1,49 @@ +// #docplaster +// #docregion +// #docregion first-config +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +// #docregion import-router +import { RouterModule, Routes } from '@angular/router'; +// #enddocregion import-router + +import { AppComponent } from './app.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { HeroListComponent } from './hero-list.component'; +// #enddocregion first-config +import { PageNotFoundComponent } from './not-found.component'; +// #docregion first-config + +// #docregion appRoutes +const appRoutes: Routes = [ + { path: 'crisis-center', component: CrisisListComponent }, + { path: 'heroes', component: HeroListComponent }, +// #enddocregion first-config + + { path: '', redirectTo: '/heroes', pathMatch: 'full' }, +// #docregion wildcard + { path: '**', component: PageNotFoundComponent } +// #enddocregion wildcard +// #docregion first-config +]; +// #enddocregion appRoutes + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + RouterModule.forRoot(appRoutes) + ], + declarations: [ + AppComponent, + HeroListComponent, + CrisisListComponent, +// #enddocregion first-config + PageNotFoundComponent +// #docregion first-config + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/app.module.2.ts b/public/docs/_examples/router/ts/src/app/app.module.2.ts new file mode 100644 index 0000000000..2ba739168c --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.2.ts @@ -0,0 +1,31 @@ +// #docplaster +// #docregion +// #docregion hero-import +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; + +import { CrisisListComponent } from './crisis-list.component'; +import { HeroListComponent } from './hero-list.component'; +import { PageNotFoundComponent } from './not-found.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + HeroListComponent, + CrisisListComponent, + PageNotFoundComponent + ], + bootstrap: [ AppComponent ] +}) +// #enddocregion hero-import +export class AppModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/app.module.3.ts b/public/docs/_examples/router/ts/src/app/app.module.3.ts new file mode 100644 index 0000000000..862faf1c51 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.3.ts @@ -0,0 +1,29 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; +import { HeroesModule } from './heroes/heroes.module'; + +import { CrisisListComponent } from './crisis-list.component'; +import { PageNotFoundComponent } from './not-found.component'; + +@NgModule({ +// #docregion module-imports + imports: [ + BrowserModule, + FormsModule, + HeroesModule, + AppRoutingModule + ], +// #enddocregion module-imports + declarations: [ + AppComponent, + CrisisListComponent, + PageNotFoundComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/router/ts/src/app/app.module.4.ts b/public/docs/_examples/router/ts/src/app/app.module.4.ts new file mode 100644 index 0000000000..4825572361 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.4.ts @@ -0,0 +1,46 @@ +// #docplaster +// #docregion +// #docregion crisis-center-module, admin-module +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { AppRoutingModule } from './app-routing.module'; +import { HeroesModule } from './heroes/heroes.module'; +import { CrisisCenterModule } from './crisis-center/crisis-center.module'; +// #enddocregion crisis-center-module, admin-module +import { ComposeMessageComponent } from './compose-message.component'; +// #docregion admin-module +import { AdminModule } from './admin/admin.module'; +// #docregion crisis-center-module + +import { DialogService } from './dialog.service'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + HeroesModule, + CrisisCenterModule, +// #enddocregion crisis-center-module + AdminModule, +// #docregion crisis-center-module + AppRoutingModule + ], + declarations: [ + AppComponent, +// #enddocregion admin-module, crisis-center-module + ComposeMessageComponent, +// #docregion admin-module, crisis-center-module + PageNotFoundComponent + ], + providers: [ + DialogService + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/app.module.5.ts b/public/docs/_examples/router/ts/src/app/app.module.5.ts new file mode 100644 index 0000000000..ad34668cea --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.5.ts @@ -0,0 +1,38 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; + +import { HeroesModule } from './heroes/heroes.module'; +import { CrisisCenterModule } from './crisis-center/crisis-center.module'; + +import { ComposeMessageComponent } from './compose-message.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { AdminModule } from './admin/admin.module'; +import { DialogService } from './dialog.service'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + HeroesModule, + CrisisCenterModule, + AdminModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + ComposeMessageComponent, + PageNotFoundComponent + ], + providers: [ + DialogService + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/router/ts/src/app/app.module.6.ts b/public/docs/_examples/router/ts/src/app/app.module.6.ts new file mode 100644 index 0000000000..4cb0b1fdd5 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.6.ts @@ -0,0 +1,29 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { Routes, RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { PageNotFoundComponent } from './not-found.component'; + +const routes: Routes = [ + +]; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + RouterModule.forRoot(routes, { useHash: true }) // .../#/crisis-center/ + ], + declarations: [ + AppComponent, + PageNotFoundComponent + ], + providers: [ + + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/router/ts/src/app/app.module.7.ts b/public/docs/_examples/router/ts/src/app/app.module.7.ts new file mode 100644 index 0000000000..b6ca81ddea --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.7.ts @@ -0,0 +1,38 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; + +import { HeroesModule } from './heroes/heroes.module'; +import { CrisisCenterModule } from './crisis-center/crisis-center.module'; +import { ComposeMessageComponent } from './compose-message.component'; +import { LoginRoutingModule } from './login-routing.module'; +import { LoginComponent } from './login.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { DialogService } from './dialog.service'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HeroesModule, + CrisisCenterModule, + LoginRoutingModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + ComposeMessageComponent, + LoginComponent, + PageNotFoundComponent + ], + providers: [ + DialogService + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/router/ts/src/app/app.module.ts b/public/docs/_examples/router/ts/src/app/app.module.ts new file mode 100644 index 0000000000..dcf3401ded --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/app.module.ts @@ -0,0 +1,56 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +// #docregion animations-module +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +// #enddocregion animations-module +// #docregion inspect-config +import { Router } from '@angular/router'; + +// #enddocregion inspect-config +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; + +import { HeroesModule } from './heroes/heroes.module'; +import { ComposeMessageComponent } from './compose-message.component'; +import { LoginRoutingModule } from './login-routing.module'; +import { LoginComponent } from './login.component'; +import { PageNotFoundComponent } from './not-found.component'; + +import { DialogService } from './dialog.service'; + +// #docregion animations-module +@NgModule({ + imports: [ + // #enddocregion animations-module + BrowserModule, + FormsModule, + HeroesModule, + LoginRoutingModule, + AppRoutingModule, + // #docregion animations-module + BrowserAnimationsModule + // #enddocregion animations-module + ], + declarations: [ + AppComponent, + ComposeMessageComponent, + LoginComponent, + PageNotFoundComponent + ], + providers: [ + DialogService + ], + bootstrap: [ AppComponent ] +}) +// #docregion inspect-config +export class AppModule { + // Diagnostic only: inspect router configuration + constructor(router: Router) { + console.log('Routes: ', JSON.stringify(router.config, undefined, 2)); + } +} +// #enddocregion inspect-config diff --git a/public/docs/_examples/router/ts/src/app/auth-guard.service.1.ts b/public/docs/_examples/router/ts/src/app/auth-guard.service.1.ts new file mode 100644 index 0000000000..c824bcb208 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/auth-guard.service.1.ts @@ -0,0 +1,11 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { CanActivate } from '@angular/router'; + +@Injectable() +export class AuthGuard implements CanActivate { + canActivate() { + console.log('AuthGuard#canActivate called'); + return true; + } +} diff --git a/public/docs/_examples/router/ts/src/app/auth-guard.service.2.ts b/public/docs/_examples/router/ts/src/app/auth-guard.service.2.ts new file mode 100644 index 0000000000..8fd00e151a --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/auth-guard.service.2.ts @@ -0,0 +1,37 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { + CanActivate, Router, + ActivatedRouteSnapshot, + RouterStateSnapshot +} from '@angular/router'; +import { AuthService } from './auth.service'; + +@Injectable() +export class AuthGuard implements CanActivate { + constructor(private authService: AuthService, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + let url: string = state.url; + + return this.checkLogin(url); + } + + checkLogin(url: string): boolean { + if (this.authService.isLoggedIn) { return true; } + + // Store the attempted URL for redirecting + this.authService.redirectUrl = url; + + // Navigate to the login page with extras + this.router.navigate(['/login']); + return false; + } +} +// #enddocregion + +/* +// #docregion can-load-interface +export class AuthGuard implements CanActivate, CanLoad { +// #enddocregion can-load-interface +*/ diff --git a/public/docs/_examples/router/ts/src/app/auth-guard.service.3.ts b/public/docs/_examples/router/ts/src/app/auth-guard.service.3.ts new file mode 100644 index 0000000000..dd89006411 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/auth-guard.service.3.ts @@ -0,0 +1,39 @@ +// #docregion +// #docregion can-activate-child +import { Injectable } from '@angular/core'; +import { + CanActivate, Router, + ActivatedRouteSnapshot, + RouterStateSnapshot, + CanActivateChild +} from '@angular/router'; +import { AuthService } from './auth.service'; + +@Injectable() +export class AuthGuard implements CanActivate, CanActivateChild { + constructor(private authService: AuthService, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + let url: string = state.url; + + return this.checkLogin(url); + } + + canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + return this.canActivate(route, state); + } + +// #enddocregion can-activate-child + checkLogin(url: string): boolean { + if (this.authService.isLoggedIn) { return true; } + + // Store the attempted URL for redirecting + this.authService.redirectUrl = url; + + // Navigate to the login page + this.router.navigate(['/login']); + return false; + } +// #docregion can-activate-child +} +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/auth-guard.service.4.ts b/public/docs/_examples/router/ts/src/app/auth-guard.service.4.ts new file mode 100644 index 0000000000..5d239a8432 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/auth-guard.service.4.ts @@ -0,0 +1,47 @@ +// #docplaster +// #docregion +import { Injectable } from '@angular/core'; +import { + CanActivate, Router, + ActivatedRouteSnapshot, + RouterStateSnapshot, + CanActivateChild, + NavigationExtras +} from '@angular/router'; +import { AuthService } from './auth.service'; + +@Injectable() +export class AuthGuard implements CanActivate, CanActivateChild { + constructor(private authService: AuthService, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + let url: string = state.url; + + return this.checkLogin(url); + } + + canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + return this.canActivate(route, state); + } + + checkLogin(url: string): boolean { + if (this.authService.isLoggedIn) { return true; } + + // Store the attempted URL for redirecting + this.authService.redirectUrl = url; + + // Create a dummy session id + let sessionId = 123456789; + + // Set our navigation extras object + // that contains our global query params and fragment + let navigationExtras: NavigationExtras = { + queryParams: { 'session_id': sessionId }, + fragment: 'anchor' + }; + + // Navigate to the login page with extras + this.router.navigate(['/login'], navigationExtras); + return false; + } +} diff --git a/public/docs/_examples/router/ts/src/app/auth-guard.service.ts b/public/docs/_examples/router/ts/src/app/auth-guard.service.ts new file mode 100644 index 0000000000..a32b5cc2b8 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/auth-guard.service.ts @@ -0,0 +1,56 @@ +// #docplaster +import { Injectable } from '@angular/core'; +import { + CanActivate, Router, + ActivatedRouteSnapshot, + RouterStateSnapshot, + CanActivateChild, + NavigationExtras, + CanLoad, Route +} from '@angular/router'; +import { AuthService } from './auth.service'; + +@Injectable() +export class AuthGuard implements CanActivate, CanActivateChild, CanLoad { + constructor(private authService: AuthService, private router: Router) {} + + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + let url: string = state.url; + + return this.checkLogin(url); + } + + canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { + return this.canActivate(route, state); + } + +// #docregion, canLoad + canLoad(route: Route): boolean { + let url = `/${route.path}`; + + return this.checkLogin(url); + } +// #enddocregion canLoad + + checkLogin(url: string): boolean { + if (this.authService.isLoggedIn) { return true; } + + // Store the attempted URL for redirecting + this.authService.redirectUrl = url; + + // Create a dummy session id + let sessionId = 123456789; + + // Set our navigation extras object + // that contains our global query params and fragment + let navigationExtras: NavigationExtras = { + queryParams: { 'session_id': sessionId }, + fragment: 'anchor' + }; + + // Navigate to the login page with extras + this.router.navigate(['/login'], navigationExtras); + return false; + } +// #docregion admin-can-load +} diff --git a/public/docs/_examples/router/ts/src/app/auth.service.ts b/public/docs/_examples/router/ts/src/app/auth.service.ts new file mode 100644 index 0000000000..f86a80ebfe --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/auth.service.ts @@ -0,0 +1,23 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/delay'; + +@Injectable() +export class AuthService { + isLoggedIn: boolean = false; + + // store the URL so we can redirect after logging in + redirectUrl: string; + + login(): Observable { + return Observable.of(true).delay(1000).do(val => this.isLoggedIn = true); + } + + logout(): void { + this.isLoggedIn = false; + } +} diff --git a/public/docs/_examples/router/ts/src/app/can-deactivate-guard.service.1.ts b/public/docs/_examples/router/ts/src/app/can-deactivate-guard.service.1.ts new file mode 100644 index 0000000000..0b7c8247cf --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/can-deactivate-guard.service.1.ts @@ -0,0 +1,31 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { CanDeactivate, + ActivatedRouteSnapshot, + RouterStateSnapshot } from '@angular/router'; + +import { CrisisDetailComponent } from './crisis-center/crisis-detail.component'; + +@Injectable() +export class CanDeactivateGuard implements CanDeactivate { + + canDeactivate( + component: CrisisDetailComponent, + route: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Promise | boolean { + // Get the Crisis Center ID + console.log(route.params['id']); + + // Get the current URL + console.log(state.url); + + // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged + if (!component.crisis || component.crisis.name === component.editName) { + return true; + } + // Otherwise ask the user with the dialog service and return its + // promise which resolves to true or false when the user decides + return component.dialogService.confirm('Discard changes?'); + } +} diff --git a/public/docs/_examples/router/ts/src/app/can-deactivate-guard.service.ts b/public/docs/_examples/router/ts/src/app/can-deactivate-guard.service.ts new file mode 100644 index 0000000000..44da69f9c7 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/can-deactivate-guard.service.ts @@ -0,0 +1,15 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { CanDeactivate } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; + +export interface CanComponentDeactivate { + canDeactivate: () => Observable | Promise | boolean; +} + +@Injectable() +export class CanDeactivateGuard implements CanDeactivate { + canDeactivate(component: CanComponentDeactivate) { + return component.canDeactivate ? component.canDeactivate() : true; + } +} diff --git a/public/docs/_examples/router/ts/src/app/compose-message.component.html b/public/docs/_examples/router/ts/src/app/compose-message.component.html new file mode 100644 index 0000000000..f0b964e6ac --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/compose-message.component.html @@ -0,0 +1,17 @@ + +

    Contact Crisis Center

    +
    + {{ details }} +
    +
    +
    + +
    +
    + +
    +
    +

    + + +

    diff --git a/public/docs/_examples/router/ts/src/app/compose-message.component.ts b/public/docs/_examples/router/ts/src/app/compose-message.component.ts new file mode 100644 index 0000000000..17a0953378 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/compose-message.component.ts @@ -0,0 +1,43 @@ +// #docregion +import { Component, HostBinding } from '@angular/core'; +import { Router } from '@angular/router'; + +import { slideInDownAnimation } from './animations'; + +@Component({ + templateUrl: './compose-message.component.html', + styles: [ ':host { position: relative; bottom: 10%; }' ], + animations: [ slideInDownAnimation ] +}) +export class ComposeMessageComponent { + @HostBinding('@routeAnimation') routeAnimation = true; + @HostBinding('style.display') display = 'block'; + @HostBinding('style.position') position = 'absolute'; + + details: string; + sending: boolean = false; + + constructor(private router: Router) {} + + send() { + this.sending = true; + this.details = 'Sending Message...'; + + setTimeout(() => { + this.sending = false; + this.closePopup(); + }, 1000); + } + + cancel() { + this.closePopup(); + } + + // #docregion closePopup + closePopup() { + // Providing a `null` value to the named outlet + // clears the contents of the named outlet + this.router.navigate([{ outlets: { popup: null }}]); + } + // #enddocregion closePopup +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-home.component.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-home.component.ts new file mode 100644 index 0000000000..a71d485c02 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-home.component.ts @@ -0,0 +1,13 @@ +// #docregion +// #docplaster +import { Component } from '@angular/core'; + +// #docregion minus-imports +@Component({ + template: ` +

    Welcome to the Crisis Center

    + ` +}) +export class CrisisCenterHomeComponent { } +// #enddocregion minus-imports +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.1.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.1.ts new file mode 100644 index 0000000000..e646f467d1 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.1.ts @@ -0,0 +1,44 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +// #docregion routes +const crisisCenterRoutes: Routes = [ + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ + { + path: '', + component: CrisisListComponent, + children: [ + { + path: ':id', + component: CrisisDetailComponent + }, + { + path: '', + component: CrisisCenterHomeComponent + } + ] + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) + ], + exports: [ + RouterModule + ] +}) +export class CrisisCenterRoutingModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.2.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.2.ts new file mode 100644 index 0000000000..9e9b514968 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.2.ts @@ -0,0 +1,72 @@ +// #docplaster +// #docregion routes +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; +// #enddocregion routes + +// #docregion can-deactivate-guard +import { CanDeactivateGuard } from '../can-deactivate-guard.service'; +// #enddocregion can-deactivate-guard +// #docregion crisis-detail-resolver +import { CrisisDetailResolver } from './crisis-detail-resolver.service'; + +// #enddocregion crisis-detail-resolver +// #docregion routes + +const crisisCenterRoutes: Routes = [ +// #enddocregion routes + // #docregion redirect, routes + { + path: '', + redirectTo: '/crisis-center', + pathMatch: 'full' + }, + // #enddocregion redirect, routes + // #docregion routes + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ + { + path: '', + component: CrisisListComponent, + children: [ + { + path: ':id', + component: CrisisDetailComponent, + // #enddocregion routes + // #docregion can-deactivate-guard + canDeactivate: [CanDeactivateGuard], + // #enddocregion can-deactivate-guard + // #docregion crisis-detail-resolver + resolve: { + crisis: CrisisDetailResolver + } + // #enddocregion crisis-detail-resolver + // #docregion routes + }, + { + path: '', + component: CrisisCenterHomeComponent + } + ] + } + ] + } + // #enddocregion routes +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) + ], + exports: [ + RouterModule + ] +}) +export class CrisisCenterRoutingModule { } diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.3.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.3.ts new file mode 100644 index 0000000000..6d605dbe84 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.3.ts @@ -0,0 +1,52 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +// #docregion can-deactivate-guard +import { CanDeactivateGuard } from '../can-deactivate-guard.service'; + +const crisisCenterRoutes: Routes = [ + { + path: '', + redirectTo: '/crisis-center', + pathMatch: 'full' + }, + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ + { + path: '', + component: CrisisListComponent, + children: [ + { + path: ':id', + component: CrisisDetailComponent, + canDeactivate: [CanDeactivateGuard] + }, + { + path: '', + component: CrisisCenterHomeComponent + } + ] + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) + ], + exports: [ + RouterModule + ] +}) +export class CrisisCenterRoutingModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.4.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.4.ts new file mode 100644 index 0000000000..b7ac88e852 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.4.ts @@ -0,0 +1,65 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +import { CanDeactivateGuard } from '../can-deactivate-guard.service'; + +// #docregion crisis-detail-resolver +import { CrisisDetailResolver } from './crisis-detail-resolver.service'; + +// #enddocregion crisis-detail-resolver +const crisisCenterRoutes: Routes = [ + // #docregion redirect + { + path: '', + redirectTo: '/crisis-center', + pathMatch: 'full' + }, + // #enddocregion redirect + { + path: 'crisis-center', + component: CrisisCenterComponent, + children: [ + { + path: '', + component: CrisisListComponent, + children: [ + { + path: ':id', + component: CrisisDetailComponent, + canDeactivate: [CanDeactivateGuard], + resolve: { + crisis: CrisisDetailResolver + } + }, + { + path: '', + component: CrisisCenterHomeComponent + } + ] + } + ] + } +]; + +// #docregion crisis-detail-resolver +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) + ], + exports: [ + RouterModule + ], + providers: [ + CrisisDetailResolver + ] +}) +export class CrisisCenterRoutingModule { } +// #enddocregion crisis-detail-resolver +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.ts new file mode 100644 index 0000000000..c01d592455 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center-routing.module.ts @@ -0,0 +1,53 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +import { CanDeactivateGuard } from '../can-deactivate-guard.service'; +import { CrisisDetailResolver } from './crisis-detail-resolver.service'; + +const crisisCenterRoutes: Routes = [ + { + path: '', + component: CrisisCenterComponent, + children: [ + { + path: '', + component: CrisisListComponent, + children: [ + { + path: ':id', + component: CrisisDetailComponent, + canDeactivate: [CanDeactivateGuard], + resolve: { + crisis: CrisisDetailResolver + } + }, + { + path: '', + component: CrisisCenterHomeComponent + } + ] + } + ] + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(crisisCenterRoutes) + ], + exports: [ + RouterModule + ], + providers: [ + CrisisDetailResolver + ] +}) +export class CrisisCenterRoutingModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.component.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.component.ts new file mode 100644 index 0000000000..31d1790f45 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.component.ts @@ -0,0 +1,14 @@ +// #docregion +// #docplaster +import { Component } from '@angular/core'; + +// #docregion minus-imports +@Component({ + template: ` +

    CRISIS CENTER

    + + ` +}) +export class CrisisCenterComponent { } +// #enddocregion minus-imports +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.module.1.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.module.1.ts new file mode 100644 index 0000000000..5a3e45f58f --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.module.1.ts @@ -0,0 +1,36 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { CommonModule } from '@angular/common'; + +import { CrisisService } from './crisis.service'; + +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +import { CrisisCenterRoutingModule } from './crisis-center-routing.module'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + CrisisCenterRoutingModule + ], + declarations: [ + CrisisCenterComponent, + CrisisListComponent, + CrisisCenterHomeComponent, + CrisisDetailComponent + ], + + // #docregion providers + providers: [ + CrisisService + ] + // #enddocregion providers +}) +export class CrisisCenterModule {} +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.module.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.module.ts new file mode 100644 index 0000000000..4061ceac60 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-center.module.ts @@ -0,0 +1,35 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { CommonModule } from '@angular/common'; + +import { CrisisService } from './crisis.service'; + +import { CrisisCenterComponent } from './crisis-center.component'; +import { CrisisListComponent } from './crisis-list.component'; +import { CrisisCenterHomeComponent } from './crisis-center-home.component'; +import { CrisisDetailComponent } from './crisis-detail.component'; + +import { CrisisCenterRoutingModule } from './crisis-center-routing.module'; + +@NgModule({ + imports: [ + CommonModule, + FormsModule, + CrisisCenterRoutingModule + ], + declarations: [ + CrisisCenterComponent, + CrisisListComponent, + CrisisCenterHomeComponent, + CrisisDetailComponent + ], + providers: [ + CrisisService + ] +}) +// #docregion crisis-center-module-export +export class CrisisCenterModule {} +// #enddocregion crisis-center-module-export +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail-resolver.service.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail-resolver.service.ts new file mode 100644 index 0000000000..94b4cd33e7 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail-resolver.service.ts @@ -0,0 +1,24 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Router, Resolve, RouterStateSnapshot, + ActivatedRouteSnapshot } from '@angular/router'; + +import { Crisis, CrisisService } from './crisis.service'; + +@Injectable() +export class CrisisDetailResolver implements Resolve { + constructor(private cs: CrisisService, private router: Router) {} + + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + let id = route.params['id']; + + return this.cs.getCrisis(id).then(crisis => { + if (crisis) { + return crisis; + } else { // id not found + this.router.navigate(['/crisis-center']); + return null; + } + }); + } +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail.component.1.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail.component.1.ts new file mode 100644 index 0000000000..d6fa27f629 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail.component.1.ts @@ -0,0 +1,87 @@ +// #docplaster +// #docregion +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit, HostBinding } from '@angular/core'; +import { ActivatedRoute, Router, Params } from '@angular/router'; + +import { slideInDownAnimation } from '../animations'; +import { Crisis, CrisisService } from './crisis.service'; +import { DialogService } from '../dialog.service'; + +@Component({ + template: ` +
    +

    "{{ editName }}"

    +
    + {{ crisis.id }}
    +
    + + +
    +

    + + +

    +
    + `, + styles: ['input {width: 20em}'], + animations: [ slideInDownAnimation ] +}) +export class CrisisDetailComponent implements OnInit { + @HostBinding('@routeAnimation') routeAnimation = true; + @HostBinding('style.display') display = 'block'; + @HostBinding('style.position') position = 'absolute'; + + crisis: Crisis; + editName: string; + + constructor( + private service: CrisisService, + private router: Router, + private route: ActivatedRoute, + public dialogService: DialogService + ) {} + + // #docregion ngOnInit + ngOnInit() { + this.route.params + .switchMap((params: Params) => this.service.getCrisis(params['id'])) + .subscribe((crisis: Crisis) => { + if (crisis) { + this.editName = crisis.name; + this.crisis = crisis; + } else { // id not found + this.gotoCrises(); + } + }); + } + // #enddocregion ngOnInit + + cancel() { + this.gotoCrises(); + } + + save() { + this.crisis.name = this.editName; + this.gotoCrises(); + } + + canDeactivate(): Promise | boolean { + // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged + if (!this.crisis || this.crisis.name === this.editName) { + return true; + } + // Otherwise ask the user with the dialog service and return its + // promise which resolves to true or false when the user decides + return this.dialogService.confirm('Discard changes?'); + } + + gotoCrises() { + let crisisId = this.crisis ? this.crisis.id : null; + // Pass along the crisis id if available + // so that the CrisisListComponent can select that crisis. + // Add a totally useless `foo` parameter for kicks. + // Relative navigation back to the crises + this.router.navigate(['../', { id: crisisId, foo: 'foo' }], { relativeTo: this.route }); + } +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail.component.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail.component.ts new file mode 100644 index 0000000000..f0939b47a8 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-detail.component.ts @@ -0,0 +1,86 @@ +// #docplaster +// #docregion +import { Component, OnInit, HostBinding } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { slideInDownAnimation } from '../animations'; +import { Crisis } from './crisis.service'; +import { DialogService } from '../dialog.service'; + +@Component({ + template: ` +
    +

    "{{ editName }}"

    +
    + {{ crisis.id }}
    +
    + + +
    +

    + + +

    +
    + `, + styles: ['input {width: 20em}'], + animations: [ slideInDownAnimation ] +}) +export class CrisisDetailComponent implements OnInit { + @HostBinding('@routeAnimation') routeAnimation = true; + @HostBinding('style.display') display = 'block'; + @HostBinding('style.position') position = 'absolute'; + + crisis: Crisis; + editName: string; + + constructor( + private route: ActivatedRoute, + private router: Router, + public dialogService: DialogService + ) {} + +// #docregion ngOnInit + ngOnInit() { + this.route.data + .subscribe((data: { crisis: Crisis }) => { + this.editName = data.crisis.name; + this.crisis = data.crisis; + }); + } +// #enddocregion ngOnInit + + // #docregion cancel-save + cancel() { + this.gotoCrises(); + } + + save() { + this.crisis.name = this.editName; + this.gotoCrises(); + } + // #enddocregion cancel-save + + // #docregion canDeactivate + canDeactivate(): Promise | boolean { + // Allow synchronous navigation (`true`) if no crisis or the crisis is unchanged + if (!this.crisis || this.crisis.name === this.editName) { + return true; + } + // Otherwise ask the user with the dialog service and return its + // promise which resolves to true or false when the user decides + return this.dialogService.confirm('Discard changes?'); + } + // #enddocregion canDeactivate + + gotoCrises() { + let crisisId = this.crisis ? this.crisis.id : null; + // Pass along the crisis id if available + // so that the CrisisListComponent can select that crisis. + // Add a totally useless `foo` parameter for kicks. + // #docregion gotoCrises-navigate + // Relative navigation back to the crises + this.router.navigate(['../', { id: crisisId, foo: 'foo' }], { relativeTo: this.route }); + // #enddocregion gotoCrises-navigate + } +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-list.component.1.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-list.component.1.ts new file mode 100644 index 0000000000..0000dde082 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-list.component.1.ts @@ -0,0 +1,44 @@ +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router, Params } from '@angular/router'; + +import { Crisis, CrisisService } from './crisis.service'; +import { Observable } from 'rxjs/Observable'; + +@Component({ + // #docregion relative-navigation-router-link + template: ` + ` + // #enddocregion relative-navigation-router-link +}) +export class CrisisListComponent implements OnInit { + crises: Observable; + selectedId: number; + + constructor( + private service: CrisisService, + private route: ActivatedRoute, + private router: Router + ) {} + + ngOnInit() { + this.crises = this.route.params + .switchMap((params: Params) => { + this.selectedId = +params['id']; + return this.service.getCrises(); + }); + } + + isSelected(crisis: Crisis) { + return crisis.id === this.selectedId; + } +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis-list.component.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-list.component.ts new file mode 100644 index 0000000000..4498a55c0f --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis-list.component.ts @@ -0,0 +1,56 @@ +// #docregion +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router, Params } from '@angular/router'; + +import { Observable } from 'rxjs/Observable'; + +import { Crisis, CrisisService } from './crisis.service'; + +@Component({ + template: ` +
      +
    • + {{ crisis.id }} + {{ crisis.name }} +
    • +
    + + + ` +}) +export class CrisisListComponent implements OnInit { + crises: Observable; + selectedId: number; + + // #docregion ctor + constructor( + private service: CrisisService, + private route: ActivatedRoute, + private router: Router + ) {} + // #enddocregion ctor + + isSelected(crisis: Crisis) { + return crisis.id === this.selectedId; + } + + ngOnInit() { + this.crises = this.route.params + .switchMap((params: Params) => { + this.selectedId = +params['id']; + return this.service.getCrises(); + }); + } + + // #docregion onSelect + onSelect(crisis: Crisis) { + this.selectedId = crisis.id; + + // Navigate with relative link + this.router.navigate([crisis.id], { relativeTo: this.route }); + } + // #enddocregion onSelect +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-center/crisis.service.ts b/public/docs/_examples/router/ts/src/app/crisis-center/crisis.service.ts new file mode 100644 index 0000000000..e7fd34d387 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-center/crisis.service.ts @@ -0,0 +1,40 @@ +// #docplaster +// #docregion , mock-crises +export class Crisis { + constructor(public id: number, public name: string) { } +} + +const CRISES = [ + new Crisis(1, 'Dragon Burning Cities'), + new Crisis(2, 'Sky Rains Great White Sharks'), + new Crisis(3, 'Giant Asteroid Heading For Earth'), + new Crisis(4, 'Procrastinators Meeting Delayed Again'), +]; +// #enddocregion mock-crises + +let crisesPromise = Promise.resolve(CRISES); + +import { Injectable } from '@angular/core'; + +@Injectable() +export class CrisisService { + + static nextCrisisId = 100; + + getCrises() { return crisesPromise; } + + getCrisis(id: number | string) { + return crisesPromise + .then(crises => crises.find(crisis => crisis.id === +id)); + } + + // #enddocregion + addCrisis(name: string) { + name = name.trim(); + if (name) { + let crisis = new Crisis(CrisisService.nextCrisisId++, name); + crisesPromise.then(crises => crises.push(crisis)); + } + } + // #docregion +} diff --git a/public/docs/_examples/router/ts/src/app/crisis-list.component.ts b/public/docs/_examples/router/ts/src/app/crisis-list.component.ts new file mode 100644 index 0000000000..6caa3653b5 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/crisis-list.component.ts @@ -0,0 +1,10 @@ +// Initial empty version +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    CRISIS CENTER

    +

    Get your crisis here

    ` +}) +export class CrisisListComponent { } diff --git a/public/docs/_examples/router/ts/src/app/dialog.service.ts b/public/docs/_examples/router/ts/src/app/dialog.service.ts new file mode 100644 index 0000000000..0f09e4936d --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/dialog.service.ts @@ -0,0 +1,19 @@ +// #docregion +import { Injectable } from '@angular/core'; +/** + * Async modal dialog service + * DialogService makes this app easier to test by faking this service. + * TODO: better modal implementation that doesn't use window.confirm + */ +@Injectable() +export class DialogService { + /** + * Ask user to confirm an action. `message` explains the action and choices. + * Returns promise resolving to `true`=confirm or `false`=cancel + */ + confirm(message?: string) { + return new Promise(resolve => { + return resolve(window.confirm(message || 'Is it OK?')); + }); + }; +} diff --git a/public/docs/_examples/router/ts/src/app/hero-list.component.ts b/public/docs/_examples/router/ts/src/app/hero-list.component.ts new file mode 100644 index 0000000000..7a8f97ca1e --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/hero-list.component.ts @@ -0,0 +1,13 @@ +/// Initial empty version +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: ` +

    HEROES

    +

    Get your heroes here

    + + + ` +}) +export class HeroListComponent { } diff --git a/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.1.ts b/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.1.ts new file mode 100644 index 0000000000..93f0efaf0b --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.1.ts @@ -0,0 +1,55 @@ +// #docplaster +// #docregion +// #docregion rxjs-operator-import +import 'rxjs/add/operator/switchMap'; +// #enddocregion rxjs-operator-import +import { Component, OnInit } from '@angular/core'; +// #docregion imports +import { Router, ActivatedRoute, Params } from '@angular/router'; +// #enddocregion imports + +import { Hero, HeroService } from './hero.service'; + +@Component({ + template: ` +

    HEROES

    +
    +

    "{{ hero.name }}"

    +
    + {{ hero.id }}
    +
    + + +
    +

    + +

    +
    + ` +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + // #docregion ctor + constructor( + private route: ActivatedRoute, + private router: Router, + private service: HeroService + ) {} + // #enddocregion ctor + + // #docregion ngOnInit + ngOnInit() { + this.route.params + // (+) converts string 'id' to a number + .switchMap((params: Params) => this.service.getHero(+params['id'])) + .subscribe((hero: Hero) => this.hero = hero); + } + // #enddocregion ngOnInit + + // #docregion gotoHeroes + gotoHeroes() { + this.router.navigate(['/heroes']); + } + // #enddocregion gotoHeroes +} diff --git a/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.2.ts b/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.2.ts new file mode 100644 index 0000000000..c3b69be965 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.2.ts @@ -0,0 +1,47 @@ +// Snapshot version +// #docregion +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; + +import { Hero, HeroService } from './hero.service'; + +@Component({ + template: ` +

    HEROES

    +
    +

    "{{ hero.name }}"

    +
    + {{ hero.id }}
    +
    + + +
    +

    + +

    +
    + ` +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + constructor( + private route: ActivatedRoute, + private router: Router, + private service: HeroService + ) {} + + // #docregion snapshot + ngOnInit() { + // (+) converts string 'id' to a number + let id = +this.route.snapshot.params['id']; + + this.service.getHero(id) + .then((hero: Hero) => this.hero = hero); + } + // #enddocregion snapshot + + gotoHeroes() { + this.router.navigate(['/heroes']); + } +} diff --git a/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.ts b/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.ts new file mode 100644 index 0000000000..8135d37d32 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/hero-detail.component.ts @@ -0,0 +1,66 @@ +// #docplaster +// #docregion +// #docregion rxjs-operator-import +import 'rxjs/add/operator/switchMap'; +// #enddocregion rxjs-operator-import +import { Component, OnInit, HostBinding } from '@angular/core'; +import { Router, ActivatedRoute, Params } from '@angular/router'; + +import { slideInDownAnimation } from '../animations'; + +import { Hero, HeroService } from './hero.service'; + +@Component({ + template: ` +

    HEROES

    +
    +

    "{{ hero.name }}"

    +
    + {{ hero.id }}
    +
    + + +
    +

    + +

    +
    + `, + animations: [ slideInDownAnimation ] +}) +export class HeroDetailComponent implements OnInit { +// #docregion host-bindings + @HostBinding('@routeAnimation') routeAnimation = true; + @HostBinding('style.display') display = 'block'; + @HostBinding('style.position') position = 'absolute'; +// #enddocregion host-bindings + + hero: Hero; + + // #docregion ctor + constructor( + private route: ActivatedRoute, + private router: Router, + private service: HeroService + ) {} + // #enddocregion ctor + + // #docregion ngOnInit + ngOnInit() { + this.route.params + // (+) converts string 'id' to a number + .switchMap((params: Params) => this.service.getHero(+params['id'])) + .subscribe((hero: Hero) => this.hero = hero); + } + // #enddocregion ngOnInit + + // #docregion gotoHeroes + gotoHeroes() { + let heroId = this.hero ? this.hero.id : null; + // Pass along the hero id if available + // so that the HeroList component can select that hero. + // Include a junk 'foo' property for fun. + this.router.navigate(['/heroes', { id: heroId, foo: 'foo' }]); + } + // #enddocregion gotoHeroes +} diff --git a/public/docs/_examples/router/ts/src/app/heroes/hero-list.component.1.ts b/public/docs/_examples/router/ts/src/app/heroes/hero-list.component.1.ts new file mode 100644 index 0000000000..59552830a4 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/hero-list.component.1.ts @@ -0,0 +1,52 @@ +// #docplaster +// #docregion +// TODO SOMEDAY: Feature Componetized like HeroCenter +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero, HeroService } from './hero.service'; + +@Component({ + // #docregion template + template: ` +

    HEROES

    +
      +
    • + {{ hero.id }} {{ hero.name }} +
    • +
    + + + ` + // #enddocregion template +}) +export class HeroListComponent implements OnInit { + heroes: Promise; + + // #docregion ctor + constructor( + private router: Router, + private service: HeroService + ) {} + // #enddocregion ctor + + ngOnInit() { + this.heroes = this.service.getHeroes(); + } + + // #docregion select + onSelect(hero: Hero) { + // #docregion nav-to-detail + this.router.navigate(['/hero', hero.id]); + // #enddocregion nav-to-detail + } + // #enddocregion select +} +// #enddocregion + +/* A link parameters array +// #docregion link-parameters-array +['/hero', hero.id] // { 15 } +// #enddocregion link-parameters-array +*/ diff --git a/public/docs/_examples/router/ts/src/app/heroes/hero-list.component.ts b/public/docs/_examples/router/ts/src/app/heroes/hero-list.component.ts new file mode 100644 index 0000000000..c7dcc3877e --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/hero-list.component.ts @@ -0,0 +1,63 @@ +// #docplaster +// #docregion +// TODO SOMEDAY: Feature Componetized like CrisisCenter +// #docregion rxjs-imports +import 'rxjs/add/operator/switchMap'; +import { Observable } from 'rxjs/Observable'; +// #enddocregion rxjs-imports +import { Component, OnInit } from '@angular/core'; +// #docregion import-router +import { Router, ActivatedRoute, Params } from '@angular/router'; +// #enddocregion import-router + +import { Hero, HeroService } from './hero.service'; + +@Component({ + // #docregion template + template: ` +

    HEROES

    +
      +
    • + {{ hero.id }} {{ hero.name }} +
    • +
    + + + ` + // #enddocregion template +}) +// #docregion ctor +export class HeroListComponent implements OnInit { + heroes: Observable; + + private selectedId: number; + + constructor( + private service: HeroService, + private route: ActivatedRoute, + private router: Router + ) {} + + ngOnInit() { + this.heroes = this.route.params + .switchMap((params: Params) => { + this.selectedId = +params['id']; + return this.service.getHeroes(); + }); + } + // #enddocregion ctor + + // #docregion isSelected + isSelected(hero: Hero) { return hero.id === this.selectedId; } + // #enddocregion isSelected + + // #docregion select + onSelect(hero: Hero) { + this.router.navigate(['/hero', hero.id]); + } + // #enddocregion select +// #docregion ctor +} +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/heroes/hero.service.ts b/public/docs/_examples/router/ts/src/app/heroes/hero.service.ts new file mode 100644 index 0000000000..6e4e7bee60 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/hero.service.ts @@ -0,0 +1,27 @@ +// #docregion +import { Injectable } from '@angular/core'; + +export class Hero { + constructor(public id: number, public name: string) { } +} + +let HEROES = [ + new Hero(11, 'Mr. Nice'), + new Hero(12, 'Narco'), + new Hero(13, 'Bombasto'), + new Hero(14, 'Celeritas'), + new Hero(15, 'Magneta'), + new Hero(16, 'RubberMan') +]; + +let heroesPromise = Promise.resolve(HEROES); + +@Injectable() +export class HeroService { + getHeroes() { return heroesPromise; } + + getHero(id: number | string) { + return heroesPromise + .then(heroes => heroes.find(hero => hero.id === +id)); + } +} diff --git a/public/docs/_examples/router/ts/src/app/heroes/heroes-routing.module.ts b/public/docs/_examples/router/ts/src/app/heroes/heroes-routing.module.ts new file mode 100644 index 0000000000..dbee521793 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/heroes-routing.module.ts @@ -0,0 +1,24 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { HeroListComponent } from './hero-list.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const heroesRoutes: Routes = [ + { path: 'heroes', component: HeroListComponent }, +// #docregion hero-detail-route + { path: 'hero/:id', component: HeroDetailComponent } +// #enddocregion hero-detail-route +]; + +@NgModule({ + imports: [ + RouterModule.forChild(heroesRoutes) + ], + exports: [ + RouterModule + ] +}) +export class HeroRoutingModule { } +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/heroes/heroes.module.ts b/public/docs/_examples/router/ts/src/app/heroes/heroes.module.ts new file mode 100644 index 0000000000..95ee64a182 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/heroes/heroes.module.ts @@ -0,0 +1,33 @@ +// #docplaster +// #docregion +// #docregion v1 +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { HeroListComponent } from './hero-list.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +import { HeroService } from './hero.service'; + +// #enddocregion v1 +import { HeroRoutingModule } from './heroes-routing.module'; + +// #docregion v1 +@NgModule({ + imports: [ + CommonModule, + FormsModule, +// #enddocregion v1 + HeroRoutingModule +// #docregion v1 + ], + declarations: [ + HeroListComponent, + HeroDetailComponent + ], + providers: [ HeroService ] +}) +export class HeroesModule {} +// #enddocregion v1 +// #enddocregion diff --git a/public/docs/_examples/router/ts/src/app/login-routing.module.ts b/public/docs/_examples/router/ts/src/app/login-routing.module.ts new file mode 100644 index 0000000000..96d05e7972 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/login-routing.module.ts @@ -0,0 +1,24 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthGuard } from './auth-guard.service'; +import { AuthService } from './auth.service'; +import { LoginComponent } from './login.component'; + +const loginRoutes: Routes = [ + { path: 'login', component: LoginComponent } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(loginRoutes) + ], + exports: [ + RouterModule + ], + providers: [ + AuthGuard, + AuthService + ] +}) +export class LoginRoutingModule {} diff --git a/public/docs/_examples/router/ts/src/app/login.component.1.ts b/public/docs/_examples/router/ts/src/app/login.component.1.ts new file mode 100644 index 0000000000..ddee339011 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/login.component.1.ts @@ -0,0 +1,46 @@ +// #docregion +import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { AuthService } from './auth.service'; + +@Component({ + template: ` +

    LOGIN

    +

    {{message}}

    +

    + + +

    ` +}) +export class LoginComponent { + message: string; + + constructor(public authService: AuthService, public router: Router) { + this.setMessage(); + } + + setMessage() { + this.message = 'Logged ' + (this.authService.isLoggedIn ? 'in' : 'out'); + } + + login() { + this.message = 'Trying to log in ...'; + + this.authService.login().subscribe(() => { + this.setMessage(); + if (this.authService.isLoggedIn) { + // Get the redirect URL from our auth service + // If no redirect has been set, use the default + let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/crisis-center/admin'; + + // Redirect the user + this.router.navigate([redirect]); + } + }); + } + + logout() { + this.authService.logout(); + this.setMessage(); + } +} diff --git a/public/docs/_examples/router/ts/src/app/login.component.ts b/public/docs/_examples/router/ts/src/app/login.component.ts new file mode 100644 index 0000000000..41c88f4068 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/login.component.ts @@ -0,0 +1,56 @@ +// #docregion +import { Component } from '@angular/core'; +import { Router, + NavigationExtras } from '@angular/router'; +import { AuthService } from './auth.service'; + +@Component({ + template: ` +

    LOGIN

    +

    {{message}}

    +

    + + +

    ` +}) +export class LoginComponent { + message: string; + + constructor(public authService: AuthService, public router: Router) { + this.setMessage(); + } + + setMessage() { + this.message = 'Logged ' + (this.authService.isLoggedIn ? 'in' : 'out'); + } + + login() { + this.message = 'Trying to log in ...'; + + this.authService.login().subscribe(() => { + this.setMessage(); + if (this.authService.isLoggedIn) { + // Get the redirect URL from our auth service + // If no redirect has been set, use the default + let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/admin'; + + // #docregion preserve + // Set our navigation extras object + // that passes on our global query params and fragment + let navigationExtras: NavigationExtras = { + preserveQueryParams: true, + preserveFragment: true + }; + + // Redirect the user + this.router.navigate([redirect], navigationExtras); + // #enddocregion preserve + } + }); + } + + logout() { + this.authService.logout(); + this.setMessage(); + } +} diff --git a/public/docs/_examples/router/ts/src/app/not-found.component.ts b/public/docs/_examples/router/ts/src/app/not-found.component.ts new file mode 100644 index 0000000000..2e74544e17 --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/not-found.component.ts @@ -0,0 +1,7 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + template: '

    Page not found

    ' +}) +export class PageNotFoundComponent {} diff --git a/public/docs/_examples/router/ts/src/app/selective-preloading-strategy.ts b/public/docs/_examples/router/ts/src/app/selective-preloading-strategy.ts new file mode 100644 index 0000000000..395f1056ef --- /dev/null +++ b/public/docs/_examples/router/ts/src/app/selective-preloading-strategy.ts @@ -0,0 +1,24 @@ +// #docregion +import 'rxjs/add/observable/of'; +import { Injectable } from '@angular/core'; +import { PreloadingStrategy, Route } from '@angular/router'; +import { Observable } from 'rxjs/Observable'; + +@Injectable() +export class SelectivePreloadingStrategy implements PreloadingStrategy { + preloadedModules: string[] = []; + + preload(route: Route, load: () => Observable): Observable { + if (route.data && route.data['preload']) { + // add the route path to the preloaded module array + this.preloadedModules.push(route.path); + + // log the route path to the console + console.log('Preloaded: ' + route.path); + + return load(); + } else { + return Observable.of(null); + } + } +} diff --git a/public/docs/_examples/router/ts/src/index.html b/public/docs/_examples/router/ts/src/index.html new file mode 100644 index 0000000000..0fa6453c36 --- /dev/null +++ b/public/docs/_examples/router/ts/src/index.html @@ -0,0 +1,32 @@ + + + + + + + + + Angular Router + + + + + + + + + + + + + + + + loading... + + + + diff --git a/public/docs/_examples/router/ts/src/main.ts b/public/docs/_examples/router/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/router/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/security/e2e-spec.ts b/public/docs/_examples/security/e2e-spec.ts new file mode 100644 index 0000000000..23d11cd12b --- /dev/null +++ b/public/docs/_examples/security/e2e-spec.ts @@ -0,0 +1,37 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, By } from 'protractor'; + +describe('Security E2E Tests', () => { + beforeAll(() => browser.get('')); + + it('sanitizes innerHTML', () => { + let interpolated = element(By.className('e2e-inner-html-interpolated')); + expect(interpolated.getText()) + .toContain('Template Syntax'); + let bound = element(By.className('e2e-inner-html-bound')); + expect(bound.getText()).toContain('Template alert("0wned") Syntax'); + let bold = element(By.css('.e2e-inner-html-bound b')); + expect(bold.getText()).toContain('Syntax'); + }); + + it('escapes untrusted URLs', () => { + let untrustedUrl = element(By.className('e2e-dangerous-url')); + expect(untrustedUrl.getAttribute('href')).toMatch(/^unsafe:javascript/); + }); + + it('binds trusted URLs', () => { + let trustedUrl = element(By.className('e2e-trusted-url')); + expect(trustedUrl.getAttribute('href')).toMatch(/^javascript:alert/); + }); + + it('escapes untrusted resource URLs', () => { + let iframe = element(By.className('e2e-iframe-untrusted-src')); + expect(iframe.getAttribute('src')).toBe(''); + }); + + it('binds trusted resource URLs', () => { + let iframe = element(By.className('e2e-iframe-trusted-src')); + expect(iframe.getAttribute('src')).toMatch(/^https:\/\/fanyv88.com:443\/https\/www.youtube.com\//); + }); +}); diff --git a/public/docs/_examples/security/ts/example-config.json b/public/docs/_examples/security/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/security/ts/plnkr.json b/public/docs/_examples/security/ts/plnkr.json new file mode 100644 index 0000000000..4c9e85ce1e --- /dev/null +++ b/public/docs/_examples/security/ts/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "Content Security", + "basePath": "src/", + "files": [ + "!**/*.d.ts", + "!**/*.js" + ], + "tags": ["security"] +} diff --git a/public/docs/_examples/security/ts/src/app/app.component.ts b/public/docs/_examples/security/ts/src/app/app.component.ts new file mode 100644 index 0000000000..c30235e8e7 --- /dev/null +++ b/public/docs/_examples/security/ts/src/app/app.component.ts @@ -0,0 +1,13 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    Security

    + + + ` +}) +export class AppComponent { +} diff --git a/public/docs/_examples/security/ts/src/app/app.module.ts b/public/docs/_examples/security/ts/src/app/app.module.ts new file mode 100644 index 0000000000..21d880be3b --- /dev/null +++ b/public/docs/_examples/security/ts/src/app/app.module.ts @@ -0,0 +1,18 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { BypassSecurityComponent } from './bypass-security.component'; +import { InnerHtmlBindingComponent } from './inner-html-binding.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ + AppComponent, + BypassSecurityComponent, + InnerHtmlBindingComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/security/ts/src/app/bypass-security.component.html b/public/docs/_examples/security/ts/src/app/bypass-security.component.html new file mode 100644 index 0000000000..96adf058e2 --- /dev/null +++ b/public/docs/_examples/security/ts/src/app/bypass-security.component.html @@ -0,0 +1,17 @@ + +

    Bypass Security Component

    + + +

    An untrusted URL:

    +

    Click me

    +

    A trusted URL:

    +

    Click me

    + + + +

    Resource URL:

    +

    Showing: {{dangerousVideoUrl}}

    +

    Trusted:

    + +

    Untrusted:

    + diff --git a/public/docs/_examples/security/ts/src/app/bypass-security.component.ts b/public/docs/_examples/security/ts/src/app/bypass-security.component.ts new file mode 100644 index 0000000000..ff41e287ba --- /dev/null +++ b/public/docs/_examples/security/ts/src/app/bypass-security.component.ts @@ -0,0 +1,38 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; +import { DomSanitizer, SafeResourceUrl, SafeUrl } from '@angular/platform-browser'; + +@Component({ + selector: 'bypass-security', + templateUrl: './bypass-security.component.html', +}) +export class BypassSecurityComponent { + dangerousUrl: string; + trustedUrl: SafeUrl; + dangerousVideoUrl: string; + videoUrl: SafeResourceUrl; + + // #docregion trust-url + constructor(private sanitizer: DomSanitizer) { + // javascript: URLs are dangerous if attacker controlled. + // Angular sanitizes them in data binding, but you can + // explicitly tell Angular to trust this value: + this.dangerousUrl = 'javascript:alert("Hi there")'; + this.trustedUrl = sanitizer.bypassSecurityTrustUrl(this.dangerousUrl); + // #enddocregion trust-url + this.updateVideoUrl('PUBnlbjZFAI'); + } + + // #docregion trust-video-url + updateVideoUrl(id: string) { + // Appending an ID to a YouTube URL is safe. + // Always make sure to construct SafeValue objects as + // close as possible to the input data so + // that it's easier to check if the value is safe. + this.dangerousVideoUrl = 'https://www.youtube.com/embed/' + id; + this.videoUrl = + this.sanitizer.bypassSecurityTrustResourceUrl(this.dangerousVideoUrl); + } + // #enddocregion trust-video-url +} diff --git a/public/docs/_examples/security/ts/src/app/inner-html-binding.component.html b/public/docs/_examples/security/ts/src/app/inner-html-binding.component.html new file mode 100644 index 0000000000..fe540d25fe --- /dev/null +++ b/public/docs/_examples/security/ts/src/app/inner-html-binding.component.html @@ -0,0 +1,6 @@ + +

    Binding innerHTML

    +

    Bound value:

    +

    {{htmlSnippet}}

    +

    Result of binding to innerHTML:

    +

    diff --git a/public/docs/_examples/security/ts/src/app/inner-html-binding.component.ts b/public/docs/_examples/security/ts/src/app/inner-html-binding.component.ts new file mode 100644 index 0000000000..8319503686 --- /dev/null +++ b/public/docs/_examples/security/ts/src/app/inner-html-binding.component.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'inner-html-binding', + templateUrl: './inner-html-binding.component.html', +}) +// #docregion class +export class InnerHtmlBindingComponent { + // For example, a user/attacker-controlled value from a URL. + htmlSnippet = 'Template Syntax'; +} diff --git a/public/docs/_examples/security/ts/src/index.html b/public/docs/_examples/security/ts/src/index.html new file mode 100644 index 0000000000..d5dd11c038 --- /dev/null +++ b/public/docs/_examples/security/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + Angular Content Security + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/security/ts/src/main.ts b/public/docs/_examples/security/ts/src/main.ts new file mode 100644 index 0000000000..105b06712d --- /dev/null +++ b/public/docs/_examples/security/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); + diff --git a/public/docs/_examples/server-communication/dart/lib/hero_data.dart b/public/docs/_examples/server-communication/dart/lib/hero_data.dart deleted file mode 100644 index 4220e6cd9d..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/hero_data.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:http_in_memory_web_api/http_in_memory_web_api.dart'; - -CreateDb heroData = () => { - 'heroes': [ - {"id": "1", "name": "Windstorm"}, - {"id": "2", "name": "Bombasto"}, - {"id": "3", "name": "Magneta"}, - {"id": "4", "name": "Tornado"} - ] - }; diff --git a/public/docs/_examples/server-communication/dart/lib/toh/hero.dart b/public/docs/_examples/server-communication/dart/lib/toh/hero.dart deleted file mode 100644 index b7dd9f00ae..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/toh/hero.dart +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -class Hero { - final int id; - final String name; - - Hero(this.id, this.name); - - factory Hero.fromJson(Map hero) { - final _id = hero['id']; - final id = _id is int ? _id : int.parse(_id); - return new Hero(id,hero['name']); - } - - Map toJson() => {'id': id, 'name': name}; -} diff --git a/public/docs/_examples/server-communication/dart/lib/toh/hero_list_component.dart b/public/docs/_examples/server-communication/dart/lib/toh/hero_list_component.dart deleted file mode 100644 index f51a98d35b..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/toh/hero_list_component.dart +++ /dev/null @@ -1,58 +0,0 @@ -// #docregion -import 'dart:async'; -import 'package:angular2/angular2.dart'; -import 'hero.dart'; -import 'hero_service.dart'; - -@Component( - selector: 'hero-list', -// #docregion template - template: ''' -

    Heroes:

    -
      -
    • - {{hero.name}} -
    • -
    - New Hero: - - -
    {{errorMessage}}
    - ''', -// #enddocregion template - styles: const ['.error {color:red;}']) -// #docregion component -class HeroListComponent implements OnInit { - final HeroService _heroService; - String errorMessage; - List heroes = []; - - HeroListComponent(this._heroService); - - bool get hasErrorMessage => errorMessage != null; - - Future ngOnInit() => getHeroes(); - - // #docregion methods - Future getHeroes() async { - try { - heroes = await _heroService.getHeroes(); - } catch (e) { - errorMessage = e.toString(); - } - } - - Future addHero(String name) async { - name = name.trim(); - if (name.isEmpty) return; - try { - heroes.add(await _heroService.addHero(name)); - } catch (e) { - errorMessage = e.toString(); - } - } - // #enddocregion methods -} -// #enddocregion component diff --git a/public/docs/_examples/server-communication/dart/lib/toh/hero_service.dart b/public/docs/_examples/server-communication/dart/lib/toh/hero_service.dart deleted file mode 100644 index f81d45be38..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/toh/hero_service.dart +++ /dev/null @@ -1,41 +0,0 @@ -// #docplaster - -// #docregion -import 'dart:async'; -import 'dart:convert'; - -import 'package:angular2/angular2.dart'; -// #enddocregion v1 -// #docregion import-request-options -import 'package:http/browser_client.dart'; -// #enddocregion import-request-options -// #docregion v1 -import 'hero.dart'; - -@Injectable() -class HeroService { - final String _heroesUrl = 'app/heroes'; - BrowserClient _http; - - HeroService(this._http); - -// #docregion methods - Future> getHeroes() async { - final response = await _http.get(_heroesUrl); - final heroes = JSON - .decode(response.body)['data'] - .map((value) => new Hero.fromJson(value)) - .toList(); - print(JSON.encode(heroes)); // eyeball results in the console - return heroes; - } - - Future addHero(String name) async { - final headers = {'content-type': 'application/json'}; - final body = JSON.encode({'name': name}); - final response = await _http.post(_heroesUrl, headers: headers, body: body); - return new Hero.fromJson(JSON.decode(response.body)); - } -// #enddocregion methods -} -// #enddocregion diff --git a/public/docs/_examples/server-communication/dart/lib/toh/toh_component.dart b/public/docs/_examples/server-communication/dart/lib/toh/toh_component.dart deleted file mode 100644 index 3b2a6b27b4..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/toh/toh_component.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:angular2/angular2.dart'; -import 'package:http_in_memory_web_api/http_in_memory_web_api.dart'; -import 'package:http/browser_client.dart'; -import 'package:server_communication/hero_data.dart'; - -import 'hero_list_component.dart'; -import 'hero_service.dart'; - -@Injectable() -HttpClientInMemoryBackendService HttpClientInMemoryBackendServiceFactory() => - new HttpClientInMemoryBackendService(heroData); // in-mem server - -@Component( - selector: 'my-toh', -// #docregion template - template: ''' -

    Tour of Heroes

    - - ''', -// #enddocregion template - providers: const [ - HeroService, -//#enddocregion -//#docregion in-mem-web-api-providers -// in-memory web api providers - const Provider(BrowserClient, - useFactory: HttpClientInMemoryBackendServiceFactory) -//#enddocregion in-mem-web-api-providers -//#docregion - ], - directives: const [ - HeroListComponent - ]) -class TohComponent {} -// #enddocregion diff --git a/public/docs/_examples/server-communication/dart/lib/wiki/wiki_component.dart b/public/docs/_examples/server-communication/dart/lib/wiki/wiki_component.dart deleted file mode 100644 index 78d44f93bc..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/wiki/wiki_component.dart +++ /dev/null @@ -1,26 +0,0 @@ -// #docregion -import 'dart:async'; -import 'package:angular2/angular2.dart'; -import 'wikipedia_service.dart'; - -@Component( - selector: 'my-wiki', - template: ''' -

    Wikipedia Demo

    -

    Fetches after each keystroke

    - -
      -
    • {{item}}
    • -
    - ''', - providers: const [WikipediaService]) -class WikiComponent { - final WikipediaService _wikipediaService; - List items = []; - - WikiComponent(this._wikipediaService); - - Future search(String term) async { - items = await this._wikipediaService.search(term); - } -} diff --git a/public/docs/_examples/server-communication/dart/lib/wiki/wiki_smart_component.dart b/public/docs/_examples/server-communication/dart/lib/wiki/wiki_smart_component.dart deleted file mode 100644 index 3be519471b..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/wiki/wiki_smart_component.dart +++ /dev/null @@ -1,37 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; -import 'package:stream_transformers/stream_transformers.dart'; - -import 'wikipedia_service.dart'; - -@Component( - selector: 'my-wiki-smart', - template: ''' -

    Smarter Wikipedia Demo

    -

    Fetches when typing stops

    - - -
      -
    • {{item}}
    • -
    - ''', - providers: const [WikipediaService]) -class WikiSmartComponent { - final WikipediaService _wikipediaService; - List items = []; - - WikiSmartComponent(this._wikipediaService) { - _searchTermStream - .transform(new Debounce(new Duration(milliseconds: 300))) - .distinct() - .transform(new FlatMapLatest( - (term) => _wikipediaService.search(term).asStream())) - .forEach((data) { - items = data; - }); - } - - final EventEmitter _searchTermStream = new EventEmitter(); - - void search(String term) => _searchTermStream.add(term); -} diff --git a/public/docs/_examples/server-communication/dart/lib/wiki/wikipedia_service.dart b/public/docs/_examples/server-communication/dart/lib/wiki/wikipedia_service.dart deleted file mode 100644 index d4314c3f08..0000000000 --- a/public/docs/_examples/server-communication/dart/lib/wiki/wikipedia_service.dart +++ /dev/null @@ -1,24 +0,0 @@ -// #docregion -import 'dart:async'; -import 'package:angular2/angular2.dart'; -import 'package:jsonpadding/jsonpadding.dart'; - -@Injectable() -class WikipediaService { - Future> search(String term) async { - // #docregion call-jsonp - Uri uri = new Uri( - scheme: 'http', - host: 'en.wikipedia.org', - path: 'w/api.php', - queryParameters: { - 'search': term, - 'action': 'opensearch', - 'format': 'json' - }); - // TODO: Error handling - List result = await jsonp(uri); - return result[1]; - // #enddocregion call-jsonp - } -} diff --git a/public/docs/_examples/server-communication/dart/pubspec.yaml b/public/docs/_examples/server-communication/dart/pubspec.yaml deleted file mode 100644 index 85706833e3..0000000000 --- a/public/docs/_examples/server-communication/dart/pubspec.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# #docregion -name: server_communication -description: Server Communication -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 - http: ^0.11.3+3 - jsonpadding: ^0.1.0 - stream_transformers: ^0.3.0+3 - http_in_memory_web_api: ^0.0.1 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES' - platform_pipes: 'package:angular2/common.dart#COMMON_PIPES' - entry_points: 'web/main.dart' -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/server-communication/dart/web/heroes.json b/public/docs/_examples/server-communication/dart/web/heroes.json deleted file mode 100644 index c6b5cc91df..0000000000 --- a/public/docs/_examples/server-communication/dart/web/heroes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "data": [ - { "id": "1", "name": "Windstorm" }, - { "id": "2", "name": "Bombasto" }, - { "id": "3", "name": "Magneta" }, - { "id": "4", "name": "Tornado" } - ] -} diff --git a/public/docs/_examples/server-communication/dart/web/index.html b/public/docs/_examples/server-communication/dart/web/index.html deleted file mode 100644 index b6b40d9193..0000000000 --- a/public/docs/_examples/server-communication/dart/web/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - Angular 2 Http Demo - - - - - - - ToH Loading... - Wiki Loading... - WikiSmart loading... - - - diff --git a/public/docs/_examples/server-communication/dart/web/main.dart b/public/docs/_examples/server-communication/dart/web/main.dart deleted file mode 100644 index d0892cf49b..0000000000 --- a/public/docs/_examples/server-communication/dart/web/main.dart +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:server_communication/toh/toh_component.dart'; -import 'package:server_communication/wiki/wiki_component.dart'; -import 'package:server_communication/wiki/wiki_smart_component.dart'; - -main() { - bootstrap(TohComponent); - bootstrap(WikiComponent); - bootstrap(WikiSmartComponent); -} diff --git a/public/docs/_examples/server-communication/e2e-spec.js b/public/docs/_examples/server-communication/e2e-spec.js deleted file mode 100644 index 4525c9514f..0000000000 --- a/public/docs/_examples/server-communication/e2e-spec.js +++ /dev/null @@ -1,141 +0,0 @@ -describe('Server Communication', function () { - - beforeAll(function () { - browser.get(''); - }); - - describe('Tour of Heroes e2e tests', function () { - - var _initialHeroCount = 4; - var _newHeroName = 'Mr. IQ'; - var _heroCountAfterAdd = 5; - - it('should display ' + _initialHeroCount + ' heroes after init', function () { - var myTohComp = element(by.tagName('my-toh')); - expect(myTohComp).toBeDefined(' must exist'); - var heroListComp = myTohComp.element(by.tagName('hero-list')); - expect(heroListComp).toBeDefined(' must exist'); - var heroTags = heroListComp.all(by.tagName('li')); - expect(heroTags.count()).toBe(_initialHeroCount); - }); - - it('should not add hero with empty name', function () { - var myTohComp = element(by.tagName('my-toh')); - expect(myTohComp).toBeDefined(' must exist'); - var addButton = myTohComp.element(by.tagName('button')); - expect(addButton).toBeDefined('"Add Hero" button must be defined'); - addButton.click().then(function() { - var heroListComp = myTohComp.element(by.tagName('hero-list')); - var heroTags = heroListComp.all(by.tagName('li')); - expect(heroTags.count()).toBe(_initialHeroCount, 'No new hero should be added'); - }); - }) - - it('should add a new hero to the list', function () { - var myTohComp = element(by.tagName('my-toh')); - expect(myTohComp).toBeDefined(' must exist'); - var heroNameInput = myTohComp.element(by.tagName('input')); - expect(heroNameInput).toBeDefined(' for hero name must exist'); - var addButton = myTohComp.element(by.tagName('button')); - expect(addButton).toBeDefined('"Add Hero" button must be defined'); - sendKeys(heroNameInput, _newHeroName); - addButton.click().then(function() { - var heroListComp = myTohComp.element(by.tagName('hero-list')); - var heroTags = heroListComp.all(by.tagName('li')); - expect(heroTags.count()).toBe(_heroCountAfterAdd, 'A new hero should be added'); - var newHeroInList = heroTags.get(_heroCountAfterAdd - 1).getText(); - expect(newHeroInList).toBe(_newHeroName, 'The hero should be added to the end of the list'); - }); - }) - }); - - describe('Wikipedia Demo e2e tests', function () { - - it('should initialize the demo with empty result list', function () { - var myWikiComp = element(by.tagName('my-wiki')); - expect(myWikiComp).toBeDefined(' must exist'); - var resultList = myWikiComp.all(by.tagName('li')); - expect(resultList.count()).toBe(0, 'result list must be empty'); - }); - - describe('Fetches after each keystroke', function () { - it('should fetch results after "B"', function(done) { - testForRefreshedResult('B', done); - }); - - it('should fetch results after "Ba"', function(done) { - testForRefreshedResult('a', done); - }); - - it('should fetch results after "Bas"', function(done) { - testForRefreshedResult('s', done); - }); - - it('should fetch results after "Basic"', function(done) { - testForRefreshedResult('ic', done); - }); - }); - - function testForRefreshedResult(keyPressed, done) { - testForResult('my-wiki', keyPressed, false, done) - } - }); - - describe('Smarter Wikipedia Demo e2e tests', function () { - - it('should initialize the demo with empty result list', function () { - var myWikiSmartComp = element(by.tagName('my-wiki-smart')); - expect(myWikiSmartComp).toBeDefined(' must exist'); - var resultList = myWikiSmartComp.all(by.tagName('li')); - expect(resultList.count()).toBe(0, 'result list must be empty'); - }); - - it('should fetch results after "Java"', function(done) { - testForNewResult('Java', done); - }); - - it('should fetch results after "JavaS"', function(done) { - testForStaleResult('S', done); - }); - - it('should fetch results after "JavaSc"', function(done) { - testForStaleResult('c', done); - }); - - it('should fetch results after "JavaScript"', function(done) { - testForStaleResult('ript', done); - }); - - - function testForNewResult(keyPressed, done) { - testForResult('my-wiki-smart', keyPressed, false, done) - } - - function testForStaleResult(keyPressed, done) { - testForResult('my-wiki-smart', keyPressed, true, done) - } - - }); - - function testForResult(componentTagName, keyPressed, hasListBeforeSearch, done) { - var searchWait = 1000; // Wait for wikipedia but not so long that tests timeout - var wikiComponent = element(by.tagName(componentTagName)); - expect(wikiComponent).toBeDefined('<' + componentTagName + '> must exist'); - var searchBox = wikiComponent.element(by.tagName('input')); - expect(searchBox).toBeDefined(' for search must exist'); - - searchBox.sendKeys(keyPressed).then(function () { - var resultList = wikiComponent.all(by.tagName('li')); - - if (hasListBeforeSearch) { - expect(resultList.count()).toBeGreaterThan(0, 'result list should not be empty before search'); - } - - setTimeout(function() { - expect(resultList.count()).toBeGreaterThan(0, 'result list should not be empty after search'); - done(); - }, searchWait); - }); - } - -}); diff --git a/public/docs/_examples/server-communication/e2e-spec.ts b/public/docs/_examples/server-communication/e2e-spec.ts new file mode 100644 index 0000000000..a85c7489f8 --- /dev/null +++ b/public/docs/_examples/server-communication/e2e-spec.ts @@ -0,0 +1,138 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Server Communication', function () { + + beforeAll(function () { + browser.get(''); + }); + + describe('Tour of Heroes (Observable)', function () { + + let initialHeroCount = 4; + let newHeroName = 'Mr. IQ'; + let heroCountAfterAdd = 5; + + let heroListComp = element(by.tagName('hero-list')); + let addButton = heroListComp.element(by.tagName('button')); + let heroTags = heroListComp.all(by.tagName('li')); + let heroNameInput = heroListComp.element(by.tagName('input')); + + it('should exist', function() { + expect(heroListComp).toBeDefined(' must exist'); + }); + + it('should display ' + initialHeroCount + ' heroes after init', function () { + expect(heroTags.count()).toBe(initialHeroCount); + }); + + it('should not add hero with empty name', function () { + expect(addButton).toBeDefined('"Add Hero" button must be defined'); + addButton.click().then(function() { + expect(heroTags.count()).toBe(initialHeroCount, 'No new hero should be added'); + }); + }); + + it('should add a new hero to the list', function () { + expect(heroNameInput).toBeDefined(' for hero name must exist'); + expect(addButton).toBeDefined('"Add Hero" button must be defined'); + heroNameInput.sendKeys(newHeroName); + addButton.click().then(function() { + expect(heroTags.count()).toBe(heroCountAfterAdd, 'A new hero should be added'); + let newHeroInList = heroTags.get(heroCountAfterAdd - 1).getText(); + expect(newHeroInList).toBe(newHeroName, 'The hero should be added to the end of the list'); + }); + }); + }); + + describe('Wikipedia Demo', function () { + + it('should initialize the demo with empty result list', function () { + let myWikiComp = element(by.tagName('my-wiki')); + expect(myWikiComp).toBeDefined(' must exist'); + let resultList = myWikiComp.all(by.tagName('li')); + expect(resultList.count()).toBe(0, 'result list must be empty'); + }); + + describe('Fetches after each keystroke', function () { + it('should fetch results after "B"', function(done: any) { + testForRefreshedResult('B', done); + }); + + it('should fetch results after "Ba"', function(done: any) { + testForRefreshedResult('a', done); + }); + + it('should fetch results after "Bas"', function(done: any) { + testForRefreshedResult('s', done); + }); + + it('should fetch results after "Basic"', function(done: any) { + testForRefreshedResult('ic', done); + }); + }); + + function testForRefreshedResult(keyPressed: string, done: () => void) { + testForResult('my-wiki', keyPressed, false, done); + } + }); + + describe('Smarter Wikipedia Demo', function () { + + it('should initialize the demo with empty result list', function () { + let myWikiSmartComp = element(by.tagName('my-wiki-smart')); + expect(myWikiSmartComp).toBeDefined(' must exist'); + let resultList = myWikiSmartComp.all(by.tagName('li')); + expect(resultList.count()).toBe(0, 'result list must be empty'); + }); + + it('should fetch results after "Java"', function(done: any) { + testForNewResult('Java', done); + }); + + it('should fetch results after "JavaS"', function(done: any) { + testForStaleResult('S', done); + }); + + it('should fetch results after "JavaSc"', function(done: any) { + testForStaleResult('c', done); + }); + + it('should fetch results after "JavaScript"', function(done: any) { + testForStaleResult('ript', done); + }); + + + function testForNewResult(keyPressed: string, done: () => void) { + testForResult('my-wiki-smart', keyPressed, false, done); + } + + function testForStaleResult(keyPressed: string, done: () => void) { + testForResult('my-wiki-smart', keyPressed, true, done); + } + + }); + + function testForResult(componentTagName: string, keyPressed: string, hasListBeforeSearch: boolean, done: () => void) { + let searchWait = 1000; // Wait for wikipedia but not so long that tests timeout + let wikiComponent = element(by.tagName(componentTagName)); + expect(wikiComponent).toBeDefined('<' + componentTagName + '> must exist'); + let searchBox = wikiComponent.element(by.tagName('input')); + expect(searchBox).toBeDefined(' for search must exist'); + + searchBox.sendKeys(keyPressed).then(function () { + let resultList = wikiComponent.all(by.tagName('li')); + + if (hasListBeforeSearch) { + expect(resultList.count()).toBeGreaterThan(0, 'result list should not be empty before search'); + } + + setTimeout(function() { + expect(resultList.count()).toBeGreaterThan(0, 'result list should not be empty after search'); + done(); + }, searchWait); + }); + } + +}); diff --git a/public/docs/_examples/server-communication/ts/.gitignore b/public/docs/_examples/server-communication/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/server-communication/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/server-communication/ts/app/hero-data.ts b/public/docs/_examples/server-communication/ts/app/hero-data.ts deleted file mode 100644 index 29f58fe663..0000000000 --- a/public/docs/_examples/server-communication/ts/app/hero-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -export class HeroData { - createDb() { - let heroes = [ - { "id": "1", "name": "Windstorm" }, - { "id": "2", "name": "Bombasto" }, - { "id": "3", "name": "Magneta" }, - { "id": "4", "name": "Tornado" } - ]; - return {heroes}; - } -} diff --git a/public/docs/_examples/server-communication/ts/app/heroes.json b/public/docs/_examples/server-communication/ts/app/heroes.json deleted file mode 100644 index c6b5cc91df..0000000000 --- a/public/docs/_examples/server-communication/ts/app/heroes.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "data": [ - { "id": "1", "name": "Windstorm" }, - { "id": "2", "name": "Bombasto" }, - { "id": "3", "name": "Magneta" }, - { "id": "4", "name": "Tornado" } - ] -} diff --git a/public/docs/_examples/server-communication/ts/app/main.ts b/public/docs/_examples/server-communication/ts/app/main.ts deleted file mode 100644 index c992809065..0000000000 --- a/public/docs/_examples/server-communication/ts/app/main.ts +++ /dev/null @@ -1,15 +0,0 @@ -//#docregion -import {bootstrap} from 'angular2/platform/browser'; - -// #docregion import-rxjs -// Add all operators to Observable -import 'rxjs/Rx'; -// #enddocregion import-rxjs - -import {WikiComponent} from './wiki/wiki.component'; -import {WikiSmartComponent} from './wiki/wiki-smart.component'; -import {TohComponent} from './toh/toh.component'; - -bootstrap(WikiComponent); -bootstrap(WikiSmartComponent); -bootstrap(TohComponent); \ No newline at end of file diff --git a/public/docs/_examples/server-communication/ts/app/toh/hero-list.component.1.ts b/public/docs/_examples/server-communication/ts/app/toh/hero-list.component.1.ts deleted file mode 100644 index 2a96ce2df3..0000000000 --- a/public/docs/_examples/server-communication/ts/app/toh/hero-list.component.1.ts +++ /dev/null @@ -1,53 +0,0 @@ -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Hero} from './hero'; -import {HeroService} from './hero.service.1'; - -@Component({ - selector: 'hero-list', -// #docregion template - template: ` -

    Heroes:

    -
      -
    • - {{ hero.name }} -
    • -
    - New Hero: - - -
    {{errorMessage}}
    - `, - // #enddocregion template - styles: ['.error {color:red;}'] -}) -// #docregion component -export class HeroListComponent implements OnInit { - - constructor (private _heroService: HeroService) {} - - errorMessage: string; - heroes:Hero[]; - - ngOnInit() { this.getHeroes(); } - - // #docregion methods - getHeroes() { - this._heroService.getHeroes() - .then( - heroes => this.heroes = heroes, - error => this.errorMessage = error); - } - - addHero (name: string) { - if (!name) {return;} - this._heroService.addHero(name) - .then( - hero => this.heroes.push(hero), - error => this.errorMessage = error); - } - // #enddocregion methods -} -// #enddocregion component diff --git a/public/docs/_examples/server-communication/ts/app/toh/hero-list.component.ts b/public/docs/_examples/server-communication/ts/app/toh/hero-list.component.ts deleted file mode 100644 index a55cf35a72..0000000000 --- a/public/docs/_examples/server-communication/ts/app/toh/hero-list.component.ts +++ /dev/null @@ -1,55 +0,0 @@ -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Hero} from './hero'; -import {HeroService} from './hero.service'; - -@Component({ - selector: 'hero-list', - template: ` -

    Heroes:

    -
      -
    • - {{ hero.name }} -
    • -
    - New Hero: - - -
    {{errorMessage}}
    - `, - styles: ['.error {color:red;}'] -}) -// #docregion component -export class HeroListComponent implements OnInit { - - constructor (private _heroService: HeroService) {} - - errorMessage: string; - heroes:Hero[]; - - ngOnInit() { this.getHeroes(); } - - // #docregion methods - // #docregion getHeroes - getHeroes() { - this._heroService.getHeroes() - .subscribe( - heroes => this.heroes = heroes, - error => this.errorMessage = error); - } - // #enddocregion getHeroes - - // #docregion addHero - addHero (name: string) { - if (!name) {return;} - this._heroService.addHero(name) - .subscribe( - hero => this.heroes.push(hero), - error => this.errorMessage = error); - } - // #enddocregion addHero - // #enddocregion methods -} -// #enddocregion component diff --git a/public/docs/_examples/server-communication/ts/app/toh/hero.service.1.ts b/public/docs/_examples/server-communication/ts/app/toh/hero.service.1.ts deleted file mode 100644 index d5734fffc5..0000000000 --- a/public/docs/_examples/server-communication/ts/app/toh/hero.service.1.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* Promise version */ -// #docplaster - -// #docregion -import {Injectable} from 'angular2/core'; -import {Http, Response} from 'angular2/http'; -import {Headers, RequestOptions} from 'angular2/http'; -import {Hero} from './hero'; - -@Injectable() -export class HeroService { - constructor (private http: Http) {} - - // URL to web api - private _heroesUrl = 'app/heroes.json'; - - // #docregion methods - getHeroes () { - return this.http.get(this._heroesUrl) - .toPromise() - .then(res => res.json().data, this.handleError) - .then(data => { console.log(data); return data; }); // eyeball results in the console - } - - addHero (name: string) : Promise { - let body = JSON.stringify({ name }); - let headers = new Headers({ 'Content-Type': 'application/json' }); - let options = new RequestOptions({ headers: headers }); - - return this.http.post(this._heroesUrl, body, options) - .toPromise() - .then(res => res.json().data) - .catch(this.handleError); - } - - private handleError (error: any) { - // in a real world app, we may send the error to some remote logging infrastructure - // instead of just logging it to the console - console.error(error); - return Promise.reject(error.message || error.json().error || 'Server error'); - } -// #enddocregion methods -} -// #enddocregion diff --git a/public/docs/_examples/server-communication/ts/app/toh/hero.service.ts b/public/docs/_examples/server-communication/ts/app/toh/hero.service.ts deleted file mode 100644 index 7ff9805ac0..0000000000 --- a/public/docs/_examples/server-communication/ts/app/toh/hero.service.ts +++ /dev/null @@ -1,74 +0,0 @@ -// #docplaster - -// #docregion -// #docregion v1 -import {Injectable} from 'angular2/core'; -import {Http, Response} from 'angular2/http'; -// #enddocregion v1 -// #docregion import-request-options -import {Headers, RequestOptions} from 'angular2/http'; -// #enddocregion import-request-options -// #docregion v1 -import {Hero} from './hero'; -import {Observable} from 'rxjs/Observable'; - -@Injectable() -export class HeroService { - constructor (private http: Http) {} -// #enddocregion -// #enddocregion v1 - - /* - // #docregion endpoint-json - private _heroesUrl = 'app/heroes.json'; // URL to JSON file - // #enddocregion endpoint-json - */ -// #docregion -// #docregion v1 - - // #docregion endpoint - private _heroesUrl = 'app/heroes'; // URL to web api - // #enddocregion endpoint - - // #docregion methods - // #docregion error-handling - getHeroes () { - // #docregion http-get, http-get-v1 - return this.http.get(this._heroesUrl) - .map(res => res.json().data) - // #enddocregion v1, http-get-v1, error-handling - .do(data => console.log(data)) // eyeball results in the console - // #docregion v1, http-get-v1, error-handling - .catch(this.handleError); - // #enddocregion http-get, http-get-v1 - } - // #enddocregion error-handling - // #enddocregion v1 - - // #docregion addhero - addHero (name: string) : Observable { - - let body = JSON.stringify({ name }); - //#docregion headers - let headers = new Headers({ 'Content-Type': 'application/json' }); - let options = new RequestOptions({ headers: headers }); - - return this.http.post(this._heroesUrl, body, options) - //#enddocregion headers - .map(res => res.json().data) - .catch(this.handleError) - } - // #enddocregion addhero - - // #docregion v1 - // #docregion error-handling - private handleError (error: Response) { - // in a real world app, we may send the error to some remote logging infrastructure - // instead of just logging it to the console - console.error(error); - return Observable.throw(error.json().error || 'Server error'); - } - // #enddocregion error-handling - // #enddocregion methods -} -// #enddocregion diff --git a/public/docs/_examples/server-communication/ts/app/toh/hero.ts b/public/docs/_examples/server-communication/ts/app/toh/hero.ts deleted file mode 100644 index bf664b0eec..0000000000 --- a/public/docs/_examples/server-communication/ts/app/toh/hero.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export class Hero { - constructor( - public id:number, - public name:string) { } -} diff --git a/public/docs/_examples/server-communication/ts/app/toh/toh.component.ts b/public/docs/_examples/server-communication/ts/app/toh/toh.component.ts deleted file mode 100644 index bc93e5c9c9..0000000000 --- a/public/docs/_examples/server-communication/ts/app/toh/toh.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -// #docplaster - -// #docregion -import {Component} from 'angular2/core'; -import {HTTP_PROVIDERS} from 'angular2/http'; - -import {Hero} from './hero'; -import {HeroListComponent} from './hero-list.component'; -import {HeroService} from './hero.service'; -//#enddocregion - -//#docregion in-mem-web-api-imports -import {provide} from 'angular2/core'; -import {XHRBackend} from 'angular2/http'; - -// in-memory web api imports -import {InMemoryBackendService, - SEED_DATA} from 'a2-in-memory-web-api/core'; -import {HeroData} from '../hero-data'; -// #enddocregion in-mem-web-api-imports -//#docregion - -@Component({ - selector: 'my-toh', -// #docregion template - template: ` -

    Tour of Heroes

    - - `, - // #enddocregion template - directives:[HeroListComponent], - providers: [ - HTTP_PROVIDERS, - HeroService, -//#enddocregion -//#docregion in-mem-web-api-providers - // in-memory web api providers - provide(XHRBackend, { useClass: InMemoryBackendService }), // in-mem server - provide(SEED_DATA, { useClass: HeroData }) // in-mem server data -//#enddocregion in-mem-web-api-providers -//#docregion - ] -}) -export class TohComponent { } -// #enddocregion diff --git a/public/docs/_examples/server-communication/ts/app/wiki/wiki-smart.component.ts b/public/docs/_examples/server-communication/ts/app/wiki/wiki-smart.component.ts deleted file mode 100644 index dad9dacaf6..0000000000 --- a/public/docs/_examples/server-communication/ts/app/wiki/wiki-smart.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {JSONP_PROVIDERS} from 'angular2/http'; -import {Observable} from 'rxjs/Observable'; -// #docregion import-subject -import {Subject} from 'rxjs/Subject'; -// #enddocregion import-subject - -import {WikipediaService} from './wikipedia.service'; - -@Component({ - selector: 'my-wiki-smart', - template: ` -

    Smarter Wikipedia Demo

    -

    Fetches when typing stops

    - - - -
      -
    • {{item}}
    • -
    - `, - providers:[JSONP_PROVIDERS, WikipediaService] -}) -export class WikiSmartComponent { - - constructor (private _wikipediaService: WikipediaService) { } - - // #docregion subject - private _searchTermStream = new Subject(); - - search(term:string) { this._searchTermStream.next(term); } - // #enddocregion subject - - // #docregion observable-operators - items:Observable = this._searchTermStream - .debounceTime(300) - .distinctUntilChanged() - .switchMap((term:string) => this._wikipediaService.search(term)); -// #enddocregion observable-operators -} diff --git a/public/docs/_examples/server-communication/ts/app/wiki/wiki.component.ts b/public/docs/_examples/server-communication/ts/app/wiki/wiki.component.ts deleted file mode 100644 index c6b6e9888a..0000000000 --- a/public/docs/_examples/server-communication/ts/app/wiki/wiki.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {JSONP_PROVIDERS} from 'angular2/http'; -import {Observable} from 'rxjs/Observable'; - -import {WikipediaService} from './wikipedia.service'; - -@Component({ - selector: 'my-wiki', - template: ` -

    Wikipedia Demo

    -

    Fetches after each keystroke

    - - - -
      -
    • {{item}}
    • -
    - `, - providers:[JSONP_PROVIDERS, WikipediaService] -}) -export class WikiComponent { - - constructor (private _wikipediaService: WikipediaService) {} - - items: Observable; - - search (term: string) { - this.items = this._wikipediaService.search(term); - } -} diff --git a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts b/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts deleted file mode 100644 index b88038f2f2..0000000000 --- a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Create the query string by hand -// #docregion -import {Injectable} from 'angular2/core'; -import {Jsonp} from 'angular2/http'; - -@Injectable() -export class WikipediaService { - constructor(private jsonp: Jsonp) { } - - // TODO: Add error handling - search(term: string) { - - let wikiUrl = 'http://en.wikipedia.org/w/api.php'; - - // #docregion query-string - let queryString = - `?search=${term}&action=opensearch&format=json&callback=JSONP_CALLBACK` - - return this.jsonp - .get(wikiUrl + queryString) - .map(request => request.json()[1]); - // #enddocregion query-string - } -} diff --git a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts b/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts deleted file mode 100644 index 01b328c3b3..0000000000 --- a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; -import {Jsonp, URLSearchParams} from 'angular2/http'; - -@Injectable() -export class WikipediaService { - constructor(private jsonp: Jsonp) {} - - search (term: string) { - - let wikiUrl = 'http://en.wikipedia.org/w/api.php'; - - // #docregion search-parameters - var params = new URLSearchParams(); - params.set('search', term); // the user's search value - params.set('action', 'opensearch'); - params.set('format', 'json'); - params.set('callback', 'JSONP_CALLBACK'); - // #enddocregion search-parameters - - // #docregion call-jsonp - // TODO: Add error handling - return this.jsonp - .get(wikiUrl, { search: params }) - .map(request => request.json()[1]); - // #enddocregion call-jsonp - } -} diff --git a/public/docs/_examples/server-communication/ts/index.html b/public/docs/_examples/server-communication/ts/index.html deleted file mode 100644 index 94c08df802..0000000000 --- a/public/docs/_examples/server-communication/ts/index.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Angular 2 Http Demo - - - - - - - - - - - - - - - - - - - - - - - - - - - - ToH Loading... - Wiki Loading... - WikiSmart Loading... - - - diff --git a/public/docs/_examples/server-communication/ts/plnkr.json b/public/docs/_examples/server-communication/ts/plnkr.json index fd35eda20d..fe966be012 100644 --- a/public/docs/_examples/server-communication/ts/plnkr.json +++ b/public/docs/_examples/server-communication/ts/plnkr.json @@ -1,9 +1,10 @@ { "description": "Http", + "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", "!**/*.[1].*" ], "tags": ["http", "jsonp"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/server-communication/ts/src/app/app.component.ts b/public/docs/_examples/server-communication/ts/src/app/app.component.ts new file mode 100644 index 0000000000..780d044cab --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/app.component.ts @@ -0,0 +1,13 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` + + + + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/server-communication/ts/src/app/app.module.1.ts b/public/docs/_examples/server-communication/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..fb7012aa02 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/app.module.1.ts @@ -0,0 +1,23 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule, JsonpModule } from '@angular/http'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + JsonpModule + ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { +} + + + diff --git a/public/docs/_examples/server-communication/ts/src/app/app.module.ts b/public/docs/_examples/server-communication/ts/src/app/app.module.ts new file mode 100644 index 0000000000..fd0c720c3c --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/app.module.ts @@ -0,0 +1,46 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule, JsonpModule } from '@angular/http'; + + +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +import { HeroData } from './hero-data'; +import { requestOptionsProvider } from './default-request-options.service'; + +import { AppComponent } from './app.component'; + +import { HeroListComponent } from './toh/hero-list.component'; +import { HeroListPromiseComponent } from './toh/hero-list.component.promise'; + +import { WikiComponent } from './wiki/wiki.component'; +import { WikiSmartComponent } from './wiki/wiki-smart.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + JsonpModule, + // #docregion in-mem-web-api + InMemoryWebApiModule.forRoot(HeroData) + // #enddocregion in-mem-web-api + ], + declarations: [ + AppComponent, + HeroListComponent, + HeroListPromiseComponent, + WikiComponent, + WikiSmartComponent + ], +// #docregion provide-default-request-options + providers: [ requestOptionsProvider ], +// #enddocregion provide-default-request-options + bootstrap: [ AppComponent ] +}) +export class AppModule {} + + + diff --git a/public/docs/_examples/server-communication/ts/src/app/default-request-options.service.ts b/public/docs/_examples/server-communication/ts/src/app/default-request-options.service.ts new file mode 100644 index 0000000000..9ec52daa80 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/default-request-options.service.ts @@ -0,0 +1,16 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { BaseRequestOptions, RequestOptions } from '@angular/http'; + +@Injectable() +export class DefaultRequestOptions extends BaseRequestOptions { + + constructor() { + super(); + + // Set the default 'Content-Type' header + this.headers.set('Content-Type', 'application/json'); + } +} + +export const requestOptionsProvider = { provide: RequestOptions, useClass: DefaultRequestOptions }; diff --git a/public/docs/_examples/server-communication/ts/src/app/hero-data.ts b/public/docs/_examples/server-communication/ts/src/app/hero-data.ts new file mode 100644 index 0000000000..4db6aca115 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/hero-data.ts @@ -0,0 +1,13 @@ +// #docregion +import { InMemoryDbService } from 'angular-in-memory-web-api'; +export class HeroData implements InMemoryDbService { + createDb() { + let heroes = [ + { id: 1, name: 'Windstorm' }, + { id: 2, name: 'Bombasto' }, + { id: 3, name: 'Magneta' }, + { id: 4, name: 'Tornado' } + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/server-communication/ts/src/app/heroes.json b/public/docs/_examples/server-communication/ts/src/app/heroes.json new file mode 100644 index 0000000000..dfb589066b --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/heroes.json @@ -0,0 +1,8 @@ +{ + "data": [ + { "id": 1, "name": "Windstorm" }, + { "id": 2, "name": "Bombasto" }, + { "id": 3, "name": "Magneta" }, + { "id": 4, "name": "Tornado" } + ] +} diff --git a/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.html b/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.html new file mode 100644 index 0000000000..65ca9cfbb7 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.html @@ -0,0 +1,11 @@ + +

    Tour of Heroes ({{mode}})

    +

    Heroes:

    +
      +
    • {{hero.name}}
    • +
    + + + + +

    {{errorMessage}}

    diff --git a/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.promise.ts b/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.promise.ts new file mode 100644 index 0000000000..4bbe7eade2 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.promise.ts @@ -0,0 +1,40 @@ +// #docregion +// Promise Version +import { Component, OnInit } from '@angular/core'; +import { Hero } from './hero'; +import { HeroService } from './hero.service.promise'; + +@Component({ + selector: 'hero-list-promise', + templateUrl: './hero-list.component.html', + providers: [ HeroService ], + styles: ['.error {color:red;}'] +}) +// #docregion component +export class HeroListPromiseComponent implements OnInit { + errorMessage: string; + heroes: Hero[]; + mode = 'Promise'; + + constructor (private heroService: HeroService) {} + + ngOnInit() { this.getHeroes(); } + + // #docregion methods + getHeroes() { + this.heroService.getHeroes() + .then( + heroes => this.heroes = heroes, + error => this.errorMessage = error); + } + + addHero (name: string) { + if (!name) { return; } + this.heroService.addHero(name) + .then( + hero => this.heroes.push(hero), + error => this.errorMessage = error); + } + // #enddocregion methods +} +// #enddocregion component diff --git a/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.ts b/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.ts new file mode 100644 index 0000000000..8cca504762 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/toh/hero-list.component.ts @@ -0,0 +1,44 @@ +// #docregion +// Observable Version +import { Component, OnInit } from '@angular/core'; +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'hero-list', + templateUrl: './hero-list.component.html', + providers: [ HeroService ], + styles: ['.error {color:red;}'] +}) +// #docregion component +export class HeroListComponent implements OnInit { + errorMessage: string; + heroes: Hero[]; + mode = 'Observable'; + + constructor (private heroService: HeroService) {} + + ngOnInit() { this.getHeroes(); } + + // #docregion methods + // #docregion getHeroes + getHeroes() { + this.heroService.getHeroes() + .subscribe( + heroes => this.heroes = heroes, + error => this.errorMessage = error); + } + // #enddocregion getHeroes + + // #docregion addHero + addHero(name: string) { + if (!name) { return; } + this.heroService.create(name) + .subscribe( + hero => this.heroes.push(hero), + error => this.errorMessage = error); + } + // #enddocregion addHero + // #enddocregion methods +} +// #enddocregion component diff --git a/public/docs/_examples/server-communication/ts/src/app/toh/hero.service.promise.ts b/public/docs/_examples/server-communication/ts/src/app/toh/hero.service.promise.ts new file mode 100644 index 0000000000..e38bd4bebf --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/toh/hero.service.promise.ts @@ -0,0 +1,60 @@ +// #docplaster +// #docregion +// Promise Version +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Headers, RequestOptions } from '@angular/http'; + +// #docregion rxjs-imports +import 'rxjs/add/operator/toPromise'; +// #enddocregion rxjs-imports + +import { Hero } from './hero'; + +@Injectable() +export class HeroService { + // URL to web api + private heroesUrl = 'app/heroes'; + + constructor (private http: Http) {} + + // #docregion methods + getHeroes (): Promise { + return this.http.get(this.heroesUrl) + .toPromise() + .then(this.extractData) + .catch(this.handleError); + } + + addHero (name: string): Promise { + let headers = new Headers({ 'Content-Type': 'application/json' }); + let options = new RequestOptions({ headers: headers }); + + return this.http.post(this.heroesUrl, { name }, options) + .toPromise() + .then(this.extractData) + .catch(this.handleError); + } + + private extractData(res: Response) { + let body = res.json(); + return body.data || { }; + } + + private handleError (error: Response | any) { + // In a real world app, we might use a remote logging infrastructure + let errMsg: string; + if (error instanceof Response) { + const body = error.json() || ''; + const err = body.error || JSON.stringify(body); + errMsg = `${error.status} - ${error.statusText || ''} ${err}`; + } else { + errMsg = error.message ? error.message : error.toString(); + } + console.error(errMsg); + return Promise.reject(errMsg); + } + +// #enddocregion methods +} +// #enddocregion diff --git a/public/docs/_examples/server-communication/ts/src/app/toh/hero.service.ts b/public/docs/_examples/server-communication/ts/src/app/toh/hero.service.ts new file mode 100644 index 0000000000..4f0da49021 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/toh/hero.service.ts @@ -0,0 +1,80 @@ +// #docplaster +// #docregion +// Observable Version +// #docregion v1 +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +// #enddocregion v1 +// #docregion import-request-options +import { Headers, RequestOptions } from '@angular/http'; +// #enddocregion import-request-options +// #docregion v1 + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/map'; +// #enddocregion rxjs-imports + +import { Hero } from './hero'; + +@Injectable() +export class HeroService { + // #docregion endpoint + private heroesUrl = 'api/heroes'; // URL to web API + // #enddocregion endpoint + + // #docregion ctor + constructor (private http: Http) {} + // #enddocregion ctor + + // #docregion methods, error-handling, http-get + getHeroes(): Observable { + return this.http.get(this.heroesUrl) + .map(this.extractData) + .catch(this.handleError); + } + // #enddocregion error-handling, http-get, v1 + + // #docregion create, create-sig + create(name: string): Observable { + // #enddocregion create-sig + let headers = new Headers({ 'Content-Type': 'application/json' }); + let options = new RequestOptions({ headers: headers }); + + return this.http.post(this.heroesUrl, { name }, options) + .map(this.extractData) + .catch(this.handleError); + } + // #enddocregion create + + // #docregion v1, extract-data + private extractData(res: Response) { + let body = res.json(); + return body.data || { }; + } + // #enddocregion extract-data + // #docregion error-handling + + private handleError (error: Response | any) { + // In a real world app, you might use a remote logging infrastructure + let errMsg: string; + if (error instanceof Response) { + const body = error.json() || ''; + const err = body.error || JSON.stringify(body); + errMsg = `${error.status} - ${error.statusText || ''} ${err}`; + } else { + errMsg = error.message ? error.message : error.toString(); + } + console.error(errMsg); + return Observable.throw(errMsg); + } + // #enddocregion error-handling, methods +} +// #enddocregion + +/* + // #docregion endpoint-json + private heroesUrl = 'app/heroes.json'; // URL to JSON file + // #enddocregion endpoint-json +*/ diff --git a/public/docs/_examples/server-communication/ts/src/app/toh/hero.ts b/public/docs/_examples/server-communication/ts/src/app/toh/hero.ts new file mode 100644 index 0000000000..09b8d295ce --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/toh/hero.ts @@ -0,0 +1,6 @@ +// #docregion +export class Hero { + constructor( + public id: number, + public name: string) { } +} diff --git a/public/docs/_examples/server-communication/ts/src/app/wiki/wiki-smart.component.ts b/public/docs/_examples/server-communication/ts/src/app/wiki/wiki-smart.component.ts new file mode 100644 index 0000000000..fc453a820e --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/wiki/wiki-smart.component.ts @@ -0,0 +1,47 @@ +/* tslint:disable: member-ordering forin */ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/distinctUntilChanged'; +import 'rxjs/add/operator/switchMap'; + +// #docregion import-subject +import { Subject } from 'rxjs/Subject'; +// #enddocregion import-subject + +import { WikipediaService } from './wikipedia.service'; + +@Component({ + selector: 'my-wiki-smart', + template: ` +

    Smarter Wikipedia Demo

    +

    Search when typing stops

    + +
      +
    • {{item}}
    • +
    `, + providers: [ WikipediaService ] +}) +export class WikiSmartComponent implements OnInit { + items: Observable; + + constructor (private wikipediaService: WikipediaService) {} + + // #docregion subject + private searchTermStream = new Subject(); + search(term: string) { this.searchTermStream.next(term); } + // #enddocregion subject + + ngOnInit() { + // #docregion observable-operators + this.items = this.searchTermStream + .debounceTime(300) + .distinctUntilChanged() + .switchMap((term: string) => this.wikipediaService.search(term)); + // #enddocregion observable-operators + } +} diff --git a/public/docs/_examples/server-communication/ts/src/app/wiki/wiki.component.ts b/public/docs/_examples/server-communication/ts/src/app/wiki/wiki.component.ts new file mode 100644 index 0000000000..4230df12a1 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/wiki/wiki.component.ts @@ -0,0 +1,26 @@ +// #docregion +import { Component } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + +import { WikipediaService } from './wikipedia.service'; + +@Component({ + selector: 'my-wiki', + template: ` +

    Wikipedia Demo

    +

    Search after each keystroke

    + +
      +
    • {{item}}
    • +
    `, + providers: [ WikipediaService ] +}) +export class WikiComponent { + items: Observable; + + constructor (private wikipediaService: WikipediaService) { } + + search (term: string) { + this.items = this.wikipediaService.search(term); + } +} diff --git a/public/docs/_examples/server-communication/ts/src/app/wiki/wikipedia.service.1.ts b/public/docs/_examples/server-communication/ts/src/app/wiki/wikipedia.service.1.ts new file mode 100644 index 0000000000..5cbcb7d707 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/wiki/wikipedia.service.1.ts @@ -0,0 +1,26 @@ +// Create the query string by hand +// #docregion +import { Injectable } from '@angular/core'; +import { Jsonp } from '@angular/http'; + +import 'rxjs/add/operator/map'; + +@Injectable() +export class WikipediaService { + constructor(private jsonp: Jsonp) { } + + // TODO: Add error handling + search(term: string) { + + let wikiUrl = 'http://en.wikipedia.org/w/api.php'; + + // #docregion query-string + let queryString = + `?search=${term}&action=opensearch&format=json&callback=JSONP_CALLBACK`; + + return this.jsonp + .get(wikiUrl + queryString) + .map(response => response.json()[1]); + // #enddocregion query-string + } +} diff --git a/public/docs/_examples/server-communication/ts/src/app/wiki/wikipedia.service.ts b/public/docs/_examples/server-communication/ts/src/app/wiki/wikipedia.service.ts new file mode 100644 index 0000000000..a38167d1c6 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/app/wiki/wikipedia.service.ts @@ -0,0 +1,30 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Jsonp, URLSearchParams } from '@angular/http'; + +import 'rxjs/add/operator/map'; + +@Injectable() +export class WikipediaService { + constructor(private jsonp: Jsonp) {} + + search (term: string) { + + let wikiUrl = 'http://en.wikipedia.org/w/api.php'; + + // #docregion search-parameters + let params = new URLSearchParams(); + params.set('search', term); // the user's search value + params.set('action', 'opensearch'); + params.set('format', 'json'); + params.set('callback', 'JSONP_CALLBACK'); + // #enddocregion search-parameters + + // #docregion call-jsonp + // TODO: Add error handling + return this.jsonp + .get(wikiUrl, { search: params }) + .map(response => response.json()[1]); + // #enddocregion call-jsonp + } +} diff --git a/public/docs/_examples/server-communication/ts/src/index.html b/public/docs/_examples/server-communication/ts/src/index.html new file mode 100644 index 0000000000..5c51f21c91 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/index.html @@ -0,0 +1,27 @@ + + + + + Angular Http Demo + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/server-communication/ts/src/main.ts b/public/docs/_examples/server-communication/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/server-communication/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/setup/e2e-spec.ts b/public/docs/_examples/setup/e2e-spec.ts new file mode 100644 index 0000000000..73921707ee --- /dev/null +++ b/public/docs/_examples/setup/e2e-spec.ts @@ -0,0 +1,17 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('QuickStart E2E Tests', function () { + + let expectedMsg = 'Hello Angular'; + + beforeEach(function () { + browser.get(''); + }); + + it(`should display: ${expectedMsg}`, function () { + expect(element(by.css('h1')).getText()).toEqual(expectedMsg); + }); + +}); diff --git a/public/docs/_examples/setup/ts/example-config.json b/public/docs/_examples/setup/ts/example-config.json new file mode 100644 index 0000000000..eb33c943c7 --- /dev/null +++ b/public/docs/_examples/setup/ts/example-config.json @@ -0,0 +1,3 @@ +{ + "unittesting": true +} diff --git a/public/docs/_examples/setup/ts/non-essential-files.txt b/public/docs/_examples/setup/ts/non-essential-files.txt new file mode 100644 index 0000000000..3c9cdde9dc --- /dev/null +++ b/public/docs/_examples/setup/ts/non-essential-files.txt @@ -0,0 +1,13 @@ +.git +.gitignore +.travis.yml +*.spec*.ts +CHANGELOG.md +e2e +favicon.ico +karma.conf.js +karma-test-shim.js +LICENSE +non-essential-files.txt +protractor.config.js +README.md diff --git a/public/docs/_examples/setup/ts/plnkr.json b/public/docs/_examples/setup/ts/plnkr.json new file mode 100644 index 0000000000..22b528eec5 --- /dev/null +++ b/public/docs/_examples/setup/ts/plnkr.json @@ -0,0 +1,13 @@ +{ + "description": "QuickStart Setup", + "basePath": "src/", + "files": [ + "app/app.component.ts", + "app/app.module.ts", + "index.html", + "main.ts", + "styles.css" + ], + "open": "app/app.component.ts", + "tags": ["quickstart", "setup", "seed"] +} diff --git a/public/docs/_examples/setup/ts/quickstart-specs.plnkr.json b/public/docs/_examples/setup/ts/quickstart-specs.plnkr.json new file mode 100644 index 0000000000..a7dfedb595 --- /dev/null +++ b/public/docs/_examples/setup/ts/quickstart-specs.plnkr.json @@ -0,0 +1,13 @@ +{ + "description": "Quickstart AppComponent Testing", + "basePath": "src/", + "files":[ + "browser-test-shim.js", + "app/app.component.ts", + "app/app.component.spec.ts", + "quickstart-specs.html" + ], + "main": "quickstart-specs.html", + "open": "app/app.component.spec.ts", + "tags": ["quickstart", "setup", "testing"] +} diff --git a/public/docs/_examples/setup/ts/src/app/app.component.spec.ts b/public/docs/_examples/setup/ts/src/app/app.component.spec.ts new file mode 100644 index 0000000000..7769024464 --- /dev/null +++ b/public/docs/_examples/setup/ts/src/app/app.component.spec.ts @@ -0,0 +1,33 @@ +import { AppComponent } from './app.component'; + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +describe('AppComponent', function () { + let de: DebugElement; + let comp: AppComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AppComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AppComponent); + comp = fixture.componentInstance; + de = fixture.debugElement.query(By.css('h1')); + }); + + it('should create component', () => expect(comp).toBeDefined() ); + + it('should have expected

    text', () => { + fixture.detectChanges(); + const h1 = de.nativeElement; + expect(h1.innerText).toMatch(/angular/i, + '

    should say something about "Angular"'); + }); +}); diff --git a/public/docs/_examples/setup/ts/src/app/app.component.ts b/public/docs/_examples/setup/ts/src/app/app.component.ts new file mode 100644 index 0000000000..1ef28fc5c4 --- /dev/null +++ b/public/docs/_examples/setup/ts/src/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: `

    Hello {{name}}

    ` +}) +export class AppComponent { name = 'Angular'; } diff --git a/public/docs/_examples/setup/ts/src/app/app.module.ts b/public/docs/_examples/setup/ts/src/app/app.module.ts new file mode 100644 index 0000000000..50a0e6eb47 --- /dev/null +++ b/public/docs/_examples/setup/ts/src/app/app.module.ts @@ -0,0 +1,11 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/setup/ts/src/index.html b/public/docs/_examples/setup/ts/src/index.html new file mode 100644 index 0000000000..58e5112308 --- /dev/null +++ b/public/docs/_examples/setup/ts/src/index.html @@ -0,0 +1,28 @@ + + + + + Angular Quickstart Seed + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/setup/ts/src/main.ts b/public/docs/_examples/setup/ts/src/main.ts new file mode 100644 index 0000000000..02d58dceac --- /dev/null +++ b/public/docs/_examples/setup/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/setup/ts/src/quickstart-specs.html b/public/docs/_examples/setup/ts/src/quickstart-specs.html new file mode 100644 index 0000000000..9bc81ccf2e --- /dev/null +++ b/public/docs/_examples/setup/ts/src/quickstart-specs.html @@ -0,0 +1,41 @@ + + + + + + + 1st Specs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/setup/ts/src/systemjs.config.extras.js b/public/docs/_examples/setup/ts/src/systemjs.config.extras.js new file mode 100644 index 0000000000..027dfe58cf --- /dev/null +++ b/public/docs/_examples/setup/ts/src/systemjs.config.extras.js @@ -0,0 +1,11 @@ +/** + * Add barrels and stuff + * Adjust as necessary for your application needs. + */ +// (function (global) { +// System.config({ +// packages: { +// // add packages here +// } +// }); +// })(this); diff --git a/public/docs/_examples/structural-directives/dart/lib/heavy_loader_component.dart b/public/docs/_examples/structural-directives/dart/lib/heavy_loader_component.dart deleted file mode 100644 index 647542accc..0000000000 --- a/public/docs/_examples/structural-directives/dart/lib/heavy_loader_component.dart +++ /dev/null @@ -1,32 +0,0 @@ -// #docregion -import 'dart:async'; - -import 'package:angular2/angular2.dart'; - -int nextId = 1; - -@Component( - selector: 'heavy-loader', - template: 'heavy loader #{{id}} on duty!') -class HeavyLoaderComponent implements OnInit, OnDestroy { - int id = nextId++; - @Input() List logs; - - // Mock todo: get 10,000 rows of data from the server - ngOnInit() => _log( - "heavy-loader $id initialized, loading 10,000 rows of data from the server"); - - // Mock todo: clean-up - ngOnDestroy() => _log("heavy-loader $id destroyed, cleaning up"); - - _log(String msg) { - logs.add(msg); - _tick(); - } - - /// Triggers the next round of Angular change detection - /// after one turn of the browser event loop - /// ensuring display of msg added in onDestroy - _tick() => new Future(() {}); -} -// #enddocregion diff --git a/public/docs/_examples/structural-directives/dart/lib/structural_directives_component.dart b/public/docs/_examples/structural-directives/dart/lib/structural_directives_component.dart deleted file mode 100644 index 477b372bb0..0000000000 --- a/public/docs/_examples/structural-directives/dart/lib/structural_directives_component.dart +++ /dev/null @@ -1,21 +0,0 @@ -// #docplaster -// #docregion -import 'package:angular2/angular2.dart'; - -import 'heavy_loader_component.dart'; -import 'unless_directive.dart'; - -@Component( - selector: 'structural-directives', - templateUrl: 'structural_directives_component.html', - styles: const ['button { min-width: 100px; }'], - directives: const [UnlessDirective, HeavyLoaderComponent]) -class StructuralDirectivesComponent { - List heroes = ['Mr. Nice', 'Narco', 'Bombasto']; - bool condition = true; - bool isVisible = true; - List logs = []; - String status = 'ready'; - - get hero => heroes[0]; -} diff --git a/public/docs/_examples/structural-directives/dart/lib/structural_directives_component.html b/public/docs/_examples/structural-directives/dart/lib/structural_directives_component.html deleted file mode 100644 index 2ea022222a..0000000000 --- a/public/docs/_examples/structural-directives/dart/lib/structural_directives_component.html +++ /dev/null @@ -1,108 +0,0 @@ - - -

    Structural Directives

    - - - -
    {{hero}}
    -
    {{hero}}
    - - -
    - - - -
    - - - -
    - - - - -

    - condition is true and ngIf is true. -

    -

    - condition is false and ngIf is false. -

    - - -

    - condition is false and myUnless is true. -

    - -

    - condition is true and myUnless is false. -

    - - -
    - - -
    - - -
    - -
    - - -
    - -

    heavy-loader log:

    -
    {{message}}
    - - -
    - - -

    - Hip! -

    - -

    - Hooray! -

    - - -
    - - - - -

    - Our heroes are true! -

    - - - - - -
    - - - - - -
    {{ hero }}
    - - - - diff --git a/public/docs/_examples/structural-directives/dart/lib/unless_directive.dart b/public/docs/_examples/structural-directives/dart/lib/unless_directive.dart deleted file mode 100644 index 7760658b48..0000000000 --- a/public/docs/_examples/structural-directives/dart/lib/unless_directive.dart +++ /dev/null @@ -1,31 +0,0 @@ -// #docplaster -// #docregion -// #docregion unless-declaration -import 'package:angular2/angular2.dart'; -// #enddocregion unless-declaration - -// #docregion unless-declaration -@Directive(selector: '[myUnless]') -class UnlessDirective { - // #enddocregion unless-declaration - - // #docregion unless-constructor - TemplateRef _templateRef; - ViewContainerRef _viewContainer; - - UnlessDirective(this._templateRef, this._viewContainer); - // #enddocregion unless-constructor - - // #docregion unless-set - @Input() - set myUnless(bool condition) { - if (!condition) { - _viewContainer.createEmbeddedView(_templateRef); - } else { - _viewContainer.clear(); - } - } - // #enddocregion unless-set - // #docregion unless-declaration -} -// #enddocregion unless-declaration diff --git a/public/docs/_examples/structural-directives/dart/pubspec.yaml b/public/docs/_examples/structural-directives/dart/pubspec.yaml deleted file mode 100644 index 24255bb66f..0000000000 --- a/public/docs/_examples/structural-directives/dart/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# #docregion -name: structural_directives -description: Structural directives example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/structural-directives/dart/web/index.html b/public/docs/_examples/structural-directives/dart/web/index.html deleted file mode 100644 index 38da87dc69..0000000000 --- a/public/docs/_examples/structural-directives/dart/web/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - Angular 2 Structural Directives - - - - - - - Loading... - - - diff --git a/public/docs/_examples/structural-directives/dart/web/main.dart b/public/docs/_examples/structural-directives/dart/web/main.dart deleted file mode 100644 index 2c00f66c65..0000000000 --- a/public/docs/_examples/structural-directives/dart/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:structural_directives/structural_directives_component.dart'; - -main() { - bootstrap(StructuralDirectivesComponent); -} diff --git a/public/docs/_examples/structural-directives/e2e-spec.js b/public/docs/_examples/structural-directives/e2e-spec.js deleted file mode 100644 index a2ed0455b9..0000000000 --- a/public/docs/_examples/structural-directives/e2e-spec.js +++ /dev/null @@ -1,64 +0,0 @@ -describe('Structural Directives', function () { - - // tests interact - so we need beforeEach instead of beforeAll - beforeEach(function () { - browser.get(''); - }); - - it('should be able to use ngFor, ngIf and ngWhen together', function () { - var allDivEles = element.all(by.css('structural-directives > div')); - expect(allDivEles.get(0).getText()).toEqual('Mr. Nice'); - expect(allDivEles.get(1).getText()).toEqual('Mr. Nice'); - expect(allDivEles.get(4).getText()).toEqual('Ready'); - }); - - it('should be able to toggle ngIf with a button', function () { - var setConditionButtonEle = element.all(by.css('button')).get(0); - var conditionTrueEles = element.all(by.cssContainingText('p', 'condition is true')); - var conditionFalseEles = element.all(by.cssContainingText('p', 'condition is false')); - expect(conditionTrueEles.count()).toBe(2, 'should be two condition true elements'); - expect(conditionFalseEles.count()).toBe(0, 'should be no condition false elements'); - setConditionButtonEle.click().then(function() { - expect(conditionTrueEles.count()).toBe(0, 'should be no condition true elements'); - expect(conditionFalseEles.count()).toBe(2, 'should be two condition false elements'); - }); - }); - - it('should be able to compare use of ngIf with changing css visibility', function () { - var setConditionButtonEle = element.all(by.css('button')).get(0); - var ngIfButtonEle = element(by.cssContainingText('button', 'if | !if')); - var ngIfParentEle = ngIfButtonEle.element(by.xpath('..')); - var ngIfSiblingEle = ngIfParentEle.element(by.css('heavy-loader')); - var cssButtonEle = element(by.cssContainingText('button', 'show | hide')); - var cssSiblingEle = cssButtonEle.element(by.xpath('..')).element(by.css('heavy-loader')); - var setConditionText; - setConditionButtonEle.getText().then(function(text) { - setConditionText = text; - expect(ngIfButtonEle.isPresent()).toBe(true, 'should be able to find ngIfButton'); - expect(cssButtonEle.isPresent()).toBe(true, 'should be able to find cssButton'); - expect(ngIfParentEle.isPresent()).toBe(true, 'should be able to find ngIfButton parent'); - expect(ngIfSiblingEle.isPresent()).toBe(true, 'should be able to find ngIfButton sibling'); - expect(cssSiblingEle.isPresent()).toBe(true, 'should be able to find cssButton sibling'); - return ngIfButtonEle.click(); - }).then(function() { - expect(ngIfSiblingEle.isPresent()).toBe(false, 'now should NOT be able to find ngIfButton sibling'); - expect(setConditionButtonEle.getText()).not.toEqual(setConditionText); - return cssButtonEle.click(); - }).then(function() { - expect(cssSiblingEle.isPresent()).toBe(true, 'now should still be able to find cssButton sibling'); - expect(cssSiblingEle.isDisplayed()).toBe(false, 'now cssButton sibling should NOT be visible'); - return ngIfButtonEle.click(); - }).then(function() { - expect(setConditionButtonEle.getText()).toEqual(setConditionText); - }); - }); - - it('should be able to use *ngIf ', function () { - var setConditionButtonEle = element.all(by.css('button')).get(0); - var displayEles = element.all(by.cssContainingText('p', 'Our heroes are true!')); - expect(displayEles.count()).toBe(2, "should be displaying two ngIf elements"); - setConditionButtonEle.click().then(function() { - expect(displayEles.count()).toBe(0, "should nog longer be displaying ngIf elements"); - }); - }); -}); diff --git a/public/docs/_examples/structural-directives/e2e-spec.ts b/public/docs/_examples/structural-directives/e2e-spec.ts new file mode 100644 index 0000000000..51f30bf0bb --- /dev/null +++ b/public/docs/_examples/structural-directives/e2e-spec.ts @@ -0,0 +1,58 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Structural Directives', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('first div should show hero name with *ngIf', function () { + const allDivs = element.all(by.tagName('div')); + expect(allDivs.get(0).getText()).toEqual('Mr. Nice'); + }); + + it('first li should show hero name with *ngFor', function () { + const allLis = element.all(by.tagName('li')); + expect(allLis.get(0).getText()).toEqual('Mr. Nice'); + }); + + it('ngSwitch have three instances', function () { + const happyHeroEls = element.all(by.tagName('happy-hero')); + expect(happyHeroEls.count()).toEqual(3); + }); + + it('should toggle *ngIf="hero" with a button', function () { + const toggleHeroButton = element.all(by.cssContainingText('button', 'Toggle hero')).get(0); + const paragraph = element.all(by.cssContainingText('p', 'I turned the corner')); + expect(paragraph.get(0).getText()).toContain('I waved'); + toggleHeroButton.click().then(() => { + expect(paragraph.get(0).getText()).not.toContain('I waved'); + }); + }); + + it('should have only one "Hip!" (the other is erased)', function () { + const paragraph = element.all(by.cssContainingText('p', 'Hip!')); + expect(paragraph.count()).toEqual(1); + }); + + it('myUnless should show 3 paragraph (A)s and (B)s at the start', function () { + const paragraph = element.all(by.css('p.unless')); + expect(paragraph.count()).toEqual(3); + for (let i = 0; i < 3; i++) { + expect(paragraph.get(i).getText()).toContain('(A)'); + } + }); + + it('myUnless should show 1 paragraph (B) after toggling condition', function () { + const toggleConditionButton = element.all(by.cssContainingText('button', 'Toggle condition')).get(0); + const paragraph = element.all(by.css('p.unless')); + + toggleConditionButton.click().then(() => { + expect(paragraph.count()).toEqual(1); + expect(paragraph.get(0).getText()).toContain('(B)'); + }); + }); +}); + diff --git a/public/docs/_examples/structural-directives/ts/.gitignore b/public/docs/_examples/structural-directives/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/structural-directives/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/structural-directives/ts/app/heavy-loader.component.ts b/public/docs/_examples/structural-directives/ts/app/heavy-loader.component.ts deleted file mode 100644 index 1b22384f75..0000000000 --- a/public/docs/_examples/structural-directives/ts/app/heavy-loader.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion -import {Component, Input, Output} from 'angular2/core'; - -let nextId = 1; - -@Component({ - selector: 'heavy-loader', - template: 'heavy loader #{{id}} on duty!' -}) -export class HeavyLoaderComponent { - id = nextId++; - @Input() logs: string[]; - - ngOnInit() { - // Mock todo: get 10,000 rows of data from the server - this._log(`heavy-loader ${this.id} initialized, - loading 10,000 rows of data from the server`); - } - - ngOnDestroy() { - // Mock todo: clean-up - this._log(`heavy-loader ${this.id} destroyed, cleaning up`); - } - - private _log(msg: string) { - this.logs.push(msg); - this._tick(); - } - - // Triggers the next round of Angular change detection - // after one turn of the browser event loop - // ensuring display of msg added in onDestroy - private _tick() { setTimeout(() => { }, 0); } -} -// #enddocregion diff --git a/public/docs/_examples/structural-directives/ts/app/main.ts b/public/docs/_examples/structural-directives/ts/app/main.ts deleted file mode 100644 index da28d75daf..0000000000 --- a/public/docs/_examples/structural-directives/ts/app/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {StructuralDirectivesComponent} from './structural-directives.component'; - -bootstrap(StructuralDirectivesComponent); diff --git a/public/docs/_examples/structural-directives/ts/app/structural-directives.component.html b/public/docs/_examples/structural-directives/ts/app/structural-directives.component.html deleted file mode 100644 index c7aa615932..0000000000 --- a/public/docs/_examples/structural-directives/ts/app/structural-directives.component.html +++ /dev/null @@ -1,109 +0,0 @@ - - -

    Structural Directives

    - - - -
    {{hero}}
    -
    {{hero}}
    - - -
    - - - -
    - - - -
    - - - - -

    - condition is true and ngIf is true. -

    -

    - condition is false and ngIf is false. -

    - - -

    - condition is false and myUnless is true. -

    - -

    - condition is true and myUnless is false. -

    - - -
    - - -
    - - -
    - -
    - - -
    - -

    heavy-loader log:

    -
    {{message}}
    - - -
    - - -

    - Hip! -

    - -

    - Hooray! -

    - - -
    - - - - -

    - Our heroes are true! -

    - - - - - -
    - - - - - -
    {{ hero }}
    - - - - - diff --git a/public/docs/_examples/structural-directives/ts/app/structural-directives.component.ts b/public/docs/_examples/structural-directives/ts/app/structural-directives.component.ts deleted file mode 100644 index 4174edb05f..0000000000 --- a/public/docs/_examples/structural-directives/ts/app/structural-directives.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -// #docplaster -// #docregion -import {Component, Input, Output} from 'angular2/core'; -import {UnlessDirective} from './unless.directive'; -import {HeavyLoaderComponent} from './heavy-loader.component'; - -@Component({ - selector: 'structural-directives', - templateUrl: 'app/structural-directives.component.html', - styles: ['button { min-width: 100px; }'], - directives: [UnlessDirective, HeavyLoaderComponent] -}) -export class StructuralDirectivesComponent { - heroes = ['Mr. Nice', 'Narco', 'Bombasto']; - hero = this.heroes[0]; - condition = true; - isVisible = true; - logs: string[] = []; - status = 'ready'; -} -//#enddocregion diff --git a/public/docs/_examples/structural-directives/ts/app/unless.directive.ts b/public/docs/_examples/structural-directives/ts/app/unless.directive.ts deleted file mode 100644 index 76f84b6408..0000000000 --- a/public/docs/_examples/structural-directives/ts/app/unless.directive.ts +++ /dev/null @@ -1,33 +0,0 @@ -// #docplaster -// #docregion -// #docregion unless-declaration -import {Directive, Input} from 'angular2/core'; - -// #enddocregion unless-declaration -import {TemplateRef, ViewContainerRef} from 'angular2/core'; - -// #docregion unless-declaration -@Directive({ selector: '[myUnless]' }) -export class UnlessDirective { - // #enddocregion unless-declaration - - // #docregion unless-constructor - constructor( - private _templateRef: TemplateRef, - private _viewContainer: ViewContainerRef - ) { } - // #enddocregion unless-constructor - - // #docregion unless-set - @Input() set myUnless(condition: boolean) { - if (!condition) { - this._viewContainer.createEmbeddedView(this._templateRef); - } else { - this._viewContainer.clear(); - } - } - // #enddocregion unless-set - // #docregion unless-declaration -} -// #enddocregion unless-declaration -// #enddocregion diff --git a/public/docs/_examples/structural-directives/ts/index.html b/public/docs/_examples/structural-directives/ts/index.html deleted file mode 100644 index 3716c56686..0000000000 --- a/public/docs/_examples/structural-directives/ts/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - Angular 2 Structural Directives - - - - - - - - - - - - - - - - - Loading... - - - diff --git a/public/docs/_examples/structural-directives/ts/plnkr.json b/public/docs/_examples/structural-directives/ts/plnkr.json index 32bfd6302a..58a26d7b4f 100644 --- a/public/docs/_examples/structural-directives/ts/plnkr.json +++ b/public/docs/_examples/structural-directives/ts/plnkr.json @@ -1,6 +1,11 @@ { "description": "Structural directives", - "files": ["!**/*.d.ts", "!**/*.js"], + "basePath": "src/", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!app/scrap.txt" + ], "tags": [ "structural", "directives", "template", "ngIf", "ngSwitch", "ngFor" diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.component.css b/public/docs/_examples/structural-directives/ts/src/app/app.component.css new file mode 100644 index 0000000000..e28be894f8 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.component.css @@ -0,0 +1,70 @@ +/* #docregion */ +button { + min-width: 100px; + font-size: 100%; +} + +.box { + border: 1px solid gray; + max-width: 600px; + padding: 4px; +} +.choices { + font-style: italic; +} + +code, .code { + background-color: #eee; + color: black; + font-family: Courier, sans-serif; + font-size: 85%; +} + +div.code { + width: 400px; +} + +.heroic { + font-size: 150%; + font-weight: bold; +} + +hr { + margin: 40px 0 +} + +.odd { + background-color: palegoldenrod; +} + +td, th { + text-align: left; + vertical-align: top; +} + +/* #docregion p-span */ +p span { color: red; font-size: 70%; } +/* #enddocregion p-span */ + +.unless { + border: 2px solid; + padding: 6px; +} + +p.unless { + width: 500px; +} + +button.a, span.a, .unless.a { + color: red; + border-color: gold; + background-color: yellow; + font-size: 100%; +} + +button.b, span.b, .unless.b { + color: black; + border-color: green; + background-color: lightgreen; + font-size: 100%; +} diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.component.html b/public/docs/_examples/structural-directives/ts/src/app/app.component.html new file mode 100644 index 0000000000..49c4928aad --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.component.html @@ -0,0 +1,250 @@ + + +

    Structural Directives

    + +

    Conditional display of hero

    + +
    + +
    {{hero.name}}
    + +
    + +

    List of heroes

    + + +
      + +
    • {{hero.name}}
    • + +
    + + + +
    + +

    NgIf

    + + +

    + Expression is true and ngIf is true. + This paragraph is in the DOM. +

    +

    + Expression is false and ngIf is false. + This paragraph is not in the DOM. +

    + + + +

    + Expression sets display to "block". + This paragraph is visible. +

    +

    + Expression sets display to "none". + This paragraph is hidden but still in the DOM. +

    + + +

    NgIf with template

    +

    <ng-template> element

    + + +
    {{hero.name}}
    +
    + + +

    template attribute

    + +
    {{hero.name}}
    + + +
    + +

    <ng-container>

    + +

    *ngIf with a <ng-container>

    + + + + +

    + I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

    + + +

    + I turned the corner + + and saw {{hero.name}}. I waved + + and continued on my way. +

    + + +

    <select> with <span>

    + +
    + Pick your favorite hero + () +
    + + + +

    <select> with <ng-container>

    + +
    + Pick your favorite hero + () +
    + + +

    + +
    + +

    NgFor

    + +
    + +

    <div *ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">

    + +
    + ({{i}}) {{hero.name}} +
    + + +

    <div template="ngFor let hero of heroes; let i=index; let odd=odd; trackBy: trackById" [class.odd]="odd">

    + +
    + ({{i}}) {{hero.name}} +
    + + +

    <template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">

    + + +
    ({{i}}) {{hero.name}}
    +
    + + +
    +
    + +

    NgSwitch

    + +
    Pick your favorite hero
    +

    + + +

    + +

    NgSwitch

    + + +
    + + + + +
    + + +

    NgSwitch with template attribute

    + +
    + + + + +
    + + +

    NgSwitch with <ng-template>

    + +
    + + + + + + + + + + + + +
    + + +
    + +

    <template>

    + +

    Hip!

    + +

    Hip!

    +
    +

    Hooray!

    + + +
    + +

    UnlessDirective

    +

    + The condition is currently + {{condition}}. + +

    + +

    + (A) This paragraph is displayed because the condition is false. +

    + +

    + (B) Although the condition is true, + this paragraph is displayed because myUnless is set to false. +

    + + + +

    UnlessDirective with template

    + + +

    Show this sentence unless the condition is true.

    + + +

    + (A) <p template="myUnless condition" class="code unless"> +

    + + +

    + (A) <template [myUnless]="condition"> +

    +
    + diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.component.ts b/public/docs/_examples/structural-directives/ts/src/app/app.component.ts new file mode 100644 index 0000000000..ff6f0e65a1 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.component.ts @@ -0,0 +1,23 @@ +// #docregion +import { Component } from '@angular/core'; + +import { Hero, heroes } from './hero'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] +}) +export class AppComponent { + heroes = heroes; + hero = this.heroes[0]; + + condition = false; + logs: string[] = []; + showSad = true; + status = 'ready'; + + // #docregion trackByHero + trackById(index: number, hero: Hero): number { return hero.id; } + // #enddocregion trackByHero +} diff --git a/public/docs/_examples/structural-directives/ts/src/app/app.module.ts b/public/docs/_examples/structural-directives/ts/src/app/app.module.ts new file mode 100644 index 0000000000..b6ffb456c9 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/app.module.ts @@ -0,0 +1,19 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { heroSwitchComponents } from './hero-switch.components'; +import { UnlessDirective } from './unless.directive'; + +@NgModule({ + imports: [ BrowserModule, FormsModule ], + declarations: [ + AppComponent, + heroSwitchComponents, + UnlessDirective + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts b/public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts new file mode 100644 index 0000000000..6608422d15 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/hero-switch.components.ts @@ -0,0 +1,43 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'happy-hero', + template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.` +}) +export class HappyHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'sad-hero', + template: `You like {{hero.name}}? Such a sad hero. Are you sad too?` +}) +export class SadHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'confused-hero', + template: `Are you as confused as {{hero.name}}?` +}) +export class ConfusedHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'unknown-hero', + template: `{{message}}` +}) +export class UnknownHeroComponent { + @Input() hero: Hero; + get message() { + return this.hero && this.hero.name ? + `${this.hero.name} is strange and mysterious.` : + 'Are you feeling indecisive?'; + } +} + +export const heroSwitchComponents = + [ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ]; diff --git a/public/docs/_examples/structural-directives/ts/src/app/hero.ts b/public/docs/_examples/structural-directives/ts/src/app/hero.ts new file mode 100644 index 0000000000..a1de3b3b82 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/hero.ts @@ -0,0 +1,13 @@ +// #docregion +export class Hero { + id: number; + name: string; + emotion?: string; +} + +export const heroes: Hero[] = [ + { id: 1, name: 'Mr. Nice', emotion: 'happy'}, + { id: 2, name: 'Narco', emotion: 'sad' }, + { id: 3, name: 'Windstorm', emotion: 'confused' }, + { id: 4, name: 'Magneta'} +]; diff --git a/public/docs/_examples/structural-directives/ts/src/app/scrap.txt b/public/docs/_examples/structural-directives/ts/src/app/scrap.txt new file mode 100644 index 0000000000..96426d37f0 --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/scrap.txt @@ -0,0 +1,21 @@ +// interesting but unused code + heroChooser(picker: HTMLFieldSetElement) { + let choices = picker.children; + this.favoriteHero = undefined; + for (let i = 0; i < choices.length; i++) { + let choice = choices[i].children[0] as HTMLInputElement; + if (choice.checked) { this.favoriteHero = this.heroes[i]; } + } + } + + +

    Switch with *ngFor repeated switchCases using <ng-container>

    + +
    + Your favorite hero is ... + + {{hero.name}} + + None of the above +
    + diff --git a/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts b/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts new file mode 100644 index 0000000000..470bbd932f --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/app/unless.directive.ts @@ -0,0 +1,51 @@ +// #docplaster +// #docregion +// #docregion no-docs, skeleton +import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core'; + +// #enddocregion skeleton +/** + * Add the template content to the DOM unless the condition is true. +// #enddocregion no-docs + * + * If the expression assigned to `myUnless` evaluates to a truthy value + * then the templated elements are removed removed from the DOM, + * the templated elements are (re)inserted into the DOM. + * + *
    + * Congrats! Everything is great! + *
    + * + * ### Syntax + * + * - `
    ...
    ` + * - `
    ...
    ` + * - `` + * +// #docregion no-docs + */ +// #docregion skeleton +@Directive({ selector: '[myUnless]'}) +export class UnlessDirective { + // #enddocregion skeleton + private hasView = false; + + // #docregion ctor + constructor( + private templateRef: TemplateRef, + private viewContainer: ViewContainerRef) { } + // #enddocregion ctor + + // #docregion set + @Input() set myUnless(condition: boolean) { + if (!condition && !this.hasView) { + this.viewContainer.createEmbeddedView(this.templateRef); + this.hasView = true; + } else if (condition && this.hasView) { + this.viewContainer.clear(); + this.hasView = false; + } + } + // #enddocregion set + // #docregion skeleton +} diff --git a/public/docs/_examples/structural-directives/ts/src/index.html b/public/docs/_examples/structural-directives/ts/src/index.html new file mode 100644 index 0000000000..ce7a33266d --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/index.html @@ -0,0 +1,27 @@ + + + + + Angular Structural Directives + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/structural-directives/ts/src/main.ts b/public/docs/_examples/structural-directives/ts/src/main.ts new file mode 100644 index 0000000000..105b06712d --- /dev/null +++ b/public/docs/_examples/structural-directives/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); + diff --git a/public/docs/_examples/style-guide/e2e-spec.ts b/public/docs/_examples/style-guide/e2e-spec.ts new file mode 100644 index 0000000000..d143ae5573 --- /dev/null +++ b/public/docs/_examples/style-guide/e2e-spec.ts @@ -0,0 +1,191 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Style Guide', function () { + it('01-01', function () { + browser.get('#/01-01'); + + let pre = element(by.tagName('toh-heroes > pre')); + expect(pre.getText()).toContain('Bombasto'); + expect(pre.getText()).toContain('Tornado'); + expect(pre.getText()).toContain('Magneta'); + }); + + it('02-07', function () { + browser.get('#/02-07'); + + let hero = element(by.tagName('toh-hero > div')); + let users = element(by.tagName('admin-users > div')); + + expect(hero.getText()).toBe('hero component'); + expect(users.getText()).toBe('users component'); + }); + + it('02-08', function () { + browser.get('#/02-08'); + + let input = element(by.tagName('input[tohvalidate]')); + expect(input.isPresent()).toBe(true); + }); + + it('03-01', function () { + browser.get('#/03-01'); + + let div = element(by.tagName('sg-app > div')); + expect(div.getText()).toBe('The expected error is 42'); + }); + + it('03-02', function () { + browser.get('#/03-02'); + + let divs = element.all(by.tagName('sg-app > div')); + expect(divs.get(0).getText()).toBe('Heroes url: api/heroes'); + expect(divs.get(1).getText()).toBe('Villains url: api/villains'); + }); + + it('03-03', function () { + browser.get('#/03-03'); + + let div = element(by.tagName('sg-app > div')); + expect(div.getText()).toBe('Our hero is RubberMan and He is so elastic'); + }); + + it('03-04', function () { + browser.get('#/03-04'); + + let buttons = element.all(by.tagName('sg-app > button')); + expect(buttons.get(0).getText()).toBe('Show toast'); + expect(buttons.get(1).getText()).toBe('Hide toast'); + }); + + it('03-06', function () { + browser.get('#/03-06'); + + let div = element(by.tagName('sg-app > div')); + expect(div.getText()).toBe('Actual favorite: Windstorm'); + + let lis = element.all(by.tagName('sg-app > ul > li')); + expect(lis.get(0).getText()).toBe('Windstorm'); + expect(lis.get(1).getText()).toBe('Bombasto'); + expect(lis.get(2).getText()).toBe('Magneta'); + expect(lis.get(3).getText()).toBe('Tornado'); + }); + + it('04-10', function () { + browser.get('#/04-10'); + + let div = element(by.tagName('sg-app > toh-heroes > div')); + expect(div.getText()).toBe('This is heroes component'); + }); + + it('05-02', function () { + browser.get('#/05-02'); + + let button = element(by.tagName('sg-app > toh-hero-button > button')); + expect(button.getText()).toBe('Hero button'); + }); + + it('05-03', function () { + browser.get('#/05-03'); + + let button = element(by.tagName('sg-app > toh-hero-button > button')); + expect(button.getText()).toBe('Hero button'); + }); + + it('05-04', function () { + browser.get('#/05-04'); + + let h2 = element(by.tagName('sg-app > toh-heroes > div > h2')); + expect(h2.getText()).toBe('My Heroes'); + }); + + it('05-12', function () { + browser.get('#/05-12'); + + let button = element(by.tagName('sg-app > toh-hero-button > button')); + expect(button.getText()).toBe('OK'); + }); + + it('05-13', function () { + browser.get('#/05-13'); + + let button = element(by.tagName('sg-app > toh-hero-button > button')); + expect(button.getText()).toBe('OK'); + }); + + it('05-14', function () { + browser.get('#/05-14'); + + let toast = element(by.tagName('sg-app > toh-toast')); + expect(toast.getText()).toBe('...'); + }); + + it('05-15', function () { + browser.get('#/05-15'); + + let heroList = element(by.tagName('sg-app > toh-hero-list')); + expect(heroList.getText()).toBe('...'); + }); + + it('05-16', function () { + browser.get('#/05-16'); + + let hero = element(by.tagName('sg-app > toh-hero')); + expect(hero.getText()).toBe('...'); + }); + + it('05-17', function () { + browser.get('#/05-17'); + + let section = element(by.tagName('sg-app > toh-hero-list > section')); + expect(section.getText()).toContain('Our list of heroes'); + expect(section.getText()).toContain('Total powers'); + expect(section.getText()).toContain('Average power'); + }); + + it('06-01', function () { + browser.get('#/06-01'); + + let div = element(by.tagName('sg-app > div[tohhighlight]')); + expect(div.getText()).toBe('Bombasta'); + }); + + it('06-03', function () { + browser.get('#/06-03'); + + let input = element(by.tagName('input[tohvalidator]')); + expect(input.isPresent()).toBe(true); + }); + + it('07-01', function () { + browser.get('#/07-01'); + + let lis = element.all(by.tagName('sg-app > ul > li')); + expect(lis.get(0).getText()).toBe('Windstorm'); + expect(lis.get(1).getText()).toBe('Bombasto'); + expect(lis.get(2).getText()).toBe('Magneta'); + expect(lis.get(3).getText()).toBe('Tornado'); + }); + + it('07-03', function () { + browser.get('#/07-03'); + + let pre = element(by.tagName('toh-heroes > pre')); + expect(pre.getText()).toContain('[]'); + }); + + it('07-04', function () { + browser.get('#/07-04'); + + let pre = element(by.tagName('toh-app > pre')); + expect(pre.getText()).toContain('[]'); + }); + + it('09-01', function () { + browser.get('#/09-01'); + + let button = element(by.tagName('sg-app > toh-hero-button > button')); + expect(button.getText()).toBe('OK'); + }); +}); diff --git a/public/docs/_examples/style-guide/ts/.gitignore b/public/docs/_examples/style-guide/ts/.gitignore new file mode 100644 index 0000000000..bd6423cecb --- /dev/null +++ b/public/docs/_examples/style-guide/ts/.gitignore @@ -0,0 +1,2 @@ +*.js +!systemjs.custom.js diff --git a/public/docs/_examples/style-guide/ts/example-config.json b/public/docs/_examples/style-guide/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/style-guide/ts/plnkr.json b/public/docs/_examples/style-guide/ts/plnkr.json new file mode 100644 index 0000000000..bf9e9681c5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/plnkr.json @@ -0,0 +1,9 @@ +{ + "description": "Style Guide", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ], + "tags": ["style guide, styleguide"] +} diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/app.component.css b/public/docs/_examples/style-guide/ts/src/01-01/app/app.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/app.component.ts new file mode 100644 index 0000000000..d5bb953540 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/app.component.ts @@ -0,0 +1,14 @@ +// #docregion +import { Component } from '@angular/core'; + +import { HeroService } from './heroes'; + +@Component({ + selector: 'toh-app', + template: ` + + `, + styleUrls: ['./app.component.css'], + providers: [ HeroService ] +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/app.module.ts new file mode 100644 index 0000000000..53f29ea8cb --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/app.module.ts @@ -0,0 +1,27 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; + +@NgModule({ + imports: [ + BrowserModule, + // #enddocregion + RouterModule.forChild([{ path: '01-01', component: AppComponent }]) + // #docregion + ], + declarations: [ + AppComponent, + HeroesComponent + ], + exports: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion + + diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/hero.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/hero.component.avoid.ts new file mode 100644 index 0000000000..853e6ab64e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/hero.component.avoid.ts @@ -0,0 +1,49 @@ +// #docregion +/* avoid */ + +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { NgModule, Component, OnInit } from '@angular/core'; + +class Hero { + id: number; + name: string; +} + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    +
    {{heroes | json}}
    + `, + styleUrls: ['app/app.component.css'] +}) +class AppComponent implements OnInit { + title = 'Tour of Heroes'; + + heroes: Hero[] = []; + + ngOnInit() { + getHeroes().then(heroes => this.heroes = heroes); + } +} + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + exports: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } + +platformBrowserDynamic().bootstrapModule(AppModule); + +const HEROES: Hero[] = [ + {id: 1, name: 'Bombasto'}, + {id: 2, name: 'Tornado'}, + {id: 3, name: 'Magneta'}, +]; + +function getHeroes(): Promise { + return Promise.resolve(HEROES); // TODO: get hero data from the server; +} diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/heroes.component.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..9e3546db90 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/heroes.component.ts @@ -0,0 +1,21 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Hero, HeroService } from './shared'; + +@Component({ + selector: 'toh-heroes', + template: ` +
    {{heroes | json}}
    + ` +}) +export class HeroesComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) {} + + ngOnInit() { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/index.ts new file mode 100644 index 0000000000..a8d7f1d422 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/index.ts @@ -0,0 +1,2 @@ +export * from './shared'; +export * from './heroes.component'; diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..d94e5bacac --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/hero.service.ts @@ -0,0 +1,11 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { HEROES } from './mock-heroes'; + +@Injectable() +export class HeroService { + getHeroes() { + return Promise.resolve(HEROES); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/index.ts new file mode 100644 index 0000000000..c0c1a87eb2 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/index.ts @@ -0,0 +1,3 @@ +export * from './hero.model'; +export * from './hero.service'; +export * from './mock-heroes'; diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/mock-heroes.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/mock-heroes.ts new file mode 100644 index 0000000000..2e9a69f59d --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/heroes/shared/mock-heroes.ts @@ -0,0 +1,8 @@ +// #docregion +import { Hero } from './hero.model'; + +export const HEROES: Hero[] = [ + {id: 1, name: 'Bombasto'}, + {id: 2, name: 'Tornado'}, + {id: 3, name: 'Magneta'}, +]; diff --git a/public/docs/_examples/style-guide/ts/src/01-01/app/index.ts b/public/docs/_examples/style-guide/ts/src/01-01/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/01-01/main.ts b/public/docs/_examples/style-guide/ts/src/01-01/main.ts new file mode 100644 index 0000000000..7e8269bd65 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/01-01/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/style-guide/ts/src/02-05/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/02-05/app/app.component.ts new file mode 100644 index 0000000000..66ebfa954e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-05/app/app.component.ts @@ -0,0 +1,10 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'toh-app', + template: ` + Tour of Heroes + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/02-05/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/02-05/app/app.module.ts new file mode 100644 index 0000000000..306ec125e0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-05/app/app.module.ts @@ -0,0 +1,23 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + // #enddocregion + RouterModule.forChild([{ path: '02-05', component: AppComponent }]) + // #docregion + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion diff --git a/public/docs/_examples/style-guide/ts/src/02-05/main.ts b/public/docs/_examples/style-guide/ts/src/02-05/main.ts new file mode 100644 index 0000000000..6c32161f84 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-05/main.ts @@ -0,0 +1,8 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule) + .then(success => console.log(`Bootstrap success`)) + .catch(err => console.error(err)); diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/app.component.ts new file mode 100644 index 0000000000..c82e12624d --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: ` + + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/app.module.ts new file mode 100644 index 0000000000..4320fe67d5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroComponent } from './heroes'; +import { UsersComponent } from './users'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '02-07', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroComponent, + UsersComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/hero.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/hero.component.avoid.ts new file mode 100644 index 0000000000..976fcb6cdf --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/hero.component.avoid.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; +// #docregion example +/* avoid */ + +// HeroComponent is in the Tour of Heroes feature +@Component({ + selector: 'hero' +}) +export class HeroComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/hero.component.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/hero.component.ts new file mode 100644 index 0000000000..44c04dd855 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/hero.component.ts @@ -0,0 +1,13 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +// #docregion example +@Component({ + // #enddocregion example + template: '
    hero component
    ', + // #docregion example + selector: 'toh-hero' +}) +export class HeroComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/index.ts new file mode 100644 index 0000000000..084f36d703 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './hero.component'; diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/index.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/index.ts new file mode 100644 index 0000000000..fc87f976b3 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/index.ts @@ -0,0 +1,3 @@ +export * from './heroes'; +export * from './users'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/users/index.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/users/index.ts new file mode 100644 index 0000000000..475ba6d2a7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/users/index.ts @@ -0,0 +1 @@ +export * from './users.component'; diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/users/users.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/users/users.component.avoid.ts new file mode 100644 index 0000000000..9a5bd936e9 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/users/users.component.avoid.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; +// #docregion example +/* avoid */ + +// UsersComponent is in an Admin feature +@Component({ + selector: 'users' +}) +export class UsersComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/02-07/app/users/users.component.ts b/public/docs/_examples/style-guide/ts/src/02-07/app/users/users.component.ts new file mode 100644 index 0000000000..2fb6d54ebe --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-07/app/users/users.component.ts @@ -0,0 +1,13 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +// #docregion example +@Component({ + // #enddocregion example + template: '
    users component
    ', + // #docregion example + selector: 'admin-users' +}) +export class UsersComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/app.component.ts new file mode 100644 index 0000000000..bf27aeaf8a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/app.module.ts new file mode 100644 index 0000000000..e840cc50a5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { InputHighlightDirective, + ValidateDirective } from './shared'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '02-08', component: AppComponent }]) + ], + declarations: [ + AppComponent, + InputHighlightDirective, + ValidateDirective + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/index.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/index.ts new file mode 100644 index 0000000000..ebe5c92f03 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/index.ts @@ -0,0 +1,2 @@ +export * from './shared'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/shared/index.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/index.ts new file mode 100644 index 0000000000..b844b75492 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/index.ts @@ -0,0 +1,2 @@ +export * from './input-highlight.directive'; +export * from './validate.directive'; diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/shared/input-highlight.directive.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/input-highlight.directive.ts new file mode 100644 index 0000000000..fd74771981 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/input-highlight.directive.ts @@ -0,0 +1,10 @@ +// #docregion +import { Directive, ElementRef } from '@angular/core'; + +@Directive({ selector: 'input'}) +/** Highlight the attached input text element in blue */ +export class InputHighlightDirective { + constructor(el: ElementRef) { + el.nativeElement.style.backgroundColor = 'powderblue'; + } +} diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/shared/validate.directive.avoid.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/validate.directive.avoid.ts new file mode 100644 index 0000000000..b038f37075 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/validate.directive.avoid.ts @@ -0,0 +1,10 @@ +// #docregion +import { Directive } from '@angular/core'; +// #docregion example +/* avoid */ + +@Directive({ + selector: '[validate]' +}) +export class ValidateDirective {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/02-08/app/shared/validate.directive.ts b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/validate.directive.ts new file mode 100644 index 0000000000..039afb846f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/02-08/app/shared/validate.directive.ts @@ -0,0 +1,9 @@ +// #docregion +import { Directive } from '@angular/core'; + +// #docregion example +@Directive({ + selector: '[tohValidate]' +}) +export class ValidateDirective {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-01/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/03-01/app/app.component.ts new file mode 100644 index 0000000000..cb9479d2d9 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-01/app/app.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; + +import { ExceptionService } from './core'; + +@Component({ + selector: 'sg-app', + template: '
    The expected error is {{errorCode}}
    ', + providers: [ExceptionService] +}) +export class AppComponent implements OnInit { + errorCode: number; + + constructor(private exceptionService: ExceptionService) { } + + ngOnInit() { + this.errorCode = this.exceptionService.getException(); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-01/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/03-01/app/app.module.ts new file mode 100644 index 0000000000..48079f21c7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-01/app/app.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '03-01', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/03-01/app/core/exception.service.avoid.ts b/public/docs/_examples/style-guide/ts/src/03-01/app/core/exception.service.avoid.ts new file mode 100644 index 0000000000..0a22811fe3 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-01/app/core/exception.service.avoid.ts @@ -0,0 +1,11 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +// #docregion example +/* avoid */ + +export class exceptionService { + constructor() { } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-01/app/core/exception.service.ts b/public/docs/_examples/style-guide/ts/src/03-01/app/core/exception.service.ts new file mode 100644 index 0000000000..dd77b4f7dc --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-01/app/core/exception.service.ts @@ -0,0 +1,14 @@ +// #docplaster +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +// #docregion example +export class ExceptionService { + constructor() { } + // #enddocregion example + // testing harness + getException() { return 42; } + // #docregion example +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-01/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/03-01/app/core/index.ts new file mode 100644 index 0000000000..8acaa4bcf9 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-01/app/core/index.ts @@ -0,0 +1 @@ +export * from './exception.service'; diff --git a/public/docs/_examples/style-guide/ts/src/03-01/app/index.ts b/public/docs/_examples/style-guide/ts/src/03-01/app/index.ts new file mode 100644 index 0000000000..e120e2dbfd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-01/app/index.ts @@ -0,0 +1,2 @@ +export * from './core'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/03-02/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/03-02/app/app.component.ts new file mode 100644 index 0000000000..132ea54c85 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-02/app/app.component.ts @@ -0,0 +1,19 @@ +import { Component } from '@angular/core'; + +import { heroesUrl, mockHeroes, VILLAINS_URL } from './core'; + +@Component({ + selector: 'sg-app', + template: ` +
    Heroes url: {{heroesUrl}}
    +
    Villains url: {{villainsUrl}}
    + +

    Mock Heroes

    +
    {{hero}}
    + ` +}) +export class AppComponent { + heroes = mockHeroes; // prefer + heroesUrl = heroesUrl; // prefer + villainsUrl = VILLAINS_URL; // tolerate +} diff --git a/public/docs/_examples/style-guide/ts/src/03-02/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/03-02/app/app.module.ts new file mode 100644 index 0000000000..2db4012ebf --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-02/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '03-02', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/03-02/app/core/data.service.ts b/public/docs/_examples/style-guide/ts/src/03-02/app/core/data.service.ts new file mode 100644 index 0000000000..5c26478c7b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-02/app/core/data.service.ts @@ -0,0 +1,4 @@ +// #docregion +export const mockHeroes = ['Sam', 'Jill']; // prefer +export const heroesUrl = 'api/heroes'; // prefer +export const VILLAINS_URL = 'api/villains'; // tolerate diff --git a/public/docs/_examples/style-guide/ts/src/03-02/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/03-02/app/core/index.ts new file mode 100644 index 0000000000..2ba773ede8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-02/app/core/index.ts @@ -0,0 +1 @@ +export * from './data.service'; diff --git a/public/docs/_examples/style-guide/ts/src/03-02/app/index.ts b/public/docs/_examples/style-guide/ts/src/03-02/app/index.ts new file mode 100644 index 0000000000..e120e2dbfd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-02/app/index.ts @@ -0,0 +1,2 @@ +export * from './core'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/app.component.ts new file mode 100644 index 0000000000..3ca522bc45 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/app.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero, HeroCollectorService } from './core'; + +@Component({ + selector: 'sg-app', + template: '
    Our hero is {{hero.name}} and {{hero.power}}
    ', + providers: [HeroCollectorService] +}) +export class AppComponent implements OnInit { + hero: Hero; + + constructor(private heroCollectorService: HeroCollectorService) { } + + ngOnInit() { + this.hero = this.heroCollectorService.getHero(); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/app.module.ts new file mode 100644 index 0000000000..29b3d2e765 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/app.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '03-03', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero-collector.service.avoid.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero-collector.service.avoid.ts new file mode 100644 index 0000000000..f481af18b6 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero-collector.service.avoid.ts @@ -0,0 +1,15 @@ +// #docregion +// #docregion example +/* avoid */ + +import { Injectable } from '@angular/core'; + +import { IHero } from './hero.model.avoid'; + +@Injectable() +export class HeroCollectorService { + hero: IHero; + + constructor() { } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero-collector.service.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero-collector.service.ts new file mode 100644 index 0000000000..1df5c0deb0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero-collector.service.ts @@ -0,0 +1,25 @@ +// #docplaster +// #docregion +// #docregion example +import { Injectable } from '@angular/core'; + +import { Hero } from './hero.model'; + +@Injectable() +export class HeroCollectorService { + hero: Hero; + + constructor() { } + // #enddocregion example + // testing harness + getHero() { + this.hero = { + name: 'RubberMan', + power: 'He is so elastic' + }; + + return this.hero; + } + // #docregion example +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero.model.avoid.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero.model.avoid.ts new file mode 100644 index 0000000000..ce93b2c59a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero.model.avoid.ts @@ -0,0 +1,14 @@ +// #docregion +// #docregion example +/* avoid */ + +export interface IHero { + name: string; + power: string; +} + +export class Hero implements IHero { + name: string; + power: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero.model.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero.model.ts new file mode 100644 index 0000000000..c3277621cb --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/core/hero.model.ts @@ -0,0 +1,7 @@ +// #docregion +// #docregion example +export class Hero { + name: string; + power: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/core/index.ts new file mode 100644 index 0000000000..17ad67b0b1 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/core/index.ts @@ -0,0 +1,2 @@ +export * from './hero-collector.service'; +export * from './hero.model'; diff --git a/public/docs/_examples/style-guide/ts/src/03-03/app/index.ts b/public/docs/_examples/style-guide/ts/src/03-03/app/index.ts new file mode 100644 index 0000000000..e120e2dbfd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-03/app/index.ts @@ -0,0 +1,2 @@ +export * from './core'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/03-04/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/03-04/app/app.component.ts new file mode 100644 index 0000000000..555c9e9441 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-04/app/app.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; + +import { ToastService } from './core'; + +@Component({ + selector: 'sg-app', + template: ` + + + `, + providers: [ToastService] +}) +export class AppComponent implements OnInit { + constructor(private toastService: ToastService) { } + + hide() { + this.toastService.hide(); + } + + show() { + this.toastService.show(); + } + + ngOnInit() { + this.toastService.activate('Hello style-guide!'); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-04/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/03-04/app/app.module.ts new file mode 100644 index 0000000000..a5a8d5bb4e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-04/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '03-04', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/03-04/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/03-04/app/core/index.ts new file mode 100644 index 0000000000..e78b628f9c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-04/app/core/index.ts @@ -0,0 +1 @@ +export * from './toast.service'; diff --git a/public/docs/_examples/style-guide/ts/src/03-04/app/core/toast.service.avoid.ts b/public/docs/_examples/style-guide/ts/src/03-04/app/core/toast.service.avoid.ts new file mode 100644 index 0000000000..0f3a7c25ea --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-04/app/core/toast.service.avoid.ts @@ -0,0 +1,27 @@ +// #docregion +// #docregion example +/* avoid */ + +import { Injectable } from '@angular/core'; + +@Injectable() +export class ToastService { + message: string; + + private _toastCount: number; + + hide() { + this._toastCount--; + this._log(); + } + + show() { + this._toastCount++; + this._log(); + } + + private _log() { + console.log(this.message); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-04/app/core/toast.service.ts b/public/docs/_examples/style-guide/ts/src/03-04/app/core/toast.service.ts new file mode 100644 index 0000000000..ab148a1732 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-04/app/core/toast.service.ts @@ -0,0 +1,32 @@ +// #docplaster +// #docregion +// #docregion example +import { Injectable } from '@angular/core'; + +@Injectable() +export class ToastService { + message: string; + + private toastCount: number; + + hide() { + this.toastCount--; + this.log(); + } + + show() { + this.toastCount++; + this.log(); + } + + private log() { + console.log(this.message); + } + // #enddocregion example + // testing harness + activate(message: string) { + this.message = message; + } + // #docregion example +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-04/app/index.ts b/public/docs/_examples/style-guide/ts/src/03-04/app/index.ts new file mode 100644 index 0000000000..e120e2dbfd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-04/app/index.ts @@ -0,0 +1,2 @@ +export * from './core'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/app.component.html b/public/docs/_examples/style-guide/ts/src/03-06/app/app.component.html new file mode 100644 index 0000000000..67fb0d5964 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/app.component.html @@ -0,0 +1,6 @@ +
    Actual favorite: {{favorite?.name}}
    +
      +
    • + {{hero.name}} +
    • +
    diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/app.component.ts new file mode 100644 index 0000000000..8ec308bc6a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/app.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero, HeroService } from './heroes'; +import { ExceptionService, SpinnerService, ToastService } from './core'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html', + providers: [HeroService, ExceptionService, SpinnerService, ToastService] +}) +export class AppComponent implements OnInit { + favorite: Hero; + heroes: Hero[]; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.heroService.getHero(1).subscribe(hero => this.favorite = hero); + this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/app.module.ts new file mode 100644 index 0000000000..f259ce23a2 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '03-06', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/exception.service.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/exception.service.ts new file mode 100644 index 0000000000..7180c88e6b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/exception.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class ExceptionService { } diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/index.ts new file mode 100644 index 0000000000..e4e6723f91 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/index.ts @@ -0,0 +1,6 @@ +// #docregion +// #docregion example +export * from './exception.service'; +export * from './spinner'; +export * from './toast'; +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/index.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/index.ts new file mode 100644 index 0000000000..1d619300c0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/index.ts @@ -0,0 +1,3 @@ +// #docregion +export * from './spinner.component'; +export * from './spinner.service'; diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/spinner.component.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/spinner.component.ts new file mode 100644 index 0000000000..1fd2a01500 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/spinner.component.ts @@ -0,0 +1,16 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; + +import { SpinnerService } from './spinner.service'; + +@Component({ + selector: 'toh-spinner', + template: '
    spinner
    ' +}) + +export class SpinnerComponent implements OnDestroy, OnInit { + constructor(private spinnerService: SpinnerService) { } + + ngOnInit() { } + + ngOnDestroy() { } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/spinner.service.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/spinner.service.ts new file mode 100644 index 0000000000..ad5d2ed6e0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/spinner/spinner.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@angular/core'; + +export interface ISpinnerState { } + +@Injectable() +export class SpinnerService { + spinnerState: any; + + show() { } + + hide() { } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/index.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/index.ts new file mode 100644 index 0000000000..01b41aff98 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/index.ts @@ -0,0 +1,3 @@ +// #docregion +export * from './toast.component'; +export * from './toast.service'; diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/toast.component.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/toast.component.ts new file mode 100644 index 0000000000..dd0bba5eba --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/toast.component.ts @@ -0,0 +1,13 @@ +import { Component, OnInit } from '@angular/core'; + +import { ToastService } from './toast.service'; + +@Component({ + selector: 'toh-toast', + template: '
    toast
    ' +}) +export class ToastComponent implements OnInit { + constructor(toastService: ToastService) { } + + ngOnInit() { } +} diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/toast.service.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/toast.service.ts new file mode 100644 index 0000000000..e92e75ee45 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/core/toast/toast.service.ts @@ -0,0 +1,6 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class ToastService { + activate: (message?: string, title?: string) => void; +} diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..c3277621cb --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.model.ts @@ -0,0 +1,7 @@ +// #docregion +// #docregion example +export class Hero { + name: string; + power: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.service.avoid.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.service.avoid.ts new file mode 100644 index 0000000000..8287c567a7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.service.avoid.ts @@ -0,0 +1,32 @@ +// #docregion +// #docregion example +/* avoid */ + +import { ExceptionService, SpinnerService, ToastService } from '../../core'; +import { Http } from '@angular/http'; +import { Injectable } from '@angular/core'; +import { Hero } from './hero.model'; +// #enddocregion example + +@Injectable() +export class HeroService { + + constructor( + private exceptionService: ExceptionService, + private spinnerService: SpinnerService, + private toastService: ToastService, + private http: Http + ) { } + + getHero(id: number) { + return this.http.get(`api/heroes/${id}`) + .map(response => response.json().data as Hero); + } + + getHeroes() { + return this.http.get(`api/heroes`) + .map(response => response.json().data as Hero[]); + } + +} + diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..5792cd1ab2 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/hero.service.ts @@ -0,0 +1,32 @@ +// #docregion +// #docregion example +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Hero } from './hero.model'; +import { ExceptionService, SpinnerService, ToastService } from '../../core'; +// #enddocregion example + +@Injectable() +export class HeroService { + cachedHeroes: Hero[]; + + constructor( + private exceptionService: ExceptionService, + private spinnerService: SpinnerService, + private toastService: ToastService, + private http: Http + ) { } + + getHero(id: number) { + return this.http.get(`api/heroes/${id}`) + .map(response => response.json().data as Hero); + } + + getHeroes() { + return this.http.get(`api/heroes`) + .map(response => response.json().data as Hero[]); + } + +} + diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/index.ts new file mode 100644 index 0000000000..dbb150d3f8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/heroes/shared/index.ts @@ -0,0 +1,2 @@ +export * from './hero.model'; +export * from './hero.service'; diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/index.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/index.ts new file mode 100644 index 0000000000..cf861e261a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/index.ts @@ -0,0 +1,3 @@ +export * from './heroes'; +export * from './core'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/03-06/app/shared/toast/toast.component.ts b/public/docs/_examples/style-guide/ts/src/03-06/app/shared/toast/toast.component.ts new file mode 100644 index 0000000000..e1c1ae6665 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/03-06/app/shared/toast/toast.component.ts @@ -0,0 +1,13 @@ +import { Component, OnInit } from '@angular/core'; + +import { ToastService } from '../../core'; + +@Component({ + selector: 'toh-toast', + template: '
    toast
    ' +}) +export class ToastComponent implements OnInit { + constructor(toastService: ToastService) { } + + ngOnInit() { } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-08/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/04-08/app/app.component.ts new file mode 100644 index 0000000000..fdd8e6ef56 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-08/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/04-08/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/04-08/app/app.module.ts new file mode 100644 index 0000000000..25568b7fb4 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-08/app/app.module.ts @@ -0,0 +1,28 @@ +// #docplaster +// #docregion +// #docregion example +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +// #enddocregion example +import { RouterModule } from '@angular/router'; +// #docregion example + +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; + +@NgModule({ + imports: [ + BrowserModule, +// #enddocregion example + RouterModule.forChild([{ path: '04-08', component: AppComponent }]) +// #docregion example + ], + declarations: [ + AppComponent, + HeroesComponent + ], + exports: [ AppComponent ], + entryComponents: [ AppComponent ] +}) +export class AppModule {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/04-08/app/heroes/heroes.component.html b/public/docs/_examples/style-guide/ts/src/04-08/app/heroes/heroes.component.html new file mode 100644 index 0000000000..1244e68a4a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-08/app/heroes/heroes.component.html @@ -0,0 +1 @@ +
    This is heroes component
    diff --git a/public/docs/_examples/style-guide/ts/src/04-08/app/heroes/heroes.component.ts b/public/docs/_examples/style-guide/ts/src/04-08/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..e2df4c91fd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-08/app/heroes/heroes.component.ts @@ -0,0 +1,11 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'toh-heroes', + templateUrl: './heroes.component.html' +}) +export class HeroesComponent implements OnInit { + constructor() { /* ... */ } + + ngOnInit() { /* ... */ } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/app.component.ts new file mode 100644 index 0000000000..fdd8e6ef56 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/app.module.ts new file mode 100644 index 0000000000..78106657ad --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/app.module.ts @@ -0,0 +1,30 @@ +// #docplaster +// #docregion +// #docregion example +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +// #enddocregion example +import { RouterModule } from '@angular/router'; +// #docregion example + +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { SharedModule } from './shared/shared.module'; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule, +// #enddocregion example + RouterModule.forChild([{ path: '04-10', component: AppComponent }]) +// #docregion example + ], + declarations: [ + AppComponent, + HeroesComponent + ], + exports: [ AppComponent ], + entryComponents: [ AppComponent ] +}) +export class AppModule {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/heroes/heroes.component.html b/public/docs/_examples/style-guide/ts/src/04-10/app/heroes/heroes.component.html new file mode 100644 index 0000000000..170f76aee1 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/heroes/heroes.component.html @@ -0,0 +1,8 @@ + +
    This is heroes component
    +
      +
    • + {{hero.name}} +
    • +
    + diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/heroes/heroes.component.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..376567650e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/heroes/heroes.component.ts @@ -0,0 +1,27 @@ +// #docregion +import { Component } from '@angular/core'; + +import { FilterTextService } from '../shared/filter-text/filter-text.service'; + +@Component({ + selector: 'toh-heroes', + templateUrl: './heroes.component.html' +}) +export class HeroesComponent { + + heroes = [ + { id: 1, name: 'Windstorm' }, + { id: 2, name: 'Bombasto' }, + { id: 3, name: 'Magneta' }, + { id: 4, name: 'Tornado' } + ]; + + filteredHeroes = this.heroes; + + constructor(private filterService: FilterTextService) { } + + filterChanged(searchText: string) { + this.filteredHeroes = this.filterService.filter(searchText, ['id', 'name'], this.heroes); + } +} + diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/shared/filter-text/filter-text.component.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/filter-text/filter-text.component.ts new file mode 100644 index 0000000000..fffe4bf0b7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/filter-text/filter-text.component.ts @@ -0,0 +1,26 @@ +// #docregion +import { Component, EventEmitter, Output } from '@angular/core'; + +@Component({ + selector: 'toh-filter-text', + template: '' +}) +export class FilterTextComponent { + @Output() changed: EventEmitter; + + filter: string; + + constructor() { + this.changed = new EventEmitter(); + } + + clear() { + this.filter = ''; + } + + filterChanged(event: any) { + event.preventDefault(); + console.log(`Filter Changed: ${this.filter}`); + this.changed.emit(this.filter); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/shared/filter-text/filter-text.service.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/filter-text/filter-text.service.ts new file mode 100644 index 0000000000..87978e10e5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/filter-text/filter-text.service.ts @@ -0,0 +1,30 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +export class FilterTextService { + constructor() { + console.log('Created an instance of FilterTextService'); + } + + filter(data: string, props: Array, originalList: Array) { + let filteredList: any[]; + if (data && props && originalList) { + data = data.toLowerCase(); + let filtered = originalList.filter(item => { + let match = false; + for (let prop of props) { + if (item[prop].toString().toLowerCase().indexOf(data) > -1) { + match = true; + break; + } + }; + return match; + }); + filteredList = filtered; + } else { + filteredList = originalList; + } + return filteredList; + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/shared/init-caps.pipe.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/init-caps.pipe.ts new file mode 100644 index 0000000000..5019bcb234 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/init-caps.pipe.ts @@ -0,0 +1,7 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ name: 'initCaps' }) +export class InitCapsPipe implements PipeTransform { + transform = (value: string) => value; +} diff --git a/public/docs/_examples/style-guide/ts/src/04-10/app/shared/shared.module.ts b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/shared.module.ts new file mode 100644 index 0000000000..6160abcc84 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-10/app/shared/shared.module.ts @@ -0,0 +1,24 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { FilterTextComponent } from './filter-text/filter-text.component'; +import { FilterTextService } from './filter-text/filter-text.service'; +import { InitCapsPipe } from './init-caps.pipe'; + +@NgModule({ + imports: [CommonModule, FormsModule], + declarations: [ + FilterTextComponent, + InitCapsPipe + ], + providers: [FilterTextService], + exports: [ + CommonModule, + FormsModule, + FilterTextComponent, + InitCapsPipe + ] +}) +export class SharedModule { } diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/app.component.ts new file mode 100644 index 0000000000..693619a982 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/app.component.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'toh-app', + template: ` + + + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/app.module.ts new file mode 100644 index 0000000000..ef3c156bcf --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/app.module.ts @@ -0,0 +1,30 @@ +// #docplaster +// #docregion +// #docregion example +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +// #enddocregion example +import { RouterModule } from '@angular/router'; +// #docregion example + +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { CoreModule } from './core/core.module'; + +@NgModule({ + imports: [ + BrowserModule, + CoreModule, +// #enddocregion example + RouterModule.forChild([{ path: '04-11', component: AppComponent }]) +// #docregion example + ], + declarations: [ + AppComponent, + HeroesComponent + ], + exports: [ AppComponent ], + entryComponents: [ AppComponent ] +}) +export class AppModule {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/core.module.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/core/core.module.ts new file mode 100644 index 0000000000..4ba5c79a14 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/core.module.ts @@ -0,0 +1,19 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { LoggerService } from './logger.service'; +import { NavComponent } from './nav/nav.component'; +import { SpinnerComponent } from './spinner/spinner.component'; +import { SpinnerService } from './spinner/spinner.service'; + +@NgModule({ + imports: [ + CommonModule // we use ngFor + ], +  exports: [NavComponent, SpinnerComponent], +  declarations: [NavComponent, SpinnerComponent], + providers: [LoggerService, SpinnerService] +}) +export class CoreModule { } + diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/core/index.ts new file mode 100644 index 0000000000..098f40c7d5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/index.ts @@ -0,0 +1,4 @@ +// #docregion +export * from './logger.service'; +export * from './spinner/spinner.service'; +export * from './nav/nav.component'; diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/logger.service.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/core/logger.service.ts new file mode 100644 index 0000000000..9c7080f07a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/logger.service.ts @@ -0,0 +1,13 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +export class LoggerService { + log(msg: string) { + console.log(msg); + } + + error(msg: string) { + console.error(msg); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.css b/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.css new file mode 100644 index 0000000000..c7903fd25c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.css @@ -0,0 +1,63 @@ +/*#docregion*/ +.mdl-layout__header { + display: flex; + position: fixed; + background-color: #222; +} + +.nav-link { + padding: 0 1em; + width: 100px; + color: rgba(255,255,255,.6); + text-align: center; + text-decoration: none; +} + +.nav-link.router-link-active { + color: rgba(255,255,255, 1); +} + +.nav-link.router-link-active::after { + height: 3px; + width: 100%; + display: block; + content: " "; + bottom: 0; + left: 0; + position: inherit; + background: rgb(83,109,254); +} + +.md-title-icon > i { + background-image: url("assets/ng.png"); + background-repeat: no-repeat; + background-position: center center; + padding: 1em 2em; +} + +.mdl-layout__header-row { + height: 56px; + padding: 0 16px 0 72px; + padding-left: 8px; + background-color: #673AB7; + background: #0033FF; + background-color: #222; +} + +#reset-button { + position: fixed; + right: 2em; + top: 1em; +} + +@media (max-width: 480px) { + #reset-button { + display: none + } +} + +@media (max-width: 320px) { + a.nav-link { + font-size: 12px; + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.html b/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.html new file mode 100644 index 0000000000..b3c7e441e0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.html @@ -0,0 +1,14 @@ + +
    +
    +

    Tour of Heroes

    +
    + +
    +
    diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.ts new file mode 100644 index 0000000000..7e21016e2b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/nav/nav.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'toh-nav', + templateUrl: './nav.component.html', + styleUrls: ['./nav.component.css'], +}) +export class NavComponent implements OnInit { + menuItems = [ + 'Heroes', + 'Villains', + 'Other' + ]; + + ngOnInit() { } + + constructor() { } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.css b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.css new file mode 100644 index 0000000000..afad0fe8e3 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.css @@ -0,0 +1,21 @@ +/*#docregion*/ +.spinner { + position: absolute; + left: 7em; + top: 20em; + position: absolute; + background-color: blue; + height: .3em; + width: 6em; + margin:-60px 0 0 -60px; + -webkit-animation:spin 4s linear infinite; + -moz-animation:spin 4s linear infinite; + animation:spin 4s linear infinite; +} +@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } } +@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } +@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } + +.spinner-hidden { + display:none; +} diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.html b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.html new file mode 100644 index 0000000000..a07e3378c0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.html @@ -0,0 +1,2 @@ + +
    diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.ts new file mode 100644 index 0000000000..de24167a2b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.component.ts @@ -0,0 +1,35 @@ +// #docregion +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs/Subscription'; + +import { LoggerService } from '../logger.service'; +import { SpinnerState, SpinnerService } from './spinner.service'; + +@Component({ + selector: 'toh-spinner', + templateUrl: './spinner.component.html', + styleUrls: ['./spinner.component.css'] +}) +export class SpinnerComponent implements OnDestroy, OnInit { + visible = false; + + private spinnerStateChanged: Subscription; + + constructor( + private loggerService: LoggerService, + private spinnerService: SpinnerService + ) { } + + ngOnInit() { + console.log(this.visible); + this.spinnerStateChanged = this.spinnerService.spinnerState + .subscribe((state: SpinnerState) => { + this.visible = state.show; + this.loggerService.log(`visible=${this.visible}`); + }); + } + + ngOnDestroy() { + this.spinnerStateChanged.unsubscribe(); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.service.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.service.ts new file mode 100644 index 0000000000..85e366c43e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/core/spinner/spinner.service.ts @@ -0,0 +1,24 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +export interface SpinnerState { + show: boolean; +} + +@Injectable() +export class SpinnerService { + private spinnerSubject = new Subject(); + + spinnerState = this.spinnerSubject.asObservable(); + + constructor() { } + + show() { + this.spinnerSubject.next({ show: true }); + } + + hide() { + this.spinnerSubject.next({ show: false }); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/heroes/heroes.component.html b/public/docs/_examples/style-guide/ts/src/04-11/app/heroes/heroes.component.html new file mode 100644 index 0000000000..9035a4b8ff --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/heroes/heroes.component.html @@ -0,0 +1,12 @@ + +
    + + + +
      +
    • + {{hero.name}} +
    • +
    + +
    diff --git a/public/docs/_examples/style-guide/ts/src/04-11/app/heroes/heroes.component.ts b/public/docs/_examples/style-guide/ts/src/04-11/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..856baadd74 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-11/app/heroes/heroes.component.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; + +import { LoggerService } from '../core/logger.service'; +import { SpinnerService } from '../core/spinner/spinner.service'; + +@Component({ + selector: 'toh-heroes', + templateUrl: './heroes.component.html' +}) +export class HeroesComponent { + heroes: any[]; + + constructor( + private loggerService: LoggerService, + private spinnerService: SpinnerService + ) { } + + getHeroes() { + this.loggerService.log(`Getting heroes`); + this.spinnerService.show(); + setTimeout(() => { + this.heroes = [ + { id: 1, name: 'Windstorm' }, + { id: 2, name: 'Bombasto' }, + { id: 3, name: 'Magneta' }, + { id: 4, name: 'Tornado' } + ]; + this.loggerService.log(`We have ${HeroesComponent.length} heroes`); + this.spinnerService.hide(); + }, 2000); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/app.component.ts new file mode 100644 index 0000000000..dc85b06e9f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/app.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'toh-app', + template: ` + + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/app.module.ts new file mode 100644 index 0000000000..7c9fb44182 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/app.module.ts @@ -0,0 +1,30 @@ +// #docplaster +// #docregion +// #docregion example +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +// #enddocregion example +import { RouterModule } from '@angular/router'; +// #docregion example + +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes/heroes.component'; +import { CoreModule } from './core/core.module'; + +@NgModule({ + imports: [ + BrowserModule, + CoreModule, +// #enddocregion example + RouterModule.forChild([{ path: '04-12', component: AppComponent }]) +// #docregion example + ], + declarations: [ + AppComponent, + HeroesComponent + ], + exports: [ AppComponent ], + entryComponents: [ AppComponent ] +}) +export class AppModule {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/core.module.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/core/core.module.ts new file mode 100644 index 0000000000..069141bf2a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/core.module.ts @@ -0,0 +1,21 @@ +// #docregion +import { NgModule, Optional, SkipSelf } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { LoggerService } from './logger.service'; +import { NavComponent } from './nav/nav.component'; +import { throwIfAlreadyLoaded } from './module-import-guard'; + +@NgModule({ + imports: [ + CommonModule // we use ngFor + ], +  exports: [NavComponent], +  declarations: [NavComponent], + providers: [LoggerService] +}) +export class CoreModule { + constructor( @Optional() @SkipSelf() parentModule: CoreModule) { + throwIfAlreadyLoaded(parentModule, 'CoreModule'); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/index.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/core/index.ts new file mode 100644 index 0000000000..8768b77f41 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/index.ts @@ -0,0 +1,3 @@ +// #docregion +export * from './logger.service'; +export * from './nav/nav.component'; diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/logger.service.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/core/logger.service.ts new file mode 100644 index 0000000000..9c7080f07a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/logger.service.ts @@ -0,0 +1,13 @@ +// #docregion +import { Injectable } from '@angular/core'; + +@Injectable() +export class LoggerService { + log(msg: string) { + console.log(msg); + } + + error(msg: string) { + console.error(msg); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/module-import-guard.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/core/module-import-guard.ts new file mode 100644 index 0000000000..5248b15b2e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/module-import-guard.ts @@ -0,0 +1,6 @@ +// #docregion +export function throwIfAlreadyLoaded(parentModule: any, moduleName: string) { + if (parentModule) { + throw new Error(`${moduleName} has already been loaded. Import Core modules in the AppModule only.`); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.css b/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.css new file mode 100644 index 0000000000..c7903fd25c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.css @@ -0,0 +1,63 @@ +/*#docregion*/ +.mdl-layout__header { + display: flex; + position: fixed; + background-color: #222; +} + +.nav-link { + padding: 0 1em; + width: 100px; + color: rgba(255,255,255,.6); + text-align: center; + text-decoration: none; +} + +.nav-link.router-link-active { + color: rgba(255,255,255, 1); +} + +.nav-link.router-link-active::after { + height: 3px; + width: 100%; + display: block; + content: " "; + bottom: 0; + left: 0; + position: inherit; + background: rgb(83,109,254); +} + +.md-title-icon > i { + background-image: url("assets/ng.png"); + background-repeat: no-repeat; + background-position: center center; + padding: 1em 2em; +} + +.mdl-layout__header-row { + height: 56px; + padding: 0 16px 0 72px; + padding-left: 8px; + background-color: #673AB7; + background: #0033FF; + background-color: #222; +} + +#reset-button { + position: fixed; + right: 2em; + top: 1em; +} + +@media (max-width: 480px) { + #reset-button { + display: none + } +} + +@media (max-width: 320px) { + a.nav-link { + font-size: 12px; + } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.html b/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.html new file mode 100644 index 0000000000..b3c7e441e0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.html @@ -0,0 +1,14 @@ + +
    +
    +

    Tour of Heroes

    +
    + +
    +
    diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.ts new file mode 100644 index 0000000000..7e21016e2b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/core/nav/nav.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'toh-nav', + templateUrl: './nav.component.html', + styleUrls: ['./nav.component.css'], +}) +export class NavComponent implements OnInit { + menuItems = [ + 'Heroes', + 'Villains', + 'Other' + ]; + + ngOnInit() { } + + constructor() { } +} diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/heroes/heroes.component.html b/public/docs/_examples/style-guide/ts/src/04-12/app/heroes/heroes.component.html new file mode 100644 index 0000000000..9035a4b8ff --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/heroes/heroes.component.html @@ -0,0 +1,12 @@ + +
    + + + +
      +
    • + {{hero.name}} +
    • +
    + +
    diff --git a/public/docs/_examples/style-guide/ts/src/04-12/app/heroes/heroes.component.ts b/public/docs/_examples/style-guide/ts/src/04-12/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..f84b16c140 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/04-12/app/heroes/heroes.component.ts @@ -0,0 +1,24 @@ +import { Component } from '@angular/core'; + +import { LoggerService } from '../core/logger.service'; + +@Component({ + selector: 'toh-heroes', + templateUrl: './heroes.component.html' +}) +export class HeroesComponent { + heroes: any[]; + + constructor(private loggerService: LoggerService) { } + + getHeroes() { + this.loggerService.log(`Getting heroes`); + this.heroes = [ + { id: 1, name: 'Windstorm' }, + { id: 2, name: 'Bombasto' }, + { id: 3, name: 'Magneta' }, + { id: 4, name: 'Tornado' } + ]; + this.loggerService.log(`We have ${HeroesComponent.length} heroes`); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/app.component.html b/public/docs/_examples/style-guide/ts/src/05-02/app/app.component.html new file mode 100644 index 0000000000..607d068557 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/app.component.html @@ -0,0 +1,2 @@ + + diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/app.component.ts new file mode 100644 index 0000000000..7c9f37919f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/app.module.ts new file mode 100644 index 0000000000..1c458e2ca1 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroButtonComponent } from './heroes'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '05-02', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroButtonComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts new file mode 100644 index 0000000000..e48d41f721 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.avoid.ts @@ -0,0 +1,11 @@ +// #docplaster +import { Component } from '@angular/core'; +// #docregion example +/* avoid */ + +@Component({ + selector: 'tohHeroButton', + templateUrl: './hero-button.component.html' +}) +export class HeroButtonComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.html b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.html new file mode 100644 index 0000000000..9ad67e50ac --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.html @@ -0,0 +1 @@ + diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts new file mode 100644 index 0000000000..c90c966f1a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/hero-button.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero-button', + templateUrl: './hero-button.component.html' +}) +export class HeroButtonComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/index.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/index.ts new file mode 100644 index 0000000000..6bb67c5670 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/hero-button/index.ts @@ -0,0 +1 @@ +export * from './hero-button.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/index.ts new file mode 100644 index 0000000000..2334d49c9a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/heroes/shared/index.ts @@ -0,0 +1 @@ +export * from './hero-button'; diff --git a/public/docs/_examples/style-guide/ts/src/05-02/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-02/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-02/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.avoid.html b/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.avoid.html new file mode 100644 index 0000000000..91bdbe403c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.avoid.html @@ -0,0 +1,4 @@ + + + +
    diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.html b/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.html new file mode 100644 index 0000000000..607d068557 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.html @@ -0,0 +1,2 @@ + + diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.ts new file mode 100644 index 0000000000..7c9f37919f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/app.module.ts new file mode 100644 index 0000000000..1b754e3ee5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroButtonComponent } from './heroes'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '05-03', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroButtonComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts new file mode 100644 index 0000000000..74f5c36339 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.avoid.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +// #docregion example +/* avoid */ + +@Component({ + selector: '[tohHeroButton]', + templateUrl: './hero-button.component.html' +}) +export class HeroButtonComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.html b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.html new file mode 100644 index 0000000000..9ad67e50ac --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.html @@ -0,0 +1 @@ + diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.ts new file mode 100644 index 0000000000..c90c966f1a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/hero-button.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero-button', + templateUrl: './hero-button.component.html' +}) +export class HeroButtonComponent {} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/index.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/index.ts new file mode 100644 index 0000000000..6bb67c5670 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/hero-button/index.ts @@ -0,0 +1 @@ +export * from './hero-button.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/index.ts new file mode 100644 index 0000000000..2334d49c9a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/heroes/shared/index.ts @@ -0,0 +1 @@ +export * from './hero-button'; diff --git a/public/docs/_examples/style-guide/ts/src/05-03/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-03/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-03/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/app.component.ts new file mode 100644 index 0000000000..0e43893f7f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/app.module.ts new file mode 100644 index 0000000000..07f97cc6e4 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/app.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroesComponent } from './heroes'; +import { HeroService } from './heroes/shared'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '05-04', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroesComponent + ], + exports: [ AppComponent ], + providers: [ HeroService ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.avoid.ts new file mode 100644 index 0000000000..0ceb37032d --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.avoid.ts @@ -0,0 +1,64 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + +import { Hero, HeroService } from './shared'; + +// #docregion example +/* avoid */ + +@Component({ + selector: 'toh-heroes', + template: ` +
    +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    +
    +

    {{selectedHero.name | uppercase}} is my hero

    +
    +
    + `, + styles: [` + .heroes { + margin: 0 0 2em 0; list-style-type: none; padding: 0; width: 15em; + } + .heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; + } + .heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; + } + `] +}) +export class HeroesComponent implements OnInit { + heroes: Observable; + selectedHero: Hero; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.heroes = this.heroService.getHeroes(); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.css b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.css new file mode 100644 index 0000000000..82f0c1d0ab --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.css @@ -0,0 +1,28 @@ +/* #docregion */ +.heroes { + margin: 0 0 2em 0; list-style-type: none; padding: 0; width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.html b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.html new file mode 100644 index 0000000000..bab05ceb2b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.html @@ -0,0 +1,12 @@ + +
    +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    +
    +

    {{selectedHero.name | uppercase}} is my hero

    +
    +
    diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.ts new file mode 100644 index 0000000000..c19bc997ae --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/heroes.component.ts @@ -0,0 +1,22 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; + +import { Hero, HeroService } from './shared'; + +// #docregion example +@Component({ + selector: 'toh-heroes', + templateUrl: './heroes.component.html', + styleUrls: ['./heroes.component.css'] +}) +export class HeroesComponent implements OnInit { + heroes: Observable; + selectedHero: Hero; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.heroes = this.heroService.getHeroes(); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/index.ts new file mode 100644 index 0000000000..a8d7f1d422 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/index.ts @@ -0,0 +1,2 @@ +export * from './shared'; +export * from './heroes.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..9d388780a6 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/hero.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +import { Hero } from './hero.model'; + +@Injectable() +export class HeroService { + + constructor(private http: Http) {} + + getHeroes(): Observable { + return this.http.get('api/heroes') + .map(resp => resp.json().data as Hero[]); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/index.ts new file mode 100644 index 0000000000..dbb150d3f8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/heroes/shared/index.ts @@ -0,0 +1,2 @@ +export * from './hero.model'; +export * from './hero.service'; diff --git a/public/docs/_examples/style-guide/ts/src/05-04/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-04/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-04/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/app.component.ts new file mode 100644 index 0000000000..dac40205c9 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/app.module.ts new file mode 100644 index 0000000000..5177b2cc64 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroButtonComponent } from './heroes'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '05-12', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroButtonComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts new file mode 100644 index 0000000000..8f393ddd32 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.avoid.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component, EventEmitter } from '@angular/core'; +// #docregion example +/* avoid */ + +@Component({ + selector: 'toh-hero-button', + template: ``, + inputs: [ + 'label' + ], + outputs: [ + 'change' + ] +}) +export class HeroButtonComponent { + change = new EventEmitter(); + label: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.ts new file mode 100644 index 0000000000..b299740765 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/hero-button.component.ts @@ -0,0 +1,13 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero-button', + template: `` +}) +export class HeroButtonComponent { + @Output() change = new EventEmitter(); + @Input() label: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/index.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/index.ts new file mode 100644 index 0000000000..6bb67c5670 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/hero-button/index.ts @@ -0,0 +1 @@ +export * from './hero-button.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/index.ts new file mode 100644 index 0000000000..2334d49c9a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/heroes/shared/index.ts @@ -0,0 +1 @@ +export * from './hero-button'; diff --git a/public/docs/_examples/style-guide/ts/src/05-12/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-12/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-12/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.avoid.html b/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.avoid.html new file mode 100644 index 0000000000..0a263a6a95 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.avoid.html @@ -0,0 +1,5 @@ + + + + + diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.html b/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.html new file mode 100644 index 0000000000..3cd94ca772 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.html @@ -0,0 +1,6 @@ + + + + + +

    The Great Bombasto

    diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.ts new file mode 100644 index 0000000000..7c9f37919f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/app.module.ts new file mode 100644 index 0000000000..7ebe91dbbc --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroButtonComponent, HeroHighlightDirective } from './heroes'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '05-13', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroButtonComponent, HeroHighlightDirective + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts new file mode 100644 index 0000000000..4e67a14113 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.avoid.ts @@ -0,0 +1,14 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +// #docregion example +/* avoid pointless aliasing */ + +@Component({ + selector: 'toh-hero-button', + template: `` +}) +export class HeroButtonComponent { + // Pointless aliases + @Output('changeEvent') change = new EventEmitter(); + @Input('labelAttribute') label: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.ts new file mode 100644 index 0000000000..af6e7d46b7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/hero-button.component.ts @@ -0,0 +1,14 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +// #docregion example +@Component({ + selector: 'toh-hero-button', + template: `` +}) +export class HeroButtonComponent { + // No aliases + @Output() change = new EventEmitter(); + @Input() label: string; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/index.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/index.ts new file mode 100644 index 0000000000..6bb67c5670 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-button/index.ts @@ -0,0 +1 @@ +export * from './hero-button.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-highlight.directive.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-highlight.directive.ts new file mode 100644 index 0000000000..737af31f4f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/hero-highlight.directive.ts @@ -0,0 +1,15 @@ +// #docregion +import { Directive, ElementRef, Input, OnChanges } from '@angular/core'; + +@Directive({ selector: '[heroHighlight]' }) +export class HeroHighlightDirective implements OnChanges { + + // Aliased because `color` is a better property name than `heroHighlight` + @Input('heroHighlight') color: string; + + constructor(private el: ElementRef) {} + + ngOnChanges() { + this.el.nativeElement.style.backgroundColor = this.color || 'yellow'; + } +} diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/index.ts new file mode 100644 index 0000000000..565f46cf4f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/heroes/shared/index.ts @@ -0,0 +1,2 @@ +export * from './hero-button'; +export * from './hero-highlight.directive'; diff --git a/public/docs/_examples/style-guide/ts/src/05-13/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-13/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-13/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/app.component.ts new file mode 100644 index 0000000000..8ed6da4c82 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: `` +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/app.module.ts new file mode 100644 index 0000000000..0b294573d2 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { ToastComponent } from './shared'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '05-14', component: AppComponent }]) + ], + declarations: [ + AppComponent, + ToastComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/index.ts new file mode 100644 index 0000000000..ebe5c92f03 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/index.ts @@ -0,0 +1,2 @@ +export * from './shared'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/index.ts new file mode 100644 index 0000000000..7ff6d415e7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/index.ts @@ -0,0 +1 @@ +export * from './toast'; diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/index.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/index.ts new file mode 100644 index 0000000000..6502de796e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/index.ts @@ -0,0 +1 @@ +export * from './toast.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/toast.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/toast.component.avoid.ts new file mode 100644 index 0000000000..037ff2c8b5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/toast.component.avoid.ts @@ -0,0 +1,40 @@ +// #docregion +import { OnInit } from '@angular/core'; +// #docregion example +/* avoid */ + +export class ToastComponent implements OnInit { + + private defaults = { + title: '', + message: 'May the Force be with you' + }; + message: string; + title: string; + private toastElement: any; + + ngOnInit() { + this.toastElement = document.getElementById('toh-toast'); + } + + // private methods + private hide() { + this.toastElement.style.opacity = 0; + window.setTimeout(() => this.toastElement.style.zIndex = 0, 400); + } + + activate(message = this.defaults.message, title = this.defaults.title) { + this.title = title; + this.message = message; + this.show(); + } + + private show() { + console.log(this.message); + this.toastElement.style.opacity = 1; + this.toastElement.style.zIndex = 9999; + + window.setTimeout(() => this.hide(), 2500); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/toast.component.ts b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/toast.component.ts new file mode 100644 index 0000000000..d7b8ea4af0 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-14/app/shared/toast/toast.component.ts @@ -0,0 +1,45 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'toh-toast', + template: `...` +}) +// #docregion example +export class ToastComponent implements OnInit { + // public properties + message: string; + title: string; + + // private fields + private defaults = { + title: '', + message: 'May the Force be with you' + }; + private toastElement: any; + + // public methods + activate(message = this.defaults.message, title = this.defaults.title) { + this.title = title; + this.message = message; + this.show(); + } + + ngOnInit() { + this.toastElement = document.getElementById('toh-toast'); + } + + // private methods + private hide() { + this.toastElement.style.opacity = 0; + window.setTimeout(() => this.toastElement.style.zIndex = 0, 400); + } + + private show() { + console.log(this.message); + this.toastElement.style.opacity = 1; + this.toastElement.style.zIndex = 9999; + window.setTimeout(() => this.hide(), 2500); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/app.component.ts new file mode 100644 index 0000000000..91b569b1e7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/app.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; + +import { HeroService } from './heroes'; + +@Component({ + selector: 'sg-app', + template: '', + providers: [HeroService] +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/app.module.ts new file mode 100644 index 0000000000..9bd4b8c9a2 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroListComponent } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '05-15', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroListComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.avoid.ts new file mode 100644 index 0000000000..c323ba2b1c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.avoid.ts @@ -0,0 +1,39 @@ +// #docregion +/* avoid */ + +import { OnInit } from '@angular/core'; +import { Http, Response } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/finally'; +import 'rxjs/add/operator/map'; + +import { Hero } from '../shared/hero.model'; + +const heroesUrl = 'http://angular.io'; + +export class HeroListComponent implements OnInit { + heroes: Hero[]; + constructor(private http: Http) {} + getHeroes() { + this.heroes = []; + this.http.get(heroesUrl) + .map((response: Response) => response.json().data) + .catch(this.catchBadResponse) + .finally(() => this.hideSpinner()) + .subscribe((heroes: Hero[]) => this.heroes = heroes); + } + ngOnInit() { + this.getHeroes(); + } + + private catchBadResponse(err: any, source: Observable) { + // log and handle the exception + return new Observable(); + } + + private hideSpinner() { + // hide the spinner + } +} diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.ts new file mode 100644 index 0000000000..1fdb893c13 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/hero-list.component.ts @@ -0,0 +1,23 @@ +// #docregion example +import { Component, OnInit } from '@angular/core'; + +import { Hero, HeroService } from '../shared'; + +@Component({ + selector: 'toh-hero-list', + template: `...` +}) +export class HeroListComponent implements OnInit { + heroes: Hero[]; + constructor(private heroService: HeroService) {} + getHeroes() { + this.heroes = []; + this.heroService.getHeroes() + .subscribe(heroes => this.heroes = heroes); + } + ngOnInit() { + this.getHeroes(); + } +} +// #enddocregion example + diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/index.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/index.ts new file mode 100644 index 0000000000..c4bcb3278e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/hero-list/index.ts @@ -0,0 +1 @@ +export * from './hero-list.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/index.ts new file mode 100644 index 0000000000..f1112f1c7c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/index.ts @@ -0,0 +1,2 @@ +export * from './hero-list'; +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..72d07bbed4 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/hero.service.ts @@ -0,0 +1,15 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; + +import { Hero } from './hero.model'; + +@Injectable() +export class HeroService { + getHeroes() { + let heroes: Hero[] = []; + return Observable.of(heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/index.ts new file mode 100644 index 0000000000..27516fdedd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/heroes/shared/index.ts @@ -0,0 +1,3 @@ +// #docregion +export * from './hero.model'; +export * from './hero.service'; diff --git a/public/docs/_examples/style-guide/ts/src/05-15/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-15/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-15/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.avoid.html b/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.avoid.html new file mode 100644 index 0000000000..2c0cea58e2 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.avoid.html @@ -0,0 +1,4 @@ + + + + diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.html b/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.html new file mode 100644 index 0000000000..4883a6940a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.html @@ -0,0 +1,2 @@ + + diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.ts new file mode 100644 index 0000000000..7c9f37919f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-16/app/app.module.ts new file mode 100644 index 0000000000..c3fb36f8ac --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroComponent } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '05-16', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/hero.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/hero.component.avoid.ts new file mode 100644 index 0000000000..823aa2e1c7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/hero.component.avoid.ts @@ -0,0 +1,13 @@ +// #docregion +import { Component, EventEmitter, Output } from '@angular/core'; +// #docregion example +/* avoid */ + +@Component({ + selector: 'toh-hero', + template: `...` +}) +export class HeroComponent { + @Output() onSavedTheDay = new EventEmitter(); +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/hero.component.ts b/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/hero.component.ts new file mode 100644 index 0000000000..bbd4a4b5f3 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/hero.component.ts @@ -0,0 +1,14 @@ +// #docregion +import { Component, EventEmitter, Output } from '@angular/core'; + +@Component({ + selector: 'toh-hero', + template: `...` +}) +// #docregion example +export class HeroComponent { + @Output() savedTheDay = new EventEmitter(); +} +// #enddocregion example + + diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/index.ts new file mode 100644 index 0000000000..084f36d703 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './hero.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-16/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-16/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-16/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/app.component.ts new file mode 100644 index 0000000000..86728b8b80 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/app.module.ts new file mode 100644 index 0000000000..e850d80ae3 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/app.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroComponent, HeroListComponent } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '05-17', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroComponent, + HeroListComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.avoid.ts new file mode 100644 index 0000000000..f007512949 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.avoid.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component } from '@angular/core'; + +import { Hero } from '../shared/hero.model'; +// #docregion example +/* avoid */ + +@Component({ + selector: 'toh-hero-list', + template: ` +
    + Our list of heroes: + + + Total powers: {{totalPowers}}
    + Average power: {{totalPowers / heroes.length}} +
    + ` +}) +export class HeroListComponent { + heroes: Hero[]; + totalPowers: number; +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.ts new file mode 100644 index 0000000000..5f18cc5b0c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/hero-list.component.ts @@ -0,0 +1,35 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +import { Hero } from '../shared/hero.model'; + +// #docregion example +@Component({ + selector: 'toh-hero-list', + template: ` +
    + Our list of heroes: + + + Total powers: {{totalPowers}}
    + Average power: {{avgPower}} +
    + ` +}) +export class HeroListComponent { + heroes: Hero[]; + totalPowers: number; + + // #enddocregion example + // testing harness + constructor() { + this.heroes = []; + } + + // #docregion example + get avgPower() { + return this.totalPowers / this.heroes.length; + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/index.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/index.ts new file mode 100644 index 0000000000..c4bcb3278e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero-list/index.ts @@ -0,0 +1 @@ +export * from './hero-list.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero/hero.component.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero/hero.component.ts new file mode 100644 index 0000000000..334f836a7d --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero/hero.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; + +import { Hero } from '../shared/hero.model'; + +@Component({ + selector: 'toh-hero', + template: `...` +}) +export class HeroComponent { + @Input() hero: Hero; +} + + diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero/index.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero/index.ts new file mode 100644 index 0000000000..084f36d703 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/hero/index.ts @@ -0,0 +1 @@ +export * from './hero.component'; diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/index.ts new file mode 100644 index 0000000000..dcf3e79bd3 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/index.ts @@ -0,0 +1,3 @@ +export * from './hero'; +export * from './hero-list'; +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/shared/index.ts new file mode 100644 index 0000000000..0dceb684c4 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/heroes/shared/index.ts @@ -0,0 +1 @@ +export * from './hero.model'; diff --git a/public/docs/_examples/style-guide/ts/src/05-17/app/index.ts b/public/docs/_examples/style-guide/ts/src/05-17/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/05-17/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/06-01/app/app.component.html b/public/docs/_examples/style-guide/ts/src/06-01/app/app.component.html new file mode 100644 index 0000000000..2ccf87d0f5 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-01/app/app.component.html @@ -0,0 +1,2 @@ + +
    Bombasta
    diff --git a/public/docs/_examples/style-guide/ts/src/06-01/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/06-01/app/app.component.ts new file mode 100644 index 0000000000..7c9f37919f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-01/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/06-01/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/06-01/app/app.module.ts new file mode 100644 index 0000000000..318cd306d7 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-01/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HighlightDirective } from './shared'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '06-01', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HighlightDirective + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/06-01/app/index.ts b/public/docs/_examples/style-guide/ts/src/06-01/app/index.ts new file mode 100644 index 0000000000..ebe5c92f03 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-01/app/index.ts @@ -0,0 +1,2 @@ +export * from './shared'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/06-01/app/shared/highlight.directive.ts b/public/docs/_examples/style-guide/ts/src/06-01/app/shared/highlight.directive.ts new file mode 100644 index 0000000000..991a6c5d25 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-01/app/shared/highlight.directive.ts @@ -0,0 +1,13 @@ +// #docregion +import { Directive, HostListener } from '@angular/core'; + +// #docregion example +@Directive({ + selector: '[tohHighlight]' +}) +export class HighlightDirective { + @HostListener('mouseover') onMouseEnter() { + // do highlight work + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/06-01/app/shared/index.ts b/public/docs/_examples/style-guide/ts/src/06-01/app/shared/index.ts new file mode 100644 index 0000000000..105a035680 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-01/app/shared/index.ts @@ -0,0 +1 @@ +export * from './highlight.directive'; diff --git a/public/docs/_examples/style-guide/ts/src/06-03/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/06-03/app/app.component.ts new file mode 100644 index 0000000000..0d0a7d107b --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-03/app/app.component.ts @@ -0,0 +1,9 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: ` + + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/06-03/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/06-03/app/app.module.ts new file mode 100644 index 0000000000..b19f3fdc00 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-03/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { ValidatorDirective, Validator2Directive } from './shared'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '06-03', component: AppComponent }]) + ], + declarations: [ + AppComponent, + ValidatorDirective, Validator2Directive + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/06-03/app/index.ts b/public/docs/_examples/style-guide/ts/src/06-03/app/index.ts new file mode 100644 index 0000000000..ebe5c92f03 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-03/app/index.ts @@ -0,0 +1,2 @@ +export * from './shared'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/06-03/app/shared/index.ts b/public/docs/_examples/style-guide/ts/src/06-03/app/shared/index.ts new file mode 100644 index 0000000000..ba25e4c458 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-03/app/shared/index.ts @@ -0,0 +1,2 @@ +export * from './validator.directive'; +export * from './validator2.directive'; diff --git a/public/docs/_examples/style-guide/ts/src/06-03/app/shared/validator.directive.ts b/public/docs/_examples/style-guide/ts/src/06-03/app/shared/validator.directive.ts new file mode 100644 index 0000000000..d9e32c017f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-03/app/shared/validator.directive.ts @@ -0,0 +1,12 @@ +// #docregion +import { Directive, HostBinding, HostListener } from '@angular/core'; + +@Directive({ + selector: '[tohValidator]' +}) +export class ValidatorDirective { + @HostBinding('attr.role') role = 'button'; + @HostListener('mouseenter') onMouseEnter() { + // do work + } +} diff --git a/public/docs/_examples/style-guide/ts/src/06-03/app/shared/validator2.directive.ts b/public/docs/_examples/style-guide/ts/src/06-03/app/shared/validator2.directive.ts new file mode 100644 index 0000000000..7936a83cb1 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/06-03/app/shared/validator2.directive.ts @@ -0,0 +1,16 @@ +// #docregion +import { Directive } from '@angular/core'; + +@Directive({ + selector: '[tohValidator2]', + host: { + 'attr.role': 'button', + '(mouseenter)': 'onMouseEnter()' + } +}) +export class Validator2Directive { + role = 'button'; + onMouseEnter() { + // do work + } +} diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/app.component.html b/public/docs/_examples/style-guide/ts/src/07-01/app/app.component.html new file mode 100644 index 0000000000..3c05329f3f --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/app.component.html @@ -0,0 +1,5 @@ +
      +
    • + {{hero.name}} +
    • +
    diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/app.component.ts new file mode 100644 index 0000000000..354b0ec303 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/app.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; + +import { Hero, HeroService } from './heroes'; + +@Component({ + selector: 'sg-app', + templateUrl: './app.component.html', + providers: [HeroService] +}) +export class AppComponent implements OnInit { + heroes: Hero[]; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/app.module.ts new file mode 100644 index 0000000000..0077500dea --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '07-01', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..b5aba5d00c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/hero.service.ts @@ -0,0 +1,17 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; + +import { Hero } from './hero.model'; + +@Injectable() +// #docregion example +export class HeroService { + constructor(private http: Http) { } + + getHeroes() { + return this.http.get('api/heroes') + .map((response: Response) => response.json().data); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/index.ts new file mode 100644 index 0000000000..dbb150d3f8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/heroes/shared/index.ts @@ -0,0 +1,2 @@ +export * from './hero.model'; +export * from './hero.service'; diff --git a/public/docs/_examples/style-guide/ts/src/07-01/app/index.ts b/public/docs/_examples/style-guide/ts/src/07-01/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-01/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/app.component.ts new file mode 100644 index 0000000000..f4d25e1ab6 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/app.component.ts @@ -0,0 +1,13 @@ +// #docregion +import { Component } from '@angular/core'; + +import { HeroService } from './heroes'; + +@Component({ + selector: 'toh-app', + template: ` + + `, + providers: [HeroService] +}) +export class AppComponent {} diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/app.module.ts new file mode 100644 index 0000000000..8ba06d22be --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroListComponent } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '07-03', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroListComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/hero-list/hero-list.component.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/hero-list/hero-list.component.ts new file mode 100644 index 0000000000..cf9bb19243 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/hero-list/hero-list.component.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Hero, HeroService } from '../shared'; + +@Component({ + selector: 'toh-heroes', + template: ` +
    {{heroes | json}}
    + ` +}) +export class HeroListComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) { } + + ngOnInit() { + this.heroService.getHeroes().subscribe(heroes => this.heroes = heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/hero-list/index.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/hero-list/index.ts new file mode 100644 index 0000000000..c4bcb3278e --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/hero-list/index.ts @@ -0,0 +1 @@ +export * from './hero-list.component'; diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/index.ts new file mode 100644 index 0000000000..f1112f1c7c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/index.ts @@ -0,0 +1,2 @@ +export * from './hero-list'; +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..72d07bbed4 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/hero.service.ts @@ -0,0 +1,15 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; + +import { Hero } from './hero.model'; + +@Injectable() +export class HeroService { + getHeroes() { + let heroes: Hero[] = []; + return Observable.of(heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/index.ts new file mode 100644 index 0000000000..27516fdedd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/heroes/shared/index.ts @@ -0,0 +1,3 @@ +// #docregion +export * from './hero.model'; +export * from './hero.service'; diff --git a/public/docs/_examples/style-guide/ts/src/07-03/app/index.ts b/public/docs/_examples/style-guide/ts/src/07-03/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-03/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/app.component.ts new file mode 100644 index 0000000000..b0bc9677fe --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/app.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { HeroArena, HeroService, Hero } from './heroes'; + +@Component({ + selector: 'toh-app', + template: '
    {{heroes | json}}
    ', + providers: [HeroArena, HeroService] +}) +export class AppComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroArena: HeroArena) { } + + ngOnInit() { + this.heroArena.getParticipants().subscribe(heroes => this.heroes = heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/app.module.ts new file mode 100644 index 0000000000..71c515c9c9 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + RouterModule.forChild([{ path: '07-04', component: AppComponent }]) + ], + declarations: [ + AppComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.avoid.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.avoid.ts new file mode 100644 index 0000000000..698fa65239 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.avoid.ts @@ -0,0 +1,14 @@ +// #docregion +import { Inject } from '@angular/core'; +import { Http } from '@angular/http'; + +import { HeroService } from './hero.service'; +// #docregion example +/* avoid */ + +export class HeroArena { + constructor( + @Inject(HeroService) private heroService: HeroService, + @Inject(Http) private http: Http) {} +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.ts new file mode 100644 index 0000000000..42bc51f9e9 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero-arena.service.ts @@ -0,0 +1,21 @@ +// #docplaster +// #docregion +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { HeroService } from './index'; + +// #docregion example +@Injectable() +export class HeroArena { + constructor( + private heroService: HeroService, + private http: Http) {} + // #enddocregion example + // test harness + getParticipants() { + return this.heroService.getHeroes(); + } + // #docregion example +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero.model.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero.model.ts new file mode 100644 index 0000000000..8f7cc205c8 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero.model.ts @@ -0,0 +1,5 @@ +// #docregion +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero.service.ts new file mode 100644 index 0000000000..72d07bbed4 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/hero.service.ts @@ -0,0 +1,15 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; + +import { Hero } from './hero.model'; + +@Injectable() +export class HeroService { + getHeroes() { + let heroes: Hero[] = []; + return Observable.of(heroes); + } +} diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/index.ts new file mode 100644 index 0000000000..e8ba54b540 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/heroes/shared/index.ts @@ -0,0 +1,4 @@ +// #docregion +export * from './hero.model'; +export * from './hero.service'; +export * from './hero-arena.service'; diff --git a/public/docs/_examples/style-guide/ts/src/07-04/app/index.ts b/public/docs/_examples/style-guide/ts/src/07-04/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/07-04/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/app.component.ts new file mode 100644 index 0000000000..ebc904f722 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'sg-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/app.module.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/app.module.ts new file mode 100644 index 0000000000..5872e801d6 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/app.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroButtonComponent } from './heroes'; + +@NgModule({ + imports: [ + RouterModule.forChild([{ path: '09-01', component: AppComponent }]) + ], + declarations: [ + AppComponent, + HeroButtonComponent + ], + exports: [ AppComponent ] +}) +export class AppModule {} diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/index.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/index.ts new file mode 100644 index 0000000000..c3da79f741 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/index.ts @@ -0,0 +1 @@ +export * from './shared'; diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts new file mode 100644 index 0000000000..7dc42c2f40 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/hero-button/hero-button.component.avoid.ts @@ -0,0 +1,15 @@ +// #docregion +import { Component } from '@angular/core'; +// #docregion example +/* avoid */ + +@Component({ + selector: 'toh-hero-button', + template: `` +}) +export class HeroButtonComponent implements OnInit { + ngOnInit() { + console.log('The component is initialized'); + } +} +// #enddocregion example diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/hero-button/index.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/hero-button/index.ts new file mode 100644 index 0000000000..6bb67c5670 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/hero-button/index.ts @@ -0,0 +1 @@ +export * from './hero-button.component'; diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/index.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/index.ts new file mode 100644 index 0000000000..2334d49c9a --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/heroes/shared/index.ts @@ -0,0 +1 @@ +export * from './hero-button'; diff --git a/public/docs/_examples/style-guide/ts/src/09-01/app/index.ts b/public/docs/_examples/style-guide/ts/src/09-01/app/index.ts new file mode 100644 index 0000000000..fe8300f1dd --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/09-01/app/index.ts @@ -0,0 +1,2 @@ +export * from './heroes'; +export * from './app.component'; diff --git a/public/docs/_examples/style-guide/ts/src/app/app.component.html b/public/docs/_examples/style-guide/ts/src/app/app.component.html new file mode 100644 index 0000000000..0680b43f9c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/app/app.component.html @@ -0,0 +1 @@ + diff --git a/public/docs/_examples/style-guide/ts/src/app/app.component.ts b/public/docs/_examples/style-guide/ts/src/app/app.component.ts new file mode 100644 index 0000000000..7556beb1ff --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/style-guide/ts/src/app/app.routes.ts b/public/docs/_examples/style-guide/ts/src/app/app.routes.ts new file mode 100644 index 0000000000..bce6b4df06 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/app/app.routes.ts @@ -0,0 +1,8 @@ +import { Routes } from '@angular/router'; + +import { AppComponent as S0101 } from '../01-01/app'; + +export const routes: Routes = [ + { path: '', redirectTo: '/01-01', pathMatch: 'full' }, + { path: '01-01', component: S0101 }, +]; diff --git a/public/docs/_examples/style-guide/ts/src/app/hero-data.ts b/public/docs/_examples/style-guide/ts/src/app/hero-data.ts new file mode 100644 index 0000000000..f3e6feb91c --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/app/hero-data.ts @@ -0,0 +1,11 @@ +export class HeroData { + createDb() { + let heroes = [ + { id: 1, name: 'Windstorm' }, + { id: 2, name: 'Bombasto' }, + { id: 3, name: 'Magneta' }, + { id: 4, name: 'Tornado' } + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/style-guide/ts/src/index.html b/public/docs/_examples/style-guide/ts/src/index.html new file mode 100644 index 0000000000..188c2c26a1 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/index.html @@ -0,0 +1,30 @@ + + + + + + + Style Guide Sample + + + + + + + + + + + + + + + + + loading... + + + + diff --git a/public/docs/_examples/style-guide/ts/src/main.ts b/public/docs/_examples/style-guide/ts/src/main.ts new file mode 100644 index 0000000000..5b4c98ba69 --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/main.ts @@ -0,0 +1,99 @@ +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; + +import { HttpModule } from '@angular/http'; +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; + +import { RouterModule } from '@angular/router'; + +import { HashLocationStrategy, + LocationStrategy } from '@angular/common'; + +import 'rxjs/add/operator/map'; + +import { HeroData } from './app/hero-data'; +import { AppComponent } from './app/app.component'; + +import * as s0101 from './01-01/app/app.module'; +import * as s0205 from './02-05/app/app.module'; +import * as s0207 from './02-07/app/app.module'; +import * as s0208 from './02-08/app/app.module'; +import * as s0301 from './03-01/app/app.module'; +import * as s0302 from './03-02/app/app.module'; +import * as s0303 from './03-03/app/app.module'; +import * as s0304 from './03-04/app/app.module'; +import * as s0306 from './03-06/app/app.module'; +import * as s0408 from './04-08/app/app.module'; +import * as s0410 from './04-10/app/app.module'; +import * as s0411 from './04-11/app/app.module'; +import * as s0412 from './04-12/app/app.module'; +import * as s0502 from './05-02/app/app.module'; +import * as s0503 from './05-03/app/app.module'; +import * as s0504 from './05-04/app/app.module'; +import * as s0512 from './05-12/app/app.module'; +import * as s0513 from './05-13/app/app.module'; +import * as s0514 from './05-14/app/app.module'; +import * as s0515 from './05-15/app/app.module'; +import * as s0516 from './05-16/app/app.module'; +import * as s0517 from './05-17/app/app.module'; +import * as s0601 from './06-01/app/app.module'; +import * as s0603 from './06-03/app/app.module'; +import * as s0701 from './07-01/app/app.module'; +import * as s0703 from './07-03/app/app.module'; +import * as s0704 from './07-04/app/app.module'; +import * as s0901 from './09-01/app/app.module'; + +/////////////////// +const moduleMetadata = { + imports: [ + BrowserModule, + HttpModule, + InMemoryWebApiModule.forRoot(HeroData), + + s0101.AppModule, + s0205.AppModule, + s0207.AppModule, + s0208.AppModule, + s0301.AppModule, + s0302.AppModule, + s0303.AppModule, + s0304.AppModule, + s0306.AppModule, + s0408.AppModule, + s0410.AppModule, + s0411.AppModule, + s0412.AppModule, + s0502.AppModule, + s0503.AppModule, + s0504.AppModule, + s0512.AppModule, + s0513.AppModule, + s0514.AppModule, + s0515.AppModule, + s0516.AppModule, + s0517.AppModule, + s0601.AppModule, + s0603.AppModule, + s0701.AppModule, + s0703.AppModule, + s0704.AppModule, + s0901.AppModule, + + RouterModule.forRoot([ + { path: '', redirectTo: '/01-01', pathMatch: 'full' } + ], {/* enableTracing: true */}), + ], + providers: [ + { provide: LocationStrategy, useClass: HashLocationStrategy } + ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}; + +@NgModule(moduleMetadata) +class MainModule { } + +platformBrowserDynamic().bootstrapModule(MainModule); + + diff --git a/public/docs/_examples/style-guide/ts/src/systemjs.custom.js b/public/docs/_examples/style-guide/ts/src/systemjs.custom.js new file mode 100644 index 0000000000..3424b2b62d --- /dev/null +++ b/public/docs/_examples/style-guide/ts/src/systemjs.custom.js @@ -0,0 +1,51 @@ +(function(global) { + // extra local packages + var packageNames = [ + '01-01', '01-01/app', '01-01/app/heroes', '01-01/app/heroes/shared', + '02-05', '02-05/app', + '02-07', '02-07/app', '02-07/app/heroes', '02-07/app/users', + '02-08', '02-08/app', '02-08/app/shared', + '03-01', '03-01/app', '03-01/app/core', + '03-02', '03-02/app', '03-02/app/core', + '03-03', '03-03/app', '03-03/app/core', + '03-04', '03-04/app', '03-04/app/core', + '03-05', '03-05/app', '03-05/app/core', '03-05/app/core/spinner', '03-05/app/core/toast', + '03-05/app/heroes', '03-05/app/heroes/shared', + '03-06', '03-06/app', '03-06/app/core', '03-06/app/core/spinner', '03-06/app/core/toast', + '03-06/app/heroes', '03-06/app/heroes/shared', + '04-08', '04-08/app', '04-08/app/heroes', + '04-10', '04-10/app', '04-10/app/shared', '04-10/app/heroes', '04-10/app/shared/spinner', '04-10/app/shared/toast', + '04-10/app/shared/filter-text', + '04-11', '04-11/app', '04-11/app/core', '04-11/app/heroes', '04-11/app/core/spinner', + '04-11/app/core/nav', + '04-12', '04-12/app', '04-12/app/core', '04-12/app/heroes', '04-12/app/core/nav', + '05-02', '05-02/app', '05-02/app/heroes', '05-02/app/heroes/shared', '05-02/app/heroes/shared/hero-button', + '05-03', '05-03/app', '05-03/app/heroes', '05-03/app/heroes/shared', '05-03/app/heroes/shared/hero-button', + '05-04', '05-04/app', '05-04/app/heroes', '05-04/app/heroes/shared', + '05-12', '05-12/app', '05-12/app/heroes', '05-12/app/heroes/shared', '05-12/app/heroes/shared/hero-button', + '05-13', '05-13/app', '05-13/app/heroes', '05-13/app/heroes/shared', '05-13/app/heroes/shared/hero-button', + '05-14', '05-14/app', '05-14/app/shared', '05-14/app/shared/toast', + '05-15', '05-15/app', '05-15/app/heroes', '05-15/app/heroes/hero-list', '05-15/app/heroes/shared', + '05-16', '05-16/app', '05-16/app/heroes', + '05-17', '05-17/app', '05-17/app/heroes', '05-17/app/heroes/hero', '05-17/app/heroes/hero-list', + '05-17/app/heroes/shared', + '06-01', '06-01/app', '06-01/app/shared', + '06-03', '06-03/app', '06-03/app/shared', + '07-01', '07-01/app', '07-01/app/heroes', '07-01/app/heroes/shared', + '07-03', '07-03/app', '07-03/app/heroes', '07-03/app/heroes/hero-list', '07-03/app/heroes/shared', + '07-04', '07-04/app', '07-04/app/heroes', '07-04/app/heroes/shared', + '09-01', '09-01/app', '09-01/app/heroes', '09-01/app/heroes/shared', '09-01/app/heroes/shared/hero-button' + ]; + + var packages = {}; + packageNames.forEach(function(pkgName) { + packages[pkgName] = { main: 'index.js', defaultExtension: 'js', meta: { './*.js': { loader: 'systemjs-angular-loader.js' }} }; + }); + + var config = { + packages: packages + } + + System.config(config); + +})(this); diff --git a/public/docs/_examples/styleguide/e2e-spec.js b/public/docs/_examples/styleguide/e2e-spec.js deleted file mode 100644 index 14edeb17ef..0000000000 --- a/public/docs/_examples/styleguide/e2e-spec.js +++ /dev/null @@ -1,27 +0,0 @@ -/*global browser, element, by */ -describe('Getting Started E2E Tests', function() { - - // #docregion shared - var expectedMsg = 'My First Angular 2 App'; - - // tests shared across languages - function sharedTests(basePath) { - beforeEach(function () { - browser.get(basePath + 'index.html'); - }); - - it('should display: '+ expectedMsg, function() { - expect(element(by.id('output')).getText()).toEqual(expectedMsg); - }); - } - // #enddocregion - - describe('Getting Started in JavaScript', function() { - sharedTests('gettingstarted/js/'); - }); - - describe('Getting Started in TypeScript', function() { - sharedTests('gettingstarted/ts/'); - }); - -}); diff --git a/public/docs/_examples/styleguide/e2e-spec.ts b/public/docs/_examples/styleguide/e2e-spec.ts new file mode 100644 index 0000000000..af10d2b71d --- /dev/null +++ b/public/docs/_examples/styleguide/e2e-spec.ts @@ -0,0 +1,16 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('Documentation StyleGuide E2E Tests', function() { + + let expectedMsg = 'My First Angular App'; + + beforeEach(function () { + browser.get(''); + }); + + it('should display: ' + expectedMsg, function() { + expect(element(by.id('output')).getText()).toEqual(expectedMsg); + }); +}); diff --git a/public/docs/_examples/styleguide/js/app.js b/public/docs/_examples/styleguide/js/app.js deleted file mode 100644 index a590cd7ed7..0000000000 --- a/public/docs/_examples/styleguide/js/app.js +++ /dev/null @@ -1,46 +0,0 @@ -(function() { -// #docregion -// #docregion class-w-annotations -var AppComponent = ng - // #docregion component - .Component({ - selector: 'my-app' - }) - // #enddocregion - // #docregion view - .View({ - template: '

    My First Angular 2 App

    ' - }) - // #enddocregion - // #docregion class - .Class({ - constructor: function () { } - }); - // #enddocregion -// #enddocregion - -// #docregion bootstrap -document.addEventListener('DOMContentLoaded', function() { - ng.bootstrap(AppComponent); -}); -// #enddocregion -// #enddocregion - -})(); - -/* Non DSL Approach */ -(function() { - -// #docregion no-dsl -function AppComponent () {} - -AppComponent.annotations = [ - new ng.ComponentAnnotation({ - selector: 'my-app' - }), - new ng.ViewAnnotation({ - template: '

    My First Angular 2 App

    ' - }) -]; -// #enddocregion -})(); diff --git a/public/docs/_examples/styleguide/js/example-config.json b/public/docs/_examples/styleguide/js/example-config.json new file mode 100644 index 0000000000..81f31aaf0d --- /dev/null +++ b/public/docs/_examples/styleguide/js/example-config.json @@ -0,0 +1,3 @@ +{ + "build": "build:babel" +} diff --git a/public/docs/_examples/styleguide/js/index.html b/public/docs/_examples/styleguide/js/index.html deleted file mode 100644 index a4e52d76a2..0000000000 --- a/public/docs/_examples/styleguide/js/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - foo2 - - diff --git a/public/docs/_examples/styleguide/js/src/app.js b/public/docs/_examples/styleguide/js/src/app.js new file mode 100644 index 0000000000..d38669cd78 --- /dev/null +++ b/public/docs/_examples/styleguide/js/src/app.js @@ -0,0 +1,55 @@ +(function(app) { + +// #docregion +// #docregion class-w-annotations +app.AppComponent = + // #docregion component + ng.core.Component({ + selector: 'my-app', + // #enddocregion + // #docregion view + template: '

    My First Angular App

    ' + }) + // #enddocregion + // #docregion class + .Class({ + constructor: function () { } + }); + // #enddocregion +// #enddocregion + +// #docregion bootstrap +app.AppModule = + ng.core.NgModule({ + imports: [ ng.platformBrowser.BrowserModule ], + declarations: [ app.AppComponent ], + bootstrap: [ app.AppComponent ] + }) + .Class({ + constructor: function() {} + }); + +document.addEventListener('DOMContentLoaded', function() { + ng.platformBrowserDynamic + .platformBrowserDynamic() + .bootstrapModule(app.AppModule); +}); +// #enddocregion +// #enddocregion + +})(window.app || (window.app = {})); + +/* Non DSL Approach */ +(function(app) { + +// #docregion no-dsl +app.AppComponent = function AppComponent () {} + +app.AppComponent.annotations = [ + new ng.core.Component({ + selector: 'my-app', + template: '

    My First Angular App

    ' + }) +]; +// #enddocregion +})(window.app || (window.app = {})); diff --git a/public/docs/_examples/styleguide/js/src/index.html b/public/docs/_examples/styleguide/js/src/index.html new file mode 100644 index 0000000000..ac2d34ba5d --- /dev/null +++ b/public/docs/_examples/styleguide/js/src/index.html @@ -0,0 +1,27 @@ + + + + Documentation Style + + + + + + + + + + + + + + + + + + + + foo2 + + + diff --git a/public/docs/_examples/styleguide/package.1.json b/public/docs/_examples/styleguide/package.1.json index 0cf4d51bc0..481f99fb12 100644 --- a/public/docs/_examples/styleguide/package.1.json +++ b/public/docs/_examples/styleguide/package.1.json @@ -7,13 +7,11 @@ "lite": "lite-server", "start": "concurrently \"npm run tsc:w\" \"npm run lite\" " }, - "license": "ISC", + "license": "MIT", "dependencies": { "angular2": "2.0.0-beta.0", "systemjs": "0.19.6", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", + "core-js": "^2.4.0", "rxjs": "5.0.0-beta.0", "zone.js": "0.5.10" }, diff --git a/public/docs/_examples/styleguide/ts/app.js b/public/docs/_examples/styleguide/ts/app.js deleted file mode 100644 index 8a05c64c63..0000000000 --- a/public/docs/_examples/styleguide/ts/app.js +++ /dev/null @@ -1,37 +0,0 @@ -var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); - switch (arguments.length) { - case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); - case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); - case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); - } -}; -var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); -}; -// #docregion -// #docregion import -var angular2_1 = require('angular2/angular2'); -// #enddocregion -// #docregion class-w-annotations -var AppComponent = (function () { - function AppComponent() { - } - AppComponent = __decorate([ - angular2_1.Component({ - selector: 'my-app' - }), - angular2_1.View({ - template: '

    My First Angular 2 App

    ' - }), - __metadata('design:paramtypes', []) - ], AppComponent); - return AppComponent; -})(); -// #enddocregion -// #enddocregion -// #docregion bootstrap -angular2_1.bootstrap(AppComponent); -// #enddocregion -// #enddocregion -//# sourceMappingURL=app.js.map \ No newline at end of file diff --git a/public/docs/_examples/styleguide/ts/app.ts b/public/docs/_examples/styleguide/ts/app.ts deleted file mode 100644 index 1e6cd84e77..0000000000 --- a/public/docs/_examples/styleguide/ts/app.ts +++ /dev/null @@ -1,21 +0,0 @@ -// #docregion -// #docregion import -import {Component, View, bootstrap} from 'angular2/angular2'; -// #enddocregion - -// #docregion class-w-annotations -@Component({ - selector: 'my-app' -}) -@View({ - template: '

    My First Angular 2 App

    ' -}) -// #docregion class -class AppComponent { } -// #enddocregion -// #enddocregion - -// #docregion bootstrap -bootstrap(AppComponent); -// #enddocregion -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/styleguide/ts/dummy.spec.js b/public/docs/_examples/styleguide/ts/dummy.spec.js deleted file mode 100644 index 3e9bcf8842..0000000000 --- a/public/docs/_examples/styleguide/ts/dummy.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -describe("Jasmine sample test", function () { - - it("1+1 should be 2", function () { - - var result = 1 + 1; - - expect(result).toBe(2); - }); -}); \ No newline at end of file diff --git a/public/docs/_examples/styleguide/ts/example-config.json b/public/docs/_examples/styleguide/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/styleguide/ts/index.html b/public/docs/_examples/styleguide/ts/index.html deleted file mode 100644 index fb24181c9e..0000000000 --- a/public/docs/_examples/styleguide/ts/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/styleguide/ts/src/app/app.component.ts b/public/docs/_examples/styleguide/ts/src/app/app.component.ts new file mode 100644 index 0000000000..8b71f6ddc4 --- /dev/null +++ b/public/docs/_examples/styleguide/ts/src/app/app.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; +@Component({ + selector: 'my-app', + template: '

    My First Angular App

    ' +}) +export class AppComponent { } + diff --git a/public/docs/_examples/styleguide/ts/src/app/app.module.ts b/public/docs/_examples/styleguide/ts/src/app/app.module.ts new file mode 100644 index 0000000000..0a9ee6adf7 --- /dev/null +++ b/public/docs/_examples/styleguide/ts/src/app/app.module.ts @@ -0,0 +1,11 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/styleguide/ts/src/index.html b/public/docs/_examples/styleguide/ts/src/index.html new file mode 100644 index 0000000000..5cb8919509 --- /dev/null +++ b/public/docs/_examples/styleguide/ts/src/index.html @@ -0,0 +1,25 @@ + + + + + Documentation Style + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/styleguide/ts/src/main.ts b/public/docs/_examples/styleguide/ts/src/main.ts new file mode 100644 index 0000000000..6b6532d428 --- /dev/null +++ b/public/docs/_examples/styleguide/ts/src/main.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/styles.css b/public/docs/_examples/styles.css deleted file mode 100644 index 054b417f6f..0000000000 --- a/public/docs/_examples/styles.css +++ /dev/null @@ -1,142 +0,0 @@ -/* Master Styles */ -h1 { - color: #369; - font-family: Arial, Helvetica, sans-serif; - font-size: 250%; -} -h2, h3 { - color: #444; - font-family: Arial, Helvetica, sans-serif; - font-weight: lighter; -} -body { - margin: 2em; -} -body, input[text], button { - color: #888; - font-family: Cambria, Georgia; -} -a { - cursor: pointer; - cursor: hand; -} -button { - font-family: Arial; - background-color: #eee; - border: none; - padding: 5px 10px; - border-radius: 4px; - cursor: pointer; - cursor: hand; -} -button:hover { - background-color: #cfd8dc; -} -button:disabled { - background-color: #eee; - color: #aaa; - cursor: auto; -} - -/* Navigation link styles */ -nav a { - padding: 5px 10px; - text-decoration: none; - margin-top: 10px; - display: inline-block; - background-color: #eee; - border-radius: 4px; -} -nav a:visited, a:link { - color: #607D8B; -} -nav a:hover { - color: #039be5; - background-color: #CFD8DC; -} -nav a.router-link-active { - color: #039be5; -} - -/* items class */ -.items { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 24em; -} -.items li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; -} -.items li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; -} -.items li.selected:hover { - background-color: #BBD8DC; - color: white; -} -.items .text { - position: relative; - top: -3px; -} -.items { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 24em; -} -.items li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; -} -.items li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; -} -.items li.selected { - background-color: #CFD8DC; - color: white; -} - -.items li.selected:hover { - background-color: #BBD8DC; -} -.items .text { - position: relative; - top: -3px; -} -.items .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; -} - -/* everywhere else */ -* { - font-family: Arial, Helvetica, sans-serif; -} diff --git a/public/docs/_examples/template-syntax/dart/.analysis_options b/public/docs/_examples/template-syntax/dart/.analysis_options deleted file mode 100644 index d8c582e96f..0000000000 --- a/public/docs/_examples/template-syntax/dart/.analysis_options +++ /dev/null @@ -1,16 +0,0 @@ -# Supported lint rules and documentation: http://dart-lang.github.io/linter/lints/ -linter: - rules: - - always_declare_return_types - - camel_case_types - - empty_constructor_bodies - - annotate_overrides - - avoid_init_to_null - - constant_identifier_names - - one_member_abstracts - - slash_for_doc_comments - - sort_constructors_first - - unnecessary_brace_in_string_interp - -analyzer: - # strong-mode: true diff --git a/public/docs/_examples/template-syntax/dart/lib/app_component.dart b/public/docs/_examples/template-syntax/dart/lib/app_component.dart deleted file mode 100644 index 0963e28b58..0000000000 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.dart +++ /dev/null @@ -1,230 +0,0 @@ -// #docregion -import 'dart:convert'; -import 'dart:html'; - -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; -import 'hero_detail_component.dart'; -import 'my_click_directive.dart'; - -enum Color { red, green, blue } - -@Component( - selector: 'my-app', - templateUrl: 'app_component.html', - directives: const [ - HeroDetailComponent, - BigHeroDetailComponent, - MyClickDirective, - MyClickDirective2 - ]) -class AppComponent implements OnInit, AfterViewInit { - @override - void ngOnInit() { - refreshHeroes(); - } - - @override - void ngAfterViewInit() { - _detectNgForTrackByEffects(); - } - - String heroName; - String help; - String actionName = 'Go for it'; - String badCurly = 'bad curly'; - String classes = 'special'; - bool canSave = true; - bool isActive = false; - bool isSpecial = true; - bool isUnchanged = true; - bool isSelected = false; - Color color = Color.red; - - List heroes; - Hero currentHero; - - // #docregion refresh-heroes - /// Updates [this.heroes] with fresh set of cloned heroes. - void refreshHeroes() { - heroes = mockHeroes.map((hero) => hero.clone()).toList(); - currentHero = heroes[0]; - } - // #enddocregion refresh-heroes - - final Hero nullHero = null; - Map product = {'name': 'frimfram', 'price': 42}; - FormElement form; - String clickity = ''; - String clickMessage = ''; - String clickMessage2 = ''; - final String iconUrl = 'assets/images/ng-logo.png'; - - // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; - // Public Domain terms of use: http://www.wpclipart.com/terms.html - final String heroImageUrl = 'assets/images/hero.png'; - - // villainImageUrl = 'http://www.clker.com/cliparts/u/s/y/L/x/9/villain-man-hi.png' - // Public Domain terms of use http://www.clker.com/disclaimer.html - final String villainImageUrl = 'assets/images/villain.png'; - - void alerter(String msg) { - window.alert(msg); - } - - void callFax(String value) { - alerter('Faxing $value ...'); - } - - void callPhone(String value) { - alerter('Calling $value ...'); - } - - void colorToggle() { - color = (color == Color.red) ? Color.blue : Color.red; - } - - int getVal() => val; - - void onCancel(MouseEvent event) { - DivElement el = event.target; - var evtMsg = event != null ? 'Event target is ${el.innerHtml}.' : ''; - alerter('Canceled. $evtMsg'); - } - - void onClickMe(MouseEvent event) { - DivElement el = event.target; - var evtMsg = event != null ? 'Event target class is ${el.className}.' : ''; - alerter('Click me. $evtMsg'); - } - - void deleteHero([Hero hero]) { - alerter('Deleted hero: ${hero?.firstName}'); - } - - bool onSave([MouseEvent event = null]) { - var evtMsg = - event != null ? ' Event target is ${event.target.innerHtml}.' : ''; - alerter('Saved. $evtMsg'); - return false; - } - - void onSubmit(NgForm form) { - var evtMsg = form.valid - ? ' Form value is ${JSON.encode(form.value)}' - : ' Form is invalid'; - alerter('Form submitted. $evtMsg'); - } - - void setUpperCaseFirstName(String firstName) { - currentHero.firstName = firstName.toUpperCase(); - } - - String getStyles(Element el) { - var showStyles = setStyles(); - return JSON.encode(showStyles); - } - - Map _previousClasses = {}; - // #docregion setClasses - Map setClasses() { - final classes = { - 'saveable': canSave, // true - 'modified': !isUnchanged, // false - 'special': isSpecial // true - }; - // #docregion setClasses - // compensate for DevMode (sigh) - if (JSON.encode(_previousClasses) == - JSON.encode(classes)) return _previousClasses; - _previousClasses = classes; - // #enddocregion setClasses - return classes; - } - // #enddocregion setClasses - - // #docregion setStyles - Map setStyles() { - return { - 'font-style': canSave ? 'italic' : 'normal', // italic - 'font-weight': !isUnchanged ? 'bold' : 'normal', // normal - 'font-size': isSpecial ? '24px' : '8px' // 24px - }; - } - // #enddocregion setStyles - - String title = 'Template Syntax'; - String toeChoice; - String toeChooser(Element picker) { - List choices = picker.children; - for (var i = 0; i < choices.length; i++) { - var choice = choices[i] as CheckboxInputElement; - if (choice.checked) { - toeChoice = choice.value; - return toeChoice; - } - } - - return null; - } - - // #docregion trackByHeroes - int trackByHeroes(int index, Hero hero) => hero.id; - // #enddocregion trackByHeroes - - // #docregion trackById - int trackById(int index, dynamic item) => item.id; - // #enddocregion trackById - - int val = 2; - - //////// Detect effects of NgForTrackBy /////////////// - int heroesNoTrackByChangeCount = 0; - int heroesWithTrackByChangeCount = 0; - - @ViewChildren('noTrackBy') QueryList childrenNoTrackBy; - @ViewChildren('withTrackBy') QueryList childrenWithTrackBy; - - void _detectNgForTrackByEffects() { - /// Converts [viewChildren] to a list of [Element]. - List _extractChildren(QueryList viewChildren) => - viewChildren.toList()[0].nativeElement.children.toList() as List; - - { - // Updates 'without TrackBy' statistics. - List _oldNoTrackBy = _extractChildren(this.childrenNoTrackBy); - - this.childrenNoTrackBy.changes.listen((Iterable changes) { - final newNoTrackBy = _extractChildren(changes); - final isSame = newNoTrackBy.fold(true, (bool isSame, Element elt) { - return isSame && _oldNoTrackBy.contains(elt); - }); - - if (!isSame) { - _oldNoTrackBy = newNoTrackBy; - this.heroesNoTrackByChangeCount++; - } - }); - } - - { - // Updates 'with TrackBy' statistics. - List _oldWithTrackBy = - _extractChildren(this.childrenWithTrackBy); - - this.childrenWithTrackBy.changes.listen((Iterable changes) { - final newWithTrackBy = _extractChildren(changes); - final isSame = newWithTrackBy.fold(true, (bool isSame, Element elt) { - return isSame && _oldWithTrackBy.contains(elt); - }); - - if (!isSame) { - _oldWithTrackBy = newWithTrackBy; - this.heroesWithTrackByChangeCount++; - } - }); - } - } - /////////////////// -} diff --git a/public/docs/_examples/template-syntax/dart/lib/app_component.html b/public/docs/_examples/template-syntax/dart/lib/app_component.html deleted file mode 100644 index 0d6e550e73..0000000000 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.html +++ /dev/null @@ -1,800 +0,0 @@ - - -

    Template Syntax

    -Interpolation
    -Mental Model
    -Buttons
    -Properties vs. Attributes
    -
    -Property Binding
    - -
    -Event Binding
    - -
    -
    Directives
    - -
    -* prefix and <template>
    -Template local variables
    -Inputs and outputs
    -Pipes
    -Elvis ?.
    - - - -

    Interpolation

    - - -

    My current hero is {{currentHero.firstName}}

    - - - -

    - {{title}} - -

    - - - - -

    The sum of 1 + 1 is {{1 + 1}}

    - - - - -

    The sum of 1 + 1 is not {{1 + 1 + getVal()}}

    - - -top - - -

    New Mental Model

    - - - - -
    Mental Model
    - - - -

    - -
    - - -
    Mental Model
    - - - -
    -

    - -
    - - - - -
    -

    - -
    - - - -
    - -
    -

    - - - - -
    click me
    - -{{clickity}} -

    - -
    - - - - Hero Name: {{heroName}} -
    -

    - - - - -

    - - -
    Special
    - -

    - - - - -top - - -

    Property vs. Attribute (img examples)

    - - - -

    - - - - - -top - - -

    Buttons

    - - - - -

    - - -

    - - - -top - - -

    Property Binding

    - - - - - - - - -
    [ngClass] binding to the classes property
    - - - - - - - - - - - - - - - - - - - -Interpolated:
    -Property bound: - -
    The interpolated title is {{title}}
    -
    - - -top - - -

    Attribute Binding

    - - - - - - - - - - -
    One-Two
    FiveSix
    - - -
    - - - - -

    - - -
    - - - - - - - - - - -
    - -top - - -

    Class Binding

    - - - -
    Bad curly special
    - - - - -
    Bad curly
    - - - - - - -
    The class binding is special
    - - - -
    This one is not so special
    - - -
    This class binding is special too
    - -top - - -

    Style Binding

    - - - - - - - - - - - -top - - -

    Event Binding

    - - - - - - - - - -
    - - - -
    click with myClick
    - - -{{clickMessage}} -
    - - - - - - -
    - - - - - -
    Click me -
    Click me too!
    -
    - -

    - - - -
    - -
    - -

    - - -
    - -
    - -

    - -top - - -

    NgModel (two-way) Binding

    - -

    Result: {{currentHero.firstName}}

    - - - - -without NgModel -
    - - - -[(ngModel)] -
    - - - -bindon-ngModel -
    - - - -(ngModelChange) = "...firstName=$event" -
    - - - -(ngModelChange) = "setUpperCaseFirstName($event)" -
    - -top - - -

    NgClass Binding

    - -

    setClasses returns {{setClasses() | json}}

    - -
    This div is saveable and special
    - -
    - After setClasses(), the classes are "{{classDiv.className}}" -
    - - - -
    This div is special
    - -
    Bad curly special
    -
    Curly special
    - -top - - -

    NgStyle Binding

    - - -
    - This div is x-large. -
    - - -

    Use setStyles() - CSS property names

    -

    setStyles returns {{setStyles()}}.

    - -
    - This div is italic, normal weight, and extra large (24px). -
    - -

    After setStyles(), the DOM confirms that the styles are - - {{getStyles(styleDiv)}} - . -

    - - - -top - - -

    NgIf Binding

    - - -
    Hello, {{currentHero.firstName}}
    - - - - -
    Hello, {{nullHero.firstName}}
    - - - - - - - - - - -
    Hero Detail removed from DOM (via template) because isActive is false
    - - - - -
    Show with class
    -
    Hide with class
    - - - - -
    Show with style
    -
    Hide with style
    - - -top - - -

    NgSwitch Binding

    - -
    - Eenie - Meanie - Miney - Moe - ??? -
    - -
    -
    Pick a toe
    -
    - You picked ... - - - - - - - Eenie - Meanie - Miney - Moe - other - - - - - - - - - - - - -
    -
    - -top - - -

    NgFor Binding

    - -
    - -
    {{hero.fullName}}
    - -
    -
    - -
    - - - - -
    - -top - -

    NgFor with index

    -

    with semi-colon separator

    -
    - -
    {{i + 1}} - {{hero.fullName}}
    - -
    - -

    with comma separator

    -
    - -
    {{i + 1}} - {{hero.fullName}}
    -
    - -top - -

    NgForTrackBy

    - -

    First hero:

    - -

    without trackBy

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    -
    - Hero DOM elements change #{{heroesNoTrackByChangeCount}} without trackBy -
    - -

    with trackBy and semi-colon separator

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    -
    - Hero DOM elements change #{{heroesWithTrackByChangeCount}} with trackBy -
    - -

    with trackBy and comma separator

    -
    -
    ({{hero.id}}) {{hero.fullName}}
    -
    - -

    with trackBy and space separator

    -
    -
    ({{hero.id}}) {{hero.fullName}}
    -
    - -

    with *ngForTrackBy

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    - -

    with generic trackById function

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    - -top - - -

    * prefix and <template>

    - -

    *ngIf expansion

    -

    *ngIf

    - - - - -

    expand to template = "..."

    - - - - -

    expand to <template>

    - - - - -

    *ngFor expansion

    -

    *ngFor

    - - - - - -

    expand to template = "..."

    -
    - - - - -
    -
    - -

    expand to <template>

    -
    - - - - -
    - -top - - -

    Template local variables

    - - - - - - - - - - - -

    Example Form

    - - -
    - -
    - - -
    - - -
    - - -

    - - - - -top - - -

    Inputs and Outputs

    - - - - - - - - - - - -
    myClick2
    -{{clickMessage2}} - -top - - -

    Pipes

    - - - -
    {{ title | uppercase }}
    - - - - -
    {{ title | uppercase | lowercase }}
    - - - - -
    Birthdate: {{currentHero?.birthdate | date:'longDate'}}
    - - - - - - - -
    Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}
    - -
    - - {{product['price'] | currency:'$'}} -
    - -top - - -

    Elvis ?.

    - -
    - - The title is {{ title }} - -
    - -
    - - The current hero's name is {{currentHero?.firstName}} - -
    - -
    - - The current hero's name is {{currentHero.firstName}} - -
    - - - - - - - -
    The null hero's name is {{nullHero.firstName}}
    - - - - -
    - - - The null hero's name is {{nullHero?.firstName}} - -
    - - - - - - - -

    My First Angular Application

    - - -top diff --git a/public/docs/_examples/template-syntax/dart/lib/assets/images/hero.png b/public/docs/_examples/template-syntax/dart/lib/assets/images/hero.png deleted file mode 100644 index b60c3ecc30..0000000000 Binary files a/public/docs/_examples/template-syntax/dart/lib/assets/images/hero.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/dart/lib/assets/images/ng-logo.png b/public/docs/_examples/template-syntax/dart/lib/assets/images/ng-logo.png deleted file mode 100644 index 7929242740..0000000000 Binary files a/public/docs/_examples/template-syntax/dart/lib/assets/images/ng-logo.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/dart/lib/assets/images/villain.png b/public/docs/_examples/template-syntax/dart/lib/assets/images/villain.png deleted file mode 100644 index d1e71cf00b..0000000000 Binary files a/public/docs/_examples/template-syntax/dart/lib/assets/images/villain.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/dart/lib/hero.dart b/public/docs/_examples/template-syntax/dart/lib/hero.dart deleted file mode 100644 index d366a23c19..0000000000 --- a/public/docs/_examples/template-syntax/dart/lib/hero.dart +++ /dev/null @@ -1,37 +0,0 @@ -// #docregion -class Hero { - static int _nextId = 1; - - final int id; - String firstName; - String lastName; - DateTime birthdate; - String url; - int rate = 100; - - Hero(this.firstName, - {this.lastName, this.birthdate, this.url, this.rate, int id}) - : this.id = id ?? _nextId++; - - String get fullName { - if (lastName == null) return firstName; - return '$firstName $lastName'; - } - - Hero clone() => new Hero(firstName, - lastName: lastName, birthdate: birthdate, url: url, rate: rate, id: id); - - @override String toString() => '$fullName (rate: $rate)'; -} - -final List mockHeroes = [ - new Hero('Hercules', - lastName: 'Son of Zeus', - birthdate: new DateTime(1970, 2, 25), - url: 'http://www.imdb.com/title/tt0065832/', - rate: 325), - new Hero('eenie', lastName: 'toe'), - new Hero('Meanie', lastName: 'Toe'), - new Hero('Miny', lastName: 'Toe'), - new Hero('Moe', lastName: 'Toe') -]; diff --git a/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart b/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart deleted file mode 100644 index 80130e0b18..0000000000 --- a/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart +++ /dev/null @@ -1,82 +0,0 @@ -// #docplaster -// #docregion -import 'package:angular2/angular2.dart'; - -import 'hero.dart'; - -var nextHeroDetailId = 1; - -// #docregion input-output-2 -@Component( -// #enddocregion input-output-2 - selector: 'hero-detail', -// #docregion input-output-2 - // ... - inputs: const ['hero'], - outputs: const ['deleteRequest'], -// #enddocregion input-output-2 - styles: const [ - 'button { margin-left: 8px} div {margin: 8px 0} img {height:24px}' - ], -// #docregion template-1 - template: ''' -
    - - - {{prefix}} {{hero?.fullName}} - - -
    ''' -// #enddocregion template-1 -// #docregion input-output-2 - ) -// #enddocregion input-output-2 -class HeroDetailComponent { - Hero hero = new Hero('Zzzzzzzz'); // default sleeping hero - String heroImageUrl = 'assets/images/hero.png'; - String lineThrough = ''; // PENDING: use null instead? - @Input() String prefix = ''; - - // #docregion deleteRequest - // This component make a request but it can't actually delete a hero. - final deleteRequest = new EventEmitter(); - - void delete() { - deleteRequest.emit(hero); - // #enddocregion deleteRequest - lineThrough = (lineThrough == '') ? 'line-through' : ''; - // #docregion deleteRequest - } - // #enddocregion deleteRequest -} - -@Component( - selector: 'big-hero-detail', - /* - inputs: ['hero'], - outputs: ['deleteRequest'], - */ - template: ''' -
    - -
    {{hero?.fullName}}
    -
    First: {{hero?.firstName}}
    -
    Last: {{hero?.lastName}}
    -
    Birthdate: {{hero?.birthdate | date:'longDate'}}
    - -
    Rate/hr: {{hero?.rate | currency:'EUR'}}
    -
    - -
    ''') -class BigHeroDetailComponent extends HeroDetailComponent { - // #docregion input-output-1 - @Input() Hero hero; - @Output() final deleteRequest = new EventEmitter(); - // #enddocregion input-output-1 - - String get heroImageUrl => 'assets/images/hero.png'; - - @override void delete() { - deleteRequest.emit(hero); - } -} diff --git a/public/docs/_examples/template-syntax/dart/lib/my_click_directive.dart b/public/docs/_examples/template-syntax/dart/lib/my_click_directive.dart deleted file mode 100644 index 74299c19c1..0000000000 --- a/public/docs/_examples/template-syntax/dart/lib/my_click_directive.dart +++ /dev/null @@ -1,42 +0,0 @@ -// #docplaster -import 'dart:html'; - -import 'package:angular2/angular2.dart'; - -@Directive(selector: '[myClick]') -class MyClickDirective { - // #docregion my-click-output-1 - // @Output(alias) [type info] propertyName = ... - @Output('myClick') final EventEmitter clicks = new EventEmitter(); - - // #enddocregion my-click-output-1 - bool _toggle = false; - - MyClickDirective(ElementRef el) { - Element nativeEl = el.nativeElement; - nativeEl.onClick.listen((Event e) { - _toggle = !_toggle; - clicks.emit(_toggle ? 'Click!' : ''); - }); - } -} - -// #docregion my-click-output-2 -@Directive( -// #enddocregion my-click-output-2 - selector: '[myClick2]', -// #docregion my-click-output-2 - // ... - outputs: const ['clicks:myClick']) // propertyName:alias -// #enddocregion my-click-output-2 -class MyClickDirective2 { - final EventEmitter clicks = new EventEmitter(); - bool _toggle = false; - - MyClickDirective2(ElementRef el) { - el.nativeElement.onClick.listen((Event e) { - _toggle = !_toggle; - clicks.emit(_toggle ? 'Click2!' : ''); - }); - } -} diff --git a/public/docs/_examples/template-syntax/dart/pubspec.yaml b/public/docs/_examples/template-syntax/dart/pubspec.yaml deleted file mode 100644 index f46f907f72..0000000000 --- a/public/docs/_examples/template-syntax/dart/pubspec.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# #docregion -name: template_syntax -description: Template Syntax -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_pipes: 'package:angular2/common.dart#COMMON_PIPES' - platform_directives: - - 'package:angular2/common.dart#COMMON_DIRECTIVES' - - 'package:angular2/common.dart#FORM_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter -- $dart2js: - checked: true diff --git a/public/docs/_examples/template-syntax/dart/web/assets/images/hero.png b/public/docs/_examples/template-syntax/dart/web/assets/images/hero.png deleted file mode 100644 index b60c3ecc30..0000000000 Binary files a/public/docs/_examples/template-syntax/dart/web/assets/images/hero.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/dart/web/assets/images/ng-logo.png b/public/docs/_examples/template-syntax/dart/web/assets/images/ng-logo.png deleted file mode 100644 index 7929242740..0000000000 Binary files a/public/docs/_examples/template-syntax/dart/web/assets/images/ng-logo.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/dart/web/assets/images/villain.png b/public/docs/_examples/template-syntax/dart/web/assets/images/villain.png deleted file mode 100644 index d1e71cf00b..0000000000 Binary files a/public/docs/_examples/template-syntax/dart/web/assets/images/villain.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/dart/web/index.html b/public/docs/_examples/template-syntax/dart/web/index.html deleted file mode 100644 index 3444f9f8f9..0000000000 --- a/public/docs/_examples/template-syntax/dart/web/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Template Syntax - - - - - - - - Loading... - - diff --git a/public/docs/_examples/template-syntax/dart/web/main.dart b/public/docs/_examples/template-syntax/dart/web/main.dart deleted file mode 100644 index f1659d0821..0000000000 --- a/public/docs/_examples/template-syntax/dart/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:template_syntax/app_component.dart'; - -void main() { - bootstrap(AppComponent); -} diff --git a/public/docs/_examples/template-syntax/dart/web/template-syntax.css b/public/docs/_examples/template-syntax/dart/web/template-syntax.css deleted file mode 100644 index c8c0925830..0000000000 --- a/public/docs/_examples/template-syntax/dart/web/template-syntax.css +++ /dev/null @@ -1,12 +0,0 @@ -fieldset {border-style:none} -img {height: 100px;} -.box {border: 1px solid black; padding:3px} -.child-div {margin-left: 1em; font-weight: normal} -.hidden {display: none} -.parent-div {margin-top: 1em; font-weight: bold} -.special {font-weight:bold; font-size: x-large} -.bad {color: red;} -.curly {font-family: "Brush Script MT"} -.toe {margin-left: 1em; font-style: italic;} -little-hero {color:blue; font-size: smaller; background-color: Turquoise } -.to-toc {margin-top: 10px; display: block} \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/e2e-spec.js b/public/docs/_examples/template-syntax/e2e-spec.js deleted file mode 100644 index 8aa140eb5c..0000000000 --- a/public/docs/_examples/template-syntax/e2e-spec.js +++ /dev/null @@ -1,29 +0,0 @@ -// Not yet complete -describe('Template Syntax', function () { - - beforeAll(function () { - browser.get(''); - }); - - it('should be able to use interpolation with a hero', function () { - var heroInterEle = element.all(by.css('h2+p')).get(0); - expect(heroInterEle.getText()).toEqual('My current hero is Hercules'); - }); - - it('should be able to use interpolation with a calculation', function () { - var theSumEles = element.all(by.cssContainingText('h3~p','The sum of')); - expect(theSumEles.count()).toBe(2); - expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2'); - expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4'); - }); - - it('should be able to use class binding syntax', function () { - var specialEle = element(by.cssContainingText('div','Special')); - expect(specialEle.getAttribute('class')).toMatch('special'); - }); - - it('should be able to use style binding syntax', function () { - var specialButtonEle = element(by.cssContainingText('div.special~button', 'button')); - expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); - }); -}); diff --git a/public/docs/_examples/template-syntax/e2e-spec.ts b/public/docs/_examples/template-syntax/e2e-spec.ts new file mode 100644 index 0000000000..71f1c58165 --- /dev/null +++ b/public/docs/_examples/template-syntax/e2e-spec.ts @@ -0,0 +1,43 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +// Not yet complete +describe('Template Syntax', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should be able to use interpolation with a hero', function () { + let heroInterEle = element.all(by.css('h2+p')).get(0); + expect(heroInterEle.getText()).toEqual('My current hero is Hercules'); + }); + + it('should be able to use interpolation with a calculation', function () { + let theSumEles = element.all(by.cssContainingText('h3~p', 'The sum of')); + expect(theSumEles.count()).toBe(2); + expect(theSumEles.get(0).getText()).toEqual('The sum of 1 + 1 is 2'); + expect(theSumEles.get(1).getText()).toEqual('The sum of 1 + 1 is not 4'); + }); + + it('should be able to use class binding syntax', function () { + let specialEle = element(by.cssContainingText('div', 'Special')); + expect(specialEle.getAttribute('class')).toMatch('special'); + }); + + it('should be able to use style binding syntax', function () { + let specialButtonEle = element(by.cssContainingText('div.special~button', 'button')); + expect(specialButtonEle.getAttribute('style')).toMatch('color: red'); + }); + + it('should two-way bind to sizer', async () => { + let div = element(by.css('div#two-way-1')); + let incButton = div.element(by.buttonText('+')); + let input = div.element(by.css('input')); + let initSize = await input.getAttribute('value'); + incButton.click(); + expect(input.getAttribute('value')).toEqual((+initSize + 1).toString()); + }); +}); + diff --git a/public/docs/_examples/template-syntax/ts/.gitignore b/public/docs/_examples/template-syntax/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/template-syntax/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.html b/public/docs/_examples/template-syntax/ts/app/app.component.html deleted file mode 100644 index 4de9728c11..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/app.component.html +++ /dev/null @@ -1,806 +0,0 @@ - - -

    Template Syntax

    -Interpolation
    -Mental Model
    -Buttons
    -Properties vs. Attributes
    -
    -Property Binding
    - -
    -Event Binding
    - -
    -
    Directives
    - -
    -* prefix and <template>
    -Template local variables
    -Inputs and outputs
    -Pipes
    -Elvis ?.
    -Enums
    - - -

    Interpolation

    - - -

    My current hero is {{currentHero.firstName}}

    - - - -

    - {{title}} - -

    - - - - -

    The sum of 1 + 1 is {{1 + 1}}

    - - - - -

    The sum of 1 + 1 is not {{1 + 1 + getVal()}}

    - - -top - - -

    New Mental Model

    - - - - -
    Mental Model
    - - - -

    - -
    - - -
    Mental Model
    - - - -
    -

    - -
    - - - - -
    -

    - -
    - - - -
    - -
    -

    - - - - -
    click me
    - -{{clicked}} -

    - -
    - - - - Hero Name: {{heroName}} -
    -

    - - - - -

    - - -
    Special
    - -

    - - - - -top - - -

    Property vs. Attribute (img examples)

    - - - -

    - - - - - -top - - -

    Buttons

    - - - - -

    - - -

    - - - -top - - -

    Property Binding

    - - - - - - - - -
    [ngClass] binding to the classes property
    - - - - - - - - - - - - - - - - - -Interpolated:
    -Property bound: - -
    The interpolated title is {{title}}
    -
    - - -top - - -

    Attribute Binding

    - - - - - - - - - - -
    One-Two
    FiveSix
    - - -
    - - - - -

    - - -
    - - - - - - - - - - -
    - -top - - -

    Class Binding

    - - - -
    Bad curly special
    - - - - -
    Bad curly
    - - - - - -
    The class binding is special
    - - - -
    This one is not so special
    - - -
    This class binding is special too
    - -top - - -

    Style Binding

    - - - - - - - - - - - -top - - -

    Event Binding

    - - - - - - - - - -
    - - - -
    click with myClick
    - - -{{clickMessage}} -
    - - - - - - -
    - - - - - -
    Click me -
    Click me too!
    -
    - -

    - - - -
    - -
    - -

    - - -
    - -
    - -

    - -top - - -

    NgModel (two-way) Binding

    - -

    Result: {{currentHero.firstName}}

    - - - - -without NgModel -
    - - - -[(ngModel)] -
    - - - -bindon-ngModel -
    - - - -(ngModelChange) = "...firstName=$event" -
    - - - -(ngModelChange) = "setUpperCaseFirstName($event)" -
    - -top - - -

    NgClass Binding

    - -

    setClasses returns {{setClasses() | json}}

    - -
    This div is saveable and special
    - -
    -After setClasses(), the classes are "{{classDiv.className}}" -
    - - - -
    This div is special
    - -
    Bad curly special
    -
    Curly special
    - -top - - -

    NgStyle Binding

    - - -
    - This div is x-large -
    - - -

    Use setStyles() - CSS property names

    -

    setStyles returns {{setStyles() | json}}

    - -
    - This div is italic, normal weight, and extra large (24px) -
    - -

    After setStyles(), the DOM confirms that the styles are - - "{{getStyles(styleDiv)}}" - . -

    - - - -top - - -

    NgIf Binding

    - - -
    Hello, {{currentHero.firstName}}
    - - - - -
    Hello, {{nullHero.firstName}}
    - - - - - - - - - - -
    Hero Detail removed from DOM (via template) because isActive is false
    - - - - -
    Show with class
    -
    Hide with class
    - - - - -
    Show with style
    -
    Hide with style
    - - -top - - -

    NgSwitch Binding

    - -
    - Eenie - Meanie - Miney - Moe - ??? -
    - -
    -
    Pick a toe
    -
    - You picked ... - - - - - - - Eenie - Meanie - Miney - Moe - other - - - - - - - - - - - - -
    -
    - -top - - -

    NgFor Binding

    - -
    - -
    {{hero.fullName}}
    - -
    -
    - -
    - - - - -
    - -top - -

    NgFor with index

    -

    with semi-colon separator

    -
    - -
    {{i + 1}} - {{hero.fullName}}
    - -
    - -

    with comma separator

    -
    - -
    {{i + 1}} - {{hero.fullName}}
    -
    - -top - -

    NgForTrackBy

    - -

    First hero:

    - -

    without trackBy

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    -
    - Hero DOM elements change #{{heroesNoTrackByChangeCount}} without trackBy -
    - -

    with trackBy and semi-colon separator

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    -
    - Hero DOM elements change #{{heroesWithTrackByChangeCount}} with trackBy -
    - -

    with trackBy and comma separator

    -
    -
    ({{hero.id}}) {{hero.fullName}}
    -
    - -

    with trackBy and space separator

    -
    -
    ({{hero.id}}) {{hero.fullName}}
    -
    - -

    with *ngForTrackBy

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    - -

    with generic trackById function

    -
    - -
    ({{hero.id}}) {{hero.fullName}}
    - -
    - -top - - -

    * prefix and <template>

    - -

    *ngIf expansion

    -

    *ngIf

    - - - - -

    expand to template = "..."

    - - - - -

    expand to <template>

    - - - - -

    *ngFor expansion

    -

    *ngFor

    - - - - - -

    expand to template = "..."

    -
    - - - - -
    - -

    expand to <template>

    -
    - - - - -
    - -top - - -

    Template local variables

    - - - - - - - - - - - -

    Example Form

    - - -
    - -
    - - -
    - - -
    - - -

    - - - - -top - - -

    Inputs and Outputs

    - - - - - - - - - - - -
    myClick2
    -{{clickMessage2}} - -top - - -

    Pipes

    - - - -
    {{ title | uppercase }}
    - - - - -
    {{ title | uppercase | lowercase }}
    - - - - -
    Birthdate: {{currentHero?.birthdate | date:'longDate'}}
    - - - -
    {{currentHero | json}}
    - - - - - -
    Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}
    - -
    - - {{product.price | currency:'USD':true}} -
    - -top - - -

    Elvis ?.

    - -
    - -The title is {{ title }} - -
    - -
    - -The current hero's name is {{currentHero?.firstName}} - -
    - -
    - -The current hero's name is {{currentHero.firstName}} - -
    - - - - - - -
    The null hero's name is {{nullHero.firstName}}
    - - -
    - -The null hero's name is {{nullHero && nullHero.firstName}} - -
    - -
    - - -The null hero's name is {{nullHero?.firstName}} - -
    - - -top - - - -

    Enums in binding

    - -

    The name of the Color.Red enum is {{Color[Color.Red]}}

    -

    The current color number is {{color}}

    -

    - -top - - -

    My First Angular Application

    - - -top diff --git a/public/docs/_examples/template-syntax/ts/app/app.component.ts b/public/docs/_examples/template-syntax/ts/app/app.component.ts deleted file mode 100644 index 5fee042818..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/app.component.ts +++ /dev/null @@ -1,244 +0,0 @@ -//#docplaster - -import {Component, AfterViewInit, ElementRef, OnInit, QueryList, ViewChildren} from 'angular2/core'; -import {NgForm} from 'angular2/common'; - -import {Hero} from './hero'; -import {HeroDetailComponent, BigHeroDetailComponent} from './hero-detail.component'; -import {MyClickDirective, MyClickDirective2} from './my-click.directive'; - -// Alerter fn: monkey patch during test -export function alerter(msg?:string) { - window.alert(msg); -} - -export enum Color {Red, Green, Blue}; - -/** - * Giant grab bag of stuff to drive the chapter - */ -@Component({ - selector: 'my-app', - templateUrl: 'app/app.component.html', - directives: [ - HeroDetailComponent, BigHeroDetailComponent, - MyClickDirective, MyClickDirective2 - ] -}) -export class AppComponent implements AfterViewInit, OnInit { - - ngOnInit(){ - this.refreshHeroes(); - } - - ngAfterViewInit() { - this._detectNgForTrackByEffects(); - } - - actionName = 'Go for it'; - alert = alerter; - badCurly = 'bad curly'; - classes = 'special'; - - callFax(value:string) {this.alert(`Faxing ${value} ...`)} - callPhone(value:string) {this.alert(`Calling ${value} ...`)} - canSave = true; - - Color = Color; - color = Color.Red; - colorToggle() {this.color = (this.color === Color.Red)? Color.Blue : Color.Red} - - currentHero = Hero.MockHeroes[0]; - - deleteHero(hero:Hero){ - this.alert('Deleted hero: '+ (hero && hero.firstName)) - } - - // DevMode memoization fields - private _priorClasses:{}; - private _priorStyles:{}; - private _priorStyles2:{}; - - getStyles(el:Element){ - let styles = window.getComputedStyle(el); - let showStyles = {}; - for (var p in this.setStyles()){ - showStyles[p] = styles[p]; - } - return JSON.stringify(showStyles); - } - - getVal() {return this.val}; - - heroes:Hero[]; - - // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; - // Public Domain terms of use: http://www.wpclipart.com/terms.html - heroImageUrl = 'images/hero.png'; - - //iconUrl = 'https://angular.io/resources/images/logos/standard/shield-large.png'; - iconUrl = 'images/ng-logo.png'; - isActive = false; - isSpecial = true; - isUnchanged = true; - - nullHero:Hero = null; // or undefined - - onCancel(event:KeyboardEvent){ - let evtMsg = event ? ' Event target is '+ (event.target).innerHTML : ''; - this.alert('Canceled.'+evtMsg) - } - - onClickMe(event:KeyboardEvent){ - let evtMsg = event ? ' Event target class is '+ (event.target).className : ''; - this.alert('Click me.'+evtMsg) - } - - onSave(event:KeyboardEvent){ - let evtMsg = event ? ' Event target is '+ (event.target).innerText : ''; - this.alert('Saved.'+evtMsg) - } - - onSubmit(form:NgForm){ - let evtMsg = form.valid ? - ' Form value is '+ JSON.stringify(form.value) : - ' Form is invalid'; - this.alert('Form submitted.'+evtMsg) - } - - product = { - name: 'frimfram', - price: 42 - }; - - // #docregion refresh-heroes - // update this.heroes with fresh set of cloned heroes - refreshHeroes() { - this.heroes = Hero.MockHeroes.map(hero => Hero.clone(hero)); - } - // #enddocregion refresh-heroes - - // #docregion same-as-it-ever-was - private _samenessCount = 5; - moreOfTheSame() {this._samenessCount++;}; - get sameAsItEverWas() { - var result:string[] = Array(this._samenessCount); - for (var i=result.length; i-- > 0;){result[i]='same as it ever was ...'} - return result; - // return [1,2,3,4,5].map(id => { - // return {id:id, text: 'same as it ever was ...'}; - // }); - } - // #enddocregion same-as-it-ever-was - - setUpperCaseFirstName(firstName:string){ - //console.log(firstName); - this.currentHero.firstName = firstName.toUpperCase(); - } - - // #docregion setClasses - setClasses() { - let classes = { - saveable: this.canSave, // true - modified: !this.isUnchanged, // false - special: this.isSpecial, // true - } - // #enddocregion setClasses - // compensate for DevMode (sigh) - if (JSON.stringify(classes) === JSON.stringify(this._priorClasses)){ - return this._priorClasses; - } - this._priorClasses = classes; - // #docregion setClasses - return classes; - } - // #enddocregion setClasses - - - // #docregion setStyles - setStyles() { - let styles = { - // CSS property names - 'font-style': this.canSave ? 'italic' : 'normal', // italic - 'font-weight': !this.isUnchanged ? 'bold' : 'normal', // normal - 'font-size': this.isSpecial ? '24px' : '8px', // 24px - } - // #enddocregion setStyles - // compensate for DevMode (sigh) - if (JSON.stringify(styles) === JSON.stringify(this._priorStyles)){ - return this._priorStyles; - } - this._priorStyles = styles; - // #docregion setStyles - return styles; - } - // #enddocregion setStyles - - toeChoice = ''; - toeChooser(picker:HTMLFieldSetElement){ - let choices = picker.children; - for (let i=0; ichoices[i]; - if (choice.checked) {return this.toeChoice = choice.value} - } - } - - title = 'Template Syntax'; - - // #docregion trackByHeroes - trackByHeroes(index: number, hero: Hero) { return hero.id; } - // #enddocregion trackByHeroes - - // #docregion trackById - trackById(index: number, item: any): string { return item['id']; } - // #enddocregion trackById - - val=2; - // villainImageUrl = 'http://www.clker.com/cliparts/u/s/y/L/x/9/villain-man-hi.png' - // Public Domain terms of use http://www.clker.com/disclaimer.html - villainImageUrl = 'images/villain.png' - - - //////// Detect effects of NgForTrackBy /////////////// - @ViewChildren('noTrackBy') childrenNoTrackBy:QueryList; - @ViewChildren('withTrackBy') childrenWithTrackBy:QueryList; - - private _oldNoTrackBy:HTMLElement[]; - private _oldWithTrackBy:HTMLElement[]; - - heroesNoTrackByChangeCount = 0; - heroesWithTrackByChangeCount = 0; - - private _detectNgForTrackByEffects() { - this._oldNoTrackBy = toArray(this.childrenNoTrackBy); - this._oldWithTrackBy = toArray(this.childrenWithTrackBy); - - this.childrenNoTrackBy.changes.subscribe((changes:any) => { - let newNoTrackBy = toArray(changes); - let isSame = this._oldNoTrackBy.every((v:any, i:number) => v === newNoTrackBy[i]); - if (!isSame) { - this._oldNoTrackBy = newNoTrackBy; - this.heroesNoTrackByChangeCount++; - } - }) - - this.childrenWithTrackBy.changes.subscribe((changes:any) => { - let newWithTrackBy = toArray(changes); - let isSame = this._oldWithTrackBy.every((v:any, i:number) => v === newWithTrackBy[i]); - if (!isSame) { - this._oldWithTrackBy = newWithTrackBy; - this.heroesWithTrackByChangeCount++; - } - }) - } - /////////////////// - -} - -// helper to convert viewChildren to an array of HTMLElements -function toArray(viewChildren:QueryList) { - let result: HTMLElement[] = []; - let children = viewChildren.toArray()[0].nativeElement.children; - for (var i = 0; i < children.length; i++) { result.push(children[i]); } - return result; -} \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/ts/app/decorator.directive.ts b/public/docs/_examples/template-syntax/ts/app/decorator.directive.ts deleted file mode 100644 index aca06f3974..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/decorator.directive.ts +++ /dev/null @@ -1,11 +0,0 @@ -// Useful for spying on an element -// for fun; not used (yet) -import {Directive, ElementRef} from 'angular2/core'; - -// set the selector for the element type to spy on. -@Directive({selector: 'select'}) -export class DecoratorDirective { - constructor(el: ElementRef){ - console.log(el) - } -} \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/ts/app/hero-detail.component.ts b/public/docs/_examples/template-syntax/ts/app/hero-detail.component.ts deleted file mode 100644 index f27f68719d..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/hero-detail.component.ts +++ /dev/null @@ -1,78 +0,0 @@ -// #docplaster -import {Component, Input, Output, EventEmitter} from 'angular2/core'; - -import {Hero} from './hero'; - -let nextHeroDetailId = 1; - -// #docregion input-output-2 -@Component({ -// #enddocregion input-output-2 - selector: 'hero-detail', - // #docregion input-output-2 - inputs: ['hero'], - outputs: ['deleteRequest'], - // #enddocregion input-output-2 - styles:['button { margin-left: 8px} div {margin: 8px 0} img {height:24px}'], - // #docregion template-1 - template: ` -
    - - - {{prefix}} {{hero?.fullName}} - - -
    ` - // #enddocregion template-1 -// #docregion input-output-2 -}) -// #enddocregion input-output-2 -export class HeroDetailComponent { - -// #docregion deleteRequest - // This component make a request but it can't actually delete a hero. - deleteRequest = new EventEmitter(); - - delete() { - this.deleteRequest.emit(this.hero); - // #enddocregion deleteRequest - this.lineThrough = this.lineThrough ? '' : 'line-through'; - // #docregion deleteRequest - } -// #enddocregion deleteRequest - - hero: Hero = new Hero('','Zzzzzzzz'); // default sleeping hero - // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; - // Public Domain terms of use: http://www.wpclipart.com/terms.html - heroImageUrl = 'images/hero.png'; - lineThrough = ''; - @Input() prefix = ''; -} - -@Component({ - selector: 'big-hero-detail', - template: ` -
    - -
    {{hero?.fullName}}
    -
    First: {{hero?.firstName}}
    -
    Last: {{hero?.lastName}}
    -
    Birthdate: {{hero?.birthdate | date:'longDate'}}
    - -
    Rate/hr: {{hero?.rate | currency:'EUR'}}
    -
    - -
    - ` -}) -export class BigHeroDetailComponent extends HeroDetailComponent { - - // #docregion input-output-1 - @Input() hero: Hero; - @Output() deleteRequest = new EventEmitter(); - // #enddocregion input-output-1 - - delete() { - this.deleteRequest.emit(this.hero); - } -} diff --git a/public/docs/_examples/template-syntax/ts/app/hero.ts b/public/docs/_examples/template-syntax/ts/app/hero.ts deleted file mode 100644 index b576908b96..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/hero.ts +++ /dev/null @@ -1,35 +0,0 @@ -export class Hero { - public id:number - - constructor( - public firstName:string, - public lastName?:string, - public birthdate?:Date, - public url?:string, - public rate:number = 100, - id?:number) { - this.id = id != null ? id : Hero.nextId++; - } - - static clone({firstName, lastName, birthdate, url, rate, id} : Hero){ - return new Hero (firstName, lastName, birthdate, url, rate, id ); - } - - get fullName() {return `${this.firstName} ${this.lastName}`;} - - static nextId = 1; - - static MockHeroes = [ - new Hero( - 'Hercules', - 'Son of Zeus', - new Date(1970, 1, 25), - 'http://www.imdb.com/title/tt0065832/', - 325), - - new Hero('eenie', 'toe'), - new Hero('Meanie', 'Toe'), - new Hero('Miny', 'Toe'), - new Hero('Moe', 'Toe') - ]; -} \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/ts/app/main.ts b/public/docs/_examples/template-syntax/ts/app/main.ts deleted file mode 100644 index 0d6c42ba10..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/main.ts +++ /dev/null @@ -1,3 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; -bootstrap(AppComponent); \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts b/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts deleted file mode 100644 index 32e708cb9e..0000000000 --- a/public/docs/_examples/template-syntax/ts/app/my-click.directive.ts +++ /dev/null @@ -1,39 +0,0 @@ -// #docplaster -import {Directive, Output, ElementRef, EventEmitter} from 'angular2/core'; - -@Directive({selector:'[myClick]'}) -export class MyClickDirective { - // #docregion my-click-output-1 - @Output('myClick') clicks = new EventEmitter(); // @Output(alias) propertyName = ... - // #enddocregion my-click-output-1 - - constructor(el: ElementRef){ - el.nativeElement - .addEventListener('click', (event:Event) => { - this._toggle = !this._toggle; - this.clicks.emit(this._toggle ? 'Click!' : ''); - }); - } - _toggle = false; -} - -// #docregion my-click-output-2 -@Directive({ -// #enddocregion my-click-output-2 - selector:'[myClick2]', -// #docregion my-click-output-2 - outputs:['clicks:myClick'] // propertyName:alias -}) -// #enddocregion my-click-output-2 -export class MyClickDirective2 { - clicks = new EventEmitter(); - - constructor(el: ElementRef){ - el.nativeElement - .addEventListener('click', (event:Event) => { - this._toggle = !this._toggle; - this.clicks.emit(this._toggle ? 'Click2!' : ''); - }); - } - _toggle = false; -} \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/ts/images/hero.png b/public/docs/_examples/template-syntax/ts/images/hero.png deleted file mode 100644 index b60c3ecc30..0000000000 Binary files a/public/docs/_examples/template-syntax/ts/images/hero.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/ts/images/ng-logo.png b/public/docs/_examples/template-syntax/ts/images/ng-logo.png deleted file mode 100644 index 7929242740..0000000000 Binary files a/public/docs/_examples/template-syntax/ts/images/ng-logo.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/ts/images/villain.png b/public/docs/_examples/template-syntax/ts/images/villain.png deleted file mode 100644 index d1e71cf00b..0000000000 Binary files a/public/docs/_examples/template-syntax/ts/images/villain.png and /dev/null differ diff --git a/public/docs/_examples/template-syntax/ts/index.html b/public/docs/_examples/template-syntax/ts/index.html deleted file mode 100644 index de5a5606aa..0000000000 --- a/public/docs/_examples/template-syntax/ts/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - Template Syntax - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/template-syntax/ts/plnkr.json b/public/docs/_examples/template-syntax/ts/plnkr.json index 05efe8f536..099616ad7c 100644 --- a/public/docs/_examples/template-syntax/ts/plnkr.json +++ b/public/docs/_examples/template-syntax/ts/plnkr.json @@ -1,5 +1,6 @@ { "description": "Template Syntax Collection", + "basePath": "src/", "files":["!**/*.d.ts", "!**/*.js"], "tags": ["template"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.component.css b/public/docs/_examples/template-syntax/ts/src/app/app.component.css new file mode 100644 index 0000000000..23f9667623 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/app.component.css @@ -0,0 +1,17 @@ +a.to-toc { margin: 30px 0; } +button { font-size: 100%; margin: 0 2px; } +div[clickable] {cursor: pointer; max-width: 200px; margin: 16px 0} +#noTrackByCnt, #withTrackByCnt {color: darkred; max-width: 450px; margin: 4px;} +img {height: 100px;} +.box {border: 1px solid black; padding: 6px; max-width: 450px;} +.child-div {margin-left: 1em; font-weight: normal} +.context {margin-left: 1em;} +.hidden {display: none} +.parent-div {margin-top: 1em; font-weight: bold} +.special {font-weight:bold; font-size: x-large} +.bad {color: red;} +.saveable {color: limegreen;} +.curly, .modified {font-family: "Brush Script MT"} +.toe {margin-left: 1em; font-style: italic;} +little-hero {color:blue; font-size: smaller; background-color: Turquoise } +.to-toc {margin-top: 10px; display: block} diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.component.html b/public/docs/_examples/template-syntax/ts/src/app/app.component.html new file mode 100644 index 0000000000..760fa3a367 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/app.component.html @@ -0,0 +1,820 @@ + + +

    Template Syntax

    +Interpolation
    +Expression context
    +Statement context
    +Mental Model
    +Buttons
    +Properties vs. Attributes
    +
    +Property Binding
    + +
    +Event Binding
    +Two-way Binding
    +
    +
    Directives
    + +
    +Template reference variables
    +Inputs and outputs
    +Pipes
    +Safe navigation operator ?.
    +Enums
    + + +

    Interpolation

    + + +

    My current hero is {{currentHero.name}}

    + + + +

    + {{title}} + +

    + + + + +

    The sum of 1 + 1 is {{1 + 1}}

    + + + + +

    The sum of 1 + 1 is not {{1 + 1 + getVal()}}

    + + +top + +

    Expression context

    + +

    Component expression context ({{title}}, [hidden]="isUnchanged")

    +
    + + {{title}} + changed + +
    + + +

    Template input variable expression context (let hero)

    + + + +

    Template reference variable expression context (#heroInput)

    +
    + Type something: + + {{heroInput.value}} + +
    + +top + +

    Statement context

    + +

    Component statement context ( (click)="onSave() ) +

    + + + +
    + +

    Template $event statement context

    +
    + + + +
    + +

    Template input variable statement context (let hero)

    + +
    + + + +
    + +

    Template reference variable statement context (#heroForm)

    +
    + +
    ...
    + +
    + +top + + +

    New Mental Model

    + + + + +
    Mental Model
    + + + +

    + +
    + + +
    Mental Model
    + + + +
    +

    + +
    + + + + +
    +

    + +
    + + + +
    + +
    +

    + + + + +
    click me
    + +{{clicked}} +

    + +
    + Hero Name: + + + + {{name}} +
    +

    + + + + +

    + + +
    Special
    + +

    + + + + +top + + +

    Property vs. Attribute (img examples)

    + + + +

    + + + + + +top + + +

    Buttons

    + + + + +

    + + +

    + + + +top + + +

    Property Binding

    + + + + + + + + +
    [ngClass] binding to the classes property
    + + + + + + + + + + + +
    + + + +
    + + + + + +

    is the interpolated image.

    +

    is the property bound image.

    + +

    "{{title}}" is the interpolated title.

    +

    "" is the property bound title.

    + + + + +

    "{{evilTitle}}" is the interpolated evil title.

    +

    "" is the property bound evil title.

    + + +top + + +

    Attribute Binding

    + + + + + + + + + + +
    One-Two
    FiveSix
    + + +
    + + + + +

    + + +
    + + + + + + + +
    + +top + + +

    Class Binding

    + + + +
    Bad curly special
    + + + + +
    Bad curly
    + + + + + +
    The class binding is special
    + + + +
    This one is not so special
    + + +
    This class binding is special too
    + +top + + +

    Style Binding

    + + + + + + + + + + + +top + + +

    Event Binding

    + + + + + + + + + +
    + + + +
    click with myClick
    + + +{{clickMessage}} +
    + + + + + + +
    + + + + + +
    Click me +
    Click me too!
    +
    + + + + +
    + +
    + + + + +
    + +
    + + +top + +

    Two-way Binding

    +
    + + +
    Resizable Text
    + + +
    +
    +
    +

    De-sugared two-way binding

    + + + +
    + +top + + +

    NgModel (two-way) Binding

    + +

    Result: {{currentHero.name}}

    + + + + +without NgModel +
    + + + +[(ngModel)] +
    + + + +bindon-ngModel +
    + + + +(ngModelChange)="...name=$event" +
    + + + +(ngModelChange)="setUppercaseName($event)" + +top + + +

    NgClass Binding

    + +

    currentClasses is {{currentClasses | json}}

    + +
    This div is initially saveable, unchanged, and special
    + + + +
    + | + | + + +

    +
    + This div should be {{ canSave ? "": "not"}} saveable, + {{ isUnchanged ? "unchanged" : "modified" }} and, + {{ isSpecial ? "": "not"}} special after clicking "Refresh".
    +

    + +
    This div is special
    + +
    Bad curly special
    +
    Curly special
    + +top + + +

    NgStyle Binding

    + + +
    + This div is x-large or smaller. +
    + + +

    [ngStyle] binding to currentStyles - CSS property names

    +

    currentStyles is {{currentStyles | json}}

    + +
    + This div is initially italic, normal weight, and extra large (24px). +
    + + + +
    + | + | + + +

    +
    + This div should be {{ canSave ? "italic": "plain"}}, + {{ isUnchanged ? "normal weight" : "bold" }} and, + {{ isSpecial ? "extra large": "normal size"}} after clicking "Refresh".
    + +top + + +

    NgIf Binding

    + + + + + + +
    Hello, {{currentHero.name}}
    +
    Hello, {{nullHero.name}}
    + + + + +Add {{currentHero.name}} with template + + +
    Hero Detail removed from DOM (via template) because isActive is false
    + + + + + + +
    Show with class
    +
    Hide with class
    + + + + +
    Show with style
    +
    Hide with style
    + + +top + + +

    NgFor Binding

    + +
    + +
    {{hero.name}}
    + +
    +
    + +
    + + + + +
    + +top + +

    *ngFor with index

    +

    with semi-colon separator

    +
    + +
    {{i + 1}} - {{hero.name}}
    + +
    + +

    with comma separator

    +
    + +
    {{i + 1}} - {{hero.name}}
    +
    + +top + +

    *ngFor trackBy

    + + + + +

    without trackBy

    +
    +
    ({{hero.id}}) {{hero.name}}
    + +
    + Hero DOM elements change #{{heroesNoTrackByCount}} without trackBy +
    +
    + +

    with trackBy

    +
    +
    ({{hero.id}}) {{hero.name}}
    + +
    + Hero DOM elements change #{{heroesWithTrackByCount}} with trackBy +
    +
    + +


    + +

    with trackBy and semi-colon separator

    +
    + +
    + ({{hero.id}}) {{hero.name}} +
    + +
    + +

    with trackBy and comma separator

    +
    +
    ({{hero.id}}) {{hero.name}}
    +
    + +

    with trackBy and space separator

    +
    +
    ({{hero.id}}) {{hero.name}}
    +
    + +

    with generic trackById function

    +
    +
    ({{hero.id}}) {{hero.name}}
    +
    + +top + + +

    NgSwitch Binding

    + +

    Pick your favorite hero

    +
    + +
    + + +
    + + + + + +
    Are you as confused as {{currentHero.name}}?
    + + + +
    + + +top + + +

    Template reference variables

    + + + + + + + + + + + + + + + + + + + + +

    Example Form

    + + +top + + +

    Inputs and Outputs

    + + + + + + + + + + + +
    myClick2
    +{{clickMessage2}} + +top + + +

    Pipes

    + + +
    Title through uppercase pipe: {{title | uppercase}}
    + + + + +
    + Title through a pipe chain: + {{title | uppercase | lowercase}} +
    + + + + +
    Birthdate: {{currentHero?.birthdate | date:'longDate'}}
    + + + +
    {{currentHero | json}}
    + + +
    Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}
    + +
    + + {{product.price | currency:'USD':true}} +
    + +top + + +

    Safe navigation operator ?.

    + +
    + + The title is {{title}} + +
    + +
    + + The current hero's name is {{currentHero?.name}} + +
    + +
    + + The current hero's name is {{currentHero.name}} + +
    + + + + + + +
    The null hero's name is {{nullHero.name}}
    + + +
    + +The null hero's name is {{nullHero && nullHero.name}} + +
    + +
    + + + The null hero's name is {{nullHero?.name}} + +
    + +top + + + +

    Enums in binding

    + +

    + + The name of the Color.Red enum is {{Color[Color.Red]}}.
    + The current color is {{Color[color]}} and its number is {{color}}.
    + + +

    + +top diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.component.ts b/public/docs/_examples/template-syntax/ts/src/app/app.component.ts new file mode 100644 index 0000000000..f0fa2a2d23 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/app.component.ts @@ -0,0 +1,183 @@ +/* tslint:disable:forin member-ordering */ +// #docplaster + +import { AfterViewInit, Component, ElementRef, OnInit, QueryList, ViewChildren } from '@angular/core'; + +import { Hero } from './hero'; + +export enum Color {Red, Green, Blue}; + +/** + * Giant grab bag of stuff to drive the chapter + */ +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: [ './app.component.css' ] +}) +export class AppComponent implements AfterViewInit, OnInit { + + ngOnInit() { + this.resetHeroes(); + this.setCurrentClasses(); + this.setCurrentStyles(); + } + + ngAfterViewInit() { + // Detect effects of NgForTrackBy + trackChanges(this.heroesNoTrackBy, () => this.heroesNoTrackByCount++); + trackChanges(this.heroesWithTrackBy, () => this.heroesWithTrackByCount++); + } + + @ViewChildren('noTrackBy') heroesNoTrackBy: QueryList; + @ViewChildren('withTrackBy') heroesWithTrackBy: QueryList; + + actionName = 'Go for it'; + badCurly = 'bad curly'; + classes = 'special'; + help = ''; + + alert(msg?: string) { window.alert(msg); } + callFax(value: string) { this.alert(`Faxing ${value} ...`); } + callPhone(value: string) { this.alert(`Calling ${value} ...`); } + canSave = true; + + changeIds() { + this.resetHeroes(); + this.heroes.forEach(h => h.id += 10 * this.heroIdIncrement++); + this.heroesWithTrackByCountReset = -1; + } + + clearTrackByCounts() { + const trackByCountReset = this.heroesWithTrackByCountReset; + this.resetHeroes(); + this.heroesNoTrackByCount = -1; + this.heroesWithTrackByCount = trackByCountReset; + this.heroIdIncrement = 1; + } + + clicked = ''; + clickMessage = ''; + clickMessage2 = ''; + + Color = Color; + color = Color.Red; + colorToggle() {this.color = (this.color === Color.Red) ? Color.Blue : Color.Red; } + + currentHero: Hero; + + deleteHero(hero: Hero) { + this.alert(`Delete ${hero ? hero.name : 'the hero'}.`); + } + + // #docregion evil-title + evilTitle = 'Template Syntax'; + // #enddocregion evil-title + + fontSizePx = 16; + + title = 'Template Syntax'; + + getVal(): number { return 2; } + + name: string = Hero.heroes[0].name; + hero: Hero; // defined to demonstrate template context precedence + heroes: Hero[]; + + // trackBy change counting + heroesNoTrackByCount = 0; + heroesWithTrackByCount = 0; + heroesWithTrackByCountReset = 0; + + heroIdIncrement = 1; + + // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; + // Public Domain terms of use: http://www.wpclipart.com/terms.html + heroImageUrl = 'images/hero.png'; + // villainImageUrl = 'http://www.clker.com/cliparts/u/s/y/L/x/9/villain-man-hi.png' + // Public Domain terms of use http://www.clker.com/disclaimer.html + villainImageUrl = 'images/villain.png'; + + iconUrl = 'images/ng-logo.png'; + isActive = false; + isSpecial = true; + isUnchanged = true; + + get nullHero(): Hero { return null; } + + onClickMe(event: KeyboardEvent) { + let evtMsg = event ? ' Event target class is ' + (event.target).className : ''; + this.alert('Click me.' + evtMsg); + } + + onSave(event: KeyboardEvent) { + let evtMsg = event ? ' Event target is ' + (event.target).innerText : ''; + this.alert('Saved.' + evtMsg); + if (event) { event.stopPropagation(); } + } + + onSubmit() {/* referenced but not used */} + + product = { + name: 'frimfram', + price: 42 + }; + + // updates with fresh set of cloned heroes + resetHeroes() { + this.heroes = Hero.heroes.map(hero => hero.clone()); + this.currentHero = this.heroes[0]; + this.heroesWithTrackByCountReset = 0; + } + + setUppercaseName(name: string) { + this.currentHero.name = name.toUpperCase(); + } + + // #docregion setClasses + currentClasses: {}; + setCurrentClasses() { + // CSS classes: added/removed per current state of component properties + this.currentClasses = { + saveable: this.canSave, + modified: !this.isUnchanged, + special: this.isSpecial + }; + } + // #enddocregion setClasses + + // #docregion setStyles + currentStyles: {}; + setCurrentStyles() { + // CSS styles: set per current state of component properties + this.currentStyles = { + 'font-style': this.canSave ? 'italic' : 'normal', + 'font-weight': !this.isUnchanged ? 'bold' : 'normal', + 'font-size': this.isSpecial ? '24px' : '12px' + }; + } + // #enddocregion setStyles + + // #docregion trackByHeroes + trackByHeroes(index: number, hero: Hero): number { return hero.id; } + // #enddocregion trackByHeroes + + // #docregion trackById + trackById(index: number, item: any): number { return item['id']; } + // #enddocregion trackById +} + +// helper to track changes to viewChildren +function trackChanges(views: QueryList, changed: () => void) { + let oldRefs = views.toArray(); + views.changes.subscribe((changes: QueryList) => { + const changedRefs = changes.toArray(); + // Is every changed ElemRef the same as old and in the same position + const isSame = oldRefs.every((v, i) => v === changedRefs[i]); + if (!isSame) { + oldRefs = changedRefs; + // wait a tick because called after views are constructed + setTimeout(changed, 0); + } + }); +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts b/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..8ea0d3d207 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/app.module.1.ts @@ -0,0 +1,15 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; // <--- JavaScript import from Angular + +/* Other imports */ + +@NgModule({ + imports: [ + BrowserModule, + FormsModule // <--- import into the NgModule + ], + /* Other module metadata */ +}) +export class AppModule { } diff --git a/public/docs/_examples/template-syntax/ts/src/app/app.module.ts b/public/docs/_examples/template-syntax/ts/src/app/app.module.ts new file mode 100644 index 0000000000..5c2fbed6f1 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/app.module.ts @@ -0,0 +1,29 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { BigHeroDetailComponent, HeroDetailComponent } from './hero-detail.component'; +import { ClickDirective, ClickDirective2 } from './click.directive'; +import { HeroFormComponent } from './hero-form.component'; +import { heroSwitchComponents } from './hero-switch.components'; +import { SizerComponent } from './sizer.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + BigHeroDetailComponent, + HeroDetailComponent, + HeroFormComponent, + heroSwitchComponents, + ClickDirective, + ClickDirective2, + SizerComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/template-syntax/ts/src/app/click.directive.ts b/public/docs/_examples/template-syntax/ts/src/app/click.directive.ts new file mode 100644 index 0000000000..09757bfeaf --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/click.directive.ts @@ -0,0 +1,41 @@ +/* tslint:disable use-output-property-decorator */ +// #docplaster +import { Directive, ElementRef, EventEmitter, Output } from '@angular/core'; + +@Directive({selector: '[myClick]'}) +export class ClickDirective { + // #docregion output-myClick + @Output('myClick') clicks = new EventEmitter(); // @Output(alias) propertyName = ... + // #enddocregion output-myClick + + toggle = false; + + constructor(el: ElementRef) { + el.nativeElement + .addEventListener('click', (event: Event) => { + this.toggle = !this.toggle; + this.clicks.emit(this.toggle ? 'Click!' : ''); + }); + } +} + +// #docregion output-myClick2 +@Directive({ + // #enddocregion output-myClick2 + selector: '[myClick2]', + // #docregion output-myClick2 + outputs: ['clicks:myClick'] // propertyName:alias +}) +// #enddocregion output-myClick2 +export class ClickDirective2 { + clicks = new EventEmitter(); + toggle = false; + + constructor(el: ElementRef) { + el.nativeElement + .addEventListener('click', (event: Event) => { + this.toggle = !this.toggle; + this.clicks.emit(this.toggle ? 'Click2!' : ''); + }); + } +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts b/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..725849d692 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-detail.component.ts @@ -0,0 +1,80 @@ +/* tslint:disable use-input-property-decorator use-output-property-decorator */ +// #docplaster +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +import { Hero } from './hero'; + +// #docregion input-output-2 +@Component({ +// #enddocregion input-output-2 + selector: 'hero-detail', + // #docregion input-output-2 + inputs: ['hero'], + outputs: ['deleteRequest'], + // #enddocregion input-output-2 + styles: ['button {margin-left: 8px} div {margin: 8px 0} img {height:24px}'], + // #docregion template-1 + template: ` +
    + + + {{prefix}} {{hero?.name}} + + +
    ` + // #enddocregion template-1 +// #docregion input-output-2 +}) +// #enddocregion input-output-2 +export class HeroDetailComponent { + hero: Hero = new Hero(-1, '', 'Zzzzzzzz'); // default sleeping hero + // heroImageUrl = 'http://www.wpclipart.com/cartoon/people/hero/hero_silhoutte_T.png'; + // Public Domain terms of use: http://www.wpclipart.com/terms.html + heroImageUrl = 'images/hero.png'; + lineThrough = ''; + @Input() prefix = ''; + + // #docregion deleteRequest + // This component make a request but it can't actually delete a hero. + deleteRequest = new EventEmitter(); + + delete() { + this.deleteRequest.emit(this.hero); + // #enddocregion deleteRequest + this.lineThrough = this.lineThrough ? '' : 'line-through'; + // #docregion deleteRequest + } + // #enddocregion deleteRequest +} + +@Component({ + selector: 'big-hero-detail', + template: ` +
    + +
    {{hero?.name}}
    +
    Name: {{hero?.name}}
    +
    Emotion: {{hero?.emotion}}
    +
    Birthdate: {{hero?.birthdate | date:'longDate'}}
    + +
    Rate/hr: {{hero?.rate | currency:'EUR'}}
    +
    + +
    + `, + styles: [` + .detail { border: 1px solid black; padding: 4px; max-width: 450px; } + img { float: left; margin-right: 8px; height: 100px; } + `] +}) +export class BigHeroDetailComponent extends HeroDetailComponent { + + // #docregion input-output-1 + @Input() hero: Hero; + @Output() deleteRequest = new EventEmitter(); + // #enddocregion input-output-1 + + delete() { + this.deleteRequest.emit(this.hero); + } +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html new file mode 100644 index 0000000000..2182060439 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.html @@ -0,0 +1,15 @@ +
    + +
    +
    + +
    + +
    +
    + {{submitMessage}} +
    + +
    diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts new file mode 100644 index 0000000000..7bdc4a0bba --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-form.component.ts @@ -0,0 +1,30 @@ +import { Component, Input, ViewChild } from '@angular/core'; +import { NgForm } from '@angular/forms'; + +import { Hero } from './hero'; + +@Component({ + selector: 'hero-form', + templateUrl: './hero-form.component.html', + styles: [` + button { margin: 6px 0; } + #heroForm { border: 1px solid black; margin: 20px 0; padding: 8px; max-width: 350px; } + `] +}) +export class HeroFormComponent { + @Input() hero: Hero; + @ViewChild('heroForm') form: NgForm; + + private _submitMessage = ''; + + get submitMessage() { + if (!this.form.valid) { + this._submitMessage = ''; + } + return this._submitMessage; + } + + onSubmit(form: NgForm) { + this._submitMessage = 'Submitted. form value is ' + JSON.stringify(form.value); + } +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts b/public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts new file mode 100644 index 0000000000..a21892e248 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero-switch.components.ts @@ -0,0 +1,42 @@ +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'happy-hero', + template: `Wow. You like {{hero.name}}. What a happy hero ... just like you.` +}) +export class HappyHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'sad-hero', + template: `You like {{hero.name}}? Such a sad hero. Are you sad too?` +}) +export class SadHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'confused-hero', + template: `Are you as confused as {{hero.name}}?` +}) +export class ConfusedHeroComponent { + @Input() hero: Hero; +} + +@Component({ + selector: 'unknown-hero', + template: `{{message}}` +}) +export class UnknownHeroComponent { + @Input() hero: Hero; + get message() { + return this.hero && this.hero.name ? + `${this.hero.name} is strange and mysterious.` : + 'Are you feeling indecisive?'; + } +} + +export const heroSwitchComponents = + [ HappyHeroComponent, SadHeroComponent, ConfusedHeroComponent, UnknownHeroComponent ]; diff --git a/public/docs/_examples/template-syntax/ts/src/app/hero.ts b/public/docs/_examples/template-syntax/ts/src/app/hero.ts new file mode 100644 index 0000000000..f8cc3b16a6 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/hero.ts @@ -0,0 +1,34 @@ +export class Hero { + static nextId = 0; + + static heroes: Hero[] = [ + new Hero( + null, + 'Hercules', + 'happy', + new Date(1970, 1, 25), + 'http://www.imdb.com/title/tt0065832/', + 325 + ), + new Hero(1, 'Mr. Nice', 'happy'), + new Hero(2, 'Narco', 'sad' ), + new Hero(3, 'Windstorm', 'confused' ), + new Hero(4, 'Magneta') + ]; + + + constructor( + public id?: number, + public name?: string, + public emotion?: string, + public birthdate?: Date, + public url?: string, + public rate = 100, + ) { + this.id = id ? id : Hero.nextId++; + } + + clone(): Hero { + return Object.assign(new Hero(), this); + } +} diff --git a/public/docs/_examples/template-syntax/ts/src/app/sizer.component.ts b/public/docs/_examples/template-syntax/ts/src/app/sizer.component.ts new file mode 100644 index 0000000000..b6065c8cd1 --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/app/sizer.component.ts @@ -0,0 +1,24 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'my-sizer', + template: ` +
    + + + +
    ` +}) +export class SizerComponent { + @Input() size: number | string; + @Output() sizeChange = new EventEmitter(); + + dec() { this.resize(-1); } + inc() { this.resize(+1); } + + resize(delta: number) { + this.size = Math.min(40, Math.max(8, +this.size + delta)); + this.sizeChange.emit(this.size); + } +} diff --git a/public/docs/_examples/template-syntax/ts/src/images/hero.png b/public/docs/_examples/template-syntax/ts/src/images/hero.png new file mode 100644 index 0000000000..2a128ac367 Binary files /dev/null and b/public/docs/_examples/template-syntax/ts/src/images/hero.png differ diff --git a/public/docs/_examples/template-syntax/ts/src/images/ng-logo.png b/public/docs/_examples/template-syntax/ts/src/images/ng-logo.png new file mode 100644 index 0000000000..1e488b1a49 Binary files /dev/null and b/public/docs/_examples/template-syntax/ts/src/images/ng-logo.png differ diff --git a/public/docs/_examples/template-syntax/ts/src/images/villain.png b/public/docs/_examples/template-syntax/ts/src/images/villain.png new file mode 100644 index 0000000000..26697d1a42 Binary files /dev/null and b/public/docs/_examples/template-syntax/ts/src/images/villain.png differ diff --git a/public/docs/_examples/template-syntax/ts/src/index.html b/public/docs/_examples/template-syntax/ts/src/index.html new file mode 100644 index 0000000000..3e711397cb --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/index.html @@ -0,0 +1,26 @@ + + + + Template Syntax + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/template-syntax/ts/src/main.ts b/public/docs/_examples/template-syntax/ts/src/main.ts new file mode 100644 index 0000000000..311c44b76d --- /dev/null +++ b/public/docs/_examples/template-syntax/ts/src/main.ts @@ -0,0 +1,5 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/template-syntax/ts/template-syntax.css b/public/docs/_examples/template-syntax/ts/template-syntax.css deleted file mode 100644 index c8c0925830..0000000000 --- a/public/docs/_examples/template-syntax/ts/template-syntax.css +++ /dev/null @@ -1,12 +0,0 @@ -fieldset {border-style:none} -img {height: 100px;} -.box {border: 1px solid black; padding:3px} -.child-div {margin-left: 1em; font-weight: normal} -.hidden {display: none} -.parent-div {margin-top: 1em; font-weight: bold} -.special {font-weight:bold; font-size: x-large} -.bad {color: red;} -.curly {font-family: "Brush Script MT"} -.toe {margin-left: 1em; font-style: italic;} -little-hero {color:blue; font-size: smaller; background-color: Turquoise } -.to-toc {margin-top: 10px; display: block} \ No newline at end of file diff --git a/public/docs/_examples/testing/ts/.gitignore b/public/docs/_examples/testing/ts/.gitignore new file mode 100644 index 0000000000..5374943421 --- /dev/null +++ b/public/docs/_examples/testing/ts/.gitignore @@ -0,0 +1 @@ +!src/browser-test-shim.js diff --git a/public/docs/_examples/testing/ts/1st-specs.plnkr.json b/public/docs/_examples/testing/ts/1st-specs.plnkr.json new file mode 100644 index 0000000000..9fe15ddef1 --- /dev/null +++ b/public/docs/_examples/testing/ts/1st-specs.plnkr.json @@ -0,0 +1,14 @@ +{ + "description": "Testing - 1st.specs", + "basePath": "src/", + "files":[ + "browser-test-shim.js", + "styles.css", + + "app/1st.spec.ts", + "1st-specs.html" + ], + "main": "1st-specs.html", + "open": "app/1st.spec.ts", + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/app-specs.plnkr.json b/public/docs/_examples/testing/ts/app-specs.plnkr.json new file mode 100644 index 0000000000..d97bf82c86 --- /dev/null +++ b/public/docs/_examples/testing/ts/app-specs.plnkr.json @@ -0,0 +1,24 @@ +{ + "description": "Testing - app.specs", + "basePath": "src/", + "files":[ + "browser-test-shim.js", + "systemjs.config.extras.js", + "styles.css", + + "app/**/*.css", + "app/**/*.html", + "app/**/*.ts", + "app/**/*.spec.ts", + + "testing/*.ts", + + "!main.ts", + "!app/bag/*.*", + "!app/1st.spec.ts", + + "app-specs.html" + ], + "main": "app-specs.html", + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/bag-specs.plnkr.json b/public/docs/_examples/testing/ts/bag-specs.plnkr.json new file mode 100644 index 0000000000..cd22e10c28 --- /dev/null +++ b/public/docs/_examples/testing/ts/bag-specs.plnkr.json @@ -0,0 +1,21 @@ +{ + "description": "Testing - bag.specs", + "basePath": "src/", + "files":[ + "browser-test-shim.js", + "systemjs.config.extras.js", + "styles.css", + + "app/bag/**/*.html", + "app/bag/**/*.ts", + "app/bag/**/*.spec.ts", + + "!app/bag/bag-main.ts", + + "testing/*.ts", + + "bag-specs.html" + ], + "main": "bag-specs.html", + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/bag.plnkr.json b/public/docs/_examples/testing/ts/bag.plnkr.json new file mode 100644 index 0000000000..4bb0ac9c5b --- /dev/null +++ b/public/docs/_examples/testing/ts/bag.plnkr.json @@ -0,0 +1,14 @@ +{ + "description": "Running the bag", + "basePath": "src/", + "files":[ + "styles.css", + + "app/bag/bag.ts", + "app/bag/bag-external-template.html", + "app/bag/bag-main.ts", + "bag.html" + ], + "main": "bag.html", + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/banner-inline-specs.plnkr.json b/public/docs/_examples/testing/ts/banner-inline-specs.plnkr.json new file mode 100644 index 0000000000..77b8c212cf --- /dev/null +++ b/public/docs/_examples/testing/ts/banner-inline-specs.plnkr.json @@ -0,0 +1,15 @@ +{ + "description": "Testing - banner-inline.component.specs", + "basePath": "src/", + "files":[ + "browser-test-shim.js", + "systemjs.config.extras.js", + + "app/banner-inline.component.ts", + "app/banner-inline.component.spec.ts", + "banner-inline-specs.html" + ], + "main": "banner-inline-specs.html", + "open": "app/banner-inline.component.spec.ts", + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/banner-specs.plnkr.json b/public/docs/_examples/testing/ts/banner-specs.plnkr.json new file mode 100644 index 0000000000..6e5f20bccb --- /dev/null +++ b/public/docs/_examples/testing/ts/banner-specs.plnkr.json @@ -0,0 +1,17 @@ +{ + "description": "Testing - banner.component.specs", + "basePath": "src/", + "files":[ + "browser-test-shim.js", + "systemjs.config.extras.js", + + "app/banner.component.css", + "app/banner.component.html", + "app/banner.component.ts", + "app/banner.component.spec.ts", + "banner-specs.html" + ], + "main": "banner-specs.html", + "open": "app/banner.component.spec.ts", + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/example-config.json b/public/docs/_examples/testing/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/testing/ts/karma-test-shim.js b/public/docs/_examples/testing/ts/karma-test-shim.js new file mode 100644 index 0000000000..1b8d6acdd4 --- /dev/null +++ b/public/docs/_examples/testing/ts/karma-test-shim.js @@ -0,0 +1,96 @@ +// #docregion +// /*global jasmine, __karma__, window*/ +Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. + +// Uncomment to get full stacktrace output. Sometimes helpful, usually not. +// Error.stackTraceLimit = Infinity; // + +jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; + +// builtPaths: root paths for output ("built") files +// get from karma.config.js, then prefix with '/src/' (default is 'app/') +var builtPaths = (__karma__.config.builtPaths || ['src/']) + .map(function(p) { return '/base/'+p;}); + +__karma__.loaded = function () { }; + +function isJsFile(path) { + return path.slice(-3) == '.js'; +} + +function isSpecFile(path) { + return /\.spec\.(.*\.)?js$/.test(path); +} + +// Is a "built" file if is JavaScript file in one of the "built" folders +function isBuiltFile(path) { + return isJsFile(path) && + builtPaths.reduce(function(keep, bp) { + return keep || (path.substr(0, bp.length) === bp); + }, false); +} + +var allSpecFiles = Object.keys(window.__karma__.files) + .filter(isSpecFile) + .filter(isBuiltFile); + +System.config({ + baseURL: 'base/src', + // Extend usual application package list with testing folder + packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, + + // Assume npm: is set in `paths` in systemjs.config + // Map the angular testing umd bundles + map: { + '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', + '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', + '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', + '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', + }, +}); + +System.import('systemjs.config.js') + .then(importSystemJsExtras) + .then(initTestBed) + .then(initTesting); + +/** Optional SystemJS configuration extras. Keep going w/o it */ +function importSystemJsExtras(){ + return System.import('systemjs.config.extras.js') + .catch(function(reason) { + console.log( + 'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.' + ); + console.log(reason); + }); +} + +function initTestBed(){ + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + + .then(function (providers) { + var coreTesting = providers[0]; + var browserTesting = providers[1]; + + coreTesting.TestBed.initTestEnvironment( + browserTesting.BrowserDynamicTestingModule, + browserTesting.platformBrowserDynamicTesting()); + }) +} + +// Import all spec files and start karma +function initTesting () { + return Promise.all( + allSpecFiles.map(function (moduleName) { + return System.import(moduleName); + }) + ) + .then(__karma__.start, __karma__.error); +} diff --git a/public/docs/_examples/testing/ts/karma.conf.js b/public/docs/_examples/testing/ts/karma.conf.js new file mode 100644 index 0000000000..a00b8add54 --- /dev/null +++ b/public/docs/_examples/testing/ts/karma.conf.js @@ -0,0 +1,98 @@ +// #docregion +module.exports = function(config) { + + var appBase = 'src/'; // transpiled app JS and map files + var appAssets = '/base/app/'; // component assets fetched by Angular's compiler + + // Testing helpers (optional) are conventionally in a folder called `testing` + var testingBase = 'src/testing/'; // transpiled test JS and map files + var testingSrcBase = 'src/testing/'; // test source TS files + + config.set({ + basePath: '', + frameworks: ['jasmine'], + + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter') + ], + + client: { + builtPaths: [appBase, testingBase], // add more spec base paths as needed + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + + customLaunchers: { + // From the CLI. Not used here but interesting + // chrome setup for travis CI using chromium + Chrome_travis_ci: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }, + + files: [ + // System.js for module loading + 'node_modules/systemjs/dist/system.src.js', + + // Polyfills + 'node_modules/core-js/client/shim.js', + + // zone.js + 'node_modules/zone.js/dist/zone.js', + 'node_modules/zone.js/dist/long-stack-trace-zone.js', + 'node_modules/zone.js/dist/proxy.js', + 'node_modules/zone.js/dist/sync-test.js', + 'node_modules/zone.js/dist/jasmine-patch.js', + 'node_modules/zone.js/dist/async-test.js', + 'node_modules/zone.js/dist/fake-async-test.js', + + // RxJs + { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false }, + { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false }, + + // Paths loaded via module imports: + // Angular itself + { pattern: 'node_modules/@angular/**/*.js', included: false, watched: false }, + { pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false }, + + { pattern: appBase + '/systemjs.config.js', included: false, watched: false }, + { pattern: appBase + '/systemjs.config.extras.js', included: false, watched: false }, + 'karma-test-shim.js', // optionally extend SystemJS mapping e.g., with barrels + + // transpiled application & spec code paths loaded via module imports + { pattern: appBase + '**/*.js', included: false, watched: true }, + { pattern: testingBase + '**/*.js', included: false, watched: true }, + + + // Asset (HTML & CSS) paths loaded via Angular's component compiler + // (these paths need to be rewritten, see proxies section) + { pattern: appBase + '**/*.html', included: false, watched: true }, + { pattern: appBase + '**/*.css', included: false, watched: true }, + + // Paths for debugging with source maps in dev tools + { pattern: appBase + '**/*.ts', included: false, watched: false }, + { pattern: appBase + '**/*.js.map', included: false, watched: false }, + { pattern: testingSrcBase + '**/*.ts', included: false, watched: false }, + { pattern: testingBase + '**/*.js.map', included: false, watched: false} + ], + + // Proxied base paths for loading assets + proxies: { + // required for modules fetched by SystemJS + '/base/src/node_modules/': '/base/node_modules/' + }, + + exclude: [], + preprocessors: {}, + reporters: ['progress', 'kjhtml'], + + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }) +} diff --git a/public/docs/_examples/testing/ts/plnkr.json b/public/docs/_examples/testing/ts/plnkr.json new file mode 100644 index 0000000000..899867159f --- /dev/null +++ b/public/docs/_examples/testing/ts/plnkr.json @@ -0,0 +1,18 @@ +{ + "description": "Heroes Test App", + "basePath": "src/", + "files":[ + "styles.css", + "systemjs.config.extras.js", + + "app/**/*.css", + "app/**/*.html", + "app/**/*.ts", + + "!app/bag/*.*", + + "main.ts", + "index.html" + ], + "tags": ["testing"] +} diff --git a/public/docs/_examples/testing/ts/src/1st-specs.html b/public/docs/_examples/testing/ts/src/1st-specs.html new file mode 100644 index 0000000000..5876a65b9a --- /dev/null +++ b/public/docs/_examples/testing/ts/src/1st-specs.html @@ -0,0 +1,41 @@ + + + + + + + 1st Specs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/testing/ts/src/app-specs.html b/public/docs/_examples/testing/ts/src/app-specs.html new file mode 100644 index 0000000000..7b7292ed7c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app-specs.html @@ -0,0 +1,56 @@ + + + + + + + Sample App Specs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/testing/ts/src/app/1st.spec.ts b/public/docs/_examples/testing/ts/src/app/1st.spec.ts new file mode 100644 index 0000000000..63f1ab134c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/1st.spec.ts @@ -0,0 +1,5 @@ +// #docplaster +// #docregion +describe('1st tests', () => { + it('true is true', () => expect(true).toBe(true)); +}); diff --git a/public/docs/_examples/testing/ts/src/app/about.component.spec.ts b/public/docs/_examples/testing/ts/src/app/about.component.spec.ts new file mode 100644 index 0000000000..0909e74434 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/about.component.spec.ts @@ -0,0 +1,27 @@ +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { AboutComponent } from './about.component'; +import { HighlightDirective } from './shared/highlight.directive'; + +let fixture: ComponentFixture; + +describe('AboutComponent (highlightDirective)', () => { + // #docregion tests + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [ AboutComponent, HighlightDirective], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .createComponent(AboutComponent); + fixture.detectChanges(); // initial binding + }); + + it('should have skyblue

    ', () => { + const de = fixture.debugElement.query(By.css('h2')); + const bgColor = de.nativeElement.style.backgroundColor; + expect(bgColor).toBe('skyblue'); + }); + // #enddocregion tests +}); diff --git a/public/docs/_examples/testing/ts/src/app/about.component.ts b/public/docs/_examples/testing/ts/src/app/about.component.ts new file mode 100644 index 0000000000..90e7132b4c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/about.component.ts @@ -0,0 +1,9 @@ +// #docregion +import { Component } from '@angular/core'; +@Component({ + template: ` +

    About

    + +

    All about this sample

    ` +}) +export class AboutComponent { } diff --git a/public/docs/_examples/testing/ts/src/app/app-routing.module.ts b/public/docs/_examples/testing/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..6096a513df --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/app-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; + +import { AboutComponent } from './about.component'; + +@NgModule({ + imports: [ + RouterModule.forRoot([ + { path: '', redirectTo: 'dashboard', pathMatch: 'full'}, + { path: 'about', component: AboutComponent }, + { path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule'} + ]) + ], + exports: [ RouterModule ] // re-export the module declarations +}) +export class AppRoutingModule { }; diff --git a/public/docs/_examples/testing/ts/src/app/app.component.html b/public/docs/_examples/testing/ts/src/app/app.component.html new file mode 100644 index 0000000000..232bcebb6d --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/app.component.html @@ -0,0 +1,11 @@ + + + + + + + diff --git a/public/docs/_examples/testing/ts/src/app/app.component.router.spec.ts b/public/docs/_examples/testing/ts/src/app/app.component.router.spec.ts new file mode 100644 index 0000000000..226d6d1ff3 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/app.component.router.spec.ts @@ -0,0 +1,198 @@ +// For more examples: +// https://github.com/angular/angular/blob/master/modules/@angular/router/test/integration.spec.ts + +import { async, ComponentFixture, fakeAsync, TestBed, tick, +} from '@angular/core/testing'; + +import { RouterTestingModule } from '@angular/router/testing'; +import { SpyLocation } from '@angular/common/testing'; + +import { click } from '../testing'; + +// r - for relatively obscure router symbols +import * as r from '@angular/router'; +import { Router, RouterLinkWithHref } from '@angular/router'; + +import { By } from '@angular/platform-browser'; +import { DebugElement, Type } from '@angular/core'; +import { Location } from '@angular/common'; + +import { AppModule } from './app.module'; +import { AppComponent } from './app.component'; +import { AboutComponent } from './about.component'; +import { DashboardHeroComponent } from './dashboard/dashboard-hero.component'; +import { TwainService } from './shared/twain.service'; + +let comp: AppComponent; +let fixture: ComponentFixture; +let page: Page; +let router: Router; +let location: SpyLocation; + +describe('AppComponent & RouterTestingModule', () => { + + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ AppModule, RouterTestingModule ] + }) + .compileComponents(); + })); + + it('should navigate to "Dashboard" immediately', fakeAsync(() => { + createComponent(); + expect(location.path()).toEqual('/dashboard', 'after initialNavigation()'); + expectElementOf(DashboardHeroComponent); + })); + + it('should navigate to "About" on click', fakeAsync(() => { + createComponent(); + click(page.aboutLinkDe); + // page.aboutLinkDe.nativeElement.click(); // ok but fails in phantom + + advance(); + expectPathToBe('/about'); + expectElementOf(AboutComponent); + + page.expectEvents([ + [r.NavigationStart, '/about'], [r.RoutesRecognized, '/about'], + [r.NavigationEnd, '/about'] + ]); + })); + + it('should navigate to "About" w/ browser location URL change', fakeAsync(() => { + createComponent(); + location.simulateHashChange('/about'); + // location.go('/about'); // also works ... except in plunker + advance(); + expectPathToBe('/about'); + expectElementOf(AboutComponent); + })); + + // Can't navigate to lazy loaded modules with this technique + xit('should navigate to "Heroes" on click', fakeAsync(() => { + createComponent(); + page.heroesLinkDe.nativeElement.click(); + advance(); + expectPathToBe('/heroes'); + })); + +}); + + +/////////////// +import { NgModuleFactoryLoader } from '@angular/core'; +import { SpyNgModuleFactoryLoader } from '@angular/router/testing'; + +import { HeroModule } from './hero/hero.module'; // should be lazy loaded +import { HeroListComponent } from './hero/hero-list.component'; + +let loader: SpyNgModuleFactoryLoader; + +///////// Can't get lazy loaded Heroes to work yet +xdescribe('AppComponent & Lazy Loading', () => { + + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ AppModule, RouterTestingModule ] + }) + .compileComponents(); + })); + + beforeEach(fakeAsync(() => { + createComponent(); + loader = TestBed.get(NgModuleFactoryLoader); + loader.stubbedModules = {expected: HeroModule}; + router.resetConfig([{path: 'heroes', loadChildren: 'expected'}]); + })); + + it('dummy', () => expect(true).toBe(true) ); + + + it('should navigate to "Heroes" on click', async(() => { + page.heroesLinkDe.nativeElement.click(); + advance(); + expectPathToBe('/heroes'); + expectElementOf(HeroListComponent); + })); + + xit('can navigate to "Heroes" w/ browser location URL change', fakeAsync(() => { + location.go('/heroes'); + advance(); + expectPathToBe('/heroes'); + expectElementOf(HeroListComponent); + + page.expectEvents([ + [r.NavigationStart, '/heroes'], [r.RoutesRecognized, '/heroes'], + [r.NavigationEnd, '/heroes'] + ]); + })); +}); + +////// Helpers ///////// + +/** Wait a tick, then detect changes */ +function advance(): void { + tick(); + fixture.detectChanges(); +} + +function createComponent() { + fixture = TestBed.createComponent(AppComponent); + comp = fixture.componentInstance; + + const injector = fixture.debugElement.injector; + location = injector.get(Location) as SpyLocation; + router = injector.get(Router); + router.initialNavigation(); + spyOn(injector.get(TwainService), 'getQuote') + .and.returnValue(Promise.resolve('Test Quote')); // fakes it + + advance(); + + page = new Page(); +} + +class Page { + aboutLinkDe: DebugElement; + dashboardLinkDe: DebugElement; + heroesLinkDe: DebugElement; + recordedEvents: any[] = []; + + // for debugging + comp: AppComponent; + location: SpyLocation; + router: Router; + fixture: ComponentFixture; + + expectEvents(pairs: any[]) { + const events = this.recordedEvents; + expect(events.length).toEqual(pairs.length, 'actual/expected events length mismatch'); + for (let i = 0; i < events.length; ++i) { + expect((events[i].constructor).name).toBe(pairs[i][0].name, 'unexpected event name'); + expect((events[i]).url).toBe(pairs[i][1], 'unexpected event url'); + } + } + + constructor() { + router.events.subscribe(e => this.recordedEvents.push(e)); + const links = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref)); + this.aboutLinkDe = links[2]; + this.dashboardLinkDe = links[0]; + this.heroesLinkDe = links[1]; + + // for debugging + this.comp = comp; + this.fixture = fixture; + this.router = router; + } +} + +function expectPathToBe(path: string, expectationFailOutput?: any) { + expect(location.path()).toEqual(path, expectationFailOutput || 'location.path()'); +} + +function expectElementOf(type: Type): any { + const el = fixture.debugElement.query(By.directive(type)); + expect(el).toBeTruthy('expected an element for ' + type.name); + return el; +} diff --git a/public/docs/_examples/testing/ts/src/app/app.component.spec.ts b/public/docs/_examples/testing/ts/src/app/app.component.spec.ts new file mode 100644 index 0000000000..20c40767c0 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/app.component.spec.ts @@ -0,0 +1,148 @@ +// #docplaster +import { async, ComponentFixture, TestBed +} from '@angular/core/testing'; + +import { DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; + + // #docregion setup-schemas + import { NO_ERRORS_SCHEMA } from '@angular/core'; + // #enddocregion setup-schemas + // #docregion setup-stubs-w-imports + import { Component } from '@angular/core'; + // #docregion setup-schemas + import { AppComponent } from './app.component'; + // #enddocregion setup-schemas + import { BannerComponent } from './banner.component'; + import { RouterLinkStubDirective } from '../testing'; + // #docregion setup-schemas + import { RouterOutletStubComponent } from '../testing'; + + // #enddocregion setup-schemas + @Component({selector: 'app-welcome', template: ''}) + class WelcomeStubComponent {} + + // #enddocregion setup-stubs-w-imports + +let comp: AppComponent; +let fixture: ComponentFixture; + +describe('AppComponent & TestModule', () => { + // #docregion setup-stubs, setup-stubs-w-imports + beforeEach( async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent, + BannerComponent, WelcomeStubComponent, + RouterLinkStubDirective, RouterOutletStubComponent + ] + }) + + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(AppComponent); + comp = fixture.componentInstance; + }); + })); + // #enddocregion setup-stubs, setup-stubs-w-imports + tests(); +}); + +//////// Testing w/ NO_ERRORS_SCHEMA ////// +describe('AppComponent & NO_ERRORS_SCHEMA', () => { + // #docregion setup-schemas + beforeEach( async(() => { + TestBed.configureTestingModule({ + declarations: [ AppComponent, RouterLinkStubDirective ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(AppComponent); + comp = fixture.componentInstance; + }); + })); + // #enddocregion setup-schemas + tests(); +}); + +//////// Testing w/ real root module ////// +// Tricky because we are disabling the router and its configuration +// Better to use RouterTestingModule +import { AppModule } from './app.module'; +import { AppRoutingModule } from './app-routing.module'; + +describe('AppComponent & AppModule', () => { + + beforeEach( async(() => { + + TestBed.configureTestingModule({ + imports: [ AppModule ] + }) + + // Get rid of app's Router configuration otherwise many failures. + // Doing so removes Router declarations; add the Router stubs + .overrideModule(AppModule, { + remove: { + imports: [ AppRoutingModule ] + }, + add: { + declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ] + } + }) + + .compileComponents() + + .then(() => { + fixture = TestBed.createComponent(AppComponent); + comp = fixture.componentInstance; + }); + })); + + tests(); +}); + +function tests() { + let links: RouterLinkStubDirective[]; + let linkDes: DebugElement[]; + + // #docregion test-setup + beforeEach(() => { + // trigger initial data binding + fixture.detectChanges(); + + // find DebugElements with an attached RouterLinkStubDirective + linkDes = fixture.debugElement + .queryAll(By.directive(RouterLinkStubDirective)); + + // get the attached link directive instances using the DebugElement injectors + links = linkDes + .map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective); + }); + // #enddocregion test-setup + + it('can instantiate it', () => { + expect(comp).not.toBeNull(); + }); + + // #docregion tests + it('can get RouterLinks from template', () => { + expect(links.length).toBe(3, 'should have 3 links'); + expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard'); + expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes'); + }); + + it('can click Heroes link in template', () => { + const heroesLinkDe = linkDes[1]; + const heroesLink = links[1]; + + expect(heroesLink.navigatedTo).toBeNull('link should not have navigated yet'); + + heroesLinkDe.triggerEventHandler('click', null); + fixture.detectChanges(); + + expect(heroesLink.navigatedTo).toBe('/heroes'); + }); + // #enddocregion tests +} diff --git a/public/docs/_examples/testing/ts/src/app/app.component.ts b/public/docs/_examples/testing/ts/src/app/app.component.ts new file mode 100644 index 0000000000..5bd535a113 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/app.component.ts @@ -0,0 +1,7 @@ +// #docregion +import { Component } from '@angular/core'; +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/testing/ts/src/app/app.module.ts b/public/docs/_examples/testing/ts/src/app/app.module.ts new file mode 100644 index 0000000000..d3c288ad11 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/app.module.ts @@ -0,0 +1,29 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './app-routing.module'; + +import { AboutComponent } from './about.component'; +import { BannerComponent } from './banner.component'; +import { HeroService, + UserService } from './model'; +import { TwainService } from './shared/twain.service'; +import { WelcomeComponent } from './welcome.component'; + + +import { DashboardModule } from './dashboard/dashboard.module'; +import { SharedModule } from './shared/shared.module'; + +@NgModule({ + imports: [ + BrowserModule, + DashboardModule, + AppRoutingModule, + SharedModule + ], + providers: [ HeroService, TwainService, UserService ], + declarations: [ AppComponent, AboutComponent, BannerComponent, WelcomeComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/testing/ts/src/app/bag/async-helper.spec.ts b/public/docs/_examples/testing/ts/src/app/bag/async-helper.spec.ts new file mode 100644 index 0000000000..12c8a4fbbd --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/bag/async-helper.spec.ts @@ -0,0 +1,68 @@ +// tslint:disable-next-line:no-unused-variable +import { async, fakeAsync, tick } from '@angular/core/testing'; + +import { Observable } from 'rxjs/Observable'; + +describe('Angular async helper', () => { + let actuallyDone = false; + + beforeEach(() => { actuallyDone = false; }); + + afterEach(() => { expect(actuallyDone).toBe(true, 'actuallyDone should be true'); }); + + it('should run normal test', () => { actuallyDone = true; }); + + it('should run normal async test', (done: DoneFn) => { + setTimeout(() => { + actuallyDone = true; + done(); + }, 0); + }); + + it('should run async test with task', + async(() => { setTimeout(() => { actuallyDone = true; }, 0); })); + + it('should run async test with successful promise', async(() => { + const p = new Promise(resolve => { setTimeout(resolve, 10); }); + p.then(() => { actuallyDone = true; }); + })); + + it('should run async test with failed promise', async(() => { + const p = new Promise((resolve, reject) => { setTimeout(reject, 10); }); + p.catch(() => { actuallyDone = true; }); + })); + + // Use done. Cannot use setInterval with async or fakeAsync + // See https://github.com/angular/angular/issues/10127 + it('should run async test with successful delayed Observable', (done: any) => { + const source = Observable.of(true).delay(10); + source.subscribe( + val => actuallyDone = true, + err => fail(err), + done + ); + }); + + // Cannot use setInterval from within an async zone test + // See https://github.com/angular/angular/issues/10127 + // xit('should run async test with successful delayed Observable', async(() => { + // const source = Observable.of(true).delay(10); + // source.subscribe( + // val => actuallyDone = true, + // err => fail(err) + // ); + // })); + + // // Fail message: Error: 1 periodic timer(s) still in the queue + // // See https://github.com/angular/angular/issues/10127 + // xit('should run async test with successful delayed Observable', fakeAsync(() => { + // const source = Observable.of(true).delay(10); + // source.subscribe( + // val => actuallyDone = true, + // err => fail(err) + // ); + + // tick(); + // })); + +}); diff --git a/public/docs/_examples/testing/ts/src/app/bag/bag-external-template.html b/public/docs/_examples/testing/ts/src/app/bag/bag-external-template.html new file mode 100644 index 0000000000..4c2b23755f --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/bag/bag-external-template.html @@ -0,0 +1 @@ +from external template diff --git a/public/docs/_examples/testing/ts/src/app/bag/bag-main.ts b/public/docs/_examples/testing/ts/src/app/bag/bag-main.ts new file mode 100644 index 0000000000..27b78200ae --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/bag/bag-main.ts @@ -0,0 +1,5 @@ +// main app entry point +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BagModule } from './bag'; + +platformBrowserDynamic().bootstrapModule(BagModule); diff --git a/public/docs/_examples/testing/ts/src/app/bag/bag.no-testbed.spec.ts b/public/docs/_examples/testing/ts/src/app/bag/bag.no-testbed.spec.ts new file mode 100644 index 0000000000..f29672ecf6 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/bag/bag.no-testbed.spec.ts @@ -0,0 +1,130 @@ +// #docplaster +import { DependentService, FancyService } from './bag'; + +///////// Fakes ///////// +export class FakeFancyService extends FancyService { + value: string = 'faked value'; +} +//////////////////////// +// #docregion FancyService +// Straight Jasmine - no imports from Angular test libraries + +describe('FancyService without the TestBed', () => { + let service: FancyService; + + beforeEach(() => { service = new FancyService(); }); + + it('#getValue should return real value', () => { + expect(service.getValue()).toBe('real value'); + }); + + it('#getAsyncValue should return async value', (done: DoneFn) => { + service.getAsyncValue().then(value => { + expect(value).toBe('async value'); + done(); + }); + }); + + // #docregion getTimeoutValue + it('#getTimeoutValue should return timeout value', (done: DoneFn) => { + service = new FancyService(); + service.getTimeoutValue().then(value => { + expect(value).toBe('timeout value'); + done(); + }); + }); + // #enddocregion getTimeoutValue + + it('#getObservableValue should return observable value', (done: DoneFn) => { + service.getObservableValue().subscribe(value => { + expect(value).toBe('observable value'); + done(); + }); + }); + +}); +// #enddocregion FancyService + +// DependentService requires injection of a FancyService +// #docregion DependentService +describe('DependentService without the TestBed', () => { + let service: DependentService; + + it('#getValue should return real value by way of the real FancyService', () => { + service = new DependentService(new FancyService()); + expect(service.getValue()).toBe('real value'); + }); + + it('#getValue should return faked value by way of a fakeService', () => { + service = new DependentService(new FakeFancyService()); + expect(service.getValue()).toBe('faked value'); + }); + + it('#getValue should return faked value from a fake object', () => { + const fake = { getValue: () => 'fake value' }; + service = new DependentService(fake as FancyService); + expect(service.getValue()).toBe('fake value'); + }); + + it('#getValue should return stubbed value from a FancyService spy', () => { + const fancy = new FancyService(); + const stubValue = 'stub value'; + const spy = spyOn(fancy, 'getValue').and.returnValue(stubValue); + service = new DependentService(fancy); + + expect(service.getValue()).toBe(stubValue, 'service returned stub value'); + expect(spy.calls.count()).toBe(1, 'stubbed method was called once'); + expect(spy.calls.mostRecent().returnValue).toBe(stubValue); + }); +}); +// #enddocregion DependentService + +// #docregion ReversePipe +import { ReversePipe } from './bag'; + +describe('ReversePipe', () => { + let pipe: ReversePipe; + + beforeEach(() => { pipe = new ReversePipe(); }); + + it('transforms "abc" to "cba"', () => { + expect(pipe.transform('abc')).toBe('cba'); + }); + + it('no change to palindrome: "able was I ere I saw elba"', () => { + const palindrome = 'able was I ere I saw elba'; + expect(pipe.transform(palindrome)).toBe(palindrome); + }); + +}); +// #enddocregion ReversePipe + + +import { ButtonComponent } from './bag'; +// #docregion ButtonComp +describe('ButtonComp', () => { + let comp: ButtonComponent; + beforeEach(() => comp = new ButtonComponent()); + + it('#isOn should be false initially', () => { + expect(comp.isOn).toBe(false); + }); + + it('#clicked() should set #isOn to true', () => { + comp.clicked(); + expect(comp.isOn).toBe(true); + }); + + it('#clicked() should set #message to "is on"', () => { + comp.clicked(); + expect(comp.message).toMatch(/is on/i); + }); + + it('#clicked() should toggle #isOn', () => { + comp.clicked(); + expect(comp.isOn).toBe(true); + comp.clicked(); + expect(comp.isOn).toBe(false); + }); +}); +// #enddocregion ButtonComp diff --git a/public/docs/_examples/testing/ts/src/app/bag/bag.spec.ts b/public/docs/_examples/testing/ts/src/app/bag/bag.spec.ts new file mode 100644 index 0000000000..d6fea7ca94 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/bag/bag.spec.ts @@ -0,0 +1,681 @@ +// #docplaster +import { + BagModule, + BankAccountComponent, BankAccountParentComponent, + ButtonComponent, + Child1Component, Child2Component, Child3Component, + FancyService, + ExternalTemplateComponent, + InputComponent, + IoComponent, IoParentComponent, + MyIfComponent, MyIfChildComponent, MyIfParentComponent, + NeedsContentComponent, ParentComponent, + TestProvidersComponent, TestViewProvidersComponent, + ReversePipeComponent, ShellComponent +} from './bag'; + +import { By } from '@angular/platform-browser'; +import { Component, + DebugElement, + Injectable } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +// Forms symbols imported only for a specific test below +import { NgModel, NgControl } from '@angular/forms'; + +import { async, ComponentFixture, fakeAsync, inject, TestBed, tick +} from '@angular/core/testing'; + +import { addMatchers, newEvent, click } from '../../testing'; + +beforeEach( addMatchers ); + +//////// Service Tests ///////////// +// #docregion FancyService +describe('use inject helper in beforeEach', () => { + let service: FancyService; + + beforeEach(() => { + TestBed.configureTestingModule({ providers: [FancyService] }); + + // `TestBed.get` returns the injectable or an + // alternative object (including null) if the service provider is not found. + // Of course it will be found in this case because we're providing it. + // #docregion testbed-get + service = TestBed.get(FancyService, null); + // #enddocregion testbed-get + }); + + it('should use FancyService', () => { + expect(service.getValue()).toBe('real value'); + }); + + it('should use FancyService', () => { + expect(service.getValue()).toBe('real value'); + }); + + it('test should wait for FancyService.getAsyncValue', async(() => { + service.getAsyncValue().then( + value => expect(value).toBe('async value') + ); + })); + + it('test should wait for FancyService.getTimeoutValue', async(() => { + service.getTimeoutValue().then( + value => expect(value).toBe('timeout value') + ); + })); + + it('test should wait for FancyService.getObservableValue', async(() => { + service.getObservableValue().subscribe( + value => expect(value).toBe('observable value') + ); + })); + + // Must use done. See https://github.com/angular/angular/issues/10127 + it('test should wait for FancyService.getObservableDelayValue', (done: DoneFn) => { + service.getObservableDelayValue().subscribe(value => { + expect(value).toBe('observable delay value'); + done(); + }); + }); + + it('should allow the use of fakeAsync', fakeAsync(() => { + let value: any; + service.getAsyncValue().then((val: any) => value = val); + tick(); // Trigger JS engine cycle until all promises resolve. + expect(value).toBe('async value'); + })); +}); +// #enddocregion FancyService + +describe('use inject within `it`', () => { + // #docregion getTimeoutValue + beforeEach(() => { + TestBed.configureTestingModule({ providers: [FancyService] }); + }); + + // #enddocregion getTimeoutValue + + it('should use modified providers', + inject([FancyService], (service: FancyService) => { + service.setValue('value modified in beforeEach'); + expect(service.getValue()).toBe('value modified in beforeEach'); + }) + ); + + // #docregion getTimeoutValue + it('test should wait for FancyService.getTimeoutValue', + async(inject([FancyService], (service: FancyService) => { + + service.getTimeoutValue().then( + value => expect(value).toBe('timeout value') + ); + }))); + // #enddocregion getTimeoutValue +}); + +describe('using async(inject) within beforeEach', () => { + let serviceValue: string; + + beforeEach(() => { + TestBed.configureTestingModule({ providers: [FancyService] }); + }); + + beforeEach( async(inject([FancyService], (service: FancyService) => { + service.getAsyncValue().then(value => serviceValue = value); + }))); + + it('should use asynchronously modified value ... in synchronous test', () => { + expect(serviceValue).toBe('async value'); + }); +}); + + +/////////// Component Tests ////////////////// + +describe('TestBed Component Tests', () => { + + beforeEach( async(() => { + TestBed + .configureTestingModule({ + imports: [BagModule], + }) + // Compile everything in BagModule + .compileComponents(); + })); + + it('should create a component with inline template', () => { + const fixture = TestBed.createComponent(Child1Component); + fixture.detectChanges(); + + expect(fixture).toHaveText('Child'); + }); + + it('should create a component with external template', () => { + const fixture = TestBed.createComponent(ExternalTemplateComponent); + fixture.detectChanges(); + + expect(fixture).toHaveText('from external template'); + }); + + it('should allow changing members of the component', () => { + const fixture = TestBed.createComponent(MyIfComponent); + + fixture.detectChanges(); + expect(fixture).toHaveText('MyIf()'); + + fixture.componentInstance.showMore = true; + fixture.detectChanges(); + expect(fixture).toHaveText('MyIf(More)'); + }); + + it('should create a nested component bound to inputs/outputs', () => { + const fixture = TestBed.createComponent(IoParentComponent); + + fixture.detectChanges(); + const heroes = fixture.debugElement.queryAll(By.css('.hero')); + expect(heroes.length).toBeGreaterThan(0, 'has heroes'); + + const comp = fixture.componentInstance; + const hero = comp.heroes[0]; + + click(heroes[0]); + fixture.detectChanges(); + + const selected = fixture.debugElement.query(By.css('p')); + expect(selected).toHaveText(hero.name); + }); + + it('can access the instance variable of an `*ngFor` row component', () => { + const fixture = TestBed.createComponent(IoParentComponent); + const comp = fixture.componentInstance; + const heroName = comp.heroes[0].name; // first hero's name + + fixture.detectChanges(); + const ngForRow = fixture.debugElement.query(By.directive(IoComponent)); // first hero ngForRow + + const hero = ngForRow.context['hero']; // the hero object passed into the row + expect(hero.name).toBe(heroName, 'ngRow.context.hero'); + + const rowComp = ngForRow.componentInstance; + // jasmine.any is an "instance-of-type" test. + expect(rowComp).toEqual(jasmine.any(IoComponent), 'component is IoComp'); + expect(rowComp.hero.name).toBe(heroName, 'component.hero'); + }); + + + // #docregion ButtonComp + it('should support clicking a button', () => { + const fixture = TestBed.createComponent(ButtonComponent); + const btn = fixture.debugElement.query(By.css('button')); + const span = fixture.debugElement.query(By.css('span')).nativeElement; + + fixture.detectChanges(); + expect(span.textContent).toMatch(/is off/i, 'before click'); + + click(btn); + fixture.detectChanges(); + expect(span.textContent).toMatch(/is on/i, 'after click'); + }); + // #enddocregion ButtonComp + + // ngModel is async so we must wait for it with promise-based `whenStable` + it('should support entering text in input box (ngModel)', async(() => { + const expectedOrigName = 'John'; + const expectedNewName = 'Sally'; + + const fixture = TestBed.createComponent(InputComponent); + fixture.detectChanges(); + + const comp = fixture.componentInstance; + const input = fixture.debugElement.query(By.css('input')).nativeElement; + + expect(comp.name).toBe(expectedOrigName, + `At start name should be ${expectedOrigName} `); + + // wait until ngModel binds comp.name to input box + fixture.whenStable().then(() => { + expect(input.value).toBe(expectedOrigName, + `After ngModel updates input box, input.value should be ${expectedOrigName} `); + + // simulate user entering new name in input + input.value = expectedNewName; + + // that change doesn't flow to the component immediately + expect(comp.name).toBe(expectedOrigName, + `comp.name should still be ${expectedOrigName} after value change, before binding happens`); + + // dispatch a DOM event so that Angular learns of input value change. + // then wait while ngModel pushes input.box value to comp.name + input.dispatchEvent(newEvent('input')); + return fixture.whenStable(); + }) + .then(() => { + expect(comp.name).toBe(expectedNewName, + `After ngModel updates the model, comp.name should be ${expectedNewName} `); + }); + })); + + // fakeAsync version of ngModel input test enables sync test style + // synchronous `tick` replaces asynchronous promise-base `whenStable` + it('should support entering text in input box (ngModel) - fakeAsync', fakeAsync(() => { + const expectedOrigName = 'John'; + const expectedNewName = 'Sally'; + + const fixture = TestBed.createComponent(InputComponent); + fixture.detectChanges(); + + const comp = fixture.componentInstance; + const input = fixture.debugElement.query(By.css('input')).nativeElement; + + expect(comp.name).toBe(expectedOrigName, + `At start name should be ${expectedOrigName} `); + + // wait until ngModel binds comp.name to input box + tick(); + expect(input.value).toBe(expectedOrigName, + `After ngModel updates input box, input.value should be ${expectedOrigName} `); + + // simulate user entering new name in input + input.value = expectedNewName; + + // that change doesn't flow to the component immediately + expect(comp.name).toBe(expectedOrigName, + `comp.name should still be ${expectedOrigName} after value change, before binding happens`); + + // dispatch a DOM event so that Angular learns of input value change. + // then wait a tick while ngModel pushes input.box value to comp.name + input.dispatchEvent(newEvent('input')); + tick(); + expect(comp.name).toBe(expectedNewName, + `After ngModel updates the model, comp.name should be ${expectedNewName} `); + })); + + // #docregion ReversePipeComp + it('ReversePipeComp should reverse the input text', fakeAsync(() => { + const inputText = 'the quick brown fox.'; + const expectedText = '.xof nworb kciuq eht'; + + const fixture = TestBed.createComponent(ReversePipeComponent); + fixture.detectChanges(); + + const comp = fixture.componentInstance; + const input = fixture.debugElement.query(By.css('input')).nativeElement as HTMLInputElement; + const span = fixture.debugElement.query(By.css('span')).nativeElement as HTMLElement; + + // simulate user entering new name in input + input.value = inputText; + + // dispatch a DOM event so that Angular learns of input value change. + // then wait a tick while ngModel pushes input.box value to comp.text + // and Angular updates the output span + input.dispatchEvent(newEvent('input')); + tick(); + fixture.detectChanges(); + expect(span.textContent).toBe(expectedText, 'output span'); + expect(comp.text).toBe(inputText, 'component.text'); + })); + // #enddocregion ReversePipeComp + + // Use this technique to find attached directives of any kind + it('can examine attached directives and listeners', () => { + const fixture = TestBed.createComponent(InputComponent); + fixture.detectChanges(); + + const inputEl = fixture.debugElement.query(By.css('input')); + + expect(inputEl.providerTokens).toContain(NgModel, 'NgModel directive'); + + const ngControl = inputEl.injector.get(NgControl); + expect(ngControl).toEqual(jasmine.any(NgControl), 'NgControl directive'); + + expect(inputEl.listeners.length).toBeGreaterThan(2, 'several listeners attached'); + }); + + // #docregion dom-attributes + it('BankAccountComponent should set attributes, styles, classes, and properties', () => { + const fixture = TestBed.createComponent(BankAccountParentComponent); + fixture.detectChanges(); + const comp = fixture.componentInstance; + + // the only child is debugElement of the BankAccount component + const el = fixture.debugElement.children[0]; + const childComp = el.componentInstance as BankAccountComponent; + expect(childComp).toEqual(jasmine.any(BankAccountComponent)); + + expect(el.context).toBe(childComp, 'context is the child component'); + + expect(el.attributes['account']).toBe(childComp.id, 'account attribute'); + expect(el.attributes['bank']).toBe(childComp.bank, 'bank attribute'); + + expect(el.classes['closed']).toBe(true, 'closed class'); + expect(el.classes['open']).toBe(false, 'open class'); + + expect(el.styles['color']).toBe(comp.color, 'color style'); + expect(el.styles['width']).toBe(comp.width + 'px', 'width style'); + // #enddocregion dom-attributes + + // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future? + // expect(el.properties['customProperty']).toBe(true, 'customProperty'); + + // #docregion dom-attributes + }); + // #enddocregion dom-attributes + + +}); + +describe('TestBed Component Overrides:', () => { + + it('should override ChildComp\'s template', () => { + + const fixture = TestBed.configureTestingModule({ + declarations: [Child1Component], + }) + .overrideComponent(Child1Component, { + set: { template: 'Fake' } + }) + .createComponent(Child1Component); + + fixture.detectChanges(); + expect(fixture).toHaveText('Fake'); + }); + + it('should override TestProvidersComp\'s FancyService provider', () => { + const fixture = TestBed.configureTestingModule({ + declarations: [TestProvidersComponent], + }) + .overrideComponent(TestProvidersComponent, { + remove: { providers: [FancyService]}, + add: { providers: [{ provide: FancyService, useClass: FakeFancyService }] }, + + // Or replace them all (this component has only one provider) + // set: { providers: [{ provide: FancyService, useClass: FakeFancyService }] }, + }) + .createComponent(TestProvidersComponent); + + fixture.detectChanges(); + expect(fixture).toHaveText('injected value: faked value', 'text'); + + // Explore the providerTokens + const tokens = fixture.debugElement.providerTokens; + expect(tokens).toContain(fixture.componentInstance.constructor, 'component ctor'); + expect(tokens).toContain(TestProvidersComponent, 'TestProvidersComp'); + expect(tokens).toContain(FancyService, 'FancyService'); + }); + + it('should override TestViewProvidersComp\'s FancyService viewProvider', () => { + const fixture = TestBed.configureTestingModule({ + declarations: [TestViewProvidersComponent], + }) + .overrideComponent(TestViewProvidersComponent, { + // remove: { viewProviders: [FancyService]}, + // add: { viewProviders: [{ provide: FancyService, useClass: FakeFancyService }] }, + + // Or replace them all (this component has only one viewProvider) + set: { viewProviders: [{ provide: FancyService, useClass: FakeFancyService }] }, + }) + .createComponent(TestViewProvidersComponent); + + fixture.detectChanges(); + expect(fixture).toHaveText('injected value: faked value'); + }); + + it('injected provider should not be same as component\'s provider', () => { + + // TestComponent is parent of TestProvidersComponent + @Component({ template: '' }) + class TestComponent {} + + // 3 levels of FancyService provider: module, TestCompomponent, TestProvidersComponent + const fixture = TestBed.configureTestingModule({ + declarations: [TestComponent, TestProvidersComponent], + providers: [FancyService] + }) + .overrideComponent(TestComponent, { + set: { providers: [{ provide: FancyService, useValue: {} }] } + }) + .overrideComponent(TestProvidersComponent, { + set: { providers: [{ provide: FancyService, useClass: FakeFancyService }] } + }) + .createComponent(TestComponent); + + let testBedProvider: FancyService; + let tcProvider: {}; + let tpcProvider: FakeFancyService; + + // `inject` uses TestBed's injector + inject([FancyService], (s: FancyService) => testBedProvider = s)(); + tcProvider = fixture.debugElement.injector.get(FancyService); + tpcProvider = fixture.debugElement.children[0].injector.get(FancyService) as FakeFancyService; + + expect(testBedProvider).not.toBe(tcProvider, 'testBed/tc not same providers'); + expect(testBedProvider).not.toBe(tpcProvider, 'testBed/tpc not same providers'); + + expect(testBedProvider instanceof FancyService).toBe(true, 'testBedProvider is FancyService'); + expect(tcProvider).toEqual({}, 'tcProvider is {}'); + expect(tpcProvider instanceof FakeFancyService).toBe(true, 'tpcProvider is FakeFancyService'); + }); + + it('can access template local variables as references', () => { + const fixture = TestBed.configureTestingModule({ + declarations: [ShellComponent, NeedsContentComponent, Child1Component, Child2Component, Child3Component], + }) + .overrideComponent(ShellComponent, { + set: { + selector: 'test-shell', + template: ` + + + + + +
    !
    +
    + ` + } + }) + .createComponent(ShellComponent); + + fixture.detectChanges(); + + // NeedsContentComp is the child of ShellComp + const el = fixture.debugElement.children[0]; + const comp = el.componentInstance; + + expect(comp.children.toArray().length).toBe(4, + 'three different child components and an ElementRef with #content'); + + expect(el.references['nc']).toBe(comp, '#nc reference to component'); + + // #docregion custom-predicate + // Filter for DebugElements with a #content reference + const contentRefs = el.queryAll( de => de.references['content']); + // #enddocregion custom-predicate + expect(contentRefs.length).toBe(4, 'elements w/ a #content reference'); + }); + +}); + +describe('Nested (one-deep) component override', () => { + + beforeEach( async(() => { + TestBed.configureTestingModule({ + declarations: [ParentComponent, FakeChildComponent] + }) + .compileComponents(); + })); + + it('ParentComp should use Fake Child component', () => { + const fixture = TestBed.createComponent(ParentComponent); + fixture.detectChanges(); + expect(fixture).toHaveText('Parent(Fake Child)'); + }); +}); + +describe('Nested (two-deep) component override', () => { + + beforeEach( async(() => { + TestBed.configureTestingModule({ + declarations: [ParentComponent, FakeChildWithGrandchildComponent, FakeGrandchildComponent] + }) + .compileComponents(); + })); + + it('should use Fake Grandchild component', () => { + const fixture = TestBed.createComponent(ParentComponent); + fixture.detectChanges(); + expect(fixture).toHaveText('Parent(Fake Child(Fake Grandchild))'); + }); +}); + +describe('Lifecycle hooks w/ MyIfParentComp', () => { + let fixture: ComponentFixture; + let parent: MyIfParentComponent; + let child: MyIfChildComponent; + + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [FormsModule], + declarations: [MyIfChildComponent, MyIfParentComponent] + }) + .compileComponents().then(() => { + fixture = TestBed.createComponent(MyIfParentComponent); + parent = fixture.componentInstance; + }); + })); + + it('should instantiate parent component', () => { + expect(parent).not.toBeNull('parent component should exist'); + }); + + it('parent component OnInit should NOT be called before first detectChanges()', () => { + expect(parent.ngOnInitCalled).toBe(false); + }); + + it('parent component OnInit should be called after first detectChanges()', () => { + fixture.detectChanges(); + expect(parent.ngOnInitCalled).toBe(true); + }); + + it('child component should exist after OnInit', () => { + fixture.detectChanges(); + getChild(); + expect(child instanceof MyIfChildComponent).toBe(true, 'should create child'); + }); + + it('should have called child component\'s OnInit ', () => { + fixture.detectChanges(); + getChild(); + expect(child.ngOnInitCalled).toBe(true); + }); + + it('child component called OnChanges once', () => { + fixture.detectChanges(); + getChild(); + expect(child.ngOnChangesCounter).toBe(1); + }); + + it('changed parent value flows to child', () => { + fixture.detectChanges(); + getChild(); + + parent.parentValue = 'foo'; + fixture.detectChanges(); + + expect(child.ngOnChangesCounter).toBe(2, + 'expected 2 changes: initial value and changed value'); + expect(child.childValue).toBe('foo', + 'childValue should eq changed parent value'); + }); + + // must be async test to see child flow to parent + it('changed child value flows to parent', async(() => { + fixture.detectChanges(); + getChild(); + + child.childValue = 'bar'; + + return new Promise(resolve => { + // Wait one JS engine turn! + setTimeout(() => resolve(), 0); + }) + .then(() => { + fixture.detectChanges(); + + expect(child.ngOnChangesCounter).toBe(2, + 'expected 2 changes: initial value and changed value'); + expect(parent.parentValue).toBe('bar', + 'parentValue should eq changed parent value'); + }); + + })); + + it('clicking "Close Child" triggers child OnDestroy', () => { + fixture.detectChanges(); + getChild(); + + const btn = fixture.debugElement.query(By.css('button')); + click(btn); + + fixture.detectChanges(); + expect(child.ngOnDestroyCalled).toBe(true); + }); + + ////// helpers /// + /** + * Get the MyIfChildComp from parent; fail w/ good message if cannot. + */ + function getChild() { + + let childDe: DebugElement; // DebugElement that should hold the MyIfChildComp + + // The Hard Way: requires detailed knowledge of the parent template + try { + childDe = fixture.debugElement.children[4].children[0]; + } catch (err) { /* we'll report the error */ } + + // DebugElement.queryAll: if we wanted all of many instances: + childDe = fixture.debugElement + .queryAll(function (de) { return de.componentInstance instanceof MyIfChildComponent; })[0]; + + // WE'LL USE THIS APPROACH ! + // DebugElement.query: find first instance (if any) + childDe = fixture.debugElement + .query(function (de) { return de.componentInstance instanceof MyIfChildComponent; }); + + if (childDe && childDe.componentInstance) { + child = childDe.componentInstance; + } else { + fail('Unable to find MyIfChildComp within MyIfParentComp'); + } + + return child; + } +}); + +////////// Fakes /////////// + +@Component({ + selector: 'child-1', + template: `Fake Child` +}) +class FakeChildComponent { } + +@Component({ + selector: 'child-1', + template: `Fake Child()` +}) +class FakeChildWithGrandchildComponent { } + +@Component({ + selector: 'grandchild-1', + template: `Fake Grandchild` +}) +class FakeGrandchildComponent { } + +@Injectable() +class FakeFancyService extends FancyService { + value: string = 'faked value'; +} diff --git a/public/docs/_examples/testing/ts/src/app/bag/bag.ts b/public/docs/_examples/testing/ts/src/app/bag/bag.ts new file mode 100644 index 0000000000..cbf1c21136 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/bag/bag.ts @@ -0,0 +1,454 @@ +/* tslint:disable:forin */ +import { Component, ContentChildren, Directive, EventEmitter, + Injectable, Input, Output, Optional, + HostBinding, HostListener, + OnInit, OnChanges, OnDestroy, + Pipe, PipeTransform, + SimpleChange } from '@angular/core'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; +import 'rxjs/add/operator/delay'; + +////////// The App: Services and Components for the tests. ////////////// + +export class Hero { + name: string; +} + +////////// Services /////////////// +// #docregion FancyService +@Injectable() +export class FancyService { + protected value: string = 'real value'; + + getValue() { return this.value; } + setValue(value: string) { this.value = value; } + + getAsyncValue() { return Promise.resolve('async value'); } + + getObservableValue() { return Observable.of('observable value'); } + + getTimeoutValue() { + return new Promise((resolve) => { + setTimeout(() => { resolve('timeout value'); }, 10); + }); + } + + getObservableDelayValue() { + return Observable.of('observable delay value').delay(10); + } +} +// #enddocregion FancyService + +// #docregion DependentService +@Injectable() +export class DependentService { + constructor(private dependentService: FancyService) { } + getValue() { return this.dependentService.getValue(); } +} +// #enddocregion DependentService + +/////////// Pipe //////////////// +/* + * Reverse the input string. +*/ +// #docregion ReversePipe +@Pipe({ name: 'reverse' }) +export class ReversePipe implements PipeTransform { + transform(s: string) { + let r = ''; + for (let i = s.length; i; ) { r += s[--i]; }; + return r; + } +} +// #enddocregion ReversePipe + +//////////// Components ///////////// +@Component({ + selector: 'bank-account', + template: ` + Bank Name: {{bank}} + Account Id: {{id}} + ` +}) +export class BankAccountComponent { + @Input() bank: string; + @Input('account') id: string; + + // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future? + // constructor(private renderer: Renderer, private el: ElementRef ) { + // renderer.setElementProperty(el.nativeElement, 'customProperty', true); + // } +} + +/** A component with attributes, styles, classes, and property setting */ +@Component({ + selector: 'bank-account-parent', + template: ` + + + ` +}) +export class BankAccountParentComponent { + width = 200; + color = 'red'; + isClosed = true; +} + +// #docregion ButtonComp +@Component({ + selector: 'button-comp', + template: ` + + {{message}}` +}) +export class ButtonComponent { + isOn = false; + clicked() { this.isOn = !this.isOn; } + get message() { return `The light is ${this.isOn ? 'On' : 'Off'}`; } +} +// #enddocregion ButtonComp + +@Component({ + selector: 'child-1', + template: `Child-1({{text}})` +}) +export class Child1Component { + @Input() text = 'Original'; +} + +@Component({ + selector: 'child-2', + template: '
    Child-2({{text}})
    ' +}) +export class Child2Component { + @Input() text: string; +} + +@Component({ + selector: 'child-3', + template: '
    Child-3({{text}})
    ' +}) +export class Child3Component { + @Input() text: string; +} + +@Component({ + selector: 'input-comp', + template: `` +}) +export class InputComponent { + name = 'John'; +} + +/* Prefer this metadata syntax */ +// @Directive({ +// selector: 'input[value]', +// host: { +// '[value]': 'value', +// '(input)': 'valueChange.emit($event.target.value)' +// }, +// inputs: ['value'], +// outputs: ['valueChange'] +// }) +// export class InputValueBinderDirective { +// value: any; +// valueChange: EventEmitter = new EventEmitter(); +// } + +// As the style-guide recommends +@Directive({ selector: 'input[value]' }) +export class InputValueBinderDirective { + @HostBinding() + @Input() + value: any; + + @Output() + valueChange: EventEmitter = new EventEmitter(); + + @HostListener('input', ['$event.target.value']) + onInput(value: any) { this.valueChange.emit(value); } +} + +@Component({ + selector: 'input-value-comp', + template: ` + Name: {{name}} + ` +}) +export class InputValueBinderComponent { + name = 'Sally'; // initial value +} + +@Component({ + selector: 'parent-comp', + template: `Parent()` +}) +export class ParentComponent { } + +@Component({ + selector: 'io-comp', + template: `
    Original {{hero.name}}
    ` +}) +export class IoComponent { + @Input() hero: Hero; + @Output() selected = new EventEmitter(); + click() { this.selected.emit(this.hero); } +} + +@Component({ + selector: 'io-parent-comp', + template: ` +

    Click to select a hero

    +

    The selected hero is {{selectedHero.name}}

    + + + ` +}) +export class IoParentComponent { + heroes: Hero[] = [ {name: 'Bob'}, {name: 'Carol'}, {name: 'Ted'}, {name: 'Alice'} ]; + selectedHero: Hero; + onSelect(hero: Hero) { this.selectedHero = hero; } +} + +@Component({ + selector: 'my-if-comp', + template: `MyIf(More)` +}) +export class MyIfComponent { + showMore = false; +} + +@Component({ + selector: 'my-service-comp', + template: `injected value: {{fancyService.value}}`, + providers: [FancyService] +}) +export class TestProvidersComponent { + constructor(private fancyService: FancyService) {} +} + + +@Component({ + selector: 'my-service-comp', + template: `injected value: {{fancyService.value}}`, + viewProviders: [FancyService] +}) +export class TestViewProvidersComponent { + constructor(private fancyService: FancyService) {} +} + +@Component({ + selector: 'external-template-comp', + templateUrl: './bag-external-template.html' +}) +export class ExternalTemplateComponent implements OnInit { + serviceValue: string; + + constructor(@Optional() private service: FancyService) { } + + ngOnInit() { + if (this.service) { this.serviceValue = this.service.getValue(); } + } +} + +@Component({ + selector: 'comp-w-ext-comp', + template: ` +

    comp-w-ext-comp

    + + ` +}) +export class InnerCompWithExternalTemplateComponent { } + +@Component({ + selector: 'bad-template-comp', + templateUrl: './non-existant.html' +}) +export class BadTemplateUrlComponent { } + + + +@Component({selector: 'needs-content', template: ''}) +export class NeedsContentComponent { + // children with #content local variable + @ContentChildren('content') children: any; +} + +///////// MyIfChildComp //////// +@Component({ + selector: 'my-if-child-1', + + template: ` +

    MyIfChildComp

    +
    + +
    +

    Change log:

    +
    {{i + 1}} - {{log}}
    ` +}) +export class MyIfChildComponent implements OnInit, OnChanges, OnDestroy { + @Input() value = ''; + @Output() valueChange = new EventEmitter(); + + get childValue() { return this.value; } + set childValue(v: string) { + if (this.value === v) { return; } + this.value = v; + this.valueChange.emit(v); + } + + changeLog: string[] = []; + + ngOnInitCalled = false; + ngOnChangesCounter = 0; + ngOnDestroyCalled = false; + + ngOnInit() { + this.ngOnInitCalled = true; + this.changeLog.push('ngOnInit called'); + } + + ngOnDestroy() { + this.ngOnDestroyCalled = true; + this.changeLog.push('ngOnDestroy called'); + } + + ngOnChanges(changes: {[propertyName: string]: SimpleChange}) { + for (let propName in changes) { + this.ngOnChangesCounter += 1; + let prop = changes[propName]; + let cur = JSON.stringify(prop.currentValue); + let prev = JSON.stringify(prop.previousValue); + this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`); + } + } +} + +///////// MyIfParentComp //////// + +@Component({ + selector: 'my-if-parent-comp', + template: ` +

    MyIfParentComp

    + +
    +
    + +
    + ` +}) +export class MyIfParentComponent implements OnInit { + ngOnInitCalled = false; + parentValue = 'Hello, World'; + showChild = false; + toggleLabel = 'Unknown'; + + ngOnInit() { + this.ngOnInitCalled = true; + this.clicked(); + } + + clicked() { + this.showChild = !this.showChild; + this.toggleLabel = this.showChild ? 'Close' : 'Show'; + } +} + + +@Component({ + selector: 'reverse-pipe-comp', + template: ` + + {{text | reverse}} + ` +}) +export class ReversePipeComponent { + text = 'my dog has fleas.'; +} + +@Component({template: '
    Replace Me
    '}) +export class ShellComponent { } + +@Component({ + selector: 'bag-comp', + template: ` +

    Specs Bag

    + +
    +

    Input/Output Component

    + +
    +

    External Template Component

    + +
    +

    Component With External Template Component

    + +
    +

    Reverse Pipe

    + +
    +

    InputValueBinder Directive

    + +
    +

    Button Component

    + +
    +

    Needs Content

    + + + + + +
    !
    +
    + ` +}) +export class BagComponent { } +//////// Aggregations //////////// + +export const bagDeclarations = [ + BagComponent, + BankAccountComponent, BankAccountParentComponent, + ButtonComponent, + Child1Component, Child2Component, Child3Component, + ExternalTemplateComponent, InnerCompWithExternalTemplateComponent, + InputComponent, + InputValueBinderDirective, InputValueBinderComponent, + IoComponent, IoParentComponent, + MyIfComponent, MyIfChildComponent, MyIfParentComponent, + NeedsContentComponent, ParentComponent, + TestProvidersComponent, TestViewProvidersComponent, + ReversePipe, ReversePipeComponent, ShellComponent +]; + +export const bagProviders = [DependentService, FancyService]; + +//////////////////// +//////////// +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +@NgModule({ + imports: [BrowserModule, FormsModule], + declarations: bagDeclarations, + providers: bagProviders, + entryComponents: [BagComponent], + bootstrap: [BagComponent] +}) +export class BagModule { } + diff --git a/public/docs/_examples/testing/ts/src/app/banner-inline.component.spec.ts b/public/docs/_examples/testing/ts/src/app/banner-inline.component.spec.ts new file mode 100644 index 0000000000..7f35d6b956 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner-inline.component.spec.ts @@ -0,0 +1,55 @@ +// #docplaster +// #docregion imports +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { BannerComponent } from './banner-inline.component'; +// #enddocregion imports + +// #docregion setup +describe('BannerComponent (inline template)', () => { + + let comp: BannerComponent; + let fixture: ComponentFixture; + let de: DebugElement; + let el: HTMLElement; + +// #docregion before-each + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ BannerComponent ], // declare the test component + }); + + fixture = TestBed.createComponent(BannerComponent); + + comp = fixture.componentInstance; // BannerComponent test instance + + // query for the title

    by CSS element selector + de = fixture.debugElement.query(By.css('h1')); + el = de.nativeElement; + }); +// #enddocregion before-each +// #enddocregion setup + + // #docregion test-w-o-detect-changes + it('no title in the DOM until manually call `detectChanges`', () => { + expect(el.textContent).toEqual(''); + }); + // #enddocregion test-w-o-detect-changes + + // #docregion tests + it('should display original title', () => { + fixture.detectChanges(); + expect(el.textContent).toContain(comp.title); + }); + + it('should display a different test title', () => { + comp.title = 'Test Title'; + fixture.detectChanges(); + expect(el.textContent).toContain('Test Title'); + }); + // #enddocregion tests +// #docregion setup +}); +// #enddocregion setup diff --git a/public/docs/_examples/testing/ts/src/app/banner-inline.component.ts b/public/docs/_examples/testing/ts/src/app/banner-inline.component.ts new file mode 100644 index 0000000000..7ec4ef6999 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner-inline.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-banner', + template: '

    {{title}}

    ' +}) +export class BannerComponent { + title = 'Test Tour of Heroes'; +} + diff --git a/public/docs/_examples/testing/ts/src/app/banner.component.css b/public/docs/_examples/testing/ts/src/app/banner.component.css new file mode 100644 index 0000000000..cd09a55b3c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner.component.css @@ -0,0 +1 @@ +h1 { color: green; font-size: 350%} diff --git a/public/docs/_examples/testing/ts/src/app/banner.component.detect-changes.spec.ts b/public/docs/_examples/testing/ts/src/app/banner.component.detect-changes.spec.ts new file mode 100644 index 0000000000..412f5be586 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner.component.detect-changes.spec.ts @@ -0,0 +1,59 @@ +// #docplaster +// #docregion +// #docregion import-async +import { async } from '@angular/core/testing'; +// #enddocregion import-async +// #docregion import-ComponentFixtureAutoDetect +import { ComponentFixtureAutoDetect } from '@angular/core/testing'; +// #enddocregion import-ComponentFixtureAutoDetect +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { BannerComponent } from './banner.component'; + +describe('BannerComponent (AutoChangeDetect)', () => { + let comp: BannerComponent; + let fixture: ComponentFixture; + let de: DebugElement; + let el: HTMLElement; + + beforeEach(async(() => { + // #docregion auto-detect + TestBed.configureTestingModule({ + declarations: [ BannerComponent ], + providers: [ + { provide: ComponentFixtureAutoDetect, useValue: true } + ] + }) + // #enddocregion auto-detect + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BannerComponent); + comp = fixture.componentInstance; + de = fixture.debugElement.query(By.css('h1')); + el = de.nativeElement; + }); + + // #docregion auto-detect-tests + it('should display original title', () => { + // Hooray! No `fixture.detectChanges()` needed + expect(el.textContent).toContain(comp.title); + }); + + it('should still see original title after comp.title change', () => { + const oldTitle = comp.title; + comp.title = 'Test Title'; + // Displayed title is old because Angular didn't hear the change :( + expect(el.textContent).toContain(oldTitle); + }); + + it('should display updated title after detectChanges', () => { + comp.title = 'Test Title'; + fixture.detectChanges(); // detect changes explicitly + expect(el.textContent).toContain(comp.title); + }); + // #enddocregion auto-detect-tests +}); diff --git a/public/docs/_examples/testing/ts/src/app/banner.component.html b/public/docs/_examples/testing/ts/src/app/banner.component.html new file mode 100644 index 0000000000..6213adcb47 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner.component.html @@ -0,0 +1 @@ +

    {{title}}

    diff --git a/public/docs/_examples/testing/ts/src/app/banner.component.spec.ts b/public/docs/_examples/testing/ts/src/app/banner.component.spec.ts new file mode 100644 index 0000000000..a564c45c85 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner.component.spec.ts @@ -0,0 +1,53 @@ +// #docplaster +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { BannerComponent } from './banner.component'; + +describe('BannerComponent (templateUrl)', () => { + + let comp: BannerComponent; + let fixture: ComponentFixture; + let de: DebugElement; + let el: HTMLElement; + + // #docregion async-before-each + // async beforeEach + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ BannerComponent ], // declare the test component + }) + .compileComponents(); // compile template and css + })); + // #enddocregion async-before-each + + // #docregion sync-before-each + // synchronous beforeEach + beforeEach(() => { + fixture = TestBed.createComponent(BannerComponent); + + comp = fixture.componentInstance; // BannerComponent test instance + + // query for the title

    by CSS element selector + de = fixture.debugElement.query(By.css('h1')); + el = de.nativeElement; + }); + // #enddocregion sync-before-each + + it('no title in the DOM until manually call `detectChanges`', () => { + expect(el.textContent).toEqual(''); + }); + + it('should display original title', () => { + fixture.detectChanges(); + expect(el.textContent).toContain(comp.title); + }); + + it('should display a different test title', () => { + comp.title = 'Test Title'; + fixture.detectChanges(); + expect(el.textContent).toContain('Test Title'); + }); + +}); diff --git a/public/docs/_examples/testing/ts/src/app/banner.component.ts b/public/docs/_examples/testing/ts/src/app/banner.component.ts new file mode 100644 index 0000000000..4355a40867 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/banner.component.ts @@ -0,0 +1,12 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-banner', + templateUrl: './banner.component.html', + styleUrls: ['./banner.component.css'] +}) +export class BannerComponent { + title = 'Test Tour of Heroes'; +} + diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.css b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.css new file mode 100644 index 0000000000..eb54d181d8 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.css @@ -0,0 +1,28 @@ +.hero { + padding: 20px; + position: relative; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} + +.hero:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} + +@media (max-width: 600px) { + .hero { + font-size: 10px; + max-height: 75px; } +} + +@media (max-width: 1024px) { + .hero { + min-width: 60px; + } +} diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.html b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.html new file mode 100644 index 0000000000..ff49bd17a5 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.html @@ -0,0 +1,4 @@ + +
    + {{hero.name | uppercase}} +
    diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.spec.ts b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.spec.ts new file mode 100644 index 0000000000..40c01571e6 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.spec.ts @@ -0,0 +1,124 @@ +import { async, ComponentFixture, TestBed +} from '@angular/core/testing'; + +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { addMatchers, click } from '../../testing'; + +import { Hero } from '../model/hero'; +import { DashboardHeroComponent } from './dashboard-hero.component'; + +beforeEach( addMatchers ); + +describe('DashboardHeroComponent when tested directly', () => { + + let comp: DashboardHeroComponent; + let expectedHero: Hero; + let fixture: ComponentFixture; + let heroEl: DebugElement; + + // #docregion setup, compile-components + // async beforeEach + beforeEach( async(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardHeroComponent ], + }) + .compileComponents(); // compile template and css + })); + // #enddocregion compile-components + + // synchronous beforeEach + beforeEach(() => { + fixture = TestBed.createComponent(DashboardHeroComponent); + comp = fixture.componentInstance; + heroEl = fixture.debugElement.query(By.css('.hero')); // find hero element + + // pretend that it was wired to something that supplied a hero + expectedHero = new Hero(42, 'Test Name'); + comp.hero = expectedHero; + fixture.detectChanges(); // trigger initial data binding + }); + // #enddocregion setup + + // #docregion name-test + it('should display hero name', () => { + const expectedPipedName = expectedHero.name.toUpperCase(); + expect(heroEl.nativeElement.textContent).toContain(expectedPipedName); + }); + // #enddocregion name-test + + // #docregion click-test + it('should raise selected event when clicked', () => { + let selectedHero: Hero; + comp.selected.subscribe((hero: Hero) => selectedHero = hero); + + // #docregion trigger-event-handler + heroEl.triggerEventHandler('click', null); + // #enddocregion trigger-event-handler + expect(selectedHero).toBe(expectedHero); + }); + // #enddocregion click-test + + // #docregion click-test-2 + it('should raise selected event when clicked', () => { + let selectedHero: Hero; + comp.selected.subscribe((hero: Hero) => selectedHero = hero); + + click(heroEl); // triggerEventHandler helper + expect(selectedHero).toBe(expectedHero); + }); + // #enddocregion click-test-2 +}); + +////////////////// + +describe('DashboardHeroComponent when inside a test host', () => { + let testHost: TestHostComponent; + let fixture: ComponentFixture; + let heroEl: DebugElement; + + // #docregion test-host-setup + beforeEach( async(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardHeroComponent, TestHostComponent ], // declare both + }).compileComponents(); + })); + + beforeEach(() => { + // create TestHostComponent instead of DashboardHeroComponent + fixture = TestBed.createComponent(TestHostComponent); + testHost = fixture.componentInstance; + heroEl = fixture.debugElement.query(By.css('.hero')); // find hero + fixture.detectChanges(); // trigger initial data binding + }); + // #enddocregion test-host-setup + + // #docregion test-host-tests + it('should display hero name', () => { + const expectedPipedName = testHost.hero.name.toUpperCase(); + expect(heroEl.nativeElement.textContent).toContain(expectedPipedName); + }); + + it('should raise selected event when clicked', () => { + click(heroEl); + // selected hero should be the same data bound hero + expect(testHost.selectedHero).toBe(testHost.hero); + }); + // #enddocregion test-host-tests +}); + +////// Test Host Component ////// +import { Component } from '@angular/core'; + +// #docregion test-host +@Component({ + template: ` + ` +}) +class TestHostComponent { + hero = new Hero(42, 'Test Name'); + selectedHero: Hero; + onSelected(hero: Hero) { this.selectedHero = hero; } +} +// #enddocregion test-host diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.ts b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.ts new file mode 100644 index 0000000000..9f6be16d7d --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard-hero.component.ts @@ -0,0 +1,17 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +import { Hero } from '../model'; + +// #docregion component +@Component({ + selector: 'dashboard-hero', + templateUrl: './dashboard-hero.component.html', + styleUrls: [ './dashboard-hero.component.css' ] +}) +export class DashboardHeroComponent { + @Input() hero: Hero; + @Output() selected = new EventEmitter(); + click() { this.selected.emit(this.hero); } +} +// #enddocregion component diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.css b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.css new file mode 100644 index 0000000000..98130b61c6 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.css @@ -0,0 +1,35 @@ +[class*='col-'] { + float: left; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +[class*='col-'] { + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } +} diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.html b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.html new file mode 100644 index 0000000000..b26e16b828 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.html @@ -0,0 +1,9 @@ +

    {{title}}

    + +
    + + + + +
    diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.no-testbed.spec.ts b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.no-testbed.spec.ts new file mode 100644 index 0000000000..125e5193b7 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.no-testbed.spec.ts @@ -0,0 +1,57 @@ +import { Router } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { Hero } from '../model'; + +import { addMatchers } from '../../testing'; +import { FakeHeroService } from '../model/testing'; + +class FakeRouter { + navigateByUrl(url: string) { return url; } +} + +describe('DashboardComponent: w/o Angular TestBed', () => { + let comp: DashboardComponent; + let heroService: FakeHeroService; + let router: Router; + + beforeEach(() => { + addMatchers(); + router = new FakeRouter() as any as Router; + heroService = new FakeHeroService(); + comp = new DashboardComponent(router, heroService); + }); + + it('should NOT have heroes before calling OnInit', () => { + expect(comp.heroes.length).toBe(0, + 'should not have heroes before OnInit'); + }); + + it('should NOT have heroes immediately after OnInit', () => { + comp.ngOnInit(); // ngOnInit -> getHeroes + expect(comp.heroes.length).toBe(0, + 'should not have heroes until service promise resolves'); + }); + + it('should HAVE heroes after HeroService gets them', (done: DoneFn) => { + comp.ngOnInit(); // ngOnInit -> getHeroes + heroService.lastPromise // the one from getHeroes + .then(() => { + // throw new Error('deliberate error'); // see it fail gracefully + expect(comp.heroes.length).toBeGreaterThan(0, + 'should have heroes after service promise resolves'); + }) + .then(done, done.fail); + }); + + it('should tell ROUTER to navigate by hero id', () => { + const hero = new Hero(42, 'Abbracadabra'); + const spy = spyOn(router, 'navigateByUrl'); + + comp.gotoDetail(hero); + + const navArgs = spy.calls.mostRecent().args[0]; + expect(navArgs).toBe('/heroes/42', 'should nav to HeroDetail for Hero 42'); + }); + +}); diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.spec.ts b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.spec.ts new file mode 100644 index 0000000000..0b0f9e213a --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.spec.ts @@ -0,0 +1,147 @@ +// #docplaster +import { async, inject, ComponentFixture, TestBed +} from '@angular/core/testing'; + +import { addMatchers, click } from '../../testing'; +import { HeroService } from '../model'; +import { FakeHeroService } from '../model/testing'; + +import { By } from '@angular/platform-browser'; +import { Router } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { DashboardModule } from './dashboard.module'; + +// #docregion router-stub +class RouterStub { + navigateByUrl(url: string) { return url; } +} +// #enddocregion router-stub + +beforeEach ( addMatchers ); + +let comp: DashboardComponent; +let fixture: ComponentFixture; + +//////// Deep //////////////// + +describe('DashboardComponent (deep)', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ DashboardModule ] + }); + }); + + compileAndCreate(); + + tests(clickForDeep); + + function clickForDeep() { + // get first
    DebugElement + const heroEl = fixture.debugElement.query(By.css('.hero')); + click(heroEl); + } +}); + +//////// Shallow //////////////// + +import { NO_ERRORS_SCHEMA } from '@angular/core'; + +describe('DashboardComponent (shallow)', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ DashboardComponent ], + schemas: [NO_ERRORS_SCHEMA] + }); + }); + + compileAndCreate(); + + tests(clickForShallow); + + function clickForShallow() { + // get first DebugElement + const heroEl = fixture.debugElement.query(By.css('dashboard-hero')); + heroEl.triggerEventHandler('selected', comp.heroes[0]); + } +}); + +/** Add TestBed providers, compile, and create DashboardComponent */ +function compileAndCreate() { + // #docregion compile-and-create-body + beforeEach( async(() => { + TestBed.configureTestingModule({ + providers: [ + { provide: HeroService, useClass: FakeHeroService }, + { provide: Router, useClass: RouterStub } + ] + }) + .compileComponents().then(() => { + fixture = TestBed.createComponent(DashboardComponent); + comp = fixture.componentInstance; + }); + // #enddocregion compile-and-create-body + })); +} + +/** + * The (almost) same tests for both. + * Only change: the way that the first hero is clicked + */ +function tests(heroClick: Function) { + + it('should NOT have heroes before ngOnInit', () => { + expect(comp.heroes.length).toBe(0, + 'should not have heroes before ngOnInit'); + }); + + it('should NOT have heroes immediately after ngOnInit', () => { + fixture.detectChanges(); // runs initial lifecycle hooks + + expect(comp.heroes.length).toBe(0, + 'should not have heroes until service promise resolves'); + }); + + describe('after get dashboard heroes', () => { + + // Trigger component so it gets heroes and binds to them + beforeEach( async(() => { + fixture.detectChanges(); // runs ngOnInit -> getHeroes + fixture.whenStable() // No need for the `lastPromise` hack! + .then(() => fixture.detectChanges()); // bind to heroes + })); + + it('should HAVE heroes', () => { + expect(comp.heroes.length).toBeGreaterThan(0, + 'should have heroes after service promise resolves'); + }); + + it('should DISPLAY heroes', () => { + // Find and examine the displayed heroes + // Look for them in the DOM by css class + const heroes = fixture.debugElement.queryAll(By.css('dashboard-hero')); + expect(heroes.length).toBe(4, 'should display 4 heroes'); + }); + + // #docregion navigate-test, inject + it('should tell ROUTER to navigate when hero clicked', + inject([Router], (router: Router) => { // ... + // #enddocregion inject + + const spy = spyOn(router, 'navigateByUrl'); + + heroClick(); // trigger click on first inner
    + + // args passed to router.navigateByUrl() + const navArgs = spy.calls.first().args[0]; + + // expecting to navigate to id of the component's first hero + const id = comp.heroes[0].id; + expect(navArgs).toBe('/heroes/' + id, + 'should nav to HeroDetail for first hero'); + // #docregion inject + })); + // #enddocregion navigate-test, inject + }); +} + diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.ts b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.ts new file mode 100644 index 0000000000..3edaa0c0ab --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.component.ts @@ -0,0 +1,40 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero, HeroService } from '../model'; + +@Component({ + selector: 'app-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +export class DashboardComponent implements OnInit { + + heroes: Hero[] = []; + + // #docregion ctor + constructor( + private router: Router, + private heroService: HeroService) { + } + // #enddocregion ctor + + ngOnInit() { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes.slice(1, 5)); + } + + // #docregion goto-detail + gotoDetail(hero: Hero) { + let url = `/heroes/${hero.id}`; + this.router.navigateByUrl(url); + } + // #enddocregion goto-detail + + get title() { + let cnt = this.heroes.length; + return cnt === 0 ? 'No Heroes' : + cnt === 1 ? 'Top Hero' : `Top ${cnt} Heroes`; + } +} diff --git a/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.module.ts b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.module.ts new file mode 100644 index 0000000000..8a70c851a0 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/dashboard/dashboard.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { SharedModule } from '../shared/shared.module'; + +import { DashboardComponent } from './dashboard.component'; +import { DashboardHeroComponent } from './dashboard-hero.component'; + +const routes: Routes = [ + { path: 'dashboard', component: DashboardComponent }, +]; + +@NgModule({ + imports: [ + SharedModule, + RouterModule.forChild(routes) + ], + declarations: [ DashboardComponent, DashboardHeroComponent ] +}) +export class DashboardModule { } diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.css b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.css new file mode 100644 index 0000000000..f6139ba274 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.css @@ -0,0 +1,29 @@ +label { + display: inline-block; + width: 3em; + margin: .5em 0; + color: #607D8B; + font-weight: bold; +} +input { + height: 2em; + font-size: 1em; + padding-left: .4em; +} +button { + margin-top: 20px; + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #ccc; + cursor: auto; +} diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.html b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.html new file mode 100644 index 0000000000..7e86a668f6 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.html @@ -0,0 +1,12 @@ + +
    +

    {{hero.name | titlecase}} Details

    +
    + {{hero.id}}
    +
    + + +
    + + +
    diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.no-testbed.spec.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.no-testbed.spec.ts new file mode 100644 index 0000000000..422dae6f77 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.no-testbed.spec.ts @@ -0,0 +1,58 @@ +import { HeroDetailComponent } from './hero-detail.component'; +import { Hero } from '../model'; + +import { ActivatedRouteStub } from '../../testing'; + +////////// Tests //////////////////// + +describe('HeroDetailComponent - no TestBed', () => { + let activatedRoute: ActivatedRouteStub; + let comp: HeroDetailComponent; + let expectedHero: Hero; + let hds: any; + let router: any; + + beforeEach((done: any) => { + expectedHero = new Hero(42, 'Bubba'); + activatedRoute = new ActivatedRouteStub(); + activatedRoute.testParams = { id: expectedHero.id }; + + router = jasmine.createSpyObj('router', ['navigate']); + + hds = jasmine.createSpyObj('HeroDetailService', ['getHero', 'saveHero']); + hds.getHero.and.returnValue(Promise.resolve(expectedHero)); + hds.saveHero.and.returnValue(Promise.resolve(expectedHero)); + + comp = new HeroDetailComponent(hds, activatedRoute, router); + comp.ngOnInit(); + + // OnInit calls HDS.getHero; wait for it to get the fake hero + hds.getHero.calls.first().returnValue.then(done); + }); + + it('should expose the hero retrieved from the service', () => { + expect(comp.hero).toBe(expectedHero); + }); + + it('should navigate when click cancel', () => { + comp.cancel(); + expect(router.navigate.calls.any()).toBe(true, 'router.navigate called'); + }); + + it('should save when click save', () => { + comp.save(); + expect(hds.saveHero.calls.any()).toBe(true, 'HeroDetailService.save called'); + expect(router.navigate.calls.any()).toBe(false, 'router.navigate not called yet'); + }); + + it('should navigate when click save resolves', (done: any) => { + comp.save(); + // waits for async save to complete before navigating + hds.saveHero.calls.first().returnValue + .then(() => { + expect(router.navigate.calls.any()).toBe(true, 'router.navigate called'); + done(); + }); + }); + +}); diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts new file mode 100644 index 0000000000..80b6450ac5 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.spec.ts @@ -0,0 +1,364 @@ +// #docplaster +import { + async, ComponentFixture, fakeAsync, inject, TestBed, tick +} from '@angular/core/testing'; + +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { + ActivatedRoute, ActivatedRouteStub, click, newEvent, Router, RouterStub +} from '../../testing'; + +import { Hero } from '../model'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroDetailService } from './hero-detail.service'; +import { HeroModule } from './hero.module'; + +////// Testing Vars ////// +let activatedRoute: ActivatedRouteStub; +let comp: HeroDetailComponent; +let fixture: ComponentFixture; +let page: Page; + +////// Tests ////// +describe('HeroDetailComponent', () => { + beforeEach(() => { + activatedRoute = new ActivatedRouteStub(); + }); + describe('with HeroModule setup', heroModuleSetup); + describe('when override its provided HeroDetailService', overrideSetup); + describe('with FormsModule setup', formsModuleSetup); + describe('with SharedModule setup', sharedModuleSetup); +}); + +//////////////////// +function overrideSetup() { + // #docregion hds-spy + class HeroDetailServiceSpy { + testHero = new Hero(42, 'Test Hero'); + + getHero = jasmine.createSpy('getHero').and.callFake( + () => Promise + .resolve(true) + .then(() => Object.assign({}, this.testHero)) + ); + + saveHero = jasmine.createSpy('saveHero').and.callFake( + (hero: Hero) => Promise + .resolve(true) + .then(() => Object.assign(this.testHero, hero)) + ); + } + // #enddocregion hds-spy + + // the `id` value is irrelevant because ignored by service stub + beforeEach(() => activatedRoute.testParams = { id: 99999 } ); + + // #docregion setup-override + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ HeroModule ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRoute }, + { provide: Router, useClass: RouterStub}, + // #enddocregion setup-override + // HeroDetailService at this level is IRRELEVANT! + { provide: HeroDetailService, useValue: {} } + // #docregion setup-override + ] + }) + + // Override component's own provider + // #docregion override-component-method + .overrideComponent(HeroDetailComponent, { + set: { + providers: [ + { provide: HeroDetailService, useClass: HeroDetailServiceSpy } + ] + } + }) + // #enddocregion override-component-method + + .compileComponents(); + })); + // #enddocregion setup-override + + // #docregion override-tests + let hdsSpy: HeroDetailServiceSpy; + + beforeEach( async(() => { + createComponent(); + // get the component's injected HeroDetailServiceSpy + hdsSpy = fixture.debugElement.injector.get(HeroDetailService) as any; + })); + + it('should have called `getHero`', () => { + expect(hdsSpy.getHero.calls.count()).toBe(1, 'getHero called once'); + }); + + it('should display stub hero\'s name', () => { + expect(page.nameDisplay.textContent).toBe(hdsSpy.testHero.name); + }); + + it('should save stub hero change', fakeAsync(() => { + const origName = hdsSpy.testHero.name; + const newName = 'New Name'; + + page.nameInput.value = newName; + page.nameInput.dispatchEvent(newEvent('input')); // tell Angular + + expect(comp.hero.name).toBe(newName, 'component hero has new name'); + expect(hdsSpy.testHero.name).toBe(origName, 'service hero unchanged before save'); + + click(page.saveBtn); + expect(hdsSpy.saveHero.calls.count()).toBe(1, 'saveHero called once'); + + tick(); // wait for async save to complete + expect(hdsSpy.testHero.name).toBe(newName, 'service hero has new name after save'); + expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called'); + })); + // #enddocregion override-tests + + it('fixture injected service is not the component injected service', + inject([HeroDetailService], (service: HeroDetailService) => { + + expect(service).toEqual({}, 'service injected from fixture'); + expect(hdsSpy).toBeTruthy('service injected into component'); + })); +} + +//////////////////// +import { HEROES, FakeHeroService } from '../model/testing'; +import { HeroService } from '../model'; + +const firstHero = HEROES[0]; + +function heroModuleSetup() { + // #docregion setup-hero-module + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ HeroModule ], + // #enddocregion setup-hero-module + // declarations: [ HeroDetailComponent ], // NO! DOUBLE DECLARATION + // #docregion setup-hero-module + providers: [ + { provide: ActivatedRoute, useValue: activatedRoute }, + { provide: HeroService, useClass: FakeHeroService }, + { provide: Router, useClass: RouterStub}, + ] + }) + .compileComponents(); + })); + // #enddocregion setup-hero-module + + // #docregion route-good-id + describe('when navigate to existing hero', () => { + let expectedHero: Hero; + + beforeEach( async(() => { + expectedHero = firstHero; + activatedRoute.testParams = { id: expectedHero.id }; + createComponent(); + })); + + // #docregion selected-tests + it('should display that hero\'s name', () => { + expect(page.nameDisplay.textContent).toBe(expectedHero.name); + }); + // #enddocregion route-good-id + + it('should navigate when click cancel', () => { + click(page.cancelBtn); + expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called'); + }); + + it('should save when click save but not navigate immediately', () => { + // Get service injected into component and spy on its`saveHero` method. + // It delegates to fake `HeroService.updateHero` which delivers a safe test result. + const hds = fixture.debugElement.injector.get(HeroDetailService); + const saveSpy = spyOn(hds, 'saveHero').and.callThrough(); + + click(page.saveBtn); + expect(saveSpy.calls.any()).toBe(true, 'HeroDetailService.save called'); + expect(page.navSpy.calls.any()).toBe(false, 'router.navigate not called'); + }); + + it('should navigate when click save and save resolves', fakeAsync(() => { + click(page.saveBtn); + tick(); // wait for async save to complete + expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called'); + })); + + // #docregion title-case-pipe + it('should convert hero name to Title Case', () => { + const inputName = 'quick BROWN fox'; + const titleCaseName = 'Quick Brown Fox'; + + // simulate user entering new name into the input box + page.nameInput.value = inputName; + + // dispatch a DOM event so that Angular learns of input value change. + page.nameInput.dispatchEvent(newEvent('input')); + + // Tell Angular to update the output span through the title pipe + fixture.detectChanges(); + + expect(page.nameDisplay.textContent).toBe(titleCaseName); + }); + // #enddocregion title-case-pipe + // #enddocregion selected-tests + // #docregion route-good-id + }); + // #enddocregion route-good-id + + // #docregion route-no-id + describe('when navigate with no hero id', () => { + beforeEach( async( createComponent )); + + it('should have hero.id === 0', () => { + expect(comp.hero.id).toBe(0); + }); + + it('should display empty hero name', () => { + expect(page.nameDisplay.textContent).toBe(''); + }); + }); + // #enddocregion route-no-id + + // #docregion route-bad-id + describe('when navigate to non-existant hero id', () => { + beforeEach( async(() => { + activatedRoute.testParams = { id: 99999 }; + createComponent(); + })); + + it('should try to navigate back to hero list', () => { + expect(page.gotoSpy.calls.any()).toBe(true, 'comp.gotoList called'); + expect(page.navSpy.calls.any()).toBe(true, 'router.navigate called'); + }); + }); + // #enddocregion route-bad-id + + // Why we must use `fixture.debugElement.injector` in `Page()` + it('cannot use `inject` to get component\'s provided HeroDetailService', () => { + let service: HeroDetailService; + fixture = TestBed.createComponent(HeroDetailComponent); + expect( + // Throws because `inject` only has access to TestBed's injector + // which is an ancestor of the component's injector + inject([HeroDetailService], (hds: HeroDetailService) => service = hds ) + ) + .toThrowError(/No provider for HeroDetailService/); + + // get `HeroDetailService` with component's own injector + service = fixture.debugElement.injector.get(HeroDetailService); + expect(service).toBeDefined('debugElement.injector'); + }); +} + +///////////////////// +import { FormsModule } from '@angular/forms'; +import { TitleCasePipe } from '../shared/title-case.pipe'; + +function formsModuleSetup() { + // #docregion setup-forms-module + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ FormsModule ], + declarations: [ HeroDetailComponent, TitleCasePipe ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRoute }, + { provide: HeroService, useClass: FakeHeroService }, + { provide: Router, useClass: RouterStub}, + ] + }) + .compileComponents(); + })); + // #enddocregion setup-forms-module + + it('should display 1st hero\'s name', fakeAsync(() => { + const expectedHero = firstHero; + activatedRoute.testParams = { id: expectedHero.id }; + createComponent().then(() => { + expect(page.nameDisplay.textContent).toBe(expectedHero.name); + }); + })); +} + +/////////////////////// +import { SharedModule } from '../shared/shared.module'; + +function sharedModuleSetup() { + // #docregion setup-shared-module + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ SharedModule ], + declarations: [ HeroDetailComponent ], + providers: [ + { provide: ActivatedRoute, useValue: activatedRoute }, + { provide: HeroService, useClass: FakeHeroService }, + { provide: Router, useClass: RouterStub}, + ] + }) + .compileComponents(); + })); + // #enddocregion setup-shared-module + + it('should display 1st hero\'s name', fakeAsync(() => { + const expectedHero = firstHero; + activatedRoute.testParams = { id: expectedHero.id }; + createComponent().then(() => { + expect(page.nameDisplay.textContent).toBe(expectedHero.name); + }); + })); +} + +/////////// Helpers ///// + +// #docregion create-component +/** Create the HeroDetailComponent, initialize it, set test variables */ +function createComponent() { + fixture = TestBed.createComponent(HeroDetailComponent); + comp = fixture.componentInstance; + page = new Page(); + + // 1st change detection triggers ngOnInit which gets a hero + fixture.detectChanges(); + return fixture.whenStable().then(() => { + // 2nd change detection displays the async-fetched hero + fixture.detectChanges(); + page.addPageElements(); + }); +} +// #enddocregion create-component + +// #docregion page +class Page { + gotoSpy: jasmine.Spy; + navSpy: jasmine.Spy; + + saveBtn: DebugElement; + cancelBtn: DebugElement; + nameDisplay: HTMLElement; + nameInput: HTMLInputElement; + + constructor() { + const router = TestBed.get(Router); // get router from root injector + this.gotoSpy = spyOn(comp, 'gotoList').and.callThrough(); + this.navSpy = spyOn(router, 'navigate'); + } + + /** Add page elements after hero arrives */ + addPageElements() { + if (comp.hero) { + // have a hero so these elements are now in the DOM + const buttons = fixture.debugElement.queryAll(By.css('button')); + this.saveBtn = buttons[0]; + this.cancelBtn = buttons[1]; + this.nameDisplay = fixture.debugElement.query(By.css('span')).nativeElement; + this.nameInput = fixture.debugElement.query(By.css('input')).nativeElement; + } + } +} +// #enddocregion page diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.ts new file mode 100644 index 0000000000..25f13b0cd5 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.component.ts @@ -0,0 +1,63 @@ +/* tslint:disable:member-ordering */ +// #docplaster +import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import 'rxjs/add/operator/map'; + +import { Hero } from '../model'; +import { HeroDetailService } from './hero-detail.service'; + +// #docregion prototype +@Component({ + selector: 'app-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: ['./hero-detail.component.css' ], + providers: [ HeroDetailService ] +}) +export class HeroDetailComponent implements OnInit { + // #docregion ctor + constructor( + private heroDetailService: HeroDetailService, + private route: ActivatedRoute, + private router: Router) { + } + // #enddocregion ctor +// #enddocregion prototype + + @Input() hero: Hero; + + // #docregion ng-on-init + ngOnInit(): void { + // get hero when `id` param changes + this.route.params.subscribe(p => this.getHero(p && p['id'])); + } + // #enddocregion ng-on-init + + private getHero(id: string): void { + // when no id or id===0, create new hero + if (!id) { + this.hero = new Hero(); + return; + } + + this.heroDetailService.getHero(id).then(hero => { + if (hero) { + this.hero = hero; + } else { + this.gotoList(); // id not found; navigate to list + } + }); + } + + save(): void { + this.heroDetailService.saveHero(this.hero).then(() => this.gotoList()); + } + + cancel() { this.gotoList(); } + + gotoList() { + this.router.navigate(['../'], {relativeTo: this.route}); + } +// #docregion prototype +} +// #enddocregion prototype diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-detail.service.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.service.ts new file mode 100644 index 0000000000..6239ae5b80 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-detail.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; + +import { Hero, HeroService } from '../model'; + +// #docregion prototype +@Injectable() +export class HeroDetailService { + constructor(private heroService: HeroService) { } +// #enddocregion prototype + + // Returns a clone which caller may modify safely + getHero(id: number | string): Promise { + if (typeof id === 'string') { + id = parseInt(id as string, 10); + } + return this.heroService.getHero(id).then(hero => { + return hero ? Object.assign({}, hero) : null; // clone or null + }); + } + + saveHero(hero: Hero) { + return this.heroService.updateHero(hero); + } +// #docregion prototype +} +// #enddocregion prototype diff --git a/public/docs/_examples/toh-5/ts/app/heroes.component.css b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.css similarity index 100% rename from public/docs/_examples/toh-5/ts/app/heroes.component.css rename to public/docs/_examples/testing/ts/src/app/hero/hero-list.component.css diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.html b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.html new file mode 100644 index 0000000000..cd37301fd6 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.html @@ -0,0 +1,8 @@ +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.spec.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.spec.ts new file mode 100644 index 0000000000..dbf9d37d71 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.spec.ts @@ -0,0 +1,139 @@ +import { async, ComponentFixture, fakeAsync, TestBed, tick +} from '@angular/core/testing'; + +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { addMatchers, newEvent, Router, RouterStub +} from '../../testing'; + +import { HEROES, FakeHeroService } from '../model/testing'; + +import { HeroModule } from './hero.module'; +import { HeroListComponent } from './hero-list.component'; +import { HighlightDirective } from '../shared/highlight.directive'; +import { HeroService } from '../model'; + +let comp: HeroListComponent; +let fixture: ComponentFixture; +let page: Page; + +/////// Tests ////// + +describe('HeroListComponent', () => { + + beforeEach( async(() => { + addMatchers(); + TestBed.configureTestingModule({ + imports: [HeroModule], + providers: [ + { provide: HeroService, useClass: FakeHeroService }, + { provide: Router, useClass: RouterStub} + ] + }) + .compileComponents() + .then(createComponent); + })); + + it('should display heroes', () => { + expect(page.heroRows.length).toBeGreaterThan(0); + }); + + it('1st hero should match 1st test hero', () => { + const expectedHero = HEROES[0]; + const actualHero = page.heroRows[0].textContent; + expect(actualHero).toContain(expectedHero.id, 'hero.id'); + expect(actualHero).toContain(expectedHero.name, 'hero.name'); + }); + + it('should select hero on click', fakeAsync(() => { + const expectedHero = HEROES[1]; + const li = page.heroRows[1]; + li.dispatchEvent(newEvent('click')); + tick(); + // `.toEqual` because selectedHero is clone of expectedHero; see FakeHeroService + expect(comp.selectedHero).toEqual(expectedHero); + })); + + it('should navigate to selected hero detail on click', fakeAsync(() => { + const expectedHero = HEROES[1]; + const li = page.heroRows[1]; + li.dispatchEvent(newEvent('click')); + tick(); + + // should have navigated + expect(page.navSpy.calls.any()).toBe(true, 'navigate called'); + + // composed hero detail will be URL like 'heroes/42' + // expect link array with the route path and hero id + // first argument to router.navigate is link array + const navArgs = page.navSpy.calls.first().args[0]; + expect(navArgs[0]).toContain('heroes', 'nav to heroes detail URL'); + expect(navArgs[1]).toBe(expectedHero.id, 'expected hero.id'); + + })); + + it('should find `HighlightDirective` with `By.directive', () => { + // #docregion by + // Can find DebugElement either by css selector or by directive + const h2 = fixture.debugElement.query(By.css('h2')); + const directive = fixture.debugElement.query(By.directive(HighlightDirective)); + // #enddocregion by + expect(h2).toBe(directive); + }); + + it('should color header with `HighlightDirective`', () => { + const h2 = page.highlightDe.nativeElement as HTMLElement; + const bgColor = h2.style.backgroundColor; + + // different browsers report color values differently + const isExpectedColor = bgColor === 'gold' || bgColor === 'rgb(255, 215, 0)'; + expect(isExpectedColor).toBe(true, 'backgroundColor'); + }); + + it('the `HighlightDirective` is among the element\'s providers', () => { + expect(page.highlightDe.providerTokens).toContain(HighlightDirective, 'HighlightDirective'); + }); +}); + +/////////// Helpers ///// + +/** Create the component and set the `page` test variables */ +function createComponent() { + fixture = TestBed.createComponent(HeroListComponent); + comp = fixture.componentInstance; + + // change detection triggers ngOnInit which gets a hero + fixture.detectChanges(); + + return fixture.whenStable().then(() => { + // got the heroes and updated component + // change detection updates the view + fixture.detectChanges(); + page = new Page(); + }); +} + +class Page { + /** Hero line elements */ + heroRows: HTMLLIElement[]; + + /** Highlighted element */ + highlightDe: DebugElement; + + /** Spy on router navigate method */ + navSpy: jasmine.Spy; + + constructor() { + this.heroRows = fixture.debugElement.queryAll(By.css('li')).map(de => de.nativeElement); + + // Find the first element with an attached HighlightDirective + this.highlightDe = fixture.debugElement.query(By.directive(HighlightDirective)); + + // Get the component's injected router and spy on it + const router = fixture.debugElement.injector.get(Router); + this.navSpy = spyOn(router, 'navigate'); + }; +} + + diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.ts new file mode 100644 index 0000000000..c61ff23f0e --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-list.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero, HeroService } from '../model'; + +@Component({ + selector: 'app-heroes', + templateUrl: './hero-list.component.html', + styleUrls: [ './hero-list.component.css' ] +}) +export class HeroListComponent implements OnInit { + heroes: Promise; + selectedHero: Hero; + + constructor( + private router: Router, + private heroService: HeroService) { } + + ngOnInit() { + this.heroes = this.heroService.getHeroes(); + } + + onSelect(hero: Hero) { + this.selectedHero = hero; + this.router.navigate(['../heroes', this.selectedHero.id ]); + } +} diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero-routing.module.ts b/public/docs/_examples/testing/ts/src/app/hero/hero-routing.module.ts new file mode 100644 index 0000000000..59ec14474c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero-routing.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { HeroListComponent } from './hero-list.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', component: HeroListComponent }, + { path: ':id', component: HeroDetailComponent } +]; + +export const routedComponents = [HeroDetailComponent, HeroListComponent]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class HeroRoutingModule {} diff --git a/public/docs/_examples/testing/ts/src/app/hero/hero.module.ts b/public/docs/_examples/testing/ts/src/app/hero/hero.module.ts new file mode 100644 index 0000000000..dfe33cc199 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/hero/hero.module.ts @@ -0,0 +1,9 @@ +import { NgModule } from '@angular/core'; +import { SharedModule } from '../shared/shared.module'; +import { routedComponents, HeroRoutingModule } from './hero-routing.module'; + +@NgModule({ + imports: [ SharedModule, HeroRoutingModule ], + declarations: [ routedComponents ] +}) +export class HeroModule { } diff --git a/public/docs/_examples/testing/ts/src/app/model/hero.service.ts b/public/docs/_examples/testing/ts/src/app/model/hero.service.ts new file mode 100644 index 0000000000..667d47312b --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/hero.service.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; + +import { Hero } from './hero'; +import { HEROES } from './test-heroes'; + +@Injectable() +/** Dummy HeroService. Pretend it makes real http requests */ +export class HeroService { + getHeroes() { + return Promise.resolve(HEROES); + } + + getHero(id: number | string): Promise { + if (typeof id === 'string') { + id = parseInt(id as string, 10); + } + return this.getHeroes().then( + heroes => heroes.find(hero => hero.id === id) + ); + } + + updateHero(hero: Hero): Promise { + return this.getHero(hero.id).then(h => { + if (!h) { + throw new Error(`Hero ${hero.id} not found`); + } + return Object.assign(h, hero); + }); + } +} diff --git a/public/docs/_examples/testing/ts/src/app/model/hero.spec.ts b/public/docs/_examples/testing/ts/src/app/model/hero.spec.ts new file mode 100644 index 0000000000..e8acf913f2 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/hero.spec.ts @@ -0,0 +1,20 @@ +// #docregion +import { Hero } from './hero'; + +describe('Hero', () => { + it('has name', () => { + const hero = new Hero(1, 'Super Cat'); + expect(hero.name).toBe('Super Cat'); + }); + + it('has id', () => { + const hero = new Hero(1, 'Super Cat'); + expect(hero.id).toBe(1); + }); + + it('can clone itself', () => { + const hero = new Hero(1, 'Super Cat'); + const clone = hero.clone(); + expect(hero).toEqual(clone); + }); +}); diff --git a/public/docs/_examples/testing/ts/src/app/model/hero.ts b/public/docs/_examples/testing/ts/src/app/model/hero.ts new file mode 100644 index 0000000000..6a98f0dfdc --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + constructor(public id = 0, public name = '') { } + clone() { return new Hero(this.id, this.name); } +} diff --git a/public/docs/_examples/testing/ts/src/app/model/http-hero.service.spec.ts b/public/docs/_examples/testing/ts/src/app/model/http-hero.service.spec.ts new file mode 100644 index 0000000000..c16b421274 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/http-hero.service.spec.ts @@ -0,0 +1,127 @@ +import { + async, inject, TestBed +} from '@angular/core/testing'; + +import { + MockBackend, + MockConnection +} from '@angular/http/testing'; + +import { + HttpModule, Http, XHRBackend, Response, ResponseOptions +} from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/of'; + +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/toPromise'; + +import { Hero } from './hero'; +import { HttpHeroService as HeroService } from './http-hero.service'; + +const makeHeroData = () => [ + { id: 1, name: 'Windstorm' }, + { id: 2, name: 'Bombasto' }, + { id: 3, name: 'Magneta' }, + { id: 4, name: 'Tornado' } +] as Hero[]; + +//////// Tests ///////////// +describe('Http-HeroService (mockBackend)', () => { + + beforeEach( async(() => { + TestBed.configureTestingModule({ + imports: [ HttpModule ], + providers: [ + HeroService, + { provide: XHRBackend, useClass: MockBackend } + ] + }) + .compileComponents(); + })); + + it('can instantiate service when inject service', + inject([HeroService], (service: HeroService) => { + expect(service instanceof HeroService).toBe(true); + })); + + + + it('can instantiate service with "new"', inject([Http], (http: Http) => { + expect(http).not.toBeNull('http should be provided'); + let service = new HeroService(http); + expect(service instanceof HeroService).toBe(true, 'new service should be ok'); + })); + + + it('can provide the mockBackend as XHRBackend', + inject([XHRBackend], (backend: MockBackend) => { + expect(backend).not.toBeNull('backend should be provided'); + })); + + describe('when getHeroes', () => { + let backend: MockBackend; + let service: HeroService; + let fakeHeroes: Hero[]; + let response: Response; + + beforeEach(inject([Http, XHRBackend], (http: Http, be: MockBackend) => { + backend = be; + service = new HeroService(http); + fakeHeroes = makeHeroData(); + let options = new ResponseOptions({status: 200, body: {data: fakeHeroes}}); + response = new Response(options); + })); + + it('should have expected fake heroes (then)', async(inject([], () => { + backend.connections.subscribe((c: MockConnection) => c.mockRespond(response)); + + service.getHeroes().toPromise() + // .then(() => Promise.reject('deliberate')) + .then(heroes => { + expect(heroes.length).toBe(fakeHeroes.length, + 'should have expected no. of heroes'); + }); + }))); + + it('should have expected fake heroes (Observable.do)', async(inject([], () => { + backend.connections.subscribe((c: MockConnection) => c.mockRespond(response)); + + service.getHeroes() + .do(heroes => { + expect(heroes.length).toBe(fakeHeroes.length, + 'should have expected no. of heroes'); + }) + .toPromise(); + }))); + + + it('should be OK returning no heroes', async(inject([], () => { + let resp = new Response(new ResponseOptions({status: 200, body: {data: []}})); + backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp)); + + service.getHeroes() + .do(heroes => { + expect(heroes.length).toBe(0, 'should have no heroes'); + }) + .toPromise(); + }))); + + it('should treat 404 as an Observable error', async(inject([], () => { + let resp = new Response(new ResponseOptions({status: 404})); + backend.connections.subscribe((c: MockConnection) => c.mockRespond(resp)); + + service.getHeroes() + .do(heroes => { + fail('should not respond with heroes'); + }) + .catch(err => { + expect(err).toMatch(/Bad response status/, 'should catch bad response status code'); + return Observable.of(null); // failure is the expected test result + }) + .toPromise(); + }))); + }); +}); diff --git a/public/docs/_examples/testing/ts/src/app/model/http-hero.service.ts b/public/docs/_examples/testing/ts/src/app/model/http-hero.service.ts new file mode 100644 index 0000000000..a5fe46b801 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/http-hero.service.ts @@ -0,0 +1,68 @@ +// #docplaster +// #docregion +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Headers, RequestOptions } from '@angular/http'; +import { Hero } from './hero'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/observable/throw'; + +import 'rxjs/add/operator/do'; +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/map'; + +@Injectable() +export class HttpHeroService { + private _heroesUrl = 'app/heroes'; // URL to web api + + constructor (private http: Http) {} + + getHeroes (): Observable { + return this.http.get(this._heroesUrl) + .map(this.extractData) + // .do(data => console.log(data)) // eyeball results in the console + .catch(this.handleError); + } + + getHero(id: number | string) { + return this.http + .get('app/heroes/?id=${id}') + .map((r: Response) => r.json().data as Hero[]); + } + + addHero (name: string): Observable { + let body = JSON.stringify({ name }); + let headers = new Headers({ 'Content-Type': 'application/json' }); + let options = new RequestOptions({ headers: headers }); + + return this.http.post(this._heroesUrl, body, options) + .map(this.extractData) + .catch(this.handleError); + } + + updateHero (hero: Hero): Observable { + let body = JSON.stringify(hero); + let headers = new Headers({ 'Content-Type': 'application/json' }); + let options = new RequestOptions({ headers: headers }); + + return this.http.put(this._heroesUrl, body, options) + .map(this.extractData) + .catch(this.handleError); + } + + private extractData(res: Response) { + if (res.status < 200 || res.status >= 300) { + throw new Error('Bad response status: ' + res.status); + } + let body = res.json(); + return body.data || { }; + } + + private handleError (error: any) { + // In a real world app, we might send the error to remote logging infrastructure + let errMsg = error.message || 'Server error'; + console.error(errMsg); // log to console instead + return Observable.throw(errMsg); + } +} diff --git a/public/docs/_examples/testing/ts/src/app/model/index.ts b/public/docs/_examples/testing/ts/src/app/model/index.ts new file mode 100644 index 0000000000..227004d5be --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/index.ts @@ -0,0 +1,7 @@ +// Model barrel +export * from './hero'; +export * from './hero.service'; +export * from './http-hero.service'; +export * from './test-heroes'; + +export * from './user.service'; diff --git a/public/docs/_examples/testing/ts/src/app/model/test-heroes.ts b/public/docs/_examples/testing/ts/src/app/model/test-heroes.ts new file mode 100644 index 0000000000..d40ce5d564 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/test-heroes.ts @@ -0,0 +1,11 @@ +// #docregion +import { Hero } from './hero'; + +export var HEROES: Hero[] = [ + new Hero(11, 'Mr. Nice'), + new Hero(12, 'Narco'), + new Hero(13, 'Bombasto'), + new Hero(14, 'Celeritas'), + new Hero(15, 'Magneta'), + new Hero(16, 'RubberMan') +]; diff --git a/public/docs/_examples/testing/ts/src/app/model/testing/fake-hero.service.ts b/public/docs/_examples/testing/ts/src/app/model/testing/fake-hero.service.ts new file mode 100644 index 0000000000..79a865cc44 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/testing/fake-hero.service.ts @@ -0,0 +1,41 @@ +// re-export for tester convenience +export { Hero } from '../hero'; +export { HeroService } from '../hero.service'; + +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +export var HEROES: Hero[] = [ + new Hero(41, 'Bob'), + new Hero(42, 'Carol'), + new Hero(43, 'Ted'), + new Hero(44, 'Alice'), + new Hero(45, 'Speedy'), + new Hero(46, 'Stealthy') +]; + +export class FakeHeroService implements HeroService { + + heroes = HEROES.map(h => h.clone()); + lastPromise: Promise; // remember so we can spy on promise calls + + getHero(id: number | string) { + if (typeof id === 'string') { + id = parseInt(id as string, 10); + } + let hero = this.heroes.find(h => h.id === id); + return this.lastPromise = Promise.resolve(hero); + } + + getHeroes() { + return this.lastPromise = Promise.resolve(this.heroes); + } + + updateHero(hero: Hero): Promise { + return this.lastPromise = this.getHero(hero.id).then(h => { + return h ? + Object.assign(h, hero) : + Promise.reject(`Hero ${hero.id} not found`) as any as Promise; + }); + } +} diff --git a/public/docs/_examples/testing/ts/src/app/model/testing/index.ts b/public/docs/_examples/testing/ts/src/app/model/testing/index.ts new file mode 100644 index 0000000000..6da76e67db --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/testing/index.ts @@ -0,0 +1 @@ +export * from './fake-hero.service'; diff --git a/public/docs/_examples/testing/ts/src/app/model/user.service.ts b/public/docs/_examples/testing/ts/src/app/model/user.service.ts new file mode 100644 index 0000000000..280efefeec --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/model/user.service.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class UserService { + isLoggedIn = true; + user = {name: 'Sam Spade'}; +} diff --git a/public/docs/_examples/testing/ts/src/app/shared/highlight.directive.spec.ts b/public/docs/_examples/testing/ts/src/app/shared/highlight.directive.spec.ts new file mode 100644 index 0000000000..b990f20b69 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/highlight.directive.spec.ts @@ -0,0 +1,104 @@ +import { Component, DebugElement } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; + +import { HighlightDirective } from './highlight.directive'; +import { newEvent } from '../../testing'; + +// #docregion test-component +@Component({ + template: ` +

    Something Yellow

    +

    The Default (Gray)

    +

    No Highlight

    + ` +}) +class TestComponent { } +// #enddocregion test-component + +describe('HighlightDirective', () => { + + let fixture: ComponentFixture; + let des: DebugElement[]; // the three elements w/ the directive + let bareH2: DebugElement; // the

    w/o the directive + + // #docregion selected-tests + beforeEach(() => { + fixture = TestBed.configureTestingModule({ + declarations: [ HighlightDirective, TestComponent ] + }) + .createComponent(TestComponent); + + fixture.detectChanges(); // initial binding + + // all elements with an attached HighlightDirective + des = fixture.debugElement.queryAll(By.directive(HighlightDirective)); + + // the h2 without the HighlightDirective + bareH2 = fixture.debugElement.query(By.css('h2:not([highlight])')); + }); + + // color tests + it('should have three highlighted elements', () => { + expect(des.length).toBe(3); + }); + + it('should color 1st

    background "yellow"', () => { + const bgColor = des[0].nativeElement.style.backgroundColor; + expect(bgColor).toBe('yellow'); + }); + + it('should color 2nd

    background w/ default color', () => { + const dir = des[1].injector.get(HighlightDirective) as HighlightDirective; + const bgColor = des[1].nativeElement.style.backgroundColor; + expect(bgColor).toBe(dir.defaultColor); + }); + + it('should bind background to value color', () => { + // easier to work with nativeElement + const input = des[2].nativeElement as HTMLInputElement; + expect(input.style.backgroundColor).toBe('cyan', 'initial backgroundColor'); + + // dispatch a DOM event so that Angular responds to the input value change. + input.value = 'green'; + input.dispatchEvent(newEvent('input')); + fixture.detectChanges(); + + expect(input.style.backgroundColor).toBe('green', 'changed backgroundColor'); + }); + + + it('bare

    should not have a customProperty', () => { + expect(bareH2.properties['customProperty']).toBeUndefined(); + }); + // #enddocregion selected-tests + + // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future? + // // customProperty tests + // it('all highlighted elements should have a true customProperty', () => { + // const allTrue = des.map(de => !!de.properties['customProperty']).every(v => v === true); + // expect(allTrue).toBe(true); + // }); + + // injected directive + // attached HighlightDirective can be injected + it('can inject `HighlightDirective` in 1st

    ', () => { + const dir = des[0].injector.get(HighlightDirective); + expect(dir).toBeTruthy(); + }); + + it('cannot inject `HighlightDirective` in 3rd

    ', () => { + const dir = bareH2.injector.get(HighlightDirective, null); + expect(dir).toBe(null); + }); + + // DebugElement.providerTokens + // attached HighlightDirective should be listed in the providerTokens + it('should have `HighlightDirective` in 1st

    providerTokens', () => { + expect(des[0].providerTokens).toContain(HighlightDirective); + }); + + it('should not have `HighlightDirective` in 3rd

    providerTokens', () => { + expect(bareH2.providerTokens).not.toContain(HighlightDirective); + }); +}); diff --git a/public/docs/_examples/testing/ts/src/app/shared/highlight.directive.ts b/public/docs/_examples/testing/ts/src/app/shared/highlight.directive.ts new file mode 100644 index 0000000000..20901878c4 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/highlight.directive.ts @@ -0,0 +1,20 @@ +// #docregion +import { Directive, ElementRef, Input, OnChanges } from '@angular/core'; + +@Directive({ selector: '[highlight]' }) +/** Set backgroundColor for the attached element to highlight color + * and set the element's customProperty to true */ +export class HighlightDirective implements OnChanges { + + defaultColor = 'rgb(211, 211, 211)'; // lightgray + + @Input('highlight') bgColor: string; + + constructor(private el: ElementRef) { + el.nativeElement.style.customProperty = true; + } + + ngOnChanges() { + this.el.nativeElement.style.backgroundColor = this.bgColor || this.defaultColor; + } +} diff --git a/public/docs/_examples/testing/ts/src/app/shared/shared.module.ts b/public/docs/_examples/testing/ts/src/app/shared/shared.module.ts new file mode 100644 index 0000000000..17c41c0410 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/shared.module.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +import { HighlightDirective } from './highlight.directive'; +import { TitleCasePipe } from './title-case.pipe'; +import { TwainComponent } from './twain.component'; + +@NgModule({ + imports: [ CommonModule ], + exports: [ CommonModule, FormsModule, + HighlightDirective, TitleCasePipe, TwainComponent ], + declarations: [ HighlightDirective, TitleCasePipe, TwainComponent ] +}) +export class SharedModule { } diff --git a/public/docs/_examples/testing/ts/src/app/shared/title-case.pipe.spec.ts b/public/docs/_examples/testing/ts/src/app/shared/title-case.pipe.spec.ts new file mode 100644 index 0000000000..5dfc5d91b0 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/title-case.pipe.spec.ts @@ -0,0 +1,34 @@ +// #docplaster +// #docregion +import { TitleCasePipe } from './title-case.pipe'; + +// #docregion excerpt, mini-excerpt +describe('TitleCasePipe', () => { + // This pipe is a pure, stateless function so no need for BeforeEach + let pipe = new TitleCasePipe(); + + it('transforms "abc" to "Abc"', () => { + expect(pipe.transform('abc')).toBe('Abc'); + }); +// #enddocregion mini-excerpt + + it('transforms "abc def" to "Abc Def"', () => { + expect(pipe.transform('abc def')).toBe('Abc Def'); + }); + + // ... more tests ... +// #enddocregion excerpt + it('leaves "Abc Def" unchanged', () => { + expect(pipe.transform('Abc Def')).toBe('Abc Def'); + }); + + it('transforms "abc-def" to "Abc-def"', () => { + expect(pipe.transform('abc-def')).toBe('Abc-def'); + }); + + it('transforms " abc def" to " Abc Def" (preserves spaces) ', () => { + expect(pipe.transform(' abc def')).toBe(' Abc Def'); + }); +// #docregion excerpt, mini-excerpt +}); +// #enddocregion excerpt, mini-excerpt diff --git a/public/docs/_examples/testing/ts/src/app/shared/title-case.pipe.ts b/public/docs/_examples/testing/ts/src/app/shared/title-case.pipe.ts new file mode 100644 index 0000000000..df2567778d --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/title-case.pipe.ts @@ -0,0 +1,11 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'titlecase', pure: false}) +/** Transform to Title Case: uppercase the first letter of the words in a string.*/ +export class TitleCasePipe implements PipeTransform { + transform(input: string): string { + return input.length === 0 ? '' : + input.replace(/\w\S*/g, (txt => txt[0].toUpperCase() + txt.substr(1).toLowerCase() )); + } +} diff --git a/public/docs/_examples/testing/ts/src/app/shared/twain.component.spec.ts b/public/docs/_examples/testing/ts/src/app/shared/twain.component.spec.ts new file mode 100644 index 0000000000..b177c0bfc3 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/twain.component.spec.ts @@ -0,0 +1,92 @@ +// #docplaster +import { async, fakeAsync, ComponentFixture, TestBed, tick } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { TwainService } from './twain.service'; +import { TwainComponent } from './twain.component'; + +describe('TwainComponent', () => { + + let comp: TwainComponent; + let fixture: ComponentFixture; + + let spy: jasmine.Spy; + let de: DebugElement; + let el: HTMLElement; + let twainService: TwainService; // the actually injected service + + const testQuote = 'Test Quote'; + + // #docregion setup + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ TwainComponent ], + providers: [ TwainService ], + }); + + fixture = TestBed.createComponent(TwainComponent); + comp = fixture.componentInstance; + + // TwainService actually injected into the component + twainService = fixture.debugElement.injector.get(TwainService); + + // Setup spy on the `getQuote` method + // #docregion spy + spy = spyOn(twainService, 'getQuote') + .and.returnValue(Promise.resolve(testQuote)); + // #enddocregion spy + + // Get the Twain quote element by CSS selector (e.g., by class name) + de = fixture.debugElement.query(By.css('.twain')); + el = de.nativeElement; + }); + // #enddocregion setup + + // #docregion tests + it('should not show quote before OnInit', () => { + expect(el.textContent).toBe('', 'nothing displayed'); + expect(spy.calls.any()).toBe(false, 'getQuote not yet called'); + }); + + it('should still not show quote after component initialized', () => { + fixture.detectChanges(); + // getQuote service is async => still has not returned with quote + expect(el.textContent).toBe('...', 'no quote yet'); + expect(spy.calls.any()).toBe(true, 'getQuote called'); + }); + + // #docregion async-test + it('should show quote after getQuote promise (async)', async(() => { + fixture.detectChanges(); + + fixture.whenStable().then(() => { // wait for async getQuote + fixture.detectChanges(); // update view with quote + expect(el.textContent).toBe(testQuote); + }); + })); + // #enddocregion async-test + + // #docregion fake-async-test + it('should show quote after getQuote promise (fakeAsync)', fakeAsync(() => { + fixture.detectChanges(); + tick(); // wait for async getQuote + fixture.detectChanges(); // update view with quote + expect(el.textContent).toBe(testQuote); + })); + // #enddocregion fake-async-test + // #enddocregion tests + + // #docregion done-test + it('should show quote after getQuote promise (done)', (done: any) => { + fixture.detectChanges(); + + // get the spy promise and wait for it to resolve + spy.calls.mostRecent().returnValue.then(() => { + fixture.detectChanges(); // update view with quote + expect(el.textContent).toBe(testQuote); + done(); + }); + }); + // #enddocregion done-test +}); diff --git a/public/docs/_examples/testing/ts/src/app/shared/twain.component.timer.spec.ts.no-work b/public/docs/_examples/testing/ts/src/app/shared/twain.component.timer.spec.ts.no-work new file mode 100644 index 0000000000..74dec3e766 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/twain.component.timer.spec.ts.no-work @@ -0,0 +1,116 @@ +// #docplaster +// When AppComponent learns to present quote with intervalTimer +import { async, discardPeriodicTasks, fakeAsync, ComponentFixture, TestBed, tick } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { TwainService } from './model'; +import { TwainComponent } from './twain.component'; + +xdescribe('TwainComponent', () => { + + let comp: TwainComponent; + let fixture: ComponentFixture; + + const quotes = [ + 'Test Quote 1', + 'Test Quote 2', + 'Test Quote 3' + ]; + + let spy: jasmine.Spy; + let twainEl: DebugElement; // the element with the Twain quote + let twainService: TwainService; // the actually injected service + + function getQuote() { return twainEl.nativeElement.textContent; } + + // #docregion setup + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ TwainComponent ], + providers: [ TwainService ], + }); + + fixture = TestBed.createComponent(TwainComponent); + comp = fixture.componentInstance; + + // TwainService actually injected into the component + twainService = fixture.debugElement.injector.get(TwainService); + + // Setup spy on the `getQuote` method + spy = spyOn(twainService, 'getQuote') + .and.returnValues(...quotes.map(q => Promise.resolve(q))); + + // Get the Twain quote element by CSS selector (e.g., by class name) + twainEl = fixture.debugElement.query(By.css('.twain')); + }); + + afterEach(() => { + // destroy component to stop the component timer + fixture.destroy(); + }); + // #enddocregion setup + + // #docregion tests + it('should not show quote before OnInit', () => { + expect(getQuote()).toBe(''); + }); + + it('should still not show quote after component initialized', () => { + // because the getQuote service is async + fixture.detectChanges(); // trigger data binding + expect(getQuote()).toContain('not initialized'); + }); + + // WIP + // If go this way, add jasmine.clock().uninstall(); to afterEach + // it('should show quote after Angular "settles"', async(() => { + // //jasmine.clock().install(); + // fixture.detectChanges(); // trigger data binding + // fixture.whenStable().then(() => { + // fixture.detectChanges(); // update view with the quote + // expect(getQuote()).toBe(quotes[0]); + // }); + // // jasmine.clock().tick(5000); + // // fixture.whenStable().then(() => { + // // fixture.detectChanges(); // update view with the quote + // // expect(getQuote()).toBe(quotes[1]); + // // }); + // })); + + it('should show quote after getQuote promise returns', fakeAsync(() => { + fixture.detectChanges(); // trigger data binding + tick(); // wait for first async getQuote to return + fixture.detectChanges(); // update view with the quote + expect(getQuote()).toBe(quotes[0]); + + // destroy component to stop the component timer before test ends + // else test errors because still have timer in the queue + fixture.destroy(); + })); + + it('should show 2nd quote after 5 seconds pass', fakeAsync(() => { + fixture.detectChanges(); // trigger data binding + tick(5000); // wait for second async getQuote to return + fixture.detectChanges(); // update view with the quote + expect(getQuote()).toBe(quotes[1]); + + // still have intervalTimer queuing requres + // discardPeriodicTasks() else test errors + discardPeriodicTasks(); + })); + + fit('should show 3rd quote after 10 seconds pass', fakeAsync(() => { + fixture.detectChanges(); // trigger data binding + tick(5000); // wait for second async getQuote to return + fixture.detectChanges(); // update view with the 2nd quote + tick(5000); // wait for third async getQuote to return + fixture.detectChanges(); // update view with the 3rd quote + expect(getQuote()).toBe(quotes[2]); + + // still have intervalTimer queuing requres + // discardPeriodicTasks() else test errors + discardPeriodicTasks(); + })); + // #enddocregion tests +}); diff --git a/public/docs/_examples/testing/ts/src/app/shared/twain.component.timer.ts.no-work b/public/docs/_examples/testing/ts/src/app/shared/twain.component.timer.ts.no-work new file mode 100644 index 0000000000..d3dc1f205d --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/twain.component.timer.ts.no-work @@ -0,0 +1,27 @@ +// #docregion +import { Component, OnInit, OnDestroy } from '@angular/core'; + +import { TwainService } from './twain.service'; + +@Component({ + selector: 'twain-quote', + template: '

    {{quote}}

    ' +}) +export class TwainComponent implements OnInit, OnDestroy { + intervalId: number; + quote = '-- not initialized yet --'; + constructor(private twainService: TwainService) { } + + getQuote() { + this.twainService.getQuote().then(quote => this.quote = quote); + } + + ngOnInit(): void { + this.getQuote(); + this.intervalId = window.setInterval(() => this.getQuote(), 5000); + } + + ngOnDestroy(): void { + clearInterval(this.intervalId); + } +} diff --git a/public/docs/_examples/testing/ts/src/app/shared/twain.component.ts b/public/docs/_examples/testing/ts/src/app/shared/twain.component.ts new file mode 100644 index 0000000000..29f24459ab --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/twain.component.ts @@ -0,0 +1,20 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { TwainService } from './twain.service'; + +// #docregion component +@Component({ + selector: 'twain-quote', + template: '

    {{quote}}

    ' +}) +export class TwainComponent implements OnInit { + intervalId: number; + quote = '...'; + constructor(private twainService: TwainService) { } + + ngOnInit(): void { + this.twainService.getQuote().then(quote => this.quote = quote); + } +} +// #enddocregion component diff --git a/public/docs/_examples/testing/ts/src/app/shared/twain.service.ts b/public/docs/_examples/testing/ts/src/app/shared/twain.service.ts new file mode 100644 index 0000000000..9e394df1ee --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/shared/twain.service.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@angular/core'; + +const quotes = [ +'Always do right. This will gratify some people and astonish the rest.', +'I have never let my schooling interfere with my education.', +'Don\'t go around saying the world owes you a living. The world owes you nothing. It was here first.', +'Whenever you find yourself on the side of the majority, it is time to pause and reflect.', +'If you tell the truth, you don\'t have to remember anything.', +'Clothes make the man. Naked people have little or no influence on society.', +'It\'s not the size of the dog in the fight, it\'s the size of the fight in the dog.', +'Truth is stranger than fiction, but it is because Fiction is obliged to stick to possibilities; Truth isn\'t.', +'The man who does not read good books has no advantage over the man who cannot read them.', +'Get your facts first, and then you can distort them as much as you please.', +]; + +@Injectable() +export class TwainService { + private next = 0; + + // Imaginary todo: get quotes from a remote quote service + // returns quote after delay simulating server latency + getQuote(): Promise { + return new Promise(resolve => { + setTimeout( () => resolve(this.nextQuote()), 500 ); + }); + } + + private nextQuote() { + if (this.next === quotes.length) { this.next = 0; } + return quotes[ this.next++ ]; + } +} diff --git a/public/docs/_examples/testing/ts/src/app/welcome.component.spec.ts b/public/docs/_examples/testing/ts/src/app/welcome.component.spec.ts new file mode 100644 index 0000000000..e506dda396 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/welcome.component.spec.ts @@ -0,0 +1,108 @@ +// #docplaster +import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { UserService } from './model'; +import { WelcomeComponent } from './welcome.component'; + +describe('WelcomeComponent', () => { + + let comp: WelcomeComponent; + let fixture: ComponentFixture; + let componentUserService: UserService; // the actually injected service + let userService: UserService; // the TestBed injected service + let de: DebugElement; // the DebugElement with the welcome message + let el: HTMLElement; // the DOM element with the welcome message + + let userServiceStub: { + isLoggedIn: boolean; + user: { name: string} + }; + + // #docregion setup + beforeEach(() => { + // stub UserService for test purposes + // #docregion user-service-stub + userServiceStub = { + isLoggedIn: true, + user: { name: 'Test User'} + }; + // #enddocregion user-service-stub + + // #docregion config-test-module + TestBed.configureTestingModule({ + declarations: [ WelcomeComponent ], + // #enddocregion setup + // providers: [ UserService ] // NO! Don't provide the real service! + // Provide a test-double instead + // #docregion setup + providers: [ {provide: UserService, useValue: userServiceStub } ] + }); + // #enddocregion config-test-module + + fixture = TestBed.createComponent(WelcomeComponent); + comp = fixture.componentInstance; + + // #enddocregion setup + // #docregion injected-service + // UserService actually injected into the component + userService = fixture.debugElement.injector.get(UserService); + // #enddocregion injected-service + componentUserService = userService; + // #docregion setup + // #docregion inject-from-testbed + // UserService from the root injector + userService = TestBed.get(UserService); + // #enddocregion inject-from-testbed + + // get the "welcome" element by CSS selector (e.g., by class name) + de = fixture.debugElement.query(By.css('.welcome')); + el = de.nativeElement; + }); + // #enddocregion setup + + // #docregion tests + it('should welcome the user', () => { + fixture.detectChanges(); + const content = el.textContent; + expect(content).toContain('Welcome', '"Welcome ..."'); + expect(content).toContain('Test User', 'expected name'); + }); + + it('should welcome "Bubba"', () => { + userService.user.name = 'Bubba'; // welcome message hasn't been shown yet + fixture.detectChanges(); + expect(el.textContent).toContain('Bubba'); + }); + + it('should request login if not logged in', () => { + userService.isLoggedIn = false; // welcome message hasn't been shown yet + fixture.detectChanges(); + const content = el.textContent; + expect(content).not.toContain('Welcome', 'not welcomed'); + expect(content).toMatch(/log in/i, '"log in"'); + }); + // #enddocregion tests + + // #docregion inject-it + it('should inject the component\'s UserService instance', + inject([UserService], (service: UserService) => { + expect(service).toBe(componentUserService); + })); + // #enddocregion inject-it + + it('TestBed and Component UserService should be the same', () => { + expect(userService === componentUserService).toBe(true); + }); + + // #docregion stub-not-injected + it('stub object and injected UserService should not be the same', () => { + expect(userServiceStub === userService).toBe(false); + + // Changing the stub object has no effect on the injected service + userServiceStub.isLoggedIn = false; + expect(userService.isLoggedIn).toBe(true); + }); + // #enddocregion stub-not-injected +}); diff --git a/public/docs/_examples/testing/ts/src/app/welcome.component.ts b/public/docs/_examples/testing/ts/src/app/welcome.component.ts new file mode 100644 index 0000000000..35958cc5c9 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/app/welcome.component.ts @@ -0,0 +1,18 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { UserService } from './model'; + +@Component({ + selector: 'app-welcome', + template: '

    {{welcome}}

    ' +}) +export class WelcomeComponent implements OnInit { + welcome = '-- not initialized yet --'; + constructor(private userService: UserService) { } + + ngOnInit(): void { + this.welcome = this.userService.isLoggedIn ? + 'Welcome, ' + this.userService.user.name : + 'Please log in.'; + } +} diff --git a/public/docs/_examples/testing/ts/src/bag-specs.html b/public/docs/_examples/testing/ts/src/bag-specs.html new file mode 100644 index 0000000000..89b46f7056 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/bag-specs.html @@ -0,0 +1,42 @@ + + + + + + + Specs Bag + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/testing/ts/src/bag.html b/public/docs/_examples/testing/ts/src/bag.html new file mode 100644 index 0000000000..3e0fcb9025 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/bag.html @@ -0,0 +1,26 @@ + + + + + + Specs Bag + + + + + + + + + + + + + + + + Loading ... + + diff --git a/public/docs/_examples/testing/ts/src/banner-inline-specs.html b/public/docs/_examples/testing/ts/src/banner-inline-specs.html new file mode 100644 index 0000000000..2a512a5647 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/banner-inline-specs.html @@ -0,0 +1,40 @@ + + + + + + + Banner Component (inline template) Specs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/testing/ts/src/banner-specs.html b/public/docs/_examples/testing/ts/src/banner-specs.html new file mode 100644 index 0000000000..d16dd977a4 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/banner-specs.html @@ -0,0 +1,40 @@ + + + + + + + Banner Component Specs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/testing/ts/src/browser-test-shim.js b/public/docs/_examples/testing/ts/src/browser-test-shim.js new file mode 100644 index 0000000000..ee21831e22 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/browser-test-shim.js @@ -0,0 +1,87 @@ +// BROWSER TESTING SHIM +// Keep it in-sync with what karma-test-shim does +// #docregion +/*global jasmine, __karma__, window*/ +(function () { + +Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. + +// Uncomment to get full stacktrace output. Sometimes helpful, usually not. +// Error.stackTraceLimit = Infinity; // + +jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000; + +var baseURL = document.baseURI; +baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/'; + +System.config({ + baseURL: baseURL, + // Extend usual application package list with test folder + packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, + + // Assume npm: is set in `paths` in systemjs.config + // Map the angular testing umd bundles + map: { + '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', + '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', + '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', + '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', + }, +}); + +System.import('systemjs.config.js') + .then(importSystemJsExtras) + .then(initTestBed) + .then(initTesting); + +/** Optional SystemJS configuration extras. Keep going w/o it */ +function importSystemJsExtras(){ + return System.import('systemjs.config.extras.js') + .catch(function(reason) { + console.log( + 'Note: System.import could not load "systemjs.config.extras.js" where you might have added more configuration. It is an optional file so we will continue without it.' + ); + console.log(reason); + }); +} + +function initTestBed(){ + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + + .then(function (providers) { + var coreTesting = providers[0]; + var browserTesting = providers[1]; + + coreTesting.TestBed.initTestEnvironment( + browserTesting.BrowserDynamicTestingModule, + browserTesting.platformBrowserDynamicTesting()); + }) +} + +// Import all spec files defined in the html (__spec_files__) +// and start Jasmine testrunner +function initTesting () { + console.log('loading spec files: '+__spec_files__.join(', ')); + return Promise.all( + __spec_files__.map(function(spec) { + return System.import(spec); + }) + ) + // After all imports load, re-execute `window.onload` which + // triggers the Jasmine test-runner start or explain what went wrong + .then(success, console.error.bind(console)); + + function success () { + console.log('Spec files loaded; starting Jasmine testrunner'); + window.onload(); + } +} + +})(); diff --git a/public/docs/_examples/testing/ts/src/index.html b/public/docs/_examples/testing/ts/src/index.html new file mode 100644 index 0000000000..fff2464efc --- /dev/null +++ b/public/docs/_examples/testing/ts/src/index.html @@ -0,0 +1,27 @@ + + + + + + App Under Test + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/testing/ts/src/main.ts b/public/docs/_examples/testing/ts/src/main.ts new file mode 100644 index 0000000000..fadce2f3c1 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/main.ts @@ -0,0 +1,5 @@ +// main app entry point +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/testing/ts/src/systemjs.config.extras.js b/public/docs/_examples/testing/ts/src/systemjs.config.extras.js new file mode 100644 index 0000000000..218e65715c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/systemjs.config.extras.js @@ -0,0 +1,9 @@ +// #docregion +/** App specific SystemJS configuration */ +System.config({ + packages: { + // barrels + 'app/model': {main:'index.js', defaultExtension:'js'}, + 'app/model/testing': {main:'index.js', defaultExtension:'js'} + } +}); diff --git a/public/docs/_examples/testing/ts/src/testing/index.ts b/public/docs/_examples/testing/ts/src/testing/index.ts new file mode 100644 index 0000000000..e3de5164ca --- /dev/null +++ b/public/docs/_examples/testing/ts/src/testing/index.ts @@ -0,0 +1,43 @@ +import { DebugElement } from '@angular/core'; +import { tick, ComponentFixture } from '@angular/core/testing'; + +export * from './jasmine-matchers'; +export * from './router-stubs'; + +///// Short utilities ///// + +/** Wait a tick, then detect changes */ +export function advance(f: ComponentFixture): void { + tick(); + f.detectChanges(); +} + +/** + * Create custom DOM event the old fashioned way + * + * https://developer.mozilla.org/en-US/docs/Web/API/Event/initEvent + * Although officially deprecated, some browsers (phantom) don't accept the preferred "new Event(eventName)" + */ +export function newEvent(eventName: string, bubbles = false, cancelable = false) { + let evt = document.createEvent('CustomEvent'); // MUST be 'CustomEvent' + evt.initCustomEvent(eventName, bubbles, cancelable, null); + return evt; +} + +// See https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button +// #docregion click-event +/** Button events to pass to `DebugElement.triggerEventHandler` for RouterLink event handler */ +export const ButtonClickEvents = { + left: { button: 0 }, + right: { button: 2 } +}; + +/** Simulate element click. Defaults to mouse left-button click event. */ +export function click(el: DebugElement | HTMLElement, eventObj: any = ButtonClickEvents.left): void { + if (el instanceof HTMLElement) { + el.click(); + } else { + el.triggerEventHandler('click', eventObj); + } +} +// #enddocregion click-event diff --git a/public/docs/_examples/testing/ts/src/testing/jasmine-matchers.d.ts b/public/docs/_examples/testing/ts/src/testing/jasmine-matchers.d.ts new file mode 100644 index 0000000000..f1c5acf77c --- /dev/null +++ b/public/docs/_examples/testing/ts/src/testing/jasmine-matchers.d.ts @@ -0,0 +1,5 @@ +declare namespace jasmine { + interface Matchers { + toHaveText(actual: any, expectationFailOutput?: any): jasmine.CustomMatcher; + } +} diff --git a/public/docs/_examples/testing/ts/src/testing/jasmine-matchers.ts b/public/docs/_examples/testing/ts/src/testing/jasmine-matchers.ts new file mode 100644 index 0000000000..4cab02e148 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/testing/jasmine-matchers.ts @@ -0,0 +1,45 @@ +/// + +//// Jasmine Custom Matchers //// +// Be sure to extend jasmine-matchers.d.ts when adding matchers + +export function addMatchers(): void { + jasmine.addMatchers({ + toHaveText: toHaveText + }); +} + +function toHaveText(): jasmine.CustomMatcher { + return { + compare: function (actual: any, expectedText: string, expectationFailOutput?: any): jasmine.CustomMatcherResult { + const actualText = elementText(actual); + const pass = actualText.indexOf(expectedText) > -1; + const message = pass ? '' : composeMessage(); + return { pass, message }; + + function composeMessage () { + const a = (actualText.length < 100 ? actualText : actualText.substr(0, 100) + '...'); + const efo = expectationFailOutput ? ` '${expectationFailOutput}'` : ''; + return `Expected element to have text content '${expectedText}' instead of '${a}'${efo}`; + } + } + }; +} + +function elementText(n: any): string { + if (n instanceof Array) { + return n.map(elementText).join(''); + } + + if (n.nodeType === Node.COMMENT_NODE) { + return ''; + } + + if (n.nodeType === Node.ELEMENT_NODE && n.hasChildNodes()) { + return elementText(Array.prototype.slice.call(n.childNodes)); + } + + if (n.nativeElement) { n = n.nativeElement; } + + return n.textContent; +} diff --git a/public/docs/_examples/testing/ts/src/testing/router-stubs.ts b/public/docs/_examples/testing/ts/src/testing/router-stubs.ts new file mode 100644 index 0000000000..75a2858f65 --- /dev/null +++ b/public/docs/_examples/testing/ts/src/testing/router-stubs.ts @@ -0,0 +1,57 @@ + // export for convenience. +export { ActivatedRoute, Router, RouterLink, RouterOutlet} from '@angular/router'; + +import { Component, Directive, Injectable, Input } from '@angular/core'; +import { NavigationExtras } from '@angular/router'; + +// #docregion router-link +@Directive({ + selector: '[routerLink]', + host: { + '(click)': 'onClick()' + } +}) +export class RouterLinkStubDirective { + @Input('routerLink') linkParams: any; + navigatedTo: any = null; + + onClick() { + this.navigatedTo = this.linkParams; + } +} +// #enddocregion router-link + +@Component({selector: 'router-outlet', template: ''}) +export class RouterOutletStubComponent { } + +@Injectable() +export class RouterStub { + navigate(commands: any[], extras?: NavigationExtras) { } +} + + +// Only implements params and part of snapshot.params +// #docregion activated-route-stub +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; + +@Injectable() +export class ActivatedRouteStub { + + // ActivatedRoute.params is Observable + private subject = new BehaviorSubject(this.testParams); + params = this.subject.asObservable(); + + // Test parameters + private _testParams: {}; + get testParams() { return this._testParams; } + set testParams(params: {}) { + this._testParams = params; + this.subject.next(params); + } + + // ActivatedRoute.snapshot.params + get snapshot() { + return { params: this.testParams }; + } +} +// #enddocregion activated-route-stub diff --git a/public/docs/_examples/testing/ts/wallaby.js b/public/docs/_examples/testing/ts/wallaby.js new file mode 100644 index 0000000000..cd31e158fe --- /dev/null +++ b/public/docs/_examples/testing/ts/wallaby.js @@ -0,0 +1,118 @@ +// Configuration for the Wallaby Visual Studio Code testing extension +// https://marketplace.visualstudio.com/items?itemName=WallabyJs.wallaby-vscode +// Note: Wallaby is not open source and costs money + +module.exports = function () { + return { + files: [ + // System.js for module loading + {pattern: 'node_modules/systemjs/dist/system.js', instrument: false}, + {pattern: 'systemjs.config.js', instrument: false}, + {pattern: 'systemjs.config.extras.js', instrument: false}, + + // Polyfills + {pattern: 'node_modules/core-js/client/shim.min.js', instrument: false}, + + // zone.js + {pattern: 'node_modules/zone.js/dist/zone.js', instrument: false}, + {pattern: 'node_modules/zone.js/dist/long-stack-trace-zone.js', instrument: false}, + {pattern: 'node_modules/zone.js/dist/proxy.js', instrument: false}, + {pattern: 'node_modules/zone.js/dist/sync-test.js', instrument: false}, + {pattern: 'node_modules/zone.js/dist/jasmine-patch.js', instrument: false}, + {pattern: 'node_modules/zone.js/dist/async-test.js', instrument: false}, + {pattern: 'node_modules/zone.js/dist/fake-async-test.js', instrument: false}, + + // application (but not specs) loaded via module imports + {pattern: 'app/**/*+(ts|html|css)', load: false}, + {pattern: 'app/**/*.spec.ts', ignore: true}, + + {pattern: 'testing/**/*+(ts|html|css)', load: false}, + ], + + tests: [ + {pattern: 'app/**/*.spec.ts', load: false} + ], + + middleware: function (app, express) { + app.use('/node_modules', express.static(require('path').join(__dirname, 'node_modules'))); + }, + + testFramework: 'jasmine', + + debug: true, + + bootstrap: bootstrap + }; +}; + +// Like karma-test-shim.js +function bootstrap (wallaby) { + wallaby.delayStart(); + + System.config({ + // Extend usual application package list with test folder + packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, + + // Assume npm: is set in `paths` in systemjs.config + // Map the angular testing umd bundles + map: { + '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', + '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', + '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', + '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', + }, + }); + + System.import('systemjs.config.js') + .then(importSystemJsExtras) + .then(initTestBed) + .then(initTesting); + + /** Optional SystemJS configuration extras. Keep going w/o it */ + function importSystemJsExtras(){ + return System.import('systemjs.config.extras.js') + .catch(function(reason) { + console.log( + 'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.' + ); + console.log(reason); + }); + } + + function initTestBed(){ + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + + .then(function (providers) { + var coreTesting = providers[0]; + var browserTesting = providers[1]; + + coreTesting.TestBed.initTestEnvironment( + browserTesting.BrowserDynamicTestingModule, + browserTesting.platformBrowserDynamicTesting()); + }) + } + + // Load all spec files and start wallaby + function initTesting () { + return Promise.all( + wallaby.tests.map(function (specFile) { + return System.import(specFile); + }) + ) + .then(function () { + wallaby.start(); + }) + .catch(function (e) { + setTimeout(function () { + throw e; + }, 0); + }); + } +} diff --git a/public/docs/_examples/toh-1/dart-snippets/app_component_snippets_pt1.dart b/public/docs/_examples/toh-1/dart-snippets/app_component_snippets_pt1.dart new file mode 100644 index 0000000000..3bfa89762d --- /dev/null +++ b/public/docs/_examples/toh-1/dart-snippets/app_component_snippets_pt1.dart @@ -0,0 +1,37 @@ +// #docregion show-hero +template: '

    {{title}}

    {{hero}} details!

    ' +// #enddocregion show-hero + +// #docregion show-hero-2 +template: '

    {{title}}

    {{hero.name}} details!

    ' +// #enddocregion show-hero-2 + +// #docregion show-hero-properties +template: '

    {{title}}

    {{hero.name}} details!

    {{hero.id}}
    {{hero.name}}
    ' +// #enddocregion show-hero-properties + +// #docregion multi-line-strings +template: ''' +

    {{title}}

    +

    {{hero.name}} details!

    +
    {{hero.id}}
    +
    {{hero.name}}
    ''' +// #enddocregion multi-line-strings + +// #docregion editing-Hero +template: ''' +

    {{title}}

    +

    {{hero.name}} details!

    +
    {{hero.id}}
    +
    + + +
    ''' +// #enddocregion editing-Hero + +// #docregion app-component-1 +class AppComponent { + String title = 'Tour of Heroes'; + var hero = 'Windstorm'; +} +// #enddocregion app-component-1 diff --git a/public/docs/_examples/toh-1/e2e-spec.ts b/public/docs/_examples/toh-1/e2e-spec.ts new file mode 100644 index 0000000000..75f99788a6 --- /dev/null +++ b/public/docs/_examples/toh-1/e2e-spec.ts @@ -0,0 +1,70 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes'; +const expectedTitle = `Angular ${expectedH1}`; + +class Hero { + id: number; + name: string; + + // Factory method + // Get hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +const nameSuffix = 'X'; +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +describe('Tutorial part 1', () => { + + const expectedHero = { id: 1, name: 'Windstorm' }; + + beforeAll(() => browser.get('')); + + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + let hText = element(by.css('h1')).getText(); + expect(hText).toEqual(expectedH1, 'h1'); + }); + + it(`shows initial hero details`, async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(expectedHero.id); + expect(hero.name).toEqual(expectedHero.name); + }); + + it(`shows updated hero name`, async () => { + addToHeroName(nameSuffix); + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + let newName = expectedHero.name + nameSuffix; + expect(hero.id).toEqual(expectedHero.id); + expect(hero.name).toEqual(newName); + }); + +}); + +function getPageElts() { + return { + heroDetail: element(by.css('my-app')) + }; +} diff --git a/public/docs/_examples/toh-1/ts-snippets/app.component.snippets.pt1.ts b/public/docs/_examples/toh-1/ts-snippets/app.component.snippets.pt1.ts deleted file mode 100644 index e4a9796bc8..0000000000 --- a/public/docs/_examples/toh-1/ts-snippets/app.component.snippets.pt1.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docregion show-hero -template: '

    {{title}}

    {{hero}} details!

    ' -// #enddocregion show-hero - -// #docregion show-hero-2 -template: '

    {{title}}

    {{hero.name}} details!

    ' -// #enddocregion show-hero-2 - -// #docregion show-hero-properties -template: '

    {{title}}

    {{hero.name}} details!

    {{hero.id}}
    {{hero.name}}
    ' -// #enddocregion show-hero-properties - -// #docregion multi-line-strings -template:` -

    {{title}}

    -

    {{hero.name}} details!

    -
    {{hero.id}}
    -
    {{hero.name}}
    - ` -// #enddocregion multi-line-strings - -// #docregion editing-Hero -template:` -

    {{title}}

    -

    {{hero.name}} details!

    -
    {{hero.id}}
    -
    - -
    -
    - ` -// #enddocregion editing-Hero - -// #docregion app-component-1 -export class AppComponent { - public title = 'Tour of Heroes'; - public hero = 'Windstorm'; -} -// #enddocregion app-component-1 - -// #docregion hero-property-1 -public hero: Hero = { - id: 1, - name: 'Windstorm' -}; -// #enddocregion hero-property-1 diff --git a/public/docs/_examples/toh-1/ts/.gitignore b/public/docs/_examples/toh-1/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/toh-1/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/toh-1/ts/app/app.component.1.ts b/public/docs/_examples/toh-1/ts/app/app.component.1.ts new file mode 100644 index 0000000000..371fe39f90 --- /dev/null +++ b/public/docs/_examples/toh-1/ts/app/app.component.1.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; + +let t = { +// #docregion show-hero +template: `

    {{title}}

    {{hero}} details!

    ` +// #enddocregion show-hero +}; + +t = { +// #docregion show-hero-2 +template: `

    {{title}}

    {{hero.name}} details!

    ` +// #enddocregion show-hero-2 +}; + +t = { +// #docregion multi-line-strings +template: ` +

    {{title}}

    +

    {{hero.name}} details!

    +
    {{hero.id}}
    +
    {{hero.name}}
    + ` +// #enddocregion multi-line-strings +}; + + +/* +// #docregion name-input +
    + + +
    +// #enddocregion name-input +*/ + +///////////////// + +@Component(t) +// #docregion app-component-1 +export class AppComponent { + title = 'Tour of Heroes'; + hero = 'Windstorm'; +} +// #enddocregion app-component-1 diff --git a/public/docs/_examples/toh-1/ts/app/app.component.ts b/public/docs/_examples/toh-1/ts/app/app.component.ts deleted file mode 100644 index 47d34e87a4..0000000000 --- a/public/docs/_examples/toh-1/ts/app/app.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -// #docregion pt1 -import {Component} from 'angular2/core'; - -// #docregion hero-interface-1 -interface Hero { - id: number; - name: string; -} -// #enddocregion hero-interface-1 - -@Component({ - selector: 'my-app', - template:` -

    {{title}}

    -

    {{hero.name}} details!

    -
    {{hero.id}}
    -
    - -
    -
    - ` -}) -export class AppComponent { - public title = 'Tour of Heroes'; - public hero: Hero = { - id: 1, - name: 'Windstorm' - }; -} - -// #enddocregion pt1 diff --git a/public/docs/_examples/toh-1/ts/app/main.ts b/public/docs/_examples/toh-1/ts/app/main.ts deleted file mode 100644 index a5cf62c0fd..0000000000 --- a/public/docs/_examples/toh-1/ts/app/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion pt1 -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); -// #enddocregion pt1 \ No newline at end of file diff --git a/public/docs/_examples/toh-1/ts/index.html b/public/docs/_examples/toh-1/ts/index.html deleted file mode 100644 index 60f79db028..0000000000 --- a/public/docs/_examples/toh-1/ts/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - Angular 2 Tour of Heroes - - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/toh-1/ts/plnkr.json b/public/docs/_examples/toh-1/ts/plnkr.json index 70479d87e5..ca75131d96 100644 --- a/public/docs/_examples/toh-1/ts/plnkr.json +++ b/public/docs/_examples/toh-1/ts/plnkr.json @@ -1,8 +1,10 @@ { "description": "Tour of Heroes: Part 1", + "basePath": "src/", "files":[ "!**/*.d.ts", - "!**/*.js" + "!**/*.js", + "!**/*.[1].*" ], "tags": ["tutorial", "tour", "heroes"] } diff --git a/public/docs/_examples/toh-1/ts/src/app/app.component.ts b/public/docs/_examples/toh-1/ts/src/app/app.component.ts new file mode 100644 index 0000000000..602781b9ba --- /dev/null +++ b/public/docs/_examples/toh-1/ts/src/app/app.component.ts @@ -0,0 +1,33 @@ +// #docregion +import { Component } from '@angular/core'; + +// #docregion hero-class-1 +export class Hero { + id: number; + name: string; +} +// #enddocregion hero-class-1 + +@Component({ + selector: 'my-app', + // #docregion editing-Hero + template: ` +

    {{title}}

    +

    {{hero.name}} details!

    +
    {{hero.id}}
    +
    + + +
    + ` + // #enddocregion editing-Hero +}) +export class AppComponent { + title = 'Tour of Heroes'; + // #docregion hero-property-1 + hero: Hero = { + id: 1, + name: 'Windstorm' + }; + // #enddocregion hero-property-1 +} diff --git a/public/docs/_examples/toh-1/ts/src/app/app.module.ts b/public/docs/_examples/toh-1/ts/src/app/app.module.ts new file mode 100644 index 0000000000..8e87678efc --- /dev/null +++ b/public/docs/_examples/toh-1/ts/src/app/app.module.ts @@ -0,0 +1,18 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; // <-- NgModel lives here + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule // <-- import the FormsModule before binding with [(ngModel)] + ], + declarations: [ + AppComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/toh-1/ts/src/index.html b/public/docs/_examples/toh-1/ts/src/index.html new file mode 100644 index 0000000000..a217238c6c --- /dev/null +++ b/public/docs/_examples/toh-1/ts/src/index.html @@ -0,0 +1,25 @@ + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-1/ts/src/main.ts b/public/docs/_examples/toh-1/ts/src/main.ts new file mode 100644 index 0000000000..80ece654a5 --- /dev/null +++ b/public/docs/_examples/toh-1/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); +// #enddocregion diff --git a/public/docs/_examples/toh-2/dart-snippets/app_component_snippets_pt2.dart b/public/docs/_examples/toh-2/dart-snippets/app_component_snippets_pt2.dart new file mode 100644 index 0000000000..9f805c5bc5 --- /dev/null +++ b/public/docs/_examples/toh-2/dart-snippets/app_component_snippets_pt2.dart @@ -0,0 +1,69 @@ +// #docregion ng-for +
  • + {{hero.id}} {{hero.name}} +
  • +// #enddocregion ng-for + +// #docregion heroes-styled +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    +// #enddocregion heroes-styled + +// #docregion selectedHero-click +
  • + {{hero.id}} {{hero.name}} +
  • +// #enddocregion selectedHero-click + +// #docregion selectedHero-details +

    {{selectedHero.name}} details!

    +
    {{selectedHero.id}}
    +
    + + +
    +// #enddocregion selectedHero-details + +// #docregion ng-if +
    +

    {{selectedHero.name}} details!

    +
    {{selectedHero.id}}
    +
    + + +
    +
    +// #enddocregion ng-if + +// #docregion hero-array-1 +final List heroes = mockHeroes; +// #enddocregion hero-array-1 + +// #docregion heroes-template-1 +

    My Heroes

    +
      +
    • + +
    • +
    +// #enddocregion heroes-template-1 + +// #docregion heroes-ngfor-1 +
  • +// #enddocregion heroes-ngfor-1 + +// #docregion class-selected-1 +[class.selected]="hero == selectedHero" +// #enddocregion class-selected-1 + +// #docregion class-selected-2 +
  • + {{hero.id}} {{hero.name}} +
  • +// #enddocregion class-selected-2 diff --git a/public/docs/_examples/toh-2/e2e-spec.ts b/public/docs/_examples/toh-2/e2e-spec.ts new file mode 100644 index 0000000000..34f9fba573 --- /dev/null +++ b/public/docs/_examples/toh-2/e2e-spec.ts @@ -0,0 +1,133 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes'; +const expectedTitle = `Angular ${expectedH1}`; +const expectedH2 = 'My Heroes'; +const targetHero = { id: 16, name: 'RubberMan' }; +const nameSuffix = 'X'; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Get hero from s formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Get hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Tutorial part 2', () => { + beforeAll(() => browser.get('')); + describe('Initial page', initialPageTests); + describe('Select hero', selectHeroTests); + describe('Update hero', updateHeroTests); +}); + +function initialPageTests() { + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + it(`has h2 '${expectedH2}'`, () => { + expectHeading(2, expectedH2); + }); + + it('has the right number of heroes', () => { + let page = getPageElts(); + expect(page.heroes.count()).toEqual(10); + }); + + it('has no selected hero and no hero details', function () { + let page = getPageElts(); + expect(page.selected.isPresent()).toBeFalsy('selected hero'); + expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail'); + }); +} + +function selectHeroTests() { + it(`selects ${targetHero.name} from hero list`, function () { + let hero = element(by.cssContainingText('li span.badge', targetHero.id.toString())); + hero.click(); + // Nothing specific to expect other than lack of exceptions. + }); + + it(`has selected ${targetHero.name}`, function () { + let page = getPageElts(); + let expectedText = `${targetHero.id} ${targetHero.name}`; + expect(page.selected.getText()).toBe(expectedText); + }); + + it('shows selected hero details', async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name); + }); +} + +function updateHeroTests() { + it(`can update hero name`, () => { + addToHeroName(nameSuffix); + // Nothing specific to expect other than lack of exceptions. + }); + + it(`shows updated hero name in details`, async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); + + it(`shows updated hero name in list`, async () => { + let page = getPageElts(); + let hero = Hero.fromString(await page.selected.getText()); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); + +} + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getPageElts() { + return { + heroes: element.all(by.css('my-app li')), + selected: element(by.css('my-app li.selected')), + heroDetail: element(by.css('my-app > div, my-app > hero-detail > div')) + }; +} diff --git a/public/docs/_examples/toh-2/ts-snippets/app.component.snippets.pt2.ts b/public/docs/_examples/toh-2/ts-snippets/app.component.snippets.pt2.ts deleted file mode 100644 index 9dc0277fc4..0000000000 --- a/public/docs/_examples/toh-2/ts-snippets/app.component.snippets.pt2.ts +++ /dev/null @@ -1,69 +0,0 @@ -// #docregion ng-for -
  • - {{hero.id}} {{hero.name}} -
  • -// #enddocregion ng-for - -// #docregion heroes-styled -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    -// #enddocregion heroes-styled - -// #docregion selectedHero-click -
  • - {{hero.id}} {{hero.name}} -
  • -// #enddocregion selectedHero-click - -// #docregion selectedHero-details -

    {{selectedHero.name}} details!

    -
    {{selectedHero.id}}
    -
    - - -
    -// #enddocregion selectedHero-details - -// #docregion ng-if -
    -

    {{selectedHero.name}} details!

    -
    {{selectedHero.id}}
    -
    - - -
    -
    -// #enddocregion ng-if - -// #docregion hero-array-1 -public heroes = HEROES; -// #enddocregion hero-array-1 - -// #docregion heroes-template-1 -

    My Heroes

    -
      -
    • - -
    • -
    -// #enddocregion heroes-template-1 - -// #docregion heroes-ngfor-1 -
  • -// #enddocregion heroes-ngfor-1 - -// #docregion class-selected-1 -[class.selected]="hero === selectedHero" -// #enddocregion class-selected-1 - -// #docregion class-selected-2 -
  • - {{hero.id}} {{hero.name}} -
  • -// #enddocregion class-selected-2 diff --git a/public/docs/_examples/toh-2/ts/.gitignore b/public/docs/_examples/toh-2/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/toh-2/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/toh-2/ts/app/app.component.ts b/public/docs/_examples/toh-2/ts/app/app.component.ts deleted file mode 100644 index cf719e6589..0000000000 --- a/public/docs/_examples/toh-2/ts/app/app.component.ts +++ /dev/null @@ -1,110 +0,0 @@ -// #docregion pt2 -import {Component} from 'angular2/core'; - -interface Hero { - id: number; - name: string; -} - -@Component({ - selector: 'my-app', - template:` -

    {{title}}

    -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    -
    -

    {{selectedHero.name}} details!

    -
    {{selectedHero.id}}
    -
    - - -
    -
    - `, -// #docregion styles-1 - styles:[` - .selected { - background-color: #CFD8DC !important; - color: white; - } - .heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 10em; - } - .heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; - } - .heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; - } - .heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; - } - .heroes .text { - position: relative; - top: -3px; - } - .heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; - } - `] -// #enddocregion styles-1 -}) -export class AppComponent { - title = 'Tour of Heroes'; - heroes = HEROES; -// #docregion selected-hero-1 - selectedHero: Hero; -// #enddocregion selected-hero-1 - -// #docregion on-select-1 - onSelect(hero: Hero) { this.selectedHero = hero; } -// #enddocregion on-select-1 -} -// #enddocregion pt2 - -// #docregion hero-array -var HEROES: Hero[] = [ - { "id": 11, "name": "Mr. Nice" }, - { "id": 12, "name": "Narco" }, - { "id": 13, "name": "Bombasto" }, - { "id": 14, "name": "Celeritas" }, - { "id": 15, "name": "Magneta" }, - { "id": 16, "name": "RubberMan" }, - { "id": 17, "name": "Dynama" }, - { "id": 18, "name": "Dr IQ" }, - { "id": 19, "name": "Magma" }, - { "id": 20, "name": "Tornado" } -]; -// #enddocregion hero-array - -// #enddocregion pt2 diff --git a/public/docs/_examples/toh-2/ts/app/main.ts b/public/docs/_examples/toh-2/ts/app/main.ts deleted file mode 100644 index a5cf62c0fd..0000000000 --- a/public/docs/_examples/toh-2/ts/app/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion pt1 -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); -// #enddocregion pt1 \ No newline at end of file diff --git a/public/docs/_examples/toh-2/ts/index.html b/public/docs/_examples/toh-2/ts/index.html deleted file mode 100644 index 22fff97287..0000000000 --- a/public/docs/_examples/toh-2/ts/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - Angular 2 Tour of Heros - - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/toh-2/ts/plnkr.json b/public/docs/_examples/toh-2/ts/plnkr.json index 61add17a65..08c7b9581a 100644 --- a/public/docs/_examples/toh-2/ts/plnkr.json +++ b/public/docs/_examples/toh-2/ts/plnkr.json @@ -1,8 +1,10 @@ { "description": "Tour of Heroes: Part 2", + "basePath": "src/", "files":[ "!**/*.d.ts", - "!**/*.js" + "!**/*.js", + "!**/*.[1].*" ], "tags": ["tutorial", "tour", "heroes"] } diff --git a/public/docs/_examples/toh-2/ts/src/app/app.component.1.html b/public/docs/_examples/toh-2/ts/src/app/app.component.1.html new file mode 100644 index 0000000000..86f8228723 --- /dev/null +++ b/public/docs/_examples/toh-2/ts/src/app/app.component.1.html @@ -0,0 +1,69 @@ + +
  • + {{hero.id}} {{hero.name}} +
  • + + + +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    + + + +
  • + ... +
  • + + + +

    {{selectedHero.name}} details!

    +
    {{selectedHero.id}}
    +
    + + +
    + + + +
    +

    {{selectedHero.name}} details!

    +
    {{selectedHero.id}}
    +
    + + +
    +
    + + + +heroes = HEROES; + + + +

    My Heroes

    +
      +
    • + +
    • +
    + + + +
  • + + + +[class.selected]="hero === selectedHero" + + + +
  • + {{hero.id}} {{hero.name}} +
  • + diff --git a/public/docs/_examples/toh-2/ts/src/app/app.component.ts b/public/docs/_examples/toh-2/ts/src/app/app.component.ts new file mode 100644 index 0000000000..3e7c86f150 --- /dev/null +++ b/public/docs/_examples/toh-2/ts/src/app/app.component.ts @@ -0,0 +1,109 @@ +// #docregion +import { Component } from '@angular/core'; + +export class Hero { + id: number; + name: string; +} + +// #docregion hero-array +const HEROES: Hero[] = [ + { id: 11, name: 'Mr. Nice' }, + { id: 12, name: 'Narco' }, + { id: 13, name: 'Bombasto' }, + { id: 14, name: 'Celeritas' }, + { id: 15, name: 'Magneta' }, + { id: 16, name: 'RubberMan' }, + { id: 17, name: 'Dynama' }, + { id: 18, name: 'Dr IQ' }, + { id: 19, name: 'Magma' }, + { id: 20, name: 'Tornado' } +]; +// #enddocregion hero-array + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    +
    +

    {{selectedHero.name}} details!

    +
    {{selectedHero.id}}
    +
    + + +
    +
    + `, + // #docregion styles + styles: [` + .selected { + background-color: #CFD8DC !important; + color: white; + } + .heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; + } + .heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; + } + .heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; + } + .heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; + } + .heroes .text { + position: relative; + top: -3px; + } + .heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; + } + `] + // #enddocregion styles +}) +export class AppComponent { + title = 'Tour of Heroes'; + heroes = HEROES; + // #docregion selected-hero + selectedHero: Hero; + // #enddocregion selected-hero + + // #docregion on-select + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + // #enddocregion on-select +} diff --git a/public/docs/_examples/toh-2/ts/src/app/app.module.ts b/public/docs/_examples/toh-2/ts/src/app/app.module.ts new file mode 100644 index 0000000000..4c0b77ea48 --- /dev/null +++ b/public/docs/_examples/toh-2/ts/src/app/app.module.ts @@ -0,0 +1,18 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/toh-2/ts/src/index.html b/public/docs/_examples/toh-2/ts/src/index.html new file mode 100644 index 0000000000..a217238c6c --- /dev/null +++ b/public/docs/_examples/toh-2/ts/src/index.html @@ -0,0 +1,25 @@ + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-2/ts/src/main.ts b/public/docs/_examples/toh-2/ts/src/main.ts new file mode 100644 index 0000000000..80ece654a5 --- /dev/null +++ b/public/docs/_examples/toh-2/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); +// #enddocregion diff --git a/public/docs/_examples/toh-3/e2e-spec.ts b/public/docs/_examples/toh-3/e2e-spec.ts new file mode 100644 index 0000000000..842716c5fc --- /dev/null +++ b/public/docs/_examples/toh-3/e2e-spec.ts @@ -0,0 +1,133 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes'; +const expectedTitle = `Angular ${expectedH1}`; +const expectedH2 = 'My Heroes'; +const targetHero = { id: 16, name: 'RubberMan' }; +const nameSuffix = 'X'; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Get hero from s formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Get hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Tutorial part 3', () => { + beforeAll(() => browser.get('')); + describe('Initial page', initialPageTests); + describe('Select hero', selectHeroTests); + describe('Update hero', updateHeroTests); +}); + +function initialPageTests() { + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + it(`has h2 '${expectedH2}'`, () => { + expectHeading(2, expectedH2); + }); + + it('has the right number of heroes', () => { + let page = getPageElts(); + expect(page.heroes.count()).toEqual(10); + }); + + it('has no selected hero and no hero details', function () { + let page = getPageElts(); + expect(page.selected.isPresent()).toBeFalsy('selected hero'); + expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail'); + }); +} + +function selectHeroTests() { + it(`selects ${targetHero.name} from hero list`, function () { + let hero = element(by.cssContainingText('li span.badge', targetHero.id.toString())); + hero.click(); + // Nothing specific to expect other than lack of exceptions. + }); + + it(`has selected ${targetHero.name}`, function () { + let page = getPageElts(); + let expectedText = `${targetHero.id} ${targetHero.name}`; + expect(page.selected.getText()).toBe(expectedText); + }); + + it('shows selected hero details', async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name); + }); +} + +function updateHeroTests() { + it(`can update hero name`, () => { + addToHeroName(nameSuffix); + // Nothing specific to expect other than lack of exceptions. + }); + + it(`shows updated hero name in details`, async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); + + it(`shows updated hero name in list`, async () => { + let page = getPageElts(); + let hero = Hero.fromString(await page.selected.getText()); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); + +} + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getPageElts() { + return { + heroes: element.all(by.css('my-app li')), + selected: element(by.css('my-app li.selected')), + heroDetail: element(by.css('my-app > div, my-app > hero-detail > div')) + }; +} diff --git a/public/docs/_examples/toh-3/ts/.gitignore b/public/docs/_examples/toh-3/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/toh-3/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/toh-3/ts/app/app.component.1.html b/public/docs/_examples/toh-3/ts/app/app.component.1.html new file mode 100644 index 0000000000..bab9dda877 --- /dev/null +++ b/public/docs/_examples/toh-3/ts/app/app.component.1.html @@ -0,0 +1,12 @@ +

    {{title}}

    +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    + + + diff --git a/public/docs/_examples/toh-3/ts/app/app.component.ts b/public/docs/_examples/toh-3/ts/app/app.component.ts deleted file mode 100644 index d0fdea50e1..0000000000 --- a/public/docs/_examples/toh-3/ts/app/app.component.ts +++ /dev/null @@ -1,98 +0,0 @@ -//#docregion -import {Component} from 'angular2/core'; -// #docregion hero-import -import {Hero} from './hero'; -// #enddocregion hero-import -// #docregion hero-detail-import -import {HeroDetailComponent} from './hero-detail.component'; -// #enddocregion hero-detail-import - -@Component({ - selector: 'my-app', -// #docregion hero-detail-template - template:` -

    {{title}}

    -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - - `, -// #enddocregion hero-detail-template - styles:[` - .selected { - background-color: #CFD8DC !important; - color: white; - } - .heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 10em; - } - .heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; - } - .heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; - } - .heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; - } - .heroes .text { - position: relative; - top: -3px; - } - .heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; - } - `], -// #docregion directives - directives: [HeroDetailComponent] -// #enddocregion directives -}) -export class AppComponent { - title = 'Tour of Heroes'; - heroes = HEROES; - selectedHero: Hero; - - onSelect(hero: Hero) { this.selectedHero = hero; } -} - -var HEROES: Hero[] = [ - { "id": 11, "name": "Mr. Nice" }, - { "id": 12, "name": "Narco" }, - { "id": 13, "name": "Bombasto" }, - { "id": 14, "name": "Celeritas" }, - { "id": 15, "name": "Magneta" }, - { "id": 16, "name": "RubberMan" }, - { "id": 17, "name": "Dynama" }, - { "id": 18, "name": "Dr IQ" }, - { "id": 19, "name": "Magma" }, - { "id": 20, "name": "Tornado" } -]; diff --git a/public/docs/_examples/toh-3/ts/app/hero-detail.component.1.ts b/public/docs/_examples/toh-3/ts/app/hero-detail.component.1.ts new file mode 100644 index 0000000000..fec477fbd7 --- /dev/null +++ b/public/docs/_examples/toh-3/ts/app/hero-detail.component.1.ts @@ -0,0 +1,35 @@ +// #docplaster +// #docregion v1 +import { Component } from '@angular/core'; + +// #enddocregion v1 +// #docregion hero-import +import { Hero } from './hero'; +// #enddocregion hero-import + +// #docregion v1 +@Component({ + selector: 'hero-detail', +// #enddocregion v1 + // #docregion template + template: ` +
    +

    {{hero.name}} details!

    +
    {{hero.id}}
    +
    + + +
    +
    + ` + // #enddocregion template +// #docregion v1 +}) +export class HeroDetailComponent { +// #enddocregion v1 +// #docregion hero + hero: Hero; +// #enddocregion hero +// #docregion v1 +} +// #enddocregion v1 diff --git a/public/docs/_examples/toh-3/ts/app/hero-detail.component.ts b/public/docs/_examples/toh-3/ts/app/hero-detail.component.ts deleted file mode 100644 index 90b47c0996..0000000000 --- a/public/docs/_examples/toh-3/ts/app/hero-detail.component.ts +++ /dev/null @@ -1,38 +0,0 @@ -// #docplaster -// #docregion -// #docregion v1 -import {Component} from 'angular2/core'; -// #enddocregion v1 -// #docregion hero-import -import {Hero} from './hero'; -// #enddocregion hero-import - -// #docregion v1 -@Component({ - selector: 'my-hero-detail', -// #enddocregion v1 - // #docregion template - template: ` -
    -

    {{hero.name}} details!

    -
    {{hero.id}}
    -
    - - -
    -
    - `, - // #enddocregion template - // #docregion inputs - inputs: ['hero'] - // #enddocregion inputs -// #docregion v1 -}) -export class HeroDetailComponent { -// #enddocregion v1 -// #docregion hero - hero: Hero; -// #enddocregion hero -// #docregion v1 -} -// #enddocregion v1 diff --git a/public/docs/_examples/toh-3/ts/app/hero.ts b/public/docs/_examples/toh-3/ts/app/hero.ts deleted file mode 100644 index ed746da042..0000000000 --- a/public/docs/_examples/toh-3/ts/app/hero.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export interface Hero { - id: number; - name: string; -} -// #enddocregion diff --git a/public/docs/_examples/toh-3/ts/app/main.ts b/public/docs/_examples/toh-3/ts/app/main.ts deleted file mode 100644 index a5cf62c0fd..0000000000 --- a/public/docs/_examples/toh-3/ts/app/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion pt1 -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); -// #enddocregion pt1 \ No newline at end of file diff --git a/public/docs/_examples/toh-3/ts/index.html b/public/docs/_examples/toh-3/ts/index.html deleted file mode 100644 index 60f79db028..0000000000 --- a/public/docs/_examples/toh-3/ts/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - Angular 2 Tour of Heroes - - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/toh-3/ts/plnkr.json b/public/docs/_examples/toh-3/ts/plnkr.json index b6e424dda7..829715877e 100644 --- a/public/docs/_examples/toh-3/ts/plnkr.json +++ b/public/docs/_examples/toh-3/ts/plnkr.json @@ -1,8 +1,10 @@ { "description": "Tour of Heroes: Part 3", + "basePath": "src/", "files":[ "!**/*.d.ts", - "!**/*.js" + "!**/*.js", + "!**/*.[1].*" ], "tags": ["tutorial", "tour", "heroes"] } diff --git a/public/docs/_examples/toh-3/ts/src/app/app.component.ts b/public/docs/_examples/toh-3/ts/src/app/app.component.ts new file mode 100644 index 0000000000..3e242914aa --- /dev/null +++ b/public/docs/_examples/toh-3/ts/src/app/app.component.ts @@ -0,0 +1,95 @@ +// #docregion +import { Component } from '@angular/core'; + +// #docregion hero-import +import { Hero } from './hero'; +// #enddocregion hero-import + +const HEROES: Hero[] = [ + { id: 11, name: 'Mr. Nice' }, + { id: 12, name: 'Narco' }, + { id: 13, name: 'Bombasto' }, + { id: 14, name: 'Celeritas' }, + { id: 15, name: 'Magneta' }, + { id: 16, name: 'RubberMan' }, + { id: 17, name: 'Dynama' }, + { id: 18, name: 'Dr IQ' }, + { id: 19, name: 'Magma' }, + { id: 20, name: 'Tornado' } +]; + +@Component({ + selector: 'my-app', +// #docregion hero-detail-template + template: ` +

    {{title}}

    +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    + + `, +// #enddocregion hero-detail-template + styles: [` + .selected { + background-color: #CFD8DC !important; + color: white; + } + .heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; + } + .heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; + } + .heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; + } + .heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; + } + .heroes .text { + position: relative; + top: -3px; + } + .heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; + } + `] +}) +export class AppComponent { + title = 'Tour of Heroes'; + heroes = HEROES; + selectedHero: Hero; + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } +} diff --git a/public/docs/_examples/toh-3/ts/src/app/app.module.ts b/public/docs/_examples/toh-3/ts/src/app/app.module.ts new file mode 100644 index 0000000000..e04b8d304b --- /dev/null +++ b/public/docs/_examples/toh-3/ts/src/app/app.module.ts @@ -0,0 +1,24 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +// #docregion hero-detail-import +import { HeroDetailComponent } from './hero-detail.component'; +// #enddocregion hero-detail-import + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], +// #docregion declarations + declarations: [ + AppComponent, + HeroDetailComponent + ], +// #enddocregion declarations + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/toh-3/ts/src/app/hero-detail.component.ts b/public/docs/_examples/toh-3/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..45a1a1e7e1 --- /dev/null +++ b/public/docs/_examples/toh-3/ts/src/app/hero-detail.component.ts @@ -0,0 +1,29 @@ +// #docregion +// #docregion import-input +import { Component, Input } from '@angular/core'; +// #enddocregion import-input + +import { Hero } from './hero'; +// #docregion template +@Component({ + selector: 'hero-detail', + template: ` +
    +

    {{hero.name}} details!

    +
    {{hero.id}}
    +
    + + +
    +
    + ` +}) +// #enddocregion template +// #docregion class +export class HeroDetailComponent { +// #docregion hero + @Input() hero: Hero; +// #enddocregion hero +} +// #enddocregion class + diff --git a/public/docs/_examples/toh-3/ts/src/app/hero.ts b/public/docs/_examples/toh-3/ts/src/app/hero.ts new file mode 100644 index 0000000000..f4b0cd6b35 --- /dev/null +++ b/public/docs/_examples/toh-3/ts/src/app/hero.ts @@ -0,0 +1,6 @@ +// #docregion +export class Hero { + id: number; + name: string; +} +// #enddocregion diff --git a/public/docs/_examples/toh-3/ts/src/index.html b/public/docs/_examples/toh-3/ts/src/index.html new file mode 100644 index 0000000000..a217238c6c --- /dev/null +++ b/public/docs/_examples/toh-3/ts/src/index.html @@ -0,0 +1,25 @@ + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-3/ts/src/main.ts b/public/docs/_examples/toh-3/ts/src/main.ts new file mode 100644 index 0000000000..aa939b3241 --- /dev/null +++ b/public/docs/_examples/toh-3/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion pt1 +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); +// #enddocregion pt1 diff --git a/public/docs/_examples/toh-4/e2e-spec.ts b/public/docs/_examples/toh-4/e2e-spec.ts new file mode 100644 index 0000000000..d6a223dd12 --- /dev/null +++ b/public/docs/_examples/toh-4/e2e-spec.ts @@ -0,0 +1,133 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes'; +const expectedTitle = `Angular ${expectedH1}`; +const expectedH2 = 'My Heroes'; +const targetHero = { id: 16, name: 'RubberMan' }; +const nameSuffix = 'X'; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Get hero from s formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Get hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Tutorial part 4', () => { + beforeAll(() => browser.get('')); + describe('Initial page', initialPageTests); + describe('Select hero', selectHeroTests); + describe('Update hero', updateHeroTests); +}); + +function initialPageTests() { + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + it(`has h2 '${expectedH2}'`, () => { + expectHeading(2, expectedH2); + }); + + it('has the right number of heroes', () => { + let page = getPageElts(); + expect(page.heroes.count()).toEqual(10); + }); + + it('has no selected hero and no hero details', function () { + let page = getPageElts(); + expect(page.selected.isPresent()).toBeFalsy('selected hero'); + expect(page.heroDetail.isPresent()).toBeFalsy('no hero detail'); + }); +} + +function selectHeroTests() { + it(`selects ${targetHero.name} from hero list`, function () { + let hero = element(by.cssContainingText('li span.badge', targetHero.id.toString())); + hero.click(); + // Nothing specific to expect other than lack of exceptions. + }); + + it(`has selected ${targetHero.name}`, function () { + let page = getPageElts(); + let expectedText = `${targetHero.id} ${targetHero.name}`; + expect(page.selected.getText()).toBe(expectedText); + }); + + it('shows selected hero details', async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name); + }); +} + +function updateHeroTests() { + it(`can update hero name`, () => { + addToHeroName(nameSuffix); + // Nothing specific to expect other than lack of exceptions. + }); + + it(`shows updated hero name in details`, async () => { + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); + + it(`shows updated hero name in list`, async () => { + let page = getPageElts(); + let hero = Hero.fromString(await page.selected.getText()); + let newName = targetHero.name + nameSuffix; + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newName); + }); + +} + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getPageElts() { + return { + heroes: element.all(by.css('my-app li')), + selected: element(by.css('my-app li.selected')), + heroDetail: element(by.css('my-app > div, my-app > hero-detail > div')) + }; +} diff --git a/public/docs/_examples/toh-4/ts/.gitignore b/public/docs/_examples/toh-4/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/toh-4/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/toh-4/ts/app/app.component.1.js b/public/docs/_examples/toh-4/ts/app/app.component.1.js deleted file mode 100644 index 94dc857004..0000000000 --- a/public/docs/_examples/toh-4/ts/app/app.component.1.js +++ /dev/null @@ -1,72 +0,0 @@ -System.register(['angular2/core', './hero-detail.component', './hero.service.1'], function(exports_1) { - var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - }; - var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); - }; - var core_1, hero_detail_component_1, hero_service_1_1; - var AppComponent; - return { - setters:[ - function (core_1_1) { - core_1 = core_1_1; - }, - function (hero_detail_component_1_1) { - hero_detail_component_1 = hero_detail_component_1_1; - }, - function (hero_service_1_1_1) { - hero_service_1_1 = hero_service_1_1_1; - }], - execute: function() { - // #enddocregion hero-service-import - // Testable but never shown - AppComponent = (function () { - // #enddocregion new-service - // #docregion ctor - function AppComponent(_heroService) { - this._heroService = _heroService; - // #enddocregion on-init - this.title = 'Tour of Heroes'; - // #docregion new-service - this.heroService = new hero_service_1_1.HeroService(); // don't do this - } - // #enddocregion ctor - // #docregion getHeroes - AppComponent.prototype.getHeroes = function () { - //#docregion get-heroes - this.heroes = this._heroService.getHeroes(); - // #enddocregion get-heroes - }; - // #enddocregion getHeroes - // #docregion ng-on-init - // #docregion on-init - AppComponent.prototype.ngOnInit = function () { - // #enddocregion on-init - this.getHeroes(); - // #docregion on-init - }; - // #enddocregion on-init - // #enddocregion ng-on-init - AppComponent.prototype.onSelect = function (hero) { this.selectedHero = hero; }; - AppComponent = __decorate([ - core_1.Component({ - selector: 'my-app', - template: "\n
    \n {{hero.name}}\n
    \n \n ", - directives: [hero_detail_component_1.HeroDetailComponent], - // #docregion providers - providers: [hero_service_1_1.HeroService] - }), - __metadata('design:paramtypes', [hero_service_1_1.HeroService]) - ], AppComponent); - return AppComponent; - })(); - exports_1("AppComponent", AppComponent); - } - } -}); -// #enddocregion on-init -//# sourceMappingURL=app.component.1.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/app.component.1.ts b/public/docs/_examples/toh-4/ts/app/app.component.1.ts deleted file mode 100644 index 20ec0babc5..0000000000 --- a/public/docs/_examples/toh-4/ts/app/app.component.1.ts +++ /dev/null @@ -1,64 +0,0 @@ -// #docplaster -// #docregion on-init -import {OnInit} from 'angular2/core'; - -// #enddocregion on-init -import {Component} from 'angular2/core'; -import {Hero} from './hero'; -import {HeroDetailComponent} from './hero-detail.component'; -// #docregion hero-service-import -import {HeroService} from './hero.service.1'; -// #enddocregion hero-service-import - -// Testable but never shown -@Component({ - selector: 'my-app', - template: ` -
    - {{hero.name}} -
    - - `, - directives: [HeroDetailComponent], - // #docregion providers - providers: [HeroService] - // #enddocregion providers -}) -// #docregion on-init -export class AppComponent implements OnInit { - // #enddocregion on-init - title = 'Tour of Heroes'; - // #docregion heroes-prop - heroes: Hero[]; - // #enddocregion heroes-prop - selectedHero: Hero; - - // #docregion new-service - heroService = new HeroService(); // don't do this - // #enddocregion new-service - // #docregion ctor - constructor(private _heroService: HeroService) { } - // #enddocregion ctor - // #docregion getHeroes - getHeroes() { - //#docregion get-heroes - this.heroes = this._heroService.getHeroes(); - // #enddocregion get-heroes - } - // #enddocregion getHeroes - - // #docregion ng-on-init - // #docregion on-init - ngOnInit() { - // #enddocregion on-init - this.getHeroes(); - // #docregion on-init - } - // #enddocregion on-init - // #enddocregion ng-on-init - - onSelect(hero: Hero) { this.selectedHero = hero; } - // #docregion on-init -} -// #enddocregion on-init -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/app.component.js b/public/docs/_examples/toh-4/ts/app/app.component.js deleted file mode 100644 index 234871c72b..0000000000 --- a/public/docs/_examples/toh-4/ts/app/app.component.js +++ /dev/null @@ -1,57 +0,0 @@ -System.register(['angular2/core', './hero-detail.component', './hero.service'], function(exports_1) { - var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - }; - var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); - }; - var core_1, hero_detail_component_1, hero_service_1; - var AppComponent; - return { - setters:[ - function (core_1_1) { - core_1 = core_1_1; - }, - function (hero_detail_component_1_1) { - hero_detail_component_1 = hero_detail_component_1_1; - }, - function (hero_service_1_1) { - hero_service_1 = hero_service_1_1; - }], - execute: function() { - // #enddocregion hero-service-import - AppComponent = (function () { - function AppComponent(_heroService) { - this._heroService = _heroService; - this.title = 'Tour of Heroes'; - } - // #docregion get-heroes - AppComponent.prototype.getHeroes = function () { - var _this = this; - this._heroService.getHeroes().then(function (heroes) { return _this.heroes = heroes; }); - }; - // #enddocregion get-heroes - AppComponent.prototype.ngOnInit = function () { - this.getHeroes(); - }; - AppComponent.prototype.onSelect = function (hero) { this.selectedHero = hero; }; - AppComponent = __decorate([ - core_1.Component({ - selector: 'my-app', - template: "\n

    {{title}}

    \n

    My Heroes

    \n
      \n
    • \n {{hero.id}} {{hero.name}}\n
    • \n
    \n \n ", - styles: ["\n .heroes {list-style-type: none; margin-left: 1em; padding: 0; width: 10em;}\n .heroes li { cursor: pointer; position: relative; left: 0; transition: all 0.2s ease; }\n .heroes li:hover {color: #369; background-color: #EEE; left: .2em;}\n .heroes .badge {\n font-size: small;\n color: white;\n padding: 0.1em 0.7em;\n background-color: #369;\n line-height: 1em;\n position: relative;\n left: -1px;\n top: -1px;\n }\n .selected { background-color: #EEE; color: #369; }\n "], - directives: [hero_detail_component_1.HeroDetailComponent], - providers: [hero_service_1.HeroService] - }), - __metadata('design:paramtypes', [hero_service_1.HeroService]) - ], AppComponent); - return AppComponent; - })(); - exports_1("AppComponent", AppComponent); - } - } -}); -//# sourceMappingURL=app.component.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/app.component.ts b/public/docs/_examples/toh-4/ts/app/app.component.ts deleted file mode 100644 index bc587e2390..0000000000 --- a/public/docs/_examples/toh-4/ts/app/app.component.ts +++ /dev/null @@ -1,96 +0,0 @@ -// #docplaster -// #docregion -import {Component, OnInit} from 'angular2/core'; -import {Hero} from './hero'; -import {HeroDetailComponent} from './hero-detail.component'; -// #docregion hero-service-import -import {HeroService} from './hero.service'; -// #enddocregion hero-service-import - -@Component({ - selector: 'my-app', - // #docregion template - template:` -

    {{title}}

    -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - - `, - // #enddocregion template - styles:[` - .selected { - background-color: #CFD8DC !important; - color: white; - } - .heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 10em; - } - .heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; - } - .heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; - } - .heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; - } - .heroes .text { - position: relative; - top: -3px; - } - .heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; - } - `], - directives: [HeroDetailComponent], - providers: [HeroService] -}) -export class AppComponent implements OnInit { - title = 'Tour of Heroes'; - heroes: Hero[]; - selectedHero: Hero; - - constructor(private _heroService: HeroService) { } - -// #docregion get-heroes - getHeroes() { - this._heroService.getHeroes().then(heroes => this.heroes = heroes); - } -// #enddocregion get-heroes - - ngOnInit() { - this.getHeroes(); - } - - onSelect(hero: Hero) { this.selectedHero = hero; } -} diff --git a/public/docs/_examples/toh-4/ts/app/hero-detail.component.js b/public/docs/_examples/toh-4/ts/app/hero-detail.component.js deleted file mode 100644 index f9dc719884..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero-detail.component.js +++ /dev/null @@ -1,36 +0,0 @@ -System.register(['angular2/core'], function(exports_1) { - var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - }; - var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); - }; - var core_1; - var HeroDetailComponent; - return { - setters:[ - function (core_1_1) { - core_1 = core_1_1; - }], - execute: function() { - HeroDetailComponent = (function () { - function HeroDetailComponent() { - } - HeroDetailComponent = __decorate([ - core_1.Component({ - selector: 'my-hero-detail', - template: "\n
    \n

    {{hero.name}} details!

    \n
    {{hero.id}}
    \n
    \n \n \n
    \n
    \n ", - inputs: ['hero'] - }), - __metadata('design:paramtypes', []) - ], HeroDetailComponent); - return HeroDetailComponent; - })(); - exports_1("HeroDetailComponent", HeroDetailComponent); - } - } -}); -//# sourceMappingURL=hero-detail.component.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/hero-detail.component.ts b/public/docs/_examples/toh-4/ts/app/hero-detail.component.ts deleted file mode 100644 index 72024f533a..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero-detail.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {Hero} from './hero'; - -@Component({ - selector: 'my-hero-detail', - template: ` -
    -

    {{hero.name}} details

    -
    - {{hero.id}} -
    -
    - - -
    -
    - `, - inputs: ['hero'] -}) -export class HeroDetailComponent { - hero: Hero; -} diff --git a/public/docs/_examples/toh-4/ts/app/hero.js b/public/docs/_examples/toh-4/ts/app/hero.js deleted file mode 100644 index 6a4d7f1427..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero.js +++ /dev/null @@ -1,8 +0,0 @@ -System.register([], function(exports_1) { - return { - setters:[], - execute: function() { - } - } -}); -//# sourceMappingURL=hero.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/hero.service.1.js b/public/docs/_examples/toh-4/ts/app/hero.service.1.js deleted file mode 100644 index 3e5ac79bad..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero.service.1.js +++ /dev/null @@ -1,45 +0,0 @@ -System.register(['./mock-heroes', 'angular2/core'], function(exports_1) { - var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - }; - var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); - }; - var mock_heroes_1, core_1; - var HeroService; - return { - setters:[ - function (mock_heroes_1_1) { - mock_heroes_1 = mock_heroes_1_1; - }, - function (core_1_1) { - core_1 = core_1_1; - }], - execute: function() { - // #docregion getHeroes-stub - HeroService = (function () { - function HeroService() { - } - // #enddocregion empty-class - HeroService.prototype.getHeroes = function () { - // #enddocregion getHeroes-stub - return mock_heroes_1.HEROES; - // #docregion getHeroes-stub - }; - HeroService = __decorate([ - core_1.Injectable(), - __metadata('design:paramtypes', []) - ], HeroService); - return HeroService; - })(); - exports_1("HeroService", HeroService); - } - } -}); -// #enddocregion getHeroes-stub -// #enddocregion empty-class -// #enddocregion -//# sourceMappingURL=hero.service.1.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/hero.service.1.ts b/public/docs/_examples/toh-4/ts/app/hero.service.1.ts deleted file mode 100644 index 4ab2917a3a..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero.service.1.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docplaster -// #docregion -import {HEROES} from './mock-heroes'; -// #docregion empty-class -import {Injectable} from 'angular2/core'; - -// #docregion getHeroes-stub -@Injectable() -export class HeroService { -// #enddocregion empty-class - getHeroes() { -// #enddocregion getHeroes-stub - return HEROES; -// #docregion getHeroes-stub - } -// #docregion empty-class -} -// #enddocregion getHeroes-stub -// #enddocregion empty-class -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/hero.service.js b/public/docs/_examples/toh-4/ts/app/hero.service.js deleted file mode 100644 index 2d5493906b..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero.service.js +++ /dev/null @@ -1,50 +0,0 @@ -System.register(['./mock-heroes', 'angular2/core'], function(exports_1) { - var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; - }; - var __metadata = (this && this.__metadata) || function (k, v) { - if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); - }; - var mock_heroes_1, core_1; - var HeroService; - return { - setters:[ - function (mock_heroes_1_1) { - mock_heroes_1 = mock_heroes_1_1; - }, - function (core_1_1) { - core_1 = core_1_1; - }], - execute: function() { - HeroService = (function () { - function HeroService() { - } - //#docregion get-heroes - HeroService.prototype.getHeroes = function () { - return Promise.resolve(mock_heroes_1.HEROES); - }; - //#enddocregion get-heroes - // See the "Take it slow" appendix - //#docregion get-heroes-slowly - HeroService.prototype.getHeroesSlowly = function () { - return new Promise(function (resolve) { - return setTimeout(function () { return resolve(mock_heroes_1.HEROES); }, 2000); - } // 2 seconds - // 2 seconds - ); - }; - HeroService = __decorate([ - core_1.Injectable(), - __metadata('design:paramtypes', []) - ], HeroService); - return HeroService; - })(); - exports_1("HeroService", HeroService); - } - } -}); -// #enddocregion -//# sourceMappingURL=hero.service.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/hero.service.ts b/public/docs/_examples/toh-4/ts/app/hero.service.ts deleted file mode 100644 index b503ebed24..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero.service.ts +++ /dev/null @@ -1,27 +0,0 @@ -// #docplaster -// #docregion -// #docregion just-get-heroes -import {Hero} from './hero'; -import {HEROES} from './mock-heroes'; -import {Injectable} from 'angular2/core'; - -@Injectable() -export class HeroService { - //#docregion get-heroes - getHeroes() { - return Promise.resolve(HEROES); - } - //#enddocregion get-heroes - // #enddocregion just-get-heroes - // See the "Take it slow" appendix - //#docregion get-heroes-slowly - getHeroesSlowly() { - return new Promise(resolve => - setTimeout(()=>resolve(HEROES), 2000) // 2 seconds - ); - } - //#enddocregion get-heroes-slowly - // #docregion just-get-heroes -} -// #enddocregion just-get-heroes -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/hero.ts b/public/docs/_examples/toh-4/ts/app/hero.ts deleted file mode 100644 index a61b497759..0000000000 --- a/public/docs/_examples/toh-4/ts/app/hero.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Hero { - id: number; - name: string; -} diff --git a/public/docs/_examples/toh-4/ts/app/main.1.ts b/public/docs/_examples/toh-4/ts/app/main.1.ts deleted file mode 100644 index 37c2c3219e..0000000000 --- a/public/docs/_examples/toh-4/ts/app/main.1.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component.1'; - -bootstrap(AppComponent); \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/main.ts b/public/docs/_examples/toh-4/ts/app/main.ts deleted file mode 100644 index acb4b6229e..0000000000 --- a/public/docs/_examples/toh-4/ts/app/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/mock-heroes.js b/public/docs/_examples/toh-4/ts/app/mock-heroes.js deleted file mode 100644 index 5c4882e9a4..0000000000 --- a/public/docs/_examples/toh-4/ts/app/mock-heroes.js +++ /dev/null @@ -1,22 +0,0 @@ -System.register([], function(exports_1) { - var HEROES; - return { - setters:[], - execute: function() { - exports_1("HEROES", HEROES = [ - { "id": 11, "name": "Mr. Nice" }, - { "id": 12, "name": "Narco" }, - { "id": 13, "name": "Bombasto" }, - { "id": 14, "name": "Celeritas" }, - { "id": 15, "name": "Magneta" }, - { "id": 16, "name": "RubberMan" }, - { "id": 17, "name": "Dynama" }, - { "id": 18, "name": "Dr IQ" }, - { "id": 19, "name": "Magma" }, - { "id": 20, "name": "Tornado" } - ]); - } - } -}); -// #enddocregion -//# sourceMappingURL=mock-heroes.js.map \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/app/mock-heroes.ts b/public/docs/_examples/toh-4/ts/app/mock-heroes.ts deleted file mode 100644 index 617bab5410..0000000000 --- a/public/docs/_examples/toh-4/ts/app/mock-heroes.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {Hero} from './hero'; - -export var HEROES: Hero[] = [ - {"id": 11, "name": "Mr. Nice"}, - {"id": 12, "name": "Narco"}, - {"id": 13, "name": "Bombasto"}, - {"id": 14, "name": "Celeritas"}, - {"id": 15, "name": "Magneta"}, - {"id": 16, "name": "RubberMan"}, - {"id": 17, "name": "Dynama"}, - {"id": 18, "name": "Dr IQ"}, - {"id": 19, "name": "Magma"}, - {"id": 20, "name": "Tornado"} -]; -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-4/ts/index.html b/public/docs/_examples/toh-4/ts/index.html deleted file mode 100644 index 96cc8e84f1..0000000000 --- a/public/docs/_examples/toh-4/ts/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - Angular 2 Tour of Heroes - - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/toh-4/ts/plnkr.json b/public/docs/_examples/toh-4/ts/plnkr.json index cb495e519e..95987d95ce 100644 --- a/public/docs/_examples/toh-4/ts/plnkr.json +++ b/public/docs/_examples/toh-4/ts/plnkr.json @@ -1,9 +1,10 @@ { "description": "Tour of Heroes: Part 4", + "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!**/*.[1].*" + "!**/*.[1,2].*" ], "tags": ["tutorial", "tour", "heroes"] } diff --git a/public/docs/_examples/toh-4/ts/src/app/app.component.1.ts b/public/docs/_examples/toh-4/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..cfddbab537 --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/app.component.1.ts @@ -0,0 +1,65 @@ +// #docplaster +// #docregion on-init +import { OnInit } from '@angular/core'; + +// #enddocregion on-init +import { Component } from '@angular/core'; + +import { Hero } from './hero'; +// #docregion hero-service-import +import { HeroService } from './hero.service.2'; +// #enddocregion hero-service-import + +// Testable but never shown +@Component({ + selector: 'my-app', + template: ` +
    + {{hero.name}} +
    + + `, + // #docregion providers + providers: [HeroService] + // #enddocregion providers +}) +// #docregion on-init +export class AppComponent implements OnInit { + // #enddocregion on-init + title = 'Tour of Heroes'; + // #docregion heroes-prop + heroes: Hero[]; + // #enddocregion heroes-prop + selectedHero: Hero; + + /* + // #docregion new-service + heroService = new HeroService(); // don't do this + // #enddocregion new-service + */ + // #docregion ctor + constructor(private heroService: HeroService) { } + // #enddocregion ctor + // #docregion getHeroes + getHeroes(): void { + // #docregion get-heroes + this.heroes = this.heroService.getHeroes(); + // #enddocregion get-heroes + } + // #enddocregion getHeroes + + // #docregion ng-on-init + // #docregion on-init + ngOnInit(): void { + // #enddocregion on-init + this.getHeroes(); + // #docregion on-init + } + // #enddocregion on-init + // #enddocregion ng-on-init + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + // #docregion on-init +} diff --git a/public/docs/_examples/toh-4/ts/src/app/app.component.ts b/public/docs/_examples/toh-4/ts/src/app/app.component.ts new file mode 100644 index 0000000000..0d57acb5b0 --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/app.component.ts @@ -0,0 +1,97 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +// #docregion hero-service-import +import { HeroService } from './hero.service'; +// #enddocregion hero-service-import + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    {{title}}

    +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    + + `, + // #enddocregion template + styles: [` + .selected { + background-color: #CFD8DC !important; + color: white; + } + .heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; + } + .heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; + } + .heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; + } + .heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; + } + .heroes .text { + position: relative; + top: -3px; + } + .heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; + } + `], + providers: [HeroService] +}) +export class AppComponent implements OnInit { + title = 'Tour of Heroes'; + heroes: Hero[]; + selectedHero: Hero; + + constructor(private heroService: HeroService) { } + +// #docregion get-heroes + getHeroes(): void { + this.heroService.getHeroes().then(heroes => this.heroes = heroes); + } +// #enddocregion get-heroes + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } +} diff --git a/public/docs/_examples/toh-4/ts/src/app/app.module.ts b/public/docs/_examples/toh-4/ts/src/app/app.module.ts new file mode 100644 index 0000000000..3df186c62a --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/app.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + HeroDetailComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts b/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..865fb98da7 --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/hero-detail.component.ts @@ -0,0 +1,22 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { Hero } from './hero'; + +@Component({ + selector: 'hero-detail', + template: ` +
    +

    {{hero.name}} details!

    +
    + {{hero.id}} +
    +
    + + +
    +
    + ` +}) +export class HeroDetailComponent { + @Input() hero: Hero; +} diff --git a/public/docs/_examples/toh-4/ts/src/app/hero.service.1.ts b/public/docs/_examples/toh-4/ts/src/app/hero.service.1.ts new file mode 100644 index 0000000000..2366215259 --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/hero.service.1.ts @@ -0,0 +1,24 @@ +// #docplaster +// #docregion +// #docregion empty-class, full +import { Injectable } from '@angular/core'; + +// #enddocregion empty-class +import { Hero } from './hero'; +import { HEROES } from './mock-heroes'; + +// #docregion empty-class, getHeroes-stub +@Injectable() +export class HeroService { + // #enddocregion empty-class, getHeroes-stub, full + /* + // #docregion getHeroes-stub + getHeroes(): void {} // stub + // #enddocregion getHeroes-stub + */ + // #docregion full + getHeroes(): Hero[] { + return HEROES; + } + // #docregion empty-class, getHeroes-stub +} diff --git a/public/docs/_examples/toh-4/ts/src/app/hero.service.2.ts b/public/docs/_examples/toh-4/ts/src/app/hero.service.2.ts new file mode 100644 index 0000000000..d14fe02410 --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/hero.service.2.ts @@ -0,0 +1,13 @@ +// #docregion +import { Injectable } from '@angular/core'; + +import { Hero } from './hero'; +import { HEROES } from './mock-heroes'; + +@Injectable() +export class HeroService { + + getHeroes(): Hero[] { + return HEROES; + } +} diff --git a/public/docs/_examples/toh-4/ts/src/app/hero.service.ts b/public/docs/_examples/toh-4/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..03a1c10a4a --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/hero.service.ts @@ -0,0 +1,29 @@ +// #docplaster +// #docregion +// #docregion just-get-heroes +import { Injectable } from '@angular/core'; + +import { Hero } from './hero'; +import { HEROES } from './mock-heroes'; + +@Injectable() +export class HeroService { + // #docregion get-heroes + getHeroes(): Promise { + return Promise.resolve(HEROES); + } + // #enddocregion get-heroes, just-get-heroes + // #enddocregion + + // See the "Take it slow" appendix + // #docregion get-heroes-slowly + getHeroesSlowly(): Promise { + return new Promise(resolve => { + // Simulate server latency with 2 second delay + setTimeout(() => resolve(this.getHeroes()), 2000); + }); + } + // #enddocregion get-heroes-slowly + // #docregion + // #docregion just-get-heroes +} diff --git a/public/docs/_examples/toh-4/ts/src/app/hero.ts b/public/docs/_examples/toh-4/ts/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/toh-4/ts/src/app/mock-heroes.ts b/public/docs/_examples/toh-4/ts/src/app/mock-heroes.ts new file mode 100644 index 0000000000..6f7c5d83a0 --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/app/mock-heroes.ts @@ -0,0 +1,15 @@ +// #docregion +import { Hero } from './hero'; + +export const HEROES: Hero[] = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} +]; diff --git a/public/docs/_examples/toh-4/ts/src/index.html b/public/docs/_examples/toh-4/ts/src/index.html new file mode 100644 index 0000000000..a217238c6c --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/index.html @@ -0,0 +1,25 @@ + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-4/ts/src/main.1.ts b/public/docs/_examples/toh-4/ts/src/main.1.ts new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/main.1.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/toh-4/ts/src/main.ts b/public/docs/_examples/toh-4/ts/src/main.ts new file mode 100644 index 0000000000..f22933ba8e --- /dev/null +++ b/public/docs/_examples/toh-4/ts/src/main.ts @@ -0,0 +1,4 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/toh-5/e2e-spec.js b/public/docs/_examples/toh-5/e2e-spec.js deleted file mode 100644 index f35fcd1287..0000000000 --- a/public/docs/_examples/toh-5/e2e-spec.js +++ /dev/null @@ -1,111 +0,0 @@ -describe('Tutorial', function () { - - beforeAll(function () { - browser.get(''); - }); - - - function getPageStruct() { - hrefEles = element.all(by.css('my-app a')); - - return { - hrefs: hrefEles, - myDashboardHref: hrefEles.get(0), - myDashboardParent: element(by.css('my-app my-dashboard')), - topHeroes: element.all(by.css('my-app my-dashboard .module.hero')), - - myHeroesHref: hrefEles.get(1), - myHeroesParent: element(by.css('my-app my-heroes')), - allHeroes: element.all(by.css('my-app my-heroes li')), - - heroDetail: element(by.css('my-app my-hero-detail')) - } - } - - it('should be able to see the start screen', function () { - var page = getPageStruct(); - expect(page.hrefs.count()).toEqual(2, 'should be two dashboard choices'); - expect(page.myDashboardHref.getText()).toEqual("Dashboard"); - expect(page.myHeroesHref.getText()).toEqual("Heroes"); - }); - - it('should be able to see dashboard choices', function () { - var page = getPageStruct(); - expect(page.topHeroes.count()).toBe(4, "should be 4 dashboard hero choices"); - }); - - it('should be able to toggle the views', function () { - var page = getPageStruct(); - - expect(page.myDashboardParent.element(by.css('h3')).getText()).toEqual('Top Heroes'); - page.myHeroesHref.click().then(function() { - expect(page.myDashboardParent.isPresent()).toBe(false, 'should no longer see dashboard element'); - expect(page.allHeroes.count()).toBeGreaterThan(4, "should be more than 4 heroes shown"); - return page.myDashboardHref.click(); - }).then(function() { - expect(page.myDashboardParent.isPresent()).toBe(true, 'should once again see the dashboard element'); - }); - - }); - - it('should be able to edit details from "Dashboard" view', function () { - var page = getPageStruct(); - expect(page.myDashboardParent.isPresent()).toBe(true, 'dashboard element should be available'); - var heroEle = page.topHeroes.get(3); - var heroDescrEle = heroEle.element(by.css('h4')); - var heroDescr; - return heroDescrEle.getText().then(function(text) { - heroDescr = text; - return heroEle.click(); - }).then(function() { - return editDetails(page, heroDescr, '-foo'); - }).then(function() { - expect(page.myDashboardParent.isPresent()).toBe(true, 'dashboard element should be back'); - expect(heroDescrEle.getText()).toEqual(heroDescr + '-foo'); - }); - }); - - it('should be able to edit details from "Heroes" view', function () { - var page = getPageStruct(); - expect(page.myDashboardParent.isPresent()).toBe(true, 'dashboard element should be present'); - var viewDetailsButtonEle = page.myHeroesParent.element(by.cssContainingText('button', 'View Details')); - var heroEle, heroDescr; - page.myHeroesHref.click().then(function() { - expect(page.myDashboardParent.isPresent()).toBe(false, 'dashboard element should NOT be present'); - expect(page.myHeroesParent.isPresent()).toBe(true, 'myHeroes element should be present'); - expect(viewDetailsButtonEle.isPresent()).toBe(false, 'viewDetails button should not yet be present'); - heroEle = page.allHeroes.get(2); - return heroEle.getText(); - }).then(function(text) { - // remove leading 'id' from the element - heroDescr = text.substr(text.indexOf(' ')+1); - return heroEle.click(); - }).then(function() { - expect(viewDetailsButtonEle.isDisplayed()).toBe(true, 'viewDetails button should now be visible'); - return viewDetailsButtonEle.click(); - }).then(function() { - return editDetails(page, heroDescr, '-bar'); - }).then(function() { - expect(page.myHeroesParent.isPresent()).toBe(true, 'myHeroes element should be back'); - expect(heroEle.getText()).toContain(heroDescr + '-bar'); - expect(viewDetailsButtonEle.isPresent()).toBe(false, 'viewDetails button should again NOT be present'); - }); - }); - - function editDetails(page, origValue, textToAdd) { - expect(page.myDashboardParent.isPresent()).toBe(false, 'dashboard element should NOT be present'); - expect(page.myHeroesParent.isPresent()).toBe(false, 'myHeroes element should NOT be present'); - expect(page.heroDetail.isDisplayed()).toBe(true, 'should be able to see hero-details'); - var inputEle = page.heroDetail.element(by.css('input')); - expect(inputEle.isDisplayed()).toBe(true, 'should be able to see the input box'); - var backButtonEle = page.heroDetail.element(by.css('button')); - expect(backButtonEle.isDisplayed()).toBe(true, 'should be able to see the back button'); - var detailTextEle = page.heroDetail.element(by.css('div h2')); - expect(detailTextEle.getText()).toContain(origValue); - return sendKeys(inputEle, textToAdd).then(function () { - expect(detailTextEle.getText()).toContain(origValue + textToAdd); - return backButtonEle.click(); - }); - } - -}); diff --git a/public/docs/_examples/toh-5/e2e-spec.ts b/public/docs/_examples/toh-5/e2e-spec.ts new file mode 100644 index 0000000000..a49f2ddb62 --- /dev/null +++ b/public/docs/_examples/toh-5/e2e-spec.ts @@ -0,0 +1,190 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes'; +const expectedTitle = `Angular ${expectedH1}`; +const targetHero = { id: 15, name: 'Magneta' }; +const targetHeroDashboardIndex = 3; +const nameSuffix = 'X'; +const newHeroName = targetHero.name + nameSuffix; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Get hero from s formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Get hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Tutorial part 5', () => { + + beforeAll(() => browser.get('')); + + function getPageElts() { + let navElts = element.all(by.css('my-app nav a')); + + return { + navElts: navElts, + + myDashboardHref: navElts.get(0), + myDashboard: element(by.css('my-app my-dashboard')), + topHeroes: element.all(by.css('my-app my-dashboard > div h4')), + + myHeroesHref: navElts.get(1), + myHeroes: element(by.css('my-app my-heroes')), + allHeroes: element.all(by.css('my-app my-heroes li')), + selectedHero: element(by.css('my-app li.selected')), + selectedHeroSubview: element(by.css('my-app my-heroes > div')), + + heroDetail: element(by.css('my-app hero-detail > div')) + }; + } + + describe('Initial page', () => { + + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + const expectedViewNames = ['Dashboard', 'Heroes']; + it(`has views ${expectedViewNames}`, () => { + let viewNames = getPageElts().navElts.map((el: ElementFinder) => el.getText()); + expect(viewNames).toEqual(expectedViewNames); + }); + + it('has dashboard as the active view', () => { + let page = getPageElts(); + expect(page.myDashboard.isPresent()).toBeTruthy(); + }); + + }); + + describe('Dashboard tests', () => { + + beforeAll(() => browser.get('')); + + it('has top heroes', () => { + let page = getPageElts(); + expect(page.topHeroes.count()).toEqual(4); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`saves and shows ${newHeroName} in Dashboard`, () => { + element(by.buttonText('Back')).click(); + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(newHeroName); + }); + + }); + + describe('Heroes tests', () => { + + beforeAll(() => browser.get('')); + + it('can switch to Heroes view', () => { + getPageElts().myHeroesHref.click(); + let page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); + }); + + it(`selects and shows ${targetHero.name} as selected in list`, () => { + getHeroLiEltById(targetHero.id).click(); + let expectedText = `${targetHero.id} ${targetHero.name}`; + expect(getPageElts().selectedHero.getText()).toBe(expectedText); + }); + + it('shows selected hero subview', async () => { + let page = getPageElts(); + let title = page.selectedHeroSubview.element(by.css('h2')).getText(); + let expectedTitle = `${targetHero.name.toUpperCase()} is my hero`; + expect(title).toEqual(expectedTitle); + }); + + it('can route to hero details', async () => { + element(by.buttonText('View Details')).click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name); + }); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`shows ${newHeroName} in Heroes list`, () => { + element(by.buttonText('Back')).click(); + let expectedText = `${targetHero.id} ${newHeroName}`; + expect(getHeroLiEltById(targetHero.id).getText()).toEqual(expectedText); + }); + + }); + + async function dashboardSelectTargetHero() { + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + targetHeroElt.click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(targetHero.name); + } + + async function updateHeroNameInDetailView() { + // Assumes that the current view is the hero details view. + addToHeroName(nameSuffix); + + let page = getPageElts(); + let hero = await Hero.fromDetail(page.heroDetail); + expect(hero.id).toEqual(targetHero.id); + expect(hero.name).toEqual(newHeroName); + } + +}); + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getHeroLiEltById(id: number) { + let spanForId = element(by.cssContainingText('li span.badge', id.toString())); + return spanForId.element(by.xpath('..')); +} diff --git a/public/docs/_examples/toh-5/ts/.gitignore b/public/docs/_examples/toh-5/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/toh-5/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/toh-5/ts/app/app.component.1.ts b/public/docs/_examples/toh-5/ts/app/app.component.1.ts deleted file mode 100644 index e0104a019c..0000000000 --- a/public/docs/_examples/toh-5/ts/app/app.component.1.ts +++ /dev/null @@ -1,30 +0,0 @@ -// #docplaster -// #docregion -import { Component } from 'angular2/core'; -import { HeroService } from './hero.service'; -import { HeroesComponent } from './heroes.component'; -// #enddocregion - -// For testing only -import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'; - -// #docregion - -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - `, - directives: [HeroesComponent], - providers: [ -// #enddocregion - ROUTER_PROVIDERS, -// #docregion - HeroService - ] -}) -export class AppComponent { - title = 'Tour of Heroes'; -} -// #enddocregion diff --git a/public/docs/_examples/toh-5/ts/app/app.component.2.ts b/public/docs/_examples/toh-5/ts/app/app.component.2.ts deleted file mode 100644 index 17ce7e9412..0000000000 --- a/public/docs/_examples/toh-5/ts/app/app.component.2.ts +++ /dev/null @@ -1,40 +0,0 @@ -// #docplaster -// #docregion -import { Component } from 'angular2/core'; -// #docregion import-router -import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'; -// #enddocregion import-router - -import { HeroService } from './hero.service'; -import { HeroesComponent } from './heroes.component'; - -@Component({ - selector: 'my-app', -// #docregion template - template: ` -

    {{title}}

    - Heroes - - `, -// #enddocregion template -// #docregion directives-and-providers - directives: [ROUTER_DIRECTIVES], - providers: [ - ROUTER_PROVIDERS, - HeroService - ] - // #enddocregion directives-and-providers -}) -// #docregion route-config -@RouteConfig([ - { - path: '/heroes', - name: 'Heroes', - component: HeroesComponent - } -]) -// #enddocregion route-config -export class AppComponent { - title = 'Tour of Heroes'; -} -// #enddocregion diff --git a/public/docs/_examples/toh-5/ts/app/app.component.css b/public/docs/_examples/toh-5/ts/app/app.component.css deleted file mode 100644 index 137e9be7be..0000000000 --- a/public/docs/_examples/toh-5/ts/app/app.component.css +++ /dev/null @@ -1,31 +0,0 @@ -/* #docplaster */ -/* #docregion css */ -h1 { - font-size: 1.2em; - color: #999; - margin-bottom: 0; -} -h2 { - font-size: 2em; - margin-top: 0; - padding-top: 0; -} -nav a { - padding: 5px 10px; - text-decoration: none; - margin-top: 10px; - display: inline-block; - background-color: #eee; - border-radius: 4px; -} -nav a:visited, a:link { - color: #607D8B; -} -nav a:hover { - color: #039be5; - background-color: #CFD8DC; -} -nav a.router-link-active { - color: #039be5; -} -/* #enddocregion css */ diff --git a/public/docs/_examples/toh-5/ts/app/app.component.ts b/public/docs/_examples/toh-5/ts/app/app.component.ts deleted file mode 100644 index df9985b5ee..0000000000 --- a/public/docs/_examples/toh-5/ts/app/app.component.ts +++ /dev/null @@ -1,59 +0,0 @@ -// #docplaster -// #docregion -import { Component } from 'angular2/core'; -import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'; - -import { HeroService } from './hero.service'; -import { DashboardComponent } from './dashboard.component'; -import { HeroesComponent } from './heroes.component'; -// #docregion hero-detail-import -import { HeroDetailComponent } from './hero-detail.component'; -// #enddocregion hero-detail-import - -@Component({ - selector: 'my-app', -// #docregion template - template: ` -

    {{title}}

    - - - `, -// #enddocregion template -// #docregion style-urls - styleUrls: ['app/app.component.css'], -// #enddocregion style-urls - directives: [ROUTER_DIRECTIVES], - providers: [ - ROUTER_PROVIDERS, - HeroService - ] -}) -@RouteConfig([ -// #docregion dashboard-route - { - path: '/dashboard', - name: 'Dashboard', - component: DashboardComponent, - useAsDefault: true - }, -// #enddocregion dashboard-route -// #docregion hero-detail-route - { - path: '/detail/:id', - name: 'HeroDetail', - component: HeroDetailComponent - }, -// #enddocregion hero-detail-route - { - path: '/heroes', - name: 'Heroes', - component: HeroesComponent - } -]) -export class AppComponent { - title = 'Tour of Heroes'; -} -// #enddocregion diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.2.ts b/public/docs/_examples/toh-5/ts/app/dashboard.component.2.ts deleted file mode 100644 index 896c7314a0..0000000000 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.2.ts +++ /dev/null @@ -1,27 +0,0 @@ -// #docplaster -// #docregion imports -import { Component, OnInit } from 'angular2/core'; - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; -// #enddocregion imports - -@Component({ - selector: 'my-dashboard', - templateUrl: 'app/dashboard.component.html' -}) -// #docregion component -export class DashboardComponent implements OnInit { - - heroes: Hero[] = []; - - constructor(private _heroService: HeroService) { } - - ngOnInit() { - this._heroService.getHeroes() - .then(heroes => this.heroes = heroes.slice(1,5)); - } - - gotoDetail(){ /* not implemented yet */} -} -// #enddocregion component diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.css b/public/docs/_examples/toh-5/ts/app/dashboard.component.css deleted file mode 100644 index ce6e963a5f..0000000000 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.css +++ /dev/null @@ -1,63 +0,0 @@ -/* #docplaster */ -/* #docregion */ -[class*='col-'] { - float: left; -} -*, *:after, *:before { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -h3 { - text-align: center; margin-bottom: 0; -} -[class*='col-'] { - padding-right: 20px; - padding-bottom: 20px; -} -[class*='col-']:last-of-type { - padding-right: 0; -} -.grid { - margin: 0; -} -.col-1-4 { - width: 25%; -} -.module { - padding: 20px; - text-align: center; - color: #eee; - max-height: 120px; - min-width: 120px; - background-color: #607D8B; - border-radius: 2px; -} -h4 { - position: relative; -} -.module:hover { - background-color: #EEE; - cursor: pointer; - color: #607d8b; -} -.grid-pad { - padding: 10px 0; -} -.grid-pad > [class*='col-']:last-of-type { - padding-right: 20px; -} -@media (max-width: 600px) { - .module { - font-size: 10px; - max-height: 75px; } -} -@media (max-width: 1024px) { - .grid { - margin: 0; - } - .module { - min-width: 60px; - } -} -/* #enddocregion */ diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.html b/public/docs/_examples/toh-5/ts/app/dashboard.component.html deleted file mode 100644 index 8cc8ce9242..0000000000 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.html +++ /dev/null @@ -1,11 +0,0 @@ - -

    Top Heroes

    -
    - -
    - -
    -

    {{hero.name}}

    -
    -
    -
    diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.ts b/public/docs/_examples/toh-5/ts/app/dashboard.component.ts deleted file mode 100644 index ee1fe7ae57..0000000000 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -// #docplaster -// #docregion -import { Component, OnInit } from 'angular2/core'; -// #docregion import-router -import { Router } from 'angular2/router'; -// #enddocregion import-router - -import { Hero } from './hero'; -import { HeroService } from './hero.service'; - -@Component({ - selector: 'my-dashboard', - templateUrl: 'app/dashboard.component.html', - // #docregion css - styleUrls: ['app/dashboard.component.css'] - // #enddocregion css -}) -// #docregion component -export class DashboardComponent implements OnInit { - - heroes: Hero[] = []; - -// #docregion ctor - constructor( - private _router: Router, - private _heroService: HeroService) { - } -// #enddocregion ctor - - ngOnInit() { - this._heroService.getHeroes() - .then(heroes => this.heroes = heroes.slice(1,5)); - } - - // #docregion goto-detail - gotoDetail(hero: Hero) { - let link = ['HeroDetail', { id: hero.id }]; - this._router.navigate(link); - } - // #enddocregion goto-detail -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-5/ts/app/hero-detail.component.html b/public/docs/_examples/toh-5/ts/app/hero-detail.component.html deleted file mode 100644 index cf96fc2169..0000000000 --- a/public/docs/_examples/toh-5/ts/app/hero-detail.component.html +++ /dev/null @@ -1,14 +0,0 @@ - - -
    -

    {{hero.name}} details!

    -
    - {{hero.id}}
    -
    - - -
    - - - -
    \ No newline at end of file diff --git a/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts b/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts deleted file mode 100644 index 1c06a4ee46..0000000000 --- a/public/docs/_examples/toh-5/ts/app/hero-detail.component.ts +++ /dev/null @@ -1,57 +0,0 @@ -// #docplaster -// #docregion -// #docregion v2 -// #docregion import-oninit -import { Component, OnInit } from 'angular2/core'; -// #enddocregion import-oninit -// #docregion import-route-params -import {RouteParams} from 'angular2/router'; -// #enddocregion import-route-params - -import { Hero } from './hero'; -// #docregion import-hero-service -import { HeroService } from './hero.service'; -// #enddocregion import-hero-service - -// #docregion extract-template -@Component({ - selector: 'my-hero-detail', - // #docregion template-url - templateUrl: 'app/hero-detail.component.html', - // #enddocregion template-url -// #enddocregion v2 - styleUrls: ['app/hero-detail.component.css'], - inputs: ['hero'] -// #docregion v2 -}) -// #enddocregion extract-template -// #docregion implement -export class HeroDetailComponent implements OnInit { -// #enddocregion implement - hero: Hero; - -// #docregion ctor - constructor( - private _heroService: HeroService, - private _routeParams: RouteParams) { - } -// #enddocregion ctor - -// #docregion ng-oninit - ngOnInit() { - // #docregion get-id - let id = +this._routeParams.get('id'); - // #enddocregion get-id - this._heroService.getHero(id) - .then(hero => this.hero = hero); - } -// #enddocregion ng-oninit - -// #docregion go-back - goBack() { - window.history.back(); - } -// #enddocregion go-back -} -// #enddocregion v2 -// #enddocregion diff --git a/public/docs/_examples/toh-5/ts/app/hero.service.ts b/public/docs/_examples/toh-5/ts/app/hero.service.ts deleted file mode 100644 index a55f71ec95..0000000000 --- a/public/docs/_examples/toh-5/ts/app/hero.service.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docplaster -// #docregion -import { Hero } from './hero'; -import { HEROES } from './mock-heroes'; -import { Injectable } from 'angular2/core'; - -@Injectable() -export class HeroService { - getHeroes() { - return Promise.resolve(HEROES); - } - - // See the "Take it slow" appendix - getHeroesSlowly() { - return new Promise(resolve => - setTimeout(()=>resolve(HEROES), 2000) // 2 seconds - ); - } - - //#docregion get-hero - getHero(id: number) { - return Promise.resolve(HEROES).then( - heroes => heroes.filter(hero => hero.id === id)[0] - ); - } - //#enddocregion get-hero -} -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-5/ts/app/hero.ts b/public/docs/_examples/toh-5/ts/app/hero.ts deleted file mode 100644 index a61b497759..0000000000 --- a/public/docs/_examples/toh-5/ts/app/hero.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Hero { - id: number; - name: string; -} diff --git a/public/docs/_examples/toh-5/ts/app/heroes.component.html b/public/docs/_examples/toh-5/ts/app/heroes.component.html deleted file mode 100644 index 9bcd2ba4e8..0000000000 --- a/public/docs/_examples/toh-5/ts/app/heroes.component.html +++ /dev/null @@ -1,21 +0,0 @@ - - -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    - -
    -

    - - {{selectedHero.name | uppercase}} is my hero - -

    - -
    - - diff --git a/public/docs/_examples/toh-5/ts/app/heroes.component.ts b/public/docs/_examples/toh-5/ts/app/heroes.component.ts deleted file mode 100644 index 6cdb00bc83..0000000000 --- a/public/docs/_examples/toh-5/ts/app/heroes.component.ts +++ /dev/null @@ -1,50 +0,0 @@ -// #docplaster -// #docregion -import { Component, OnInit } from 'angular2/core'; -import { Router } from 'angular2/router'; - -import { Hero } from './hero'; -import { HeroDetailComponent } from './hero-detail.component'; -import { HeroService } from './hero.service'; - -// #docregion metadata -// #docregion heroes-component-renaming -@Component({ - selector: 'my-heroes', -// #enddocregion heroes-component-renaming - templateUrl: 'app/heroes.component.html', - styleUrls: ['app/heroes.component.css'], - directives: [HeroDetailComponent] -// #docregion heroes-component-renaming -}) -// #enddocregion heroes-component-renaming -// #enddocregion metadata -// #docregion class -// #docregion heroes-component-renaming -export class HeroesComponent implements OnInit { -// #enddocregion heroes-component-renaming - heroes: Hero[]; - selectedHero: Hero; - - constructor( - private _router: Router, - private _heroService: HeroService) { } - - getHeroes() { - this._heroService.getHeroes().then(heroes => this.heroes = heroes); - } - - ngOnInit() { - this.getHeroes(); - } - - onSelect(hero: Hero) { this.selectedHero = hero; } - - gotoDetail() { - this._router.navigate(['HeroDetail', { id: this.selectedHero.id }]); - } -// #docregion heroes-component-renaming -} -// #enddocregion heroes-component-renaming -// #enddocregion class -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-5/ts/app/main.ts b/public/docs/_examples/toh-5/ts/app/main.ts deleted file mode 100644 index c469e18fd0..0000000000 --- a/public/docs/_examples/toh-5/ts/app/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { bootstrap } from 'angular2/platform/browser'; -import { AppComponent } from './app.component'; - -bootstrap(AppComponent); \ No newline at end of file diff --git a/public/docs/_examples/toh-5/ts/app/mock-heroes.ts b/public/docs/_examples/toh-5/ts/app/mock-heroes.ts deleted file mode 100644 index cdcba35097..0000000000 --- a/public/docs/_examples/toh-5/ts/app/mock-heroes.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import { Hero } from './hero'; - -export var HEROES: Hero[] = [ - {"id": 11, "name": "Mr. Nice"}, - {"id": 12, "name": "Narco"}, - {"id": 13, "name": "Bombasto"}, - {"id": 14, "name": "Celeritas"}, - {"id": 15, "name": "Magneta"}, - {"id": 16, "name": "RubberMan"}, - {"id": 17, "name": "Dynama"}, - {"id": 18, "name": "Dr IQ"}, - {"id": 19, "name": "Magma"}, - {"id": 20, "name": "Tornado"} -]; -// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-5/ts/index.html b/public/docs/_examples/toh-5/ts/index.html deleted file mode 100644 index 0e91f05760..0000000000 --- a/public/docs/_examples/toh-5/ts/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - Angular 2 Tour of Heroes - - - - - - - - - - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/toh-5/ts/plnkr.json b/public/docs/_examples/toh-5/ts/plnkr.json index 019630c28f..db4b15d160 100644 --- a/public/docs/_examples/toh-5/ts/plnkr.json +++ b/public/docs/_examples/toh-5/ts/plnkr.json @@ -1,9 +1,10 @@ { "description": "Tour of Heroes: Part 5", + "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!**/*.[1,2].*" + "!**/*.[1,2,3].*" ], "tags": ["tutorial", "tour", "heroes", "router"] } diff --git a/public/docs/_examples/toh-5/ts/src/app/app-routing.module.ts b/public/docs/_examples/toh-5/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..dfd957782b --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app-routing.module.ts @@ -0,0 +1,20 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'detail/:id', component: HeroDetailComponent }, + { path: 'heroes', component: HeroesComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/toh-5/ts/src/app/app.component.1.ts b/public/docs/_examples/toh-5/ts/src/app/app.component.1.ts new file mode 100644 index 0000000000..c9f5db9712 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.component.1.ts @@ -0,0 +1,42 @@ +// #docplaster +// #docregion , v2 +import { Component } from '@angular/core'; + +// #enddocregion v2 +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + ` +}) +// #enddocregion +// #docregion v2 +@Component({ + selector: 'my-app', + // #docregion template-v2 + template: ` +

    {{title}}

    + Heroes + + ` + // #enddocregion template-v2 +}) +// #enddocregion +@Component({ + selector: 'my-app', + // #docregion template-v3 + template: ` +

    {{title}}

    + + + ` + // #enddocregion template-v3 +}) +// #docregion , v2 +export class AppComponent { + title = 'Tour of Heroes'; +} diff --git a/public/docs/_examples/toh-5/ts/src/app/app.component.css b/public/docs/_examples/toh-5/ts/src/app/app.component.css new file mode 100644 index 0000000000..071e665767 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +h1 { + font-size: 1.2em; + color: #999; + margin-bottom: 0; +} +h2 { + font-size: 2em; + margin-top: 0; + padding-top: 0; +} +nav a { + padding: 5px 10px; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} diff --git a/public/docs/_examples/toh-5/ts/src/app/app.component.ts b/public/docs/_examples/toh-5/ts/src/app/app.component.ts new file mode 100644 index 0000000000..96bc3fe694 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.component.ts @@ -0,0 +1,22 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + // #docregion template + template: ` +

    {{title}}

    + + + `, + // #enddocregion template + // #docregion styleUrls + styleUrls: ['./app.component.css'], + // #enddocregion styleUrls +}) +export class AppComponent { + title = 'Tour of Heroes'; +} diff --git a/public/docs/_examples/toh-5/ts/src/app/app.module.1.ts b/public/docs/_examples/toh-5/ts/src/app/app.module.1.ts new file mode 100644 index 0000000000..e1cda9b620 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.module.1.ts @@ -0,0 +1,28 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroService } from './hero.service'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule + ], + declarations: [ + AppComponent, + HeroDetailComponent, + HeroesComponent + ], + providers: [ + HeroService + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { +} +// #enddocregion diff --git a/public/docs/_examples/toh-5/ts/src/app/app.module.2.ts b/public/docs/_examples/toh-5/ts/src/app/app.module.2.ts new file mode 100644 index 0000000000..00876570f3 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.module.2.ts @@ -0,0 +1,48 @@ +// #docplaster +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroService } from './hero.service'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + RouterModule.forRoot([ + { + path: 'heroes', + component: HeroesComponent + } + ]) + ], + declarations: [ + AppComponent, + HeroDetailComponent, + HeroesComponent + ], + providers: [ + HeroService + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { +} +// #enddocregion +/* +// #docregion heroes, routing +import { RouterModule } from '@angular/router'; + +RouterModule.forRoot([ + { + path: 'heroes', + component: HeroesComponent + } +]) +// #enddocregion heroes, routing +*/ diff --git a/public/docs/_examples/toh-5/ts/src/app/app.module.3.ts b/public/docs/_examples/toh-5/ts/src/app/app.module.3.ts new file mode 100644 index 0000000000..306d9958f0 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.module.3.ts @@ -0,0 +1,58 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { AppComponent } from './app.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroService } from './hero.service'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + RouterModule.forRoot([ + // #docregion redirect + { + path: '', + redirectTo: '/dashboard', + pathMatch: 'full' + }, + // #enddocregion redirect + // #docregion dashboard + { + path: 'dashboard', + component: DashboardComponent + }, + // #enddocregion dashboard + // #docregion hero-detail + { + path: 'detail/:id', + component: HeroDetailComponent + }, + // #enddocregion hero-detail + // #docregion heroes, routing + { + path: 'heroes', + component: HeroesComponent + } + // #enddocregion heroes, routing + ]) + ], + declarations: [ + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent + ], + providers: [ + HeroService + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { +} +// #enddocregion diff --git a/public/docs/_examples/toh-5/ts/src/app/app.module.ts b/public/docs/_examples/toh-5/ts/src/app/app.module.ts new file mode 100644 index 0000000000..b376d69aba --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/app.module.ts @@ -0,0 +1,35 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; + +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroService } from './hero.service'; + +// #docregion routing-module +import { AppRoutingModule } from './app-routing.module'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + AppRoutingModule + ], +// #enddocregion routing-module + // #docregion dashboard + declarations: [ + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent + ], + // #enddocregion dashboard + providers: [ HeroService ], + bootstrap: [ AppComponent ] +// #docregion routing-module +}) +export class AppModule { } +// #enddocregion routing-module diff --git a/public/docs/_examples/toh-5/ts/src/app/dashboard.component.1.html b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.1.html new file mode 100644 index 0000000000..0c556b8de0 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.1.html @@ -0,0 +1,9 @@ + +

    Top Heroes

    +
    +
    +
    +

    {{hero.name}}

    +
    +
    +
    diff --git a/public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.1.ts similarity index 75% rename from public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts rename to public/docs/_examples/toh-5/ts/src/app/dashboard.component.1.ts index eae02d1e95..3c92b205c8 100644 --- a/public/docs/_examples/toh-5/ts/app/dashboard.component.1.ts +++ b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.1.ts @@ -1,5 +1,5 @@ // #docregion -import { Component } from 'angular2/core'; +import { Component } from '@angular/core'; @Component({ selector: 'my-dashboard', diff --git a/public/docs/_examples/toh-5/ts/src/app/dashboard.component.css b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.css new file mode 100644 index 0000000000..dc7fb7ce06 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.css @@ -0,0 +1,62 @@ +/* #docregion */ +[class*='col-'] { + float: left; + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +a { + text-decoration: none; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +h4 { + position: relative; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.module { + padding: 20px; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} +.module:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 600px) { + .module { + font-size: 10px; + max-height: 75px; } +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } + .module { + min-width: 60px; + } +} diff --git a/public/docs/_examples/toh-5/ts/src/app/dashboard.component.html b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.html new file mode 100644 index 0000000000..49e77c460c --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.html @@ -0,0 +1,11 @@ + +

    Top Heroes

    + diff --git a/public/docs/_examples/toh-5/ts/src/app/dashboard.component.ts b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.ts new file mode 100644 index 0000000000..416cf8868e --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/dashboard.component.ts @@ -0,0 +1,33 @@ +// #docplaster +// #docregion , imports +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; +// #enddocregion imports + +// #docregion metadata +@Component({ + selector: 'my-dashboard', + templateUrl: './dashboard.component.html', + // #enddocregion metadata + // #docregion css + styleUrls: [ './dashboard.component.css' ] + // #enddocregion css + // #docregion metadata +}) +// #enddocregion metadata +// #docregion class +export class DashboardComponent implements OnInit { + + heroes: Hero[] = []; + + // #docregion ctor + constructor(private heroService: HeroService) { } + // #enddocregion ctor + + ngOnInit(): void { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes.slice(1, 5)); + } +} diff --git a/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.1.ts b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.1.ts new file mode 100644 index 0000000000..2f5081bdce --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.1.ts @@ -0,0 +1,29 @@ +// Imports in comments cause problems when the app is executed +// (some error about 'traceur' missing). Hence this separate file +// is solely for containing the transitory state of the imports. + +// #docregion added-imports +// Keep the Input import for now, you'll remove it later: +import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Location } from '@angular/common'; + +import { HeroService } from './hero.service'; +// #enddocregion added-imports + +// Bogus code below this point. It is only here to make lint happy. +import { Hero } from './hero'; + +@Component({}) +export class HeroDetailComponent implements OnInit { + @Input() hero: Hero; + bogus: Params; + + constructor( + private heroService: HeroService, + private route: ActivatedRoute, + private location: Location + ) {} + + ngOnInit() {} +} diff --git a/public/docs/_examples/toh-5/ts/app/hero-detail.component.css b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.css similarity index 100% rename from public/docs/_examples/toh-5/ts/app/hero-detail.component.css rename to public/docs/_examples/toh-5/ts/src/app/hero-detail.component.css diff --git a/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.html b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..8f2ff9d90c --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.html @@ -0,0 +1,14 @@ + + +
    +

    {{hero.name}} details!

    +
    + {{hero.id}}
    +
    + + +
    + + + +
    diff --git a/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.ts b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..222b6705d7 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/hero-detail.component.ts @@ -0,0 +1,46 @@ +// #docplaster +// #docregion , v2, rxjs-import +import 'rxjs/add/operator/switchMap'; +// #enddocregion rxjs-import +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; +// #docregion metadata +@Component({ + selector: 'hero-detail', + templateUrl: './hero-detail.component.html', + // #enddocregion metadata, v2 + styleUrls: [ './hero-detail.component.css' ] + // #docregion metadata, v2 +}) +// #enddocregion metadata +// #docregion implement +export class HeroDetailComponent implements OnInit { +// #enddocregion implement + hero: Hero; + + // #docregion ctor + constructor( + private heroService: HeroService, + private route: ActivatedRoute, + private location: Location + ) {} + // #enddocregion ctor + + // #docregion ngOnInit + ngOnInit(): void { + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); + } + // #enddocregion ngOnInit + + // #docregion goBack + goBack(): void { + this.location.back(); + } +// #enddocregion goBack +} diff --git a/public/docs/_examples/toh-5/ts/src/app/hero.service.ts b/public/docs/_examples/toh-5/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..ee5a684762 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/hero.service.ts @@ -0,0 +1,26 @@ +// #docplaster +// #docregion +import { Hero } from './hero'; +import { HEROES } from './mock-heroes'; +import { Injectable } from '@angular/core'; + +@Injectable() +export class HeroService { + getHeroes(): Promise { + return Promise.resolve(HEROES); + } + + getHeroesSlowly(): Promise { + return new Promise(resolve => { + // Simulate server latency with 2 second delay + setTimeout(() => resolve(this.getHeroes()), 2000); + }); + } + + // #docregion getHero + getHero(id: number): Promise { + return this.getHeroes() + .then(heroes => heroes.find(hero => hero.id === id)); + } + // #enddocregion getHero +} diff --git a/public/docs/_examples/toh-5/ts/src/app/hero.ts b/public/docs/_examples/toh-5/ts/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/toh-5/ts/src/app/heroes.component.css b/public/docs/_examples/toh-5/ts/src/app/heroes.component.css new file mode 100644 index 0000000000..b49fa0a419 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/heroes.component.css @@ -0,0 +1,60 @@ +/* #docregion */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} diff --git a/public/docs/_examples/toh-5/ts/src/app/heroes.component.html b/public/docs/_examples/toh-5/ts/src/app/heroes.component.html new file mode 100644 index 0000000000..db41c4692e --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/heroes.component.html @@ -0,0 +1,19 @@ + + +

    My Heroes

    +
      +
    • + {{hero.id}} {{hero.name}} +
    • +
    + +
    +

    + + {{selectedHero.name | uppercase}} is my hero + +

    + +
    diff --git a/public/docs/_examples/toh-5/ts/src/app/heroes.component.ts b/public/docs/_examples/toh-5/ts/src/app/heroes.component.ts new file mode 100644 index 0000000000..def615e6b9 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/heroes.component.ts @@ -0,0 +1,46 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +// #docregion renaming, metadata +@Component({ + selector: 'my-heroes', + // #enddocregion renaming + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] + // #docregion renaming +}) +// #enddocregion metadata +// #docregion class +export class HeroesComponent implements OnInit { + // #enddocregion renaming + heroes: Hero[]; + selectedHero: Hero; + + constructor( + private router: Router, + private heroService: HeroService) { } + + getHeroes(): void { + this.heroService.getHeroes().then(heroes => this.heroes = heroes); + } + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + // #docregion gotoDetail + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } + // #enddocregion gotoDetail + // #docregion renaming +} diff --git a/public/docs/_examples/toh-5/ts/src/app/mock-heroes.ts b/public/docs/_examples/toh-5/ts/src/app/mock-heroes.ts new file mode 100644 index 0000000000..69afde3d34 --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/app/mock-heroes.ts @@ -0,0 +1,15 @@ +// #docregion +import { Hero } from './hero'; + +export var HEROES: Hero[] = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} +]; diff --git a/public/docs/_examples/toh-5/ts/src/index.html b/public/docs/_examples/toh-5/ts/src/index.html new file mode 100644 index 0000000000..cbacc9b83b --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/index.html @@ -0,0 +1,33 @@ + + + + + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-5/ts/src/main.ts b/public/docs/_examples/toh-5/ts/src/main.ts new file mode 100644 index 0000000000..505f60b35b --- /dev/null +++ b/public/docs/_examples/toh-5/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +// main entry point +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/toh-5/ts/styles.1.css b/public/docs/_examples/toh-5/ts/styles.1.css deleted file mode 100644 index 5b77b74d1c..0000000000 --- a/public/docs/_examples/toh-5/ts/styles.1.css +++ /dev/null @@ -1,34 +0,0 @@ -/* #docregion */ -h2 { - color: #444; - font-family: Arial, Helvetica, sans-serif; - font-weight: lighter; -} -body { - margin: 2em; -} -body, input[text], button { - color: #888; - font-family: Cambria, Georgia; -} -button { - font-family: Arial; - background-color: #eee; - border: none; - padding: 5px 10px; - border-radius: 4px; - cursor: pointer; - cursor: hand; -} -button:hover { - background-color: #cfd8dc; -} -button:disabled { - background-color: #eee; - color: #aaa; - cursor: auto; -} -/* everywhere else */ -* { - font-family: Arial, Helvetica, sans-serif; -} diff --git a/public/docs/_examples/toh-6/e2e-spec.ts b/public/docs/_examples/toh-6/e2e-spec.ts new file mode 100644 index 0000000000..80d9660263 --- /dev/null +++ b/public/docs/_examples/toh-6/e2e-spec.ts @@ -0,0 +1,283 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder, ElementArrayFinder } from 'protractor'; +import { promise } from 'selenium-webdriver'; + +const expectedH1 = 'Tour of Heroes'; +const expectedTitle = `Angular ${expectedH1}`; +const targetHero = { id: 15, name: 'Magneta' }; +const targetHeroDashboardIndex = 3; +const nameSuffix = 'X'; +const newHeroName = targetHero.name + nameSuffix; + +class Hero { + id: number; + name: string; + + // Factory methods + + // Hero from string formatted as ' '. + static fromString(s: string): Hero { + return { + id: +s.substr(0, s.indexOf(' ')), + name: s.substr(s.indexOf(' ') + 1), + }; + } + + // Hero from hero list
  • element. + static async fromLi(li: ElementFinder): Promise { + let strings = await li.all(by.xpath('span')).getText(); + return { id: +strings[0], name: strings[1] }; + } + + // Hero id and name from the given detail element. + static async fromDetail(detail: ElementFinder): Promise { + // Get hero id from the first
    + let _id = await detail.all(by.css('div')).first().getText(); + // Get name from the h2 + let _name = await detail.element(by.css('h2')).getText(); + return { + id: +_id.substr(_id.indexOf(' ') + 1), + name: _name.substr(0, _name.lastIndexOf(' ')) + }; + } +} + +describe('Tutorial part 6', () => { + + beforeAll(() => browser.get('')); + + function getPageElts() { + let navElts = element.all(by.css('my-app nav a')); + + return { + navElts: navElts, + + myDashboardHref: navElts.get(0), + myDashboard: element(by.css('my-app my-dashboard')), + topHeroes: element.all(by.css('my-app my-dashboard > div h4')), + + myHeroesHref: navElts.get(1), + myHeroes: element(by.css('my-app my-heroes')), + allHeroes: element.all(by.css('my-app my-heroes li')), + selectedHero: element(by.css('my-app li.selected')), + selectedHeroSubview: element(by.css('my-app my-heroes > div:last-child')), + + heroDetail: element(by.css('my-app hero-detail > div')), + + searchBox: element(by.css('#search-box')), + searchResults: element.all(by.css('.search-result')) + }; + } + + describe('Initial page', () => { + + it(`has title '${expectedTitle}'`, () => { + expect(browser.getTitle()).toEqual(expectedTitle); + }); + + it(`has h1 '${expectedH1}'`, () => { + expectHeading(1, expectedH1); + }); + + const expectedViewNames = ['Dashboard', 'Heroes']; + it(`has views ${expectedViewNames}`, () => { + let viewNames = getPageElts().navElts.map((el: ElementFinder) => el.getText()); + expect(viewNames).toEqual(expectedViewNames); + }); + + it('has dashboard as the active view', () => { + let page = getPageElts(); + expect(page.myDashboard.isPresent()).toBeTruthy(); + }); + + }); + + describe('Dashboard tests', () => { + + beforeAll(() => browser.get('')); + + it('has top heroes', () => { + let page = getPageElts(); + expect(page.topHeroes.count()).toEqual(4); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`cancels and shows ${targetHero.name} in Dashboard`, () => { + element(by.buttonText('Back')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + }); + + it(`selects and routes to ${targetHero.name} details`, dashboardSelectTargetHero); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`saves and shows ${newHeroName} in Dashboard`, () => { + element(by.buttonText('Save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(newHeroName); + }); + + }); + + describe('Heroes tests', () => { + + beforeAll(() => browser.get('')); + + it('can switch to Heroes view', () => { + getPageElts().myHeroesHref.click(); + let page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(10, 'number of heroes'); + }); + + it(`selects and shows ${targetHero.name} as selected in list`, () => { + getHeroLiEltById(targetHero.id).click(); + expect(Hero.fromLi(getPageElts().selectedHero)).toEqual(targetHero); + }); + + it('shows selected hero subview', () => { + let page = getPageElts(); + let title = page.selectedHeroSubview.element(by.css('h2')).getText(); + let expectedTitle = `${targetHero.name.toUpperCase()} is my hero`; + expect(title).toEqual(expectedTitle); + }); + + it('can route to hero details', () => { + element(by.buttonText('View Details')).click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = Hero.fromDetail(page.heroDetail); + expect(hero).toEqual(targetHero); + }); + + it(`updates hero name (${newHeroName}) in details view`, updateHeroNameInDetailView); + + it(`shows ${newHeroName} in Heroes list`, () => { + element(by.buttonText('Save')).click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + let expectedHero = {id: targetHero.id, name: newHeroName}; + expect(Hero.fromLi(getHeroLiEltById(targetHero.id))).toEqual(expectedHero); + }); + + it(`deletes ${newHeroName} from Heroes list`, async () => { + const heroesBefore = await toHeroArray(getPageElts().allHeroes); + const li = getHeroLiEltById(targetHero.id); + li.element(by.buttonText('x')).click(); + + const page = getPageElts(); + expect(page.myHeroes.isPresent()).toBeTruthy(); + expect(page.allHeroes.count()).toEqual(9, 'number of heroes'); + const heroesAfter = await toHeroArray(page.allHeroes); + const expectedHeroes = heroesBefore.filter(h => h.name !== newHeroName); + expect(heroesAfter).toEqual(expectedHeroes); + expect(page.selectedHeroSubview.isPresent()).toBeFalsy(); + }); + + it(`adds back ${targetHero.name}`, async () => { + const newHeroName = 'Alice'; + const heroesBefore = await toHeroArray(getPageElts().allHeroes); + const numHeroes = heroesBefore.length; + + element(by.css('input')).sendKeys(newHeroName); + element(by.buttonText('Add')).click(); + + let page = getPageElts(); + let heroesAfter = await toHeroArray(page.allHeroes); + expect(heroesAfter.length).toEqual(numHeroes + 1, 'number of heroes'); + + expect(heroesAfter.slice(0, numHeroes)).toEqual(heroesBefore, 'Old heroes are still there'); + + const maxId = heroesBefore[heroesBefore.length - 1].id; + expect(heroesAfter[numHeroes]).toEqual({id: maxId + 1, name: newHeroName}); + }); + }); + + describe('Progressive hero search', () => { + + beforeAll(() => browser.get('')); + + it(`searches for 'Ma'`, async () => { + getPageElts().searchBox.sendKeys('Ma'); + browser.sleep(1000); + expect(getPageElts().searchResults.count()).toBe(4); + }); + + it(`continues search with 'g'`, async () => { + getPageElts().searchBox.sendKeys('g'); + browser.sleep(1000); + expect(getPageElts().searchResults.count()).toBe(2); + }); + + it(`continues search with 'n' and gets ${targetHero.name}`, async () => { + getPageElts().searchBox.sendKeys('n'); + browser.sleep(1000); + let page = getPageElts(); + expect(page.searchResults.count()).toBe(1); + let hero = page.searchResults.get(0); + expect(hero.getText()).toEqual(targetHero.name); + }); + + it(`navigates to ${targetHero.name} details view`, async () => { + let hero = getPageElts().searchResults.get(0); + expect(hero.getText()).toEqual(targetHero.name); + hero.click(); + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + expect(Hero.fromDetail(page.heroDetail)).toEqual(targetHero); + }); + }); + + function dashboardSelectTargetHero() { + let targetHeroElt = getPageElts().topHeroes.get(targetHeroDashboardIndex); + expect(targetHeroElt.getText()).toEqual(targetHero.name); + targetHeroElt.click(); + browser.waitForAngular(); // seems necessary to gets tests to past for toh-6 + + let page = getPageElts(); + expect(page.heroDetail.isPresent()).toBeTruthy('shows hero detail'); + let hero = Hero.fromDetail(page.heroDetail); + expect(hero).toEqual(targetHero); + } + + async function updateHeroNameInDetailView() { + // Assumes that the current view is the hero details view. + addToHeroName(nameSuffix); + + let hero = await Hero.fromDetail(getPageElts().heroDetail); + expect(hero).toEqual({id: targetHero.id, name: newHeroName}); + } + +}); + +function addToHeroName(text: string): promise.Promise { + let input = element(by.css('input')); + return input.sendKeys(text); +} + +function expectHeading(hLevel: number, expectedText: string): void { + let hTag = `h${hLevel}`; + let hText = element(by.css(hTag)).getText(); + expect(hText).toEqual(expectedText, hTag); +}; + +function getHeroLiEltById(id: number): ElementFinder { + let spanForId = element(by.cssContainingText('li span.badge', id.toString())); + return spanForId.element(by.xpath('..')); +} + +async function toHeroArray(allHeroes: ElementArrayFinder): Promise { + let promisedHeroes = await allHeroes.map(Hero.fromLi); + // The cast is necessary to get around issuing with the signature of Promise.all() + return > Promise.all(promisedHeroes); +} diff --git a/public/docs/_examples/toh-6/ts/.gitignore b/public/docs/_examples/toh-6/ts/.gitignore new file mode 100644 index 0000000000..804879d44a --- /dev/null +++ b/public/docs/_examples/toh-6/ts/.gitignore @@ -0,0 +1,8 @@ +aot/**/*.ts +**/*.ngfactory.ts +**/*.ngsummary.json +**/*.metadata.json +**/*.js +dist +!app/tsconfig.json +!rollup-config.js diff --git a/public/docs/_examples/toh-6/ts/aot/index.html b/public/docs/_examples/toh-6/ts/aot/index.html new file mode 100644 index 0000000000..cb8ecc4461 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/aot/index.html @@ -0,0 +1,19 @@ + + + + + + Angular Tour of Heroes + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/toh-6/ts/aot/styles.css b/public/docs/_examples/toh-6/ts/aot/styles.css new file mode 100644 index 0000000000..d81835d0cd --- /dev/null +++ b/public/docs/_examples/toh-6/ts/aot/styles.css @@ -0,0 +1,116 @@ +/* #docregion , quickstart, toh */ +/* Master Styles */ +h1 { + color: #369; + font-family: Arial, Helvetica, sans-serif; + font-size: 250%; +} +h2, h3 { + color: #444; + font-family: Arial, Helvetica, sans-serif; + font-weight: lighter; +} +body { + margin: 2em; +} +/* #enddocregion quickstart */ +body, input[text], button { + color: #888; + font-family: Cambria, Georgia; +} +/* #enddocregion toh */ +a { + cursor: pointer; + cursor: hand; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #aaa; + cursor: auto; +} + +/* Navigation link styles */ +nav a { + padding: 5px 10px; + text-decoration: none; + margin-right: 10px; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} + +/* items class */ +.items { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 24em; +} +.items li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.items li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.items li.selected { + background-color: #CFD8DC; + color: white; +} +.items li.selected:hover { + background-color: #BBD8DC; +} +.items .text { + position: relative; + top: -3px; +} +.items .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +/* #docregion toh */ +/* everywhere else */ +* { + font-family: Arial, Helvetica, sans-serif; +} diff --git a/public/docs/_examples/toh-6/ts/bs-config.aot.json b/public/docs/_examples/toh-6/ts/bs-config.aot.json new file mode 100644 index 0000000000..e59a7403a0 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/bs-config.aot.json @@ -0,0 +1,14 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": { + "0": null + } + } +} diff --git a/public/docs/_examples/toh-6/ts/copy-dist-files.js b/public/docs/_examples/toh-6/ts/copy-dist-files.js new file mode 100644 index 0000000000..080864e99c --- /dev/null +++ b/public/docs/_examples/toh-6/ts/copy-dist-files.js @@ -0,0 +1,12 @@ +// #docregion +var fs = require('fs'); +var resources = [ + 'node_modules/core-js/client/shim.min.js', + 'node_modules/zone.js/dist/zone.min.js', + 'src/styles.css' +]; +resources.map(function(f) { + var path = f.split('/'); + var t = 'aot/' + path[path.length-1]; + fs.createReadStream(f).pipe(fs.createWriteStream(t)); +}); diff --git a/public/docs/_examples/toh-6/ts/example-config.json b/public/docs/_examples/toh-6/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/toh-6/ts/plnkr.json b/public/docs/_examples/toh-6/ts/plnkr.json new file mode 100644 index 0000000000..d355bc9ff2 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "Tour of Heroes: Part 6", + "basePath": "src/", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*" + ], + "tags": ["tutorial", "tour", "heroes", "http"] +} diff --git a/public/docs/_examples/toh-6/ts/rollup-config.js b/public/docs/_examples/toh-6/ts/rollup-config.js new file mode 100644 index 0000000000..5689edcff4 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/rollup-config.js @@ -0,0 +1,30 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +//paths are relative to the execution path +export default { + entry: 'src/main-aot.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + onwarn: function(warning) { + // Skip certain warnings + + // should intercept ... but doesn't in some rollup versions + if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } + + // console.warn everything else + console.warn( warning.message ); + }, + plugins: [ + nodeResolve({jsnext: true, module: true}), + commonjs({ + include: ['node_modules/rxjs/**'] + }), + uglify() + ] +} diff --git a/public/docs/_examples/toh-6/ts/src/app/app-routing.module.ts b/public/docs/_examples/toh-6/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..bc070f6c31 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/app-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'detail/:id', component: HeroDetailComponent }, + { path: 'heroes', component: HeroesComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/toh-6/ts/src/app/app.component.css b/public/docs/_examples/toh-6/ts/src/app/app.component.css new file mode 100644 index 0000000000..071e665767 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/app.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +h1 { + font-size: 1.2em; + color: #999; + margin-bottom: 0; +} +h2 { + font-size: 2em; + margin-top: 0; + padding-top: 0; +} +nav a { + padding: 5px 10px; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} diff --git a/public/docs/_examples/toh-6/ts/src/app/app.component.ts b/public/docs/_examples/toh-6/ts/src/app/app.component.ts new file mode 100644 index 0000000000..a9fe05a9a8 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + + `, + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'Tour of Heroes'; +} diff --git a/public/docs/_examples/toh-6/ts/src/app/app.module.ts b/public/docs/_examples/toh-6/ts/src/app/app.module.ts new file mode 100644 index 0000000000..58eeb10c54 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/app.module.ts @@ -0,0 +1,52 @@ +// #docplaster +// #docregion +// #docregion v1, v2 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; + +// #enddocregion v1 +// Imports for loading & configuring the in-memory web api +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +import { InMemoryDataService } from './in-memory-data.service'; + +// #docregion v1 +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroService } from './hero.service'; +// #enddocregion v1, v2 +import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + // #enddocregion v1 + // #docregion in-mem-web-api + InMemoryWebApiModule.forRoot(InMemoryDataService), + // #enddocregion in-mem-web-api + // #docregion v1 + AppRoutingModule + ], + // #docregion search + declarations: [ + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent, + // #enddocregion v1, v2 + HeroSearchComponent + // #docregion v1, v2 + ], + // #enddocregion search + providers: [ HeroService ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/toh-6/ts/src/app/dashboard.component.css b/public/docs/_examples/toh-6/ts/src/app/dashboard.component.css new file mode 100644 index 0000000000..dc7fb7ce06 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/dashboard.component.css @@ -0,0 +1,62 @@ +/* #docregion */ +[class*='col-'] { + float: left; + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +a { + text-decoration: none; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +h4 { + position: relative; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.module { + padding: 20px; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} +.module:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 600px) { + .module { + font-size: 10px; + max-height: 75px; } +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } + .module { + min-width: 60px; + } +} diff --git a/public/docs/_examples/toh-6/ts/src/app/dashboard.component.html b/public/docs/_examples/toh-6/ts/src/app/dashboard.component.html new file mode 100644 index 0000000000..db8546ccd2 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/dashboard.component.html @@ -0,0 +1,10 @@ + +

    Top Heroes

    + + diff --git a/public/docs/_examples/toh-6/ts/src/app/dashboard.component.ts b/public/docs/_examples/toh-6/ts/src/app/dashboard.component.ts new file mode 100644 index 0000000000..9960aa77d4 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/dashboard.component.ts @@ -0,0 +1,22 @@ +// #docregion , search +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +// #enddocregion search +export class DashboardComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) { } + + ngOnInit(): void { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes.slice(1, 5)); + } +} diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.css b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.css new file mode 100644 index 0000000000..ab2437efd8 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.css @@ -0,0 +1,30 @@ +/* #docregion */ +label { + display: inline-block; + width: 3em; + margin: .5em 0; + color: #607D8B; + font-weight: bold; +} +input { + height: 2em; + font-size: 1em; + padding-left: .4em; +} +button { + margin-top: 20px; + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #ccc; + cursor: auto; +} diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.html b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..32fe6d4391 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.html @@ -0,0 +1,14 @@ + +
    +

    {{hero.name}} details!

    +
    + {{hero.id}}
    +
    + + +
    + + + + +
    diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..6224f10ac1 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-detail.component.ts @@ -0,0 +1,40 @@ +// #docregion +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + constructor( + private heroService: HeroService, + private route: ActivatedRoute, + private location: Location + ) {} + + ngOnInit(): void { + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); + } + + // #docregion save + save(): void { + this.heroService.update(this.hero) + .then(() => this.goBack()); + } + // #enddocregion save + + goBack(): void { + this.location.back(); + } +} diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-search.component.css b/public/docs/_examples/toh-6/ts/src/app/hero-search.component.css new file mode 100644 index 0000000000..9bf8d13457 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-search.component.css @@ -0,0 +1,21 @@ +/* #docregion */ +.search-result{ + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width:195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; +} + +.search-result:hover { + color: #eee; + background-color: #607D8B; +} + +#search-box{ + width: 200px; + height: 20px; +} diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-search.component.html b/public/docs/_examples/toh-6/ts/src/app/hero-search.component.html new file mode 100644 index 0000000000..08c0560c5b --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-search.component.html @@ -0,0 +1,11 @@ + +
    +

    Hero Search

    + +
    +
    + {{hero.name}} +
    +
    +
    diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-search.component.ts b/public/docs/_examples/toh-6/ts/src/app/hero-search.component.ts new file mode 100644 index 0000000000..8b2d32f06b --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-search.component.ts @@ -0,0 +1,69 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; + +// Observable class extensions +import 'rxjs/add/observable/of'; + +// Observable operators +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/distinctUntilChanged'; +// #enddocregion rxjs-imports + +import { HeroSearchService } from './hero-search.service'; +import { Hero } from './hero'; + +@Component({ + selector: 'hero-search', + templateUrl: './hero-search.component.html', + styleUrls: [ './hero-search.component.css' ], + providers: [HeroSearchService] +}) +export class HeroSearchComponent implements OnInit { + // #docregion search + heroes: Observable; + // #enddocregion search + // #docregion searchTerms + private searchTerms = new Subject(); + // #enddocregion searchTerms + + constructor( + private heroSearchService: HeroSearchService, + private router: Router) {} + // #docregion searchTerms + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + // #enddocregion searchTerms + // #docregion search + + ngOnInit(): void { + this.heroes = this.searchTerms + .debounceTime(300) // wait 300ms after each keystroke before considering the term + .distinctUntilChanged() // ignore if next search term is same as previous + .switchMap(term => term // switch to new observable each time the term changes + // return the http search observable + ? this.heroSearchService.search(term) + // or the observable of empty heroes if there was no search term + : Observable.of([])) + .catch(error => { + // TODO: add real error handling + console.log(error); + return Observable.of([]); + }); + } + // #enddocregion search + + gotoDetail(hero: Hero): void { + let link = ['/detail', hero.id]; + this.router.navigate(link); + } +} diff --git a/public/docs/_examples/toh-6/ts/src/app/hero-search.service.ts b/public/docs/_examples/toh-6/ts/src/app/hero-search.service.ts new file mode 100644 index 0000000000..d24e0fba41 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero-search.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +import { Hero } from './hero'; + +@Injectable() +export class HeroSearchService { + + constructor(private http: Http) {} + + search(term: string): Observable { + return this.http + .get(`app/heroes/?name=${term}`) + .map(response => response.json().data as Hero[]); + } +} diff --git a/public/docs/_examples/toh-6/ts/src/app/hero.service.ts b/public/docs/_examples/toh-6/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..29fe5c2e0e --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero.service.ts @@ -0,0 +1,87 @@ +// #docplaster +// #docregion , imports +import { Injectable } from '@angular/core'; +import { Headers, Http } from '@angular/http'; + +// #docregion rxjs +import 'rxjs/add/operator/toPromise'; +// #enddocregion rxjs + +import { Hero } from './hero'; +// #enddocregion imports + +@Injectable() +export class HeroService { + + // #docregion update + private headers = new Headers({'Content-Type': 'application/json'}); + // #enddocregion update + // #docregion getHeroes + private heroesUrl = 'api/heroes'; // URL to web api + + constructor(private http: Http) { } + + getHeroes(): Promise { + return this.http.get(this.heroesUrl) + // #docregion to-promise + .toPromise() + // #enddocregion to-promise + // #docregion to-data + .then(response => response.json().data as Hero[]) + // #enddocregion to-data + // #docregion catch + .catch(this.handleError); + // #enddocregion catch + } + + // #enddocregion getHeroes + + // #docregion getHero + getHero(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.get(url) + .toPromise() + .then(response => response.json().data as Hero) + .catch(this.handleError); + } + // #enddocregion getHero + + // #docregion delete + delete(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.delete(url, {headers: this.headers}) + .toPromise() + .then(() => null) + .catch(this.handleError); + } + // #enddocregion delete + + // #docregion create + create(name: string): Promise { + return this.http + .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers}) + .toPromise() + .then(res => res.json().data as Hero) + .catch(this.handleError); + } + // #enddocregion create + // #docregion update + + update(hero: Hero): Promise { + const url = `${this.heroesUrl}/${hero.id}`; + return this.http + .put(url, JSON.stringify(hero), {headers: this.headers}) + .toPromise() + .then(() => hero) + .catch(this.handleError); + } + // #enddocregion update + + // #docregion getHeroes, handleError + private handleError(error: any): Promise { + console.error('An error occurred', error); // for demo purposes only + return Promise.reject(error.message || error); + } + // #enddocregion getHeroes, handleError +} + diff --git a/public/docs/_examples/toh-6/ts/src/app/hero.ts b/public/docs/_examples/toh-6/ts/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/toh-6/ts/src/app/heroes.component.css b/public/docs/_examples/toh-6/ts/src/app/heroes.component.css new file mode 100644 index 0000000000..d2c958a911 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/heroes.component.css @@ -0,0 +1,68 @@ +/* #docregion */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +/* #docregion additions */ +button.delete { + float:right; + margin-top: 2px; + margin-right: .8em; + background-color: gray !important; + color:white; +} diff --git a/public/docs/_examples/toh-6/ts/src/app/heroes.component.html b/public/docs/_examples/toh-6/ts/src/app/heroes.component.html new file mode 100644 index 0000000000..392d241d52 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/heroes.component.html @@ -0,0 +1,29 @@ + +

    My Heroes

    + +
    + + +
    + +
      + +
    • + {{hero.id}} + {{hero.name}} + + + +
    • + +
    +
    +

    + {{selectedHero.name | uppercase}} is my hero +

    + +
    diff --git a/public/docs/_examples/toh-6/ts/src/app/heroes.component.ts b/public/docs/_examples/toh-6/ts/src/app/heroes.component.ts new file mode 100644 index 0000000000..6350b803c4 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/heroes.component.ts @@ -0,0 +1,61 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + heroes: Hero[]; + selectedHero: Hero; + + constructor( + private heroService: HeroService, + private router: Router) { } + + getHeroes(): void { + this.heroService + .getHeroes() + .then(heroes => this.heroes = heroes); + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + this.heroService.create(name) + .then(hero => { + this.heroes.push(hero); + this.selectedHero = null; + }); + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + this.heroService + .delete(hero.id) + .then(() => { + this.heroes = this.heroes.filter(h => h !== hero); + if (this.selectedHero === hero) { this.selectedHero = null; } + }); + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/toh-6/ts/src/app/in-memory-data.service.ts b/public/docs/_examples/toh-6/ts/src/app/in-memory-data.service.ts new file mode 100644 index 0000000000..c915955e22 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/app/in-memory-data.service.ts @@ -0,0 +1,19 @@ +// #docregion , init +import { InMemoryDbService } from 'angular-in-memory-web-api'; +export class InMemoryDataService implements InMemoryDbService { + createDb() { + let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/toh-6/ts/src/index.html b/public/docs/_examples/toh-6/ts/src/index.html new file mode 100644 index 0000000000..18977969bb --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + + Angular Tour of Heroes + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-6/ts/src/main-aot.ts b/public/docs/_examples/toh-6/ts/src/main-aot.ts new file mode 100644 index 0000000000..bd2ca604a3 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/main-aot.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; + +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/public/docs/_examples/toh-6/ts/src/main.ts b/public/docs/_examples/toh-6/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/toh-6/ts/src/tsconfig.1.json b/public/docs/_examples/toh-6/ts/src/tsconfig.1.json new file mode 100644 index 0000000000..fb3d43db90 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/src/tsconfig.1.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + } +} \ No newline at end of file diff --git a/public/docs/_examples/toh-6/ts/tsconfig-aot.json b/public/docs/_examples/toh-6/ts/tsconfig-aot.json new file mode 100644 index 0000000000..fe1e6df520 --- /dev/null +++ b/public/docs/_examples/toh-6/ts/tsconfig-aot.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "src/app/app.module.ts", + "src/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/tsconfig.json b/public/docs/_examples/tsconfig.json index 6ee6719cb3..51ea56dc7f 100644 --- a/public/docs/_examples/tsconfig.json +++ b/public/docs/_examples/tsconfig.json @@ -1,18 +1,24 @@ +// this tsconfig is used for protractor tests +// see _boilerplate/tsconfig.json for the tsconfig used in examples { "compilerOptions": { - "target": "es5", - "module": "system", + "target": "es6", + "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "removeComments": false, + "lib": ["es2015", "dom"], "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types" + ] }, - "exclude": [ - "node_modules", - "typings/main", - "typings/main.d.ts" + "files": [ + "protractor-helpers.ts" + ], + "include": [ + "*/e2e-spec.ts" ] } diff --git a/public/docs/_examples/tutorial/e2e-spec.js b/public/docs/_examples/tutorial/e2e-spec.js deleted file mode 100644 index f35fcd1287..0000000000 --- a/public/docs/_examples/tutorial/e2e-spec.js +++ /dev/null @@ -1,111 +0,0 @@ -describe('Tutorial', function () { - - beforeAll(function () { - browser.get(''); - }); - - - function getPageStruct() { - hrefEles = element.all(by.css('my-app a')); - - return { - hrefs: hrefEles, - myDashboardHref: hrefEles.get(0), - myDashboardParent: element(by.css('my-app my-dashboard')), - topHeroes: element.all(by.css('my-app my-dashboard .module.hero')), - - myHeroesHref: hrefEles.get(1), - myHeroesParent: element(by.css('my-app my-heroes')), - allHeroes: element.all(by.css('my-app my-heroes li')), - - heroDetail: element(by.css('my-app my-hero-detail')) - } - } - - it('should be able to see the start screen', function () { - var page = getPageStruct(); - expect(page.hrefs.count()).toEqual(2, 'should be two dashboard choices'); - expect(page.myDashboardHref.getText()).toEqual("Dashboard"); - expect(page.myHeroesHref.getText()).toEqual("Heroes"); - }); - - it('should be able to see dashboard choices', function () { - var page = getPageStruct(); - expect(page.topHeroes.count()).toBe(4, "should be 4 dashboard hero choices"); - }); - - it('should be able to toggle the views', function () { - var page = getPageStruct(); - - expect(page.myDashboardParent.element(by.css('h3')).getText()).toEqual('Top Heroes'); - page.myHeroesHref.click().then(function() { - expect(page.myDashboardParent.isPresent()).toBe(false, 'should no longer see dashboard element'); - expect(page.allHeroes.count()).toBeGreaterThan(4, "should be more than 4 heroes shown"); - return page.myDashboardHref.click(); - }).then(function() { - expect(page.myDashboardParent.isPresent()).toBe(true, 'should once again see the dashboard element'); - }); - - }); - - it('should be able to edit details from "Dashboard" view', function () { - var page = getPageStruct(); - expect(page.myDashboardParent.isPresent()).toBe(true, 'dashboard element should be available'); - var heroEle = page.topHeroes.get(3); - var heroDescrEle = heroEle.element(by.css('h4')); - var heroDescr; - return heroDescrEle.getText().then(function(text) { - heroDescr = text; - return heroEle.click(); - }).then(function() { - return editDetails(page, heroDescr, '-foo'); - }).then(function() { - expect(page.myDashboardParent.isPresent()).toBe(true, 'dashboard element should be back'); - expect(heroDescrEle.getText()).toEqual(heroDescr + '-foo'); - }); - }); - - it('should be able to edit details from "Heroes" view', function () { - var page = getPageStruct(); - expect(page.myDashboardParent.isPresent()).toBe(true, 'dashboard element should be present'); - var viewDetailsButtonEle = page.myHeroesParent.element(by.cssContainingText('button', 'View Details')); - var heroEle, heroDescr; - page.myHeroesHref.click().then(function() { - expect(page.myDashboardParent.isPresent()).toBe(false, 'dashboard element should NOT be present'); - expect(page.myHeroesParent.isPresent()).toBe(true, 'myHeroes element should be present'); - expect(viewDetailsButtonEle.isPresent()).toBe(false, 'viewDetails button should not yet be present'); - heroEle = page.allHeroes.get(2); - return heroEle.getText(); - }).then(function(text) { - // remove leading 'id' from the element - heroDescr = text.substr(text.indexOf(' ')+1); - return heroEle.click(); - }).then(function() { - expect(viewDetailsButtonEle.isDisplayed()).toBe(true, 'viewDetails button should now be visible'); - return viewDetailsButtonEle.click(); - }).then(function() { - return editDetails(page, heroDescr, '-bar'); - }).then(function() { - expect(page.myHeroesParent.isPresent()).toBe(true, 'myHeroes element should be back'); - expect(heroEle.getText()).toContain(heroDescr + '-bar'); - expect(viewDetailsButtonEle.isPresent()).toBe(false, 'viewDetails button should again NOT be present'); - }); - }); - - function editDetails(page, origValue, textToAdd) { - expect(page.myDashboardParent.isPresent()).toBe(false, 'dashboard element should NOT be present'); - expect(page.myHeroesParent.isPresent()).toBe(false, 'myHeroes element should NOT be present'); - expect(page.heroDetail.isDisplayed()).toBe(true, 'should be able to see hero-details'); - var inputEle = page.heroDetail.element(by.css('input')); - expect(inputEle.isDisplayed()).toBe(true, 'should be able to see the input box'); - var backButtonEle = page.heroDetail.element(by.css('button')); - expect(backButtonEle.isDisplayed()).toBe(true, 'should be able to see the back button'); - var detailTextEle = page.heroDetail.element(by.css('div h2')); - expect(detailTextEle.getText()).toContain(origValue); - return sendKeys(inputEle, textToAdd).then(function () { - expect(detailTextEle.getText()).toContain(origValue + textToAdd); - return backButtonEle.click(); - }); - } - -}); diff --git a/public/docs/_examples/tutorial/ts/.gitignore b/public/docs/_examples/tutorial/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/tutorial/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/tutorial/ts/app/app.component.css b/public/docs/_examples/tutorial/ts/app/app.component.css deleted file mode 100644 index 246b8c875b..0000000000 --- a/public/docs/_examples/tutorial/ts/app/app.component.css +++ /dev/null @@ -1,28 +0,0 @@ -nav a { - padding: 5px 10px; - text-decoration: none; - margin-top: 10px; - display: inline-block; - background-color: #eee; - border-radius: 4px; -} -nav a:visited, a:link { - color: #607D8B; -} -nav a:hover { - color: #039be5; - background-color: #CFD8DC; -} -nav a.router-link-active { - color: #039be5; -} -h1 { - font-size: 1.2em; - color: #999; - margin-bottom: 0; -} -h2 { - font-size: 2em; - margin-top: 0; - padding-top: 0; -} \ No newline at end of file diff --git a/public/docs/_examples/tutorial/ts/app/app.component.ts b/public/docs/_examples/tutorial/ts/app/app.component.ts deleted file mode 100644 index 1cea6e8f9c..0000000000 --- a/public/docs/_examples/tutorial/ts/app/app.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; -import {HeroesComponent} from './heroes.component'; -import {HeroDetailComponent} from './hero-detail.component'; -import {DashboardComponent} from './dashboard.component'; -import {HeroService} from './hero.service'; - -@Component({ - selector: 'my-app', - template: ` -

    {{title}}

    - - - `, - styleUrls: ['app/app.component.css'], - directives: [ROUTER_DIRECTIVES], - providers: [HeroService] -}) -@RouteConfig([ - // {path: '/', redirectTo: ['Dashboard'] }, - {path: '/dashboard', name: 'Dashboard', component: DashboardComponent, useAsDefault: true}, - {path: '/heroes', name: 'Heroes', component: HeroesComponent}, - {path: '/detail/:id', name: 'HeroDetail', component: HeroDetailComponent} -]) -export class AppComponent { - public title = 'Tour of Heroes'; -} diff --git a/public/docs/_examples/tutorial/ts/app/dashboard.component.css b/public/docs/_examples/tutorial/ts/app/dashboard.component.css deleted file mode 100644 index d000c0c77e..0000000000 --- a/public/docs/_examples/tutorial/ts/app/dashboard.component.css +++ /dev/null @@ -1,60 +0,0 @@ -[class*='col-'] { - float: left; -} -*, *:after, *:before { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -h3 { - text-align: center; margin-bottom: 0; -} -[class*='col-'] { - padding-right: 20px; - padding-bottom: 20px; -} -[class*='col-']:last-of-type { - padding-right: 0; -} -.grid { - margin: 0; -} -.col-1-4 { - width: 25%; -} -.module { - padding: 20px; - text-align: center; - color: #eee; - max-height: 120px; - min-width: 120px; - background-color: #607D8B; - border-radius: 2px; -} -h4 { - position: relative; -} -.module:hover { - background-color: #EEE; - cursor: pointer; - color: #607d8b; -} -.grid-pad { - padding: 10px 0; -} -.grid-pad > [class*='col-']:last-of-type { - padding-right: 20px; -} -@media (max-width: 600px) { - .module { - font-size: 10px; - max-height: 75px; } -} -@media (max-width: 1024px) { - .grid { - margin: 0; - } - .module { - min-width: 60px; - } -} diff --git a/public/docs/_examples/tutorial/ts/app/dashboard.component.html b/public/docs/_examples/tutorial/ts/app/dashboard.component.html deleted file mode 100644 index f9b9b2f3bb..0000000000 --- a/public/docs/_examples/tutorial/ts/app/dashboard.component.html +++ /dev/null @@ -1,8 +0,0 @@ -

    Top Heroes

    -
    -
    -
    -

    {{hero.name}}

    -
    -
    -
    diff --git a/public/docs/_examples/tutorial/ts/app/dashboard.component.ts b/public/docs/_examples/tutorial/ts/app/dashboard.component.ts deleted file mode 100644 index ae5f048a57..0000000000 --- a/public/docs/_examples/tutorial/ts/app/dashboard.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import {Component, OnInit} from 'angular2/core'; -import {Router} from 'angular2/router'; -import {Hero} from './hero'; -import {HeroService} from './hero.service'; - -@Component({ - selector: 'my-dashboard', - templateUrl: 'app/dashboard.component.html', - styleUrls: ['app/dashboard.component.css'] -}) -export class DashboardComponent implements OnInit { - public heroes: Hero[] = []; - - constructor(private _heroService: HeroService, private _router: Router) { } - - ngOnInit() { - this._heroService.getHeroes().then(heroes => this.heroes = heroes.slice(1,5)); - } - - gotoDetail(hero: Hero) { - let link = ['HeroDetail', { id: hero.id }]; - this._router.navigate(link); - } -} diff --git a/public/docs/_examples/tutorial/ts/app/hero-detail.component.css b/public/docs/_examples/tutorial/ts/app/hero-detail.component.css deleted file mode 100644 index b5ab6e6e0b..0000000000 --- a/public/docs/_examples/tutorial/ts/app/hero-detail.component.css +++ /dev/null @@ -1,29 +0,0 @@ -label { - display: inline-block; - width: 3em; - margin: .5em 0; - color: #607D8B; - font-weight: bold; -} -input { - height: 2em; - font-size: 1em; - padding-left: .4em; -} -button { - margin-top: 20px; - font-family: Arial; - background-color: #eee; - border: none; - padding: 5px 10px; - border-radius: 4px; - cursor: pointer; cursor: hand; -} -button:hover { - background-color: #cfd8dc; -} -button:disabled { - background-color: #eee; - color: #ccc; - cursor: auto; -} diff --git a/public/docs/_examples/tutorial/ts/app/hero-detail.component.html b/public/docs/_examples/tutorial/ts/app/hero-detail.component.html deleted file mode 100644 index af9039dc9f..0000000000 --- a/public/docs/_examples/tutorial/ts/app/hero-detail.component.html +++ /dev/null @@ -1,10 +0,0 @@ -
    -

    {{hero.name}} details!

    -
    - {{hero.id}}
    -
    - - -
    - -
    \ No newline at end of file diff --git a/public/docs/_examples/tutorial/ts/app/hero-detail.component.ts b/public/docs/_examples/tutorial/ts/app/hero-detail.component.ts deleted file mode 100644 index 0014918b8b..0000000000 --- a/public/docs/_examples/tutorial/ts/app/hero-detail.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Component, OnInit} from 'angular2/core'; -import {RouteParams} from 'angular2/router'; - -import {Hero} from './hero'; -import {HeroService} from './hero.service'; - -@Component({ - selector: 'my-hero-detail', - templateUrl: 'app/hero-detail.component.html', - styleUrls: ['app/hero-detail.component.css'], - inputs: ['hero'] -}) -export class HeroDetailComponent implements OnInit { - public hero: Hero; - - constructor(private _heroService: HeroService, - private _routeParams: RouteParams) { - } - - ngOnInit() { - let id = +this._routeParams.get('id'); - this._heroService.getHero(id).then(hero => this.hero = hero); - } - - goBack() { - window.history.back(); - } -} diff --git a/public/docs/_examples/tutorial/ts/app/hero.service.ts b/public/docs/_examples/tutorial/ts/app/hero.service.ts deleted file mode 100644 index c3d6bc0cee..0000000000 --- a/public/docs/_examples/tutorial/ts/app/hero.service.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {Injectable} from 'angular2/core'; -import {HEROES} from './mock-heroes'; - -@Injectable() -export class HeroService { - getHeroes() { - return Promise.resolve(HEROES); - } - - getHero(id: number) { - return Promise.resolve(HEROES).then( - heroes => heroes.filter(hero => hero.id === id)[0] - ); - } -} diff --git a/public/docs/_examples/tutorial/ts/app/hero.ts b/public/docs/_examples/tutorial/ts/app/hero.ts deleted file mode 100644 index 34f6058c2f..0000000000 --- a/public/docs/_examples/tutorial/ts/app/hero.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Hero { - id: number; - name: string; -} diff --git a/public/docs/_examples/tutorial/ts/app/heroes.component.css b/public/docs/_examples/tutorial/ts/app/heroes.component.css deleted file mode 100644 index d939ab565d..0000000000 --- a/public/docs/_examples/tutorial/ts/app/heroes.component.css +++ /dev/null @@ -1,59 +0,0 @@ -.selected { - background-color: #CFD8DC !important; - color: white; -} -.heroes { - margin: 0 0 2em 0; - list-style-type: none; - padding: 0; - width: 10em; -} -.heroes li { - cursor: pointer; - position: relative; - left: 0; - background-color: #EEE; - margin: .5em; - padding: .3em 0; - height: 1.6em; - border-radius: 4px; -} -.heroes li:hover { - color: #607D8B; - background-color: #DDD; - left: .1em; -} -.heroes li.selected:hover { - background-color: #BBD8DC !important; - color: white; -} -.heroes .text { - position: relative; - top: -3px; -} -.heroes .badge { - display: inline-block; - font-size: small; - color: white; - padding: 0.8em 0.7em 0 0.7em; - background-color: #607D8B; - line-height: 1em; - position: relative; - left: -1px; - top: -4px; - height: 1.8em; - margin-right: .8em; - border-radius: 4px 0 0 4px; -} -button { - font-family: Arial; - background-color: #eee; - border: none; - padding: 5px 10px; - border-radius: 4px; - cursor: pointer; - cursor: hand; -} -button:hover { - background-color: #cfd8dc; -} diff --git a/public/docs/_examples/tutorial/ts/app/heroes.component.html b/public/docs/_examples/tutorial/ts/app/heroes.component.html deleted file mode 100644 index c54fdc17aa..0000000000 --- a/public/docs/_examples/tutorial/ts/app/heroes.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
    -

    My Heroes

    -
      -
    • - {{hero.id}} {{hero.name}} -
    • -
    -
    -

    {{selectedHero.name | uppercase}} is my hero

    - -
    -
    diff --git a/public/docs/_examples/tutorial/ts/app/heroes.component.ts b/public/docs/_examples/tutorial/ts/app/heroes.component.ts deleted file mode 100644 index 2783981337..0000000000 --- a/public/docs/_examples/tutorial/ts/app/heroes.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {Component, OnInit} from 'angular2/core'; -import {Router} from 'angular2/router'; -import {HeroService} from './hero.service'; -import {HeroDetailComponent} from './hero-detail.component'; -import {Hero} from './hero'; - -@Component({ - selector: 'my-heroes', - templateUrl: 'app/heroes.component.html', - styleUrls: ['app/heroes.component.css'], - directives: [HeroDetailComponent] -}) -export class HeroesComponent implements OnInit { - public heroes: Hero[]; - public selectedHero: Hero; - - constructor(private _heroService: HeroService, private _router: Router) { } - - getHeroes() { - this._heroService.getHeroes().then(heroes => this.heroes = heroes); - } - - gotoDetail() { - this._router.navigate(['HeroDetail', { id: this.selectedHero.id }]); - } - - ngOnInit() { - this.getHeroes(); - } - - onSelect(hero: Hero) { this.selectedHero = hero; } -} diff --git a/public/docs/_examples/tutorial/ts/app/main.ts b/public/docs/_examples/tutorial/ts/app/main.ts deleted file mode 100644 index c8f833639e..0000000000 --- a/public/docs/_examples/tutorial/ts/app/main.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {ROUTER_PROVIDERS} from 'angular2/router'; -import {HeroService} from './hero.service'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent, [ - ROUTER_PROVIDERS, - HeroService -]); diff --git a/public/docs/_examples/tutorial/ts/app/mock-heroes.ts b/public/docs/_examples/tutorial/ts/app/mock-heroes.ts deleted file mode 100644 index 406e5eb7f8..0000000000 --- a/public/docs/_examples/tutorial/ts/app/mock-heroes.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Hero } from './hero'; - -export var HEROES: Hero[] = [ - {"id": 11, "name": "Mr. Nice"}, - {"id": 12, "name": "Narco"}, - {"id": 13, "name": "Bombasto"}, - {"id": 14, "name": "Celeritas"}, - {"id": 15, "name": "Magneta"}, - {"id": 16, "name": "RubberMan"}, - {"id": 17, "name": "Dynama"}, - {"id": 18, "name": "Dr IQ"}, - {"id": 19, "name": "Magma"}, - {"id": 20, "name": "Tornado"} -]; diff --git a/public/docs/_examples/tutorial/ts/index.html b/public/docs/_examples/tutorial/ts/index.html deleted file mode 100644 index 84795fd309..0000000000 --- a/public/docs/_examples/tutorial/ts/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Angular 2 Tour of Heroes - - - - - - - - - - - - - - - - - - Loading... - - diff --git a/public/docs/_examples/tutorial/ts/plnkr.json b/public/docs/_examples/tutorial/ts/plnkr.json deleted file mode 100644 index fc4ea3e22c..0000000000 --- a/public/docs/_examples/tutorial/ts/plnkr.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "description": "Tour of Heroes", - "files":[ - "!**/*.d.ts", - "!**/*.js" - ], - "tags": ["tutorial", "tour", "heroes"] -} diff --git a/public/docs/_examples/typings.json b/public/docs/_examples/typings.json deleted file mode 100644 index f10b7c5416..0000000000 --- a/public/docs/_examples/typings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ambientDependencies": { - "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#bc92442c075929849ec41d28ab618892ba493504" - } -} diff --git a/public/docs/_examples/universal/ts/.gitignore b/public/docs/_examples/universal/ts/.gitignore new file mode 100644 index 0000000000..62993511f8 --- /dev/null +++ b/public/docs/_examples/universal/ts/.gitignore @@ -0,0 +1,8 @@ +aot/**/*.ts +**/*.ngfactory.ts +**/*.ngsummary.json +**/*.metadata.json +**/*.js +dist +!app/tsconfig.json +!/*.js diff --git a/public/docs/_examples/universal/ts/bs-config.aot.js b/public/docs/_examples/universal/ts/bs-config.aot.js new file mode 100644 index 0000000000..7bb795b9e2 --- /dev/null +++ b/public/docs/_examples/universal/ts/bs-config.aot.js @@ -0,0 +1,18 @@ +module.exports = { + port: 3100, + server: { + baseDir: "src", + routes: { + "/node_modules": "node_modules" + }, + middleware: { + // overrides the fallback middleware to use index-aot + 1: require('connect-history-api-fallback')({ index: '/index-aot.html' }) + } + } + // ,"snippetOptions": { + // "rule": { + // "match": "/dummy/" // disable browsersync by giving it an invalid injection target + // } + // } +}; diff --git a/public/docs/_examples/universal/ts/bs-config.uni.js b/public/docs/_examples/universal/ts/bs-config.uni.js new file mode 100644 index 0000000000..e15de19940 --- /dev/null +++ b/public/docs/_examples/universal/ts/bs-config.uni.js @@ -0,0 +1,41 @@ +module.exports = function(bs) { + + return { + "open": true, + "port": 3200, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": [ + testMiddleware + ] + } + }; + +}; + +function testMiddleware (req, res, next) { + + var routes = []; //['/', '/dashboard', '/heroes']; + var prefixRoutes = ['/detail/', '/styles.css']; + var url = req.originalUrl; + + if (routes.indexOf(url) >= 0 || prefixRoutes.some(function(r) { return url.startsWith(r); })) { + console.log('test handling ' + url); + res.setHeader('Content-Type', 'text/css'); + res.end("this should be css"); + return; + } + + console.log('test skipping ' + url); + // var parsed = require("url").parse(req.url); + // if (parsed.pathname.match(/\.less$/)) { + // return less(parsed.pathname).then(function (o) { + // res.setHeader('Content-Type', 'text/css'); + // res.end(o.css); + // }); + // } + next(); +} diff --git a/public/docs/_examples/universal/ts/example-config.json b/public/docs/_examples/universal/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/universal/ts/package.steve.json b/public/docs/_examples/universal/ts/package.steve.json new file mode 100644 index 0000000000..15ef45e849 --- /dev/null +++ b/public/docs/_examples/universal/ts/package.steve.json @@ -0,0 +1,62 @@ +{ + "name": "toh-universal", + "version": "1.0.0", + "description": "Tour-of-Heroes application with ng-universal server-side rendering", + "scripts": { + "build": "tsc -p src/", + "build:watch": "tsc -w", + "build:aot": "webpack --config webpack.config.aot.js", + "build:uni": "webpack --config webpack.config.uni.js", + + "serve": "lite-server -c=bs-config.json", + "serve:aot": "lite-server -c=bs-config.aot.js", + "serve:uni": "node src/dist/server.js", + "serve:uni2": "lite-server -c bs-config.uni.js", + + "prestart": "npm run build", + "start": "concurrently \"npm run build:watch\" \"npm run serve\"", + + "lint": "tslint ./src/**/*.ts -t verbose", + "ngc": "ngc", + "clean": "rimraf src/dist && rimraf src/app/*.js* && rimraf src/uni/*.js* && rimraf src/main.js*" + }, + "keywords": [], + "author": "", + "license": "MIT", + "dependencies": { + "@angular/common": "angular/common-builds", + "@angular/compiler": "angular/compiler-builds", + "@angular/compiler-cli": "angular/compiler-cli-builds", + "@angular/core": "angular/core-builds", + "@angular/forms": "angular/forms-builds", + "@angular/http": "angular/http-builds", + "@angular/platform-browser": "angular/platform-browser-builds", + "@angular/platform-browser-dynamic": "angular/platform-browser-dynamic-builds", + "@angular/platform-server": "angular/platform-server-builds", + "@angular/router": "angular/router-builds", + + "angular-in-memory-web-api": "^0.3.1", + "systemjs": "0.19.40", + "core-js": "^2.4.1", + "rxjs": "5.1.1", + "zone.js": "^0.7.7" + }, + "devDependencies": { + "concurrently": "^3.2.0", + "lite-server": "^2.2.2", + "typescript": "~2.1.6", + + "canonical-path": "0.0.2", + "tslint": "^3.15.1", + "lodash": "^4.16.4", + "rimraf": "^2.5.4", + + "@types/node": "^6.0.46", + + "@ngtools/webpack": "^1.2.11", + "@types/express": "^4.0.35", + "raw-loader": "^0.5.1", + "webpack": "^2.2.1" + }, + "repository": {} +} diff --git a/public/docs/_examples/universal/ts/src/app/app-routing.module.ts b/public/docs/_examples/universal/ts/src/app/app-routing.module.ts new file mode 100644 index 0000000000..bc070f6c31 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; + +const routes: Routes = [ + { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, + { path: 'dashboard', component: DashboardComponent }, + { path: 'detail/:id', component: HeroDetailComponent }, + { path: 'heroes', component: HeroesComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ] +}) +export class AppRoutingModule {} diff --git a/public/docs/_examples/universal/ts/src/app/app.component.css b/public/docs/_examples/universal/ts/src/app/app.component.css new file mode 100644 index 0000000000..071e665767 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app.component.css @@ -0,0 +1,29 @@ +/* #docregion */ +h1 { + font-size: 1.2em; + color: #999; + margin-bottom: 0; +} +h2 { + font-size: 2em; + margin-top: 0; + padding-top: 0; +} +nav a { + padding: 5px 10px; + text-decoration: none; + margin-top: 10px; + display: inline-block; + background-color: #eee; + border-radius: 4px; +} +nav a:visited, a:link { + color: #607D8B; +} +nav a:hover { + color: #039be5; + background-color: #CFD8DC; +} +nav a.active { + color: #039be5; +} diff --git a/public/docs/_examples/universal/ts/src/app/app.component.ts b/public/docs/_examples/universal/ts/src/app/app.component.ts new file mode 100644 index 0000000000..a9fe05a9a8 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app.component.ts @@ -0,0 +1,19 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` +

    {{title}}

    + + + `, + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + title = 'Tour of Heroes'; +} diff --git a/public/docs/_examples/universal/ts/src/app/app.module.ts b/public/docs/_examples/universal/ts/src/app/app.module.ts new file mode 100644 index 0000000000..e078044928 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/app.module.ts @@ -0,0 +1,54 @@ +// #docplaster +// #docregion +// #docregion v1, v2 +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; + +// #enddocregion v1 +// Imports for loading & configuring the in-memory web api +import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; +import { InMemoryDataService } from './in-memory-data.service'; + +// #docregion v1 +import { AppComponent } from './app.component'; +import { DashboardComponent } from './dashboard.component'; +import { HeroesComponent } from './heroes.component'; +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroService } from './hero.service'; +// #enddocregion v1, v2 +import { HeroSearchComponent } from './hero-search.component'; +// #docregion v1, v2 + +@NgModule({ + imports: [ + BrowserModule.withServerTransition({ + appId: 'toh-universal' + }), + FormsModule, + HttpModule, + // #enddocregion v1 + // #docregion in-mem-web-api + InMemoryWebApiModule.forRoot(InMemoryDataService), + // #enddocregion in-mem-web-api + // #docregion v1 + AppRoutingModule + ], + // #docregion search + declarations: [ + AppComponent, + DashboardComponent, + HeroDetailComponent, + HeroesComponent, + // #enddocregion v1, v2 + HeroSearchComponent + // #docregion v1, v2 + ], + // #enddocregion search + providers: [ HeroService ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/universal/ts/src/app/dashboard.component.css b/public/docs/_examples/universal/ts/src/app/dashboard.component.css new file mode 100644 index 0000000000..dc7fb7ce06 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/dashboard.component.css @@ -0,0 +1,62 @@ +/* #docregion */ +[class*='col-'] { + float: left; + padding-right: 20px; + padding-bottom: 20px; +} +[class*='col-']:last-of-type { + padding-right: 0; +} +a { + text-decoration: none; +} +*, *:after, *:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +h3 { + text-align: center; margin-bottom: 0; +} +h4 { + position: relative; +} +.grid { + margin: 0; +} +.col-1-4 { + width: 25%; +} +.module { + padding: 20px; + text-align: center; + color: #eee; + max-height: 120px; + min-width: 120px; + background-color: #607D8B; + border-radius: 2px; +} +.module:hover { + background-color: #EEE; + cursor: pointer; + color: #607d8b; +} +.grid-pad { + padding: 10px 0; +} +.grid-pad > [class*='col-']:last-of-type { + padding-right: 20px; +} +@media (max-width: 600px) { + .module { + font-size: 10px; + max-height: 75px; } +} +@media (max-width: 1024px) { + .grid { + margin: 0; + } + .module { + min-width: 60px; + } +} diff --git a/public/docs/_examples/universal/ts/src/app/dashboard.component.html b/public/docs/_examples/universal/ts/src/app/dashboard.component.html new file mode 100644 index 0000000000..db8546ccd2 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/dashboard.component.html @@ -0,0 +1,10 @@ + +

    Top Heroes

    + + diff --git a/public/docs/_examples/universal/ts/src/app/dashboard.component.ts b/public/docs/_examples/universal/ts/src/app/dashboard.component.ts new file mode 100644 index 0000000000..9960aa77d4 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/dashboard.component.ts @@ -0,0 +1,22 @@ +// #docregion , search +import { Component, OnInit } from '@angular/core'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: [ './dashboard.component.css' ] +}) +// #enddocregion search +export class DashboardComponent implements OnInit { + heroes: Hero[] = []; + + constructor(private heroService: HeroService) { } + + ngOnInit(): void { + this.heroService.getHeroes() + .then(heroes => this.heroes = heroes.slice(1, 5)); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-detail.component.css b/public/docs/_examples/universal/ts/src/app/hero-detail.component.css new file mode 100644 index 0000000000..ab2437efd8 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-detail.component.css @@ -0,0 +1,30 @@ +/* #docregion */ +label { + display: inline-block; + width: 3em; + margin: .5em 0; + color: #607D8B; + font-weight: bold; +} +input { + height: 2em; + font-size: 1em; + padding-left: .4em; +} +button { + margin-top: 20px; + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +button:disabled { + background-color: #eee; + color: #ccc; + cursor: auto; +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-detail.component.html b/public/docs/_examples/universal/ts/src/app/hero-detail.component.html new file mode 100644 index 0000000000..32fe6d4391 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-detail.component.html @@ -0,0 +1,14 @@ + +
    +

    {{hero.name}} details!

    +
    + {{hero.id}}
    +
    + + +
    + + + + +
    diff --git a/public/docs/_examples/universal/ts/src/app/hero-detail.component.ts b/public/docs/_examples/universal/ts/src/app/hero-detail.component.ts new file mode 100644 index 0000000000..b3bbbd2f3d --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-detail.component.ts @@ -0,0 +1,40 @@ +// #docregion +import 'rxjs/add/operator/switchMap'; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Params } from '@angular/router'; +import { Location } from '@angular/common'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-hero-detail', + templateUrl: './hero-detail.component.html', + styleUrls: [ './hero-detail.component.css' ] +}) +export class HeroDetailComponent implements OnInit { + hero: Hero; + + constructor( + private heroService: HeroService, + private route: ActivatedRoute, + private location: Location + ) {} + + ngOnInit(): void { + this.route.params + .switchMap((params: Params) => this.heroService.getHero(+params['id'])) + .subscribe(hero => this.hero = hero); + } + + // #docregion save + save(): void { + this.heroService.update(this.hero) + .then(() => this.goBack()); + } + // #enddocregion save + + goBack(): void { + this.location.back(); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.component.css b/public/docs/_examples/universal/ts/src/app/hero-search.component.css new file mode 100644 index 0000000000..9bf8d13457 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.component.css @@ -0,0 +1,21 @@ +/* #docregion */ +.search-result{ + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width:195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; +} + +.search-result:hover { + color: #eee; + background-color: #607D8B; +} + +#search-box{ + width: 200px; + height: 20px; +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.component.html b/public/docs/_examples/universal/ts/src/app/hero-search.component.html new file mode 100644 index 0000000000..08c0560c5b --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.component.html @@ -0,0 +1,11 @@ + +
    +

    Hero Search

    + +
    +
    + {{hero.name}} +
    +
    +
    diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.component.ts b/public/docs/_examples/universal/ts/src/app/hero-search.component.ts new file mode 100644 index 0000000000..8b2d32f06b --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.component.ts @@ -0,0 +1,69 @@ +// #docplaster +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +// #docregion rxjs-imports +import { Observable } from 'rxjs/Observable'; +import { Subject } from 'rxjs/Subject'; + +// Observable class extensions +import 'rxjs/add/observable/of'; + +// Observable operators +import 'rxjs/add/operator/catch'; +import 'rxjs/add/operator/debounceTime'; +import 'rxjs/add/operator/distinctUntilChanged'; +// #enddocregion rxjs-imports + +import { HeroSearchService } from './hero-search.service'; +import { Hero } from './hero'; + +@Component({ + selector: 'hero-search', + templateUrl: './hero-search.component.html', + styleUrls: [ './hero-search.component.css' ], + providers: [HeroSearchService] +}) +export class HeroSearchComponent implements OnInit { + // #docregion search + heroes: Observable; + // #enddocregion search + // #docregion searchTerms + private searchTerms = new Subject(); + // #enddocregion searchTerms + + constructor( + private heroSearchService: HeroSearchService, + private router: Router) {} + // #docregion searchTerms + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + // #enddocregion searchTerms + // #docregion search + + ngOnInit(): void { + this.heroes = this.searchTerms + .debounceTime(300) // wait 300ms after each keystroke before considering the term + .distinctUntilChanged() // ignore if next search term is same as previous + .switchMap(term => term // switch to new observable each time the term changes + // return the http search observable + ? this.heroSearchService.search(term) + // or the observable of empty heroes if there was no search term + : Observable.of([])) + .catch(error => { + // TODO: add real error handling + console.log(error); + return Observable.of([]); + }); + } + // #enddocregion search + + gotoDetail(hero: Hero): void { + let link = ['/detail', hero.id]; + this.router.navigate(link); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero-search.service.ts b/public/docs/_examples/universal/ts/src/app/hero-search.service.ts new file mode 100644 index 0000000000..d24e0fba41 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero-search.service.ts @@ -0,0 +1,20 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http } from '@angular/http'; + +import { Observable } from 'rxjs/Observable'; +import 'rxjs/add/operator/map'; + +import { Hero } from './hero'; + +@Injectable() +export class HeroSearchService { + + constructor(private http: Http) {} + + search(term: string): Observable { + return this.http + .get(`app/heroes/?name=${term}`) + .map(response => response.json().data as Hero[]); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/hero.service.ts b/public/docs/_examples/universal/ts/src/app/hero.service.ts new file mode 100644 index 0000000000..18af476123 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero.service.ts @@ -0,0 +1,87 @@ +// #docplaster +// #docregion , imports +import { Injectable } from '@angular/core'; +import { Headers, Http } from '@angular/http'; + +// #docregion rxjs +import 'rxjs/add/operator/toPromise'; +// #enddocregion rxjs + +import { Hero } from './hero'; +// #enddocregion imports + +@Injectable() +export class HeroService { + + // #docregion update + private headers = new Headers({'Content-Type': 'application/json'}); + // #enddocregion update + // #docregion getHeroes + private heroesUrl = 'api/heroes'; // URL to web api + + constructor(private http: Http) { } + + getHeroes(): Promise { + return this.http.get(this.heroesUrl) + // #docregion to-promise + .toPromise() + // #enddocregion to-promise + // #docregion to-data + .then(response => response.json().data as Hero[]) + // #enddocregion to-data + // #docregion catch + .catch(this.handleError); + // #enddocregion catch + } + + // #enddocregion getHeroes + + // #docregion getHero + getHero(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.get(url) + .toPromise() + .then(response => response.json().data as Hero) + .catch(this.handleError); + } + // #enddocregion getHero + + // #docregion delete + delete(id: number): Promise { + const url = `${this.heroesUrl}/${id}`; + return this.http.delete(url, {headers: this.headers}) + .toPromise() + .then(() => null) + .catch(this.handleError); + } + // #enddocregion delete + + // #docregion create + create(name: string): Promise { + return this.http + .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers}) + .toPromise() + .then(res => res.json().data) + .catch(this.handleError); + } + // #enddocregion create + // #docregion update + + update(hero: Hero): Promise { + const url = `${this.heroesUrl}/${hero.id}`; + return this.http + .put(url, JSON.stringify(hero), {headers: this.headers}) + .toPromise() + .then(() => hero) + .catch(this.handleError); + } + // #enddocregion update + + // #docregion getHeroes, handleError + private handleError(error: any): Promise { + console.error('An error occurred', error); // for demo purposes only + return Promise.reject(error.message || error); + } + // #enddocregion getHeroes, handleError +} + diff --git a/public/docs/_examples/universal/ts/src/app/hero.ts b/public/docs/_examples/universal/ts/src/app/hero.ts new file mode 100644 index 0000000000..e3eac516da --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/hero.ts @@ -0,0 +1,4 @@ +export class Hero { + id: number; + name: string; +} diff --git a/public/docs/_examples/universal/ts/src/app/heroes.component.css b/public/docs/_examples/universal/ts/src/app/heroes.component.css new file mode 100644 index 0000000000..d2c958a911 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/heroes.component.css @@ -0,0 +1,68 @@ +/* #docregion */ +.selected { + background-color: #CFD8DC !important; + color: white; +} +.heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 15em; +} +.heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0; + height: 1.6em; + border-radius: 4px; +} +.heroes li:hover { + color: #607D8B; + background-color: #DDD; + left: .1em; +} +.heroes li.selected:hover { + background-color: #BBD8DC !important; + color: white; +} +.heroes .text { + position: relative; + top: -3px; +} +.heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0 0 4px; +} +button { + font-family: Arial; + background-color: #eee; + border: none; + padding: 5px 10px; + border-radius: 4px; + cursor: pointer; + cursor: hand; +} +button:hover { + background-color: #cfd8dc; +} +/* #docregion additions */ +button.delete { + float:right; + margin-top: 2px; + margin-right: .8em; + background-color: gray !important; + color:white; +} diff --git a/public/docs/_examples/universal/ts/src/app/heroes.component.html b/public/docs/_examples/universal/ts/src/app/heroes.component.html new file mode 100644 index 0000000000..392d241d52 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/heroes.component.html @@ -0,0 +1,29 @@ + +

    My Heroes

    + +
    + + +
    + +
      + +
    • + {{hero.id}} + {{hero.name}} + + + +
    • + +
    +
    +

    + {{selectedHero.name | uppercase}} is my hero +

    + +
    diff --git a/public/docs/_examples/universal/ts/src/app/heroes.component.ts b/public/docs/_examples/universal/ts/src/app/heroes.component.ts new file mode 100644 index 0000000000..6350b803c4 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/heroes.component.ts @@ -0,0 +1,61 @@ +// #docregion +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { Hero } from './hero'; +import { HeroService } from './hero.service'; + +@Component({ + selector: 'my-heroes', + templateUrl: './heroes.component.html', + styleUrls: [ './heroes.component.css' ] +}) +export class HeroesComponent implements OnInit { + heroes: Hero[]; + selectedHero: Hero; + + constructor( + private heroService: HeroService, + private router: Router) { } + + getHeroes(): void { + this.heroService + .getHeroes() + .then(heroes => this.heroes = heroes); + } + + // #docregion add + add(name: string): void { + name = name.trim(); + if (!name) { return; } + this.heroService.create(name) + .then(hero => { + this.heroes.push(hero); + this.selectedHero = null; + }); + } + // #enddocregion add + + // #docregion delete + delete(hero: Hero): void { + this.heroService + .delete(hero.id) + .then(() => { + this.heroes = this.heroes.filter(h => h !== hero); + if (this.selectedHero === hero) { this.selectedHero = null; } + }); + } + // #enddocregion delete + + ngOnInit(): void { + this.getHeroes(); + } + + onSelect(hero: Hero): void { + this.selectedHero = hero; + } + + gotoDetail(): void { + this.router.navigate(['/detail', this.selectedHero.id]); + } +} diff --git a/public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts b/public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts new file mode 100644 index 0000000000..c915955e22 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/app/in-memory-data.service.ts @@ -0,0 +1,19 @@ +// #docregion , init +import { InMemoryDbService } from 'angular-in-memory-web-api'; +export class InMemoryDataService implements InMemoryDbService { + createDb() { + let heroes = [ + {id: 11, name: 'Mr. Nice'}, + {id: 12, name: 'Narco'}, + {id: 13, name: 'Bombasto'}, + {id: 14, name: 'Celeritas'}, + {id: 15, name: 'Magneta'}, + {id: 16, name: 'RubberMan'}, + {id: 17, name: 'Dynama'}, + {id: 18, name: 'Dr IQ'}, + {id: 19, name: 'Magma'}, + {id: 20, name: 'Tornado'} + ]; + return {heroes}; + } +} diff --git a/public/docs/_examples/universal/ts/src/index-aot.html b/public/docs/_examples/universal/ts/src/index-aot.html new file mode 100644 index 0000000000..096bfbb512 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/index-aot.html @@ -0,0 +1,18 @@ + + + + + Angular Tour of Heroes + + + + + + + + Loading... + + + + + diff --git a/public/docs/_examples/universal/ts/src/index.html b/public/docs/_examples/universal/ts/src/index.html new file mode 100644 index 0000000000..727b1fc833 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/index.html @@ -0,0 +1,26 @@ + + + + + + Angular Universal Tour of Heroes + + + + + + + + + + + + + + + + Loading... + + diff --git a/public/docs/_examples/universal/ts/src/main-aot.ts b/public/docs/_examples/universal/ts/src/main-aot.ts new file mode 100644 index 0000000000..fcb35dc9dc --- /dev/null +++ b/public/docs/_examples/universal/ts/src/main-aot.ts @@ -0,0 +1,5 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; +import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory); diff --git a/public/docs/_examples/universal/ts/src/main.ts b/public/docs/_examples/universal/ts/src/main.ts new file mode 100644 index 0000000000..f332d1d245 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/main.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/universal/ts/src/uni/app.server.ts b/public/docs/_examples/universal/ts/src/uni/app.server.ts new file mode 100644 index 0000000000..585470cd09 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/uni/app.server.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { APP_BASE_HREF } from '@angular/common'; +import { ServerModule } from '@angular/platform-server'; +import { AppComponent } from '../app/app.component'; +import { AppModule } from '../app/app.module'; + +@NgModule({ + imports: [ + ServerModule, + AppModule + ], + bootstrap: [ + AppComponent + ], + providers: [ + {provide: APP_BASE_HREF, useValue: '/'} + // { provide: NgModuleFactoryLoader, useClass: ServerRouterLoader } + ] +}) +export class AppServerModule { +} diff --git a/public/docs/_examples/universal/ts/src/uni/server-aot.ts b/public/docs/_examples/universal/ts/src/uni/server-aot.ts new file mode 100644 index 0000000000..38eb3f6b33 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/uni/server-aot.ts @@ -0,0 +1,40 @@ +import 'zone.js/dist/zone-node'; +import { enableProdMode } from '@angular/core'; +// import { AppServerModule } from './app.server'; +import { AppServerModuleNgFactory } from '../../aot/src/uni/app.server.ngfactory'; +import * as express from 'express'; +import { ngUniversalEngine } from './universal-engine'; + +enableProdMode(); + +const server = express(); + +// set our angular engine as the handler for html files, so it will be used to render them. +server.engine('html', ngUniversalEngine({ + bootstrap: [AppServerModuleNgFactory] +})); + +// set default view directory +server.set('views', 'src'); + +// handle requests for routes in the app. ngExpressEngine does the rendering. +server.get(['/', '/dashboard', '/heroes', '/detail/:id'], (req, res) => { + res.render('index-aot.html', {req}); +}); + +// handle requests for static files +server.get(['/*.js', '/*.css'], (req, res, next) => { + let fileName: string = req.originalUrl; + console.log(fileName); + let root = fileName.startsWith('/node_modules/') ? '.' : 'src'; + res.sendFile(fileName, { root: root }, function (err) { + if (err) { + next(err); + } + }); +}); + +// start the server +server.listen(3200, () => { + console.log('listening on port 3200...'); +}); diff --git a/public/docs/_examples/universal/ts/src/uni/universal-engine.ts b/public/docs/_examples/universal/ts/src/uni/universal-engine.ts new file mode 100644 index 0000000000..3c0ac6b528 --- /dev/null +++ b/public/docs/_examples/universal/ts/src/uni/universal-engine.ts @@ -0,0 +1,38 @@ +/** + * Express/Connect middleware for rendering pages using Angular Universal + */ +import * as fs from 'fs'; +import { renderModuleFactory } from '@angular/platform-server'; + +const templateCache = {}; // cache for page templates +const outputCache = {}; // cache for rendered pages + +export function ngUniversalEngine(setupOptions: any) { + + return function (filePath: string, options: { req: Request }, callback: (err: Error, html: string) => void) { + let url: string = options.req.url; + let html: string = outputCache[url]; + if (html) { + // return already-built page for this url + console.log('from cache: ' + url); + callback(null, html); + return; + } + + console.log('building: ' + url); + if (!templateCache[filePath]) { + let file = fs.readFileSync(filePath); + templateCache[filePath] = file.toString(); + } + + // render the page via angular platform-server + let appModuleFactory = setupOptions.bootstrap[0]; + renderModuleFactory(appModuleFactory, { + document: templateCache[filePath], + url: url + }).then(str => { + outputCache[url] = str; + callback(null, str); + }); + }; +} diff --git a/public/docs/_examples/universal/ts/tsconfig-aot.json b/public/docs/_examples/universal/ts/tsconfig-aot.json new file mode 100644 index 0000000000..023bf2fb68 --- /dev/null +++ b/public/docs/_examples/universal/ts/tsconfig-aot.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types/" + ] + }, + + "files": [ + "src/app/app.module.ts", + "src/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "entryModule": "./src/app/app.module#AppModule", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/universal/ts/tsconfig-uni.json b/public/docs/_examples/universal/ts/tsconfig-uni.json new file mode 100644 index 0000000000..fcb6a7c92d --- /dev/null +++ b/public/docs/_examples/universal/ts/tsconfig-uni.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "src/uni/app.server.ts", + "src/uni/server-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "entryModule": "./src/app/app.module#AppModule", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/universal/ts/tsconfig.json b/public/docs/_examples/universal/ts/tsconfig.json new file mode 100644 index 0000000000..58307adfe0 --- /dev/null +++ b/public/docs/_examples/universal/ts/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*" + ] +} diff --git a/public/docs/_examples/universal/ts/webpack.config.aot.js b/public/docs/_examples/universal/ts/webpack.config.aot.js new file mode 100644 index 0000000000..f16ce50294 --- /dev/null +++ b/public/docs/_examples/universal/ts/webpack.config.aot.js @@ -0,0 +1,30 @@ +const ngtools = require('@ngtools/webpack'); +const webpack = require('webpack'); + +module.exports = { + devtool: 'source-map', + entry: { + main: './src/main-aot.ts' + }, + resolve: { + extensions: ['.ts', '.js'] + }, + target: 'node', + output: { + path: 'src/dist', + filename: 'build.js' + }, + plugins: [ + new ngtools.AotPlugin({ + tsConfigPath: './tsconfig-aot.json' + }), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) + ], + module: { + rules: [ + { test: /\.css$/, loader: 'raw-loader' }, + { test: /\.html$/, loader: 'raw-loader' }, + { test: /\.ts$/, loader: '@ngtools/webpack' } + ] + } +} diff --git a/public/docs/_examples/universal/ts/webpack.config.uni.js b/public/docs/_examples/universal/ts/webpack.config.uni.js new file mode 100644 index 0000000000..1ccccb6f1a --- /dev/null +++ b/public/docs/_examples/universal/ts/webpack.config.uni.js @@ -0,0 +1,30 @@ +const ngtools = require('@ngtools/webpack'); +const webpack = require('webpack'); + +module.exports = { + devtool: 'source-map', + entry: { + main: ['./src/uni/app.server.ts', './src/uni/server-aot.ts'] + }, + resolve: { + extensions: ['.ts', '.js'] + }, + target: 'node', + output: { + path: 'src/dist', + filename: 'server.js' + }, + plugins: [ + new ngtools.AotPlugin({ + tsConfigPath: './tsconfig-uni.json' + }), + new webpack.optimize.UglifyJsPlugin({ sourceMap: true }) + ], + module: { + rules: [ + { test: /\.css$/, loader: 'raw-loader' }, + { test: /\.html$/, loader: 'raw-loader' }, + { test: /\.ts$/, loader: '@ngtools/webpack' } + ] + } +} diff --git a/public/docs/_examples/upgrade-module/e2e-spec.ts b/public/docs/_examples/upgrade-module/e2e-spec.ts new file mode 100644 index 0000000000..0c45fb78b8 --- /dev/null +++ b/public/docs/_examples/upgrade-module/e2e-spec.ts @@ -0,0 +1,182 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; +import { setProtractorToHybridMode } from '../protractor-helpers'; + +describe('Upgrade Tests', function () { + + beforeAll(function () { + setProtractorToHybridMode(); + }); + + describe('AngularJS Auto-bootstrap', function() { + + beforeAll(function () { + browser.get('/index-ng-app.html'); + }); + + it('bootstraps as expected', function () { + expect(element(by.css('#message')).getText()).toEqual('Hello world'); + }); + + }); + + describe('AngularJS JavaScript Bootstrap', function() { + + beforeAll(function () { + browser.get('/index-bootstrap.html'); + }); + + it('bootstraps as expected', function () { + expect(element(by.css('#message')).getText()).toEqual('Hello world'); + }); + + }); + + describe('AngularJS-Angular Hybrid Bootstrap', function() { + + beforeAll(function () { + browser.get('/index-ajs-a-hybrid-bootstrap.html'); + }); + + it('bootstraps as expected', function () { + expect(element(by.css('#message')).getText()).toEqual('Hello world'); + }); + + }); + + describe('Upgraded static component', function() { + + beforeAll(function () { + browser.get('/index-upgrade-static.html'); + }); + + it('renders', function () { + expect(element(by.css('h2')).getText()).toEqual('Windstorm details!'); + }); + + }); + + + describe('Upgraded component with IO', function() { + + beforeAll(function () { + browser.get('/index-upgrade-io.html'); + }); + + it('has inputs', function () { + expect(element(by.css('h2')).getText()).toEqual('Windstorm details!'); + }); + + it('has outputs', function () { + element(by.buttonText('Delete')).click(); + expect(element(by.css('h2')).getText()).toEqual('Ex-Windstorm details!'); + }); + + }); + + + describe('Downgraded static component', function() { + + beforeAll(function () { + browser.get('/index-downgrade-static.html'); + }); + + it('renders', function () { + expect(element(by.css('h2')).getText()).toEqual('Windstorm details!'); + }); + + }); + + describe('Downgraded component with IO', function() { + + beforeAll(function () { + browser.get('/index-downgrade-io.html'); + }); + + it('has inputs', function () { + expect(element.all(by.css('h2')).first().getText()).toEqual('Windstorm details!'); + }); + + it('has outputs', function () { + element.all(by.buttonText('Delete')).first().click(); + expect(element.all(by.css('h2')).first().getText()).toEqual('Ex-Windstorm details!'); + }); + + it('supports ng-repeat', function () { + expect(element.all(by.css('hero-detail')).count()).toBe(3); + }); + + }); + + + describe('Downgraded component with content projection', function() { + + beforeAll(function () { + browser.get('/index-ajs-to-a-projection.html'); + }); + + it('can be transcluded into', function () { + expect(element(by.css('hero-detail')).getText()).toContain('Specific powers of controlling winds'); + }); + + }); + + + describe('Upgraded component with transclusion', function() { + + beforeAll(function () { + browser.get('/index-a-to-ajs-transclusion.html'); + }); + + it('can be projected into', function () { + expect(element(by.css('hero-detail')).getText()).toContain('Specific powers of controlling winds'); + }); + + }); + + + describe('Upgrading AngularJS Providers', function() { + + beforeAll(function () { + browser.get('/index-ajs-to-a-providers.html'); + }); + + it('works', function () { + expect(element(by.css('h2')).getText()).toBe('1: Windstorm'); + }); + + }); + + + describe('Downgrading Angular Providers', function() { + + beforeAll(function () { + browser.get('/index-a-to-ajs-providers.html'); + }); + + it('works', function () { + expect(element(by.css('h2')).getText()).toBe('1: Windstorm'); + }); + + }); + + describe('Dividing routes', function() { + + beforeAll(function () { + browser.get('/index-divide-routes.html'); + }); + + it('allows ng1 routes', function () { + browser.get('/index-divide-routes.html#/villain'); + expect(element(by.css('h2')).getText()).toBe('Mr. Nice - No More Mr. Nice Guy'); + }); + + it('allows ng2 routes', function () { + browser.get('/index-divide-routes.html#/hero'); + expect(element(by.css('h2')).getText()).toBe('Windstorm - Specific powers of controlling winds'); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-module/ts/.gitignore b/public/docs/_examples/upgrade-module/ts/.gitignore new file mode 100644 index 0000000000..7f5c313a3e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/.gitignore @@ -0,0 +1,7 @@ +**/*.js +aot/**/* +!aot/bs-config.json +!aot/index.html +!copy-dist-files.js +!rollup-config.js +!systemjs.config.1.js diff --git a/public/docs/_examples/upgrade-module/ts/example-config.json b/public/docs/_examples/upgrade-module/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/app.module.ts new file mode 100644 index 0000000000..91235a1485 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/app.module.ts @@ -0,0 +1,34 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { heroDetailComponent } from './hero-detail.component'; + +// #docregion ngmodule +import { Heroes } from './heroes'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + providers: [ Heroes ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion ngmodule +// #docregion register +import { downgradeInjectable } from '@angular/upgrade/static'; + +angular.module('heroApp', []) + .factory('heroes', downgradeInjectable(Heroes)) + .component('heroDetail', heroDetailComponent); +// #enddocregion register + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/hero-detail.component.ts new file mode 100644 index 0000000000..dd7aa10d79 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/hero-detail.component.ts @@ -0,0 +1,11 @@ +import { Heroes } from './heroes'; + +// #docregion +export const heroDetailComponent = { + template: ` +

    {{$ctrl.hero.id}}: {{$ctrl.hero.name}}

    + `, + controller: ['heroes', function(heroes: Heroes) { + this.hero = heroes.get()[0]; + }] +}; diff --git a/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/heroes.ts b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/heroes.ts new file mode 100644 index 0000000000..f5f6d87ed8 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-providers/heroes.ts @@ -0,0 +1,13 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Hero } from '../hero'; + +@Injectable() +export class Heroes { + get() { + return [ + new Hero(1, 'Windstorm'), + new Hero(2, 'Spiderman') + ]; + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/app.module.ts new file mode 100644 index 0000000000..599e711b5e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/app.module.ts @@ -0,0 +1,39 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { heroDetail, HeroDetailDirective } from './hero-detail.component'; +import { ContainerComponent } from './container.component'; + +// #docregion heroupgrade +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + ContainerComponent, + HeroDetailDirective + ], + entryComponents: [ + ContainerComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion heroupgrade + +angular.module('heroApp', []) + .component('heroDetail', heroDetail) + .directive( + 'myContainer', + downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/container.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/container.component.ts new file mode 100644 index 0000000000..1b740d6554 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/container.component.ts @@ -0,0 +1,16 @@ +// #docregion +import { Component } from '@angular/core'; +import { Hero } from '../hero'; + +@Component({ + selector: 'my-container', + template: ` + + +

    {{hero.description}}

    +
    + ` +}) +export class ContainerComponent { + hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds'); +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/hero-detail.component.ts new file mode 100644 index 0000000000..a1bec385e0 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/a-to-ajs-transclusion/hero-detail.component.ts @@ -0,0 +1,28 @@ +// #docregion +export const heroDetail = { + bindings: { + hero: '=' + }, + template: ` +

    {{$ctrl.hero.name}}

    +
    + +
    + ` +}; +// #enddocregion + +import { Directive, ElementRef, Injector, Input } from '@angular/core'; +import { UpgradeComponent } from '@angular/upgrade/static'; +import { Hero } from '../hero'; + +@Directive({ + selector: 'hero-detail' +}) +export class HeroDetailDirective extends UpgradeComponent { + @Input() hero: Hero; + + constructor(elementRef: ElementRef, injector: Injector) { + super('heroDetail', elementRef, injector); + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-a-hybrid-bootstrap/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-a-hybrid-bootstrap/app.module.ts new file mode 100644 index 0000000000..7a6b82cf92 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-a-hybrid-bootstrap/app.module.ts @@ -0,0 +1,29 @@ +declare var angular: angular.IAngularStatic; +// #docregion ngmodule +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion ngmodule +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + +// #docregion bootstrap +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); +// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-bootstrap/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-bootstrap/app.module.ts new file mode 100644 index 0000000000..639b780d1b --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-bootstrap/app.module.ts @@ -0,0 +1,10 @@ +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); + +document.addEventListener('DOMContentLoaded', function() { + // #docregion bootstrap + angular.bootstrap(document.body, ['heroApp'], {strictDi: true}); + // #enddocregion bootstrap +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-ng-app/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-ng-app/app.module.ts new file mode 100644 index 0000000000..904f7578b8 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-ng-app/app.module.ts @@ -0,0 +1,4 @@ +angular.module('heroApp', []) + .controller('MainCtrl', function() { + this.message = 'Hello world'; + }); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/app.module.ts new file mode 100644 index 0000000000..080f80f0ef --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/app.module.ts @@ -0,0 +1,36 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { MainController } from './main.controller'; +import { HeroDetailComponent } from './hero-detail.component'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} + +angular.module('heroApp', []) + .controller('MainController', MainController) + .directive('heroDetail', downgradeComponent({ + component: HeroDetailComponent, + inputs: ['hero'] + }) as angular.IDirectiveFactory); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/hero-detail.component.ts new file mode 100644 index 0000000000..7a2956eb26 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/hero-detail.component.ts @@ -0,0 +1,16 @@ +// #docregion +import { Component, Input } from '@angular/core'; +import { Hero } from '../hero'; + +@Component({ + selector: 'hero-detail', + template: ` +

    {{hero.name}}

    +
    + +
    + ` +}) +export class HeroDetailComponent { + @Input() hero: Hero; +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/main.controller.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/main.controller.ts new file mode 100644 index 0000000000..c6041ac788 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-projection/main.controller.ts @@ -0,0 +1,5 @@ +import { Hero } from '../hero'; + +export class MainController { + hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds'); +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts new file mode 100644 index 0000000000..52d4e74a1f --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/ajs-upgraded-providers.ts @@ -0,0 +1,12 @@ +// #docregion +import { HeroesService } from './heroes.service'; + +export function heroesServiceFactory(i: any) { + return i.get('heroes'); +} + +export const heroesServiceProvider = { + provide: HeroesService, + useFactory: heroesServiceFactory, + deps: ['$injector'] +}; diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/app.module.ts new file mode 100644 index 0000000000..4e0eca003a --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/app.module.ts @@ -0,0 +1,44 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { HeroDetailComponent } from './hero-detail.component'; +import { HeroesService } from './heroes.service'; +// #docregion register +import { heroesServiceProvider } from './ajs-upgraded-providers'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + providers: [ + heroesServiceProvider + ], + // #enddocregion register + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +// #docregion register +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion register + +angular.module('heroApp', []) + .service('heroes', HeroesService) + .directive( + 'heroDetail', + downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/hero-detail.component.ts new file mode 100644 index 0000000000..b02f85b99a --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/hero-detail.component.ts @@ -0,0 +1,17 @@ +// #docregion +import { Component } from '@angular/core'; +import { HeroesService } from './heroes.service'; +import { Hero } from '../hero'; + +@Component({ + selector: 'hero-detail', + template: ` +

    {{hero.id}}: {{hero.name}}

    + ` +}) +export class HeroDetailComponent { + hero: Hero; + constructor(heroes: HeroesService) { + this.hero = heroes.get()[0]; + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/heroes.service.ts b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/heroes.service.ts new file mode 100644 index 0000000000..4a258e205a --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/ajs-to-a-providers/heroes.service.ts @@ -0,0 +1,11 @@ +// #docregion +import { Hero } from '../hero'; + +export class HeroesService { + get() { + return [ + new Hero(1, 'Windstorm'), + new Hero(2, 'Spiderman') + ]; + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/app.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/app.component.ts new file mode 100644 index 0000000000..1fae3f84c6 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/app.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + template: ` + +
    + `, +}) +export class AppComponent { } diff --git a/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/app.module.ts new file mode 100644 index 0000000000..7d85a23c94 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/app.module.ts @@ -0,0 +1,62 @@ +// #docregion +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { HeroModule } from './hero.module'; + +// #docregion router-config +import { HashLocationStrategy, LocationStrategy } from '@angular/common'; +import { RouterModule, UrlHandlingStrategy, UrlTree } from '@angular/router'; +import { AppComponent } from './app.component'; + +class HybridUrlHandlingStrategy implements UrlHandlingStrategy { + // use only process the `/hero` url + shouldProcessUrl(url: UrlTree) { return url.toString().startsWith('/hero'); } + extract(url: UrlTree) { return url; } + merge(url: UrlTree, whole: UrlTree) { return url; } +} + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule, + HeroModule, + RouterModule.forRoot([]) + ], + providers: [ + // use hash location strategy + { provide: LocationStrategy, useClass: HashLocationStrategy }, + // use custom url handling strategy + { provide: UrlHandlingStrategy, useClass: HybridUrlHandlingStrategy } + ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion router-config + +import { Villain } from '../villain'; + +export const villainDetail = { + template: ` +

    Villain detail

    +

    {{$ctrl.villain.name}} - {{$ctrl.villain.description}}

    + `, + controller: function() { + this.villain = new Villain(1, 'Mr. Nice', 'No More Mr. Nice Guy'); + } +}; + +angular.module('heroApp', ['ngRoute']) + .component('villainDetail', villainDetail) + .config(['$locationProvider', '$routeProvider', + function config($locationProvider: angular.ILocationProvider, + $routeProvider: angular.route.IRouteProvider) { + // #docregion ajs-route + $routeProvider + .when('/villain', { template: '' }); + // #enddocregion ajs-route + } + ]); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/hero.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/hero.module.ts new file mode 100644 index 0000000000..33099d0a9f --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/hero.module.ts @@ -0,0 +1,32 @@ +// #docregion +import { Component } from '@angular/core'; +import { Hero } from '../hero'; + +@Component({ + template: ` +

    Hero detail

    +

    {{hero.name}} - {{hero.description}}

    + ` +}) +export class HeroDetailComponent { + hero = new Hero(1, 'Windstorm', 'Specific powers of controlling winds'); +} + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; + +@NgModule({ + imports: [ + CommonModule, + // #docregion a-route + RouterModule.forChild([ + { path: 'hero', children: [ + { path: '', component: HeroDetailComponent }, + ] }, + ]) + // #enddocregion a-route + ], + declarations: [ HeroDetailComponent ] +}) +export class HeroModule {} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/main.ts b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/main.ts new file mode 100644 index 0000000000..9b4d37ebc3 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/divide-routes/main.ts @@ -0,0 +1,10 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/app.module.ts new file mode 100644 index 0000000000..1e836cfc9d --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/app.module.ts @@ -0,0 +1,43 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { MainController } from './main.controller'; + +// #docregion downgradecomponent +import { HeroDetailComponent } from './hero-detail.component'; + +// #enddocregion downgradecomponent +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #docregion downgradecomponent + +angular.module('heroApp', []) + .controller('MainController', MainController) + .directive('heroDetail', downgradeComponent({ + component: HeroDetailComponent, + inputs: ['hero'], + outputs: ['deleted'] + }) as angular.IDirectiveFactory); + +// #enddocregion downgradecomponent + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/hero-detail.component.ts new file mode 100644 index 0000000000..94082813fd --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/hero-detail.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Hero } from '../hero'; + +@Component({ + selector: 'hero-detail', + template: ` +

    {{hero.name}} details!

    +
    {{hero.id}}
    + + ` +}) +export class HeroDetailComponent { + @Input() hero: Hero; + @Output() deleted = new EventEmitter(); + onDelete() { + this.deleted.emit(this.hero); + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/main.controller.ts b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/main.controller.ts new file mode 100644 index 0000000000..d50272073f --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-io/main.controller.ts @@ -0,0 +1,12 @@ +import { Hero } from '../hero'; + +export class MainController { + hero = new Hero(1, 'Windstorm'); + heroes = [ + new Hero(2, 'Superman'), + new Hero(3, 'Spiderman') + ]; + onDelete(hero: Hero) { + hero.name = 'Ex-' + hero.name; + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/downgrade-static/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-static/app.module.ts new file mode 100644 index 0000000000..4d621d2f03 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-static/app.module.ts @@ -0,0 +1,42 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +// #docregion downgradecomponent, ngmodule +import { HeroDetailComponent } from './hero-detail.component'; + +// #enddocregion downgradecomponent +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailComponent + ], + entryComponents: [ + HeroDetailComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion ngmodule +// #docregion downgradecomponent + +import { downgradeComponent } from '@angular/upgrade/static'; + +angular.module('heroApp', []) + .directive( + 'heroDetail', + downgradeComponent({component: HeroDetailComponent}) as angular.IDirectiveFactory + ); + +// #enddocregion downgradecomponent + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/downgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-static/hero-detail.component.ts new file mode 100644 index 0000000000..df4a705f37 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/downgrade-static/hero-detail.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'hero-detail', + template: ` +

    Windstorm details!

    +
    1
    + ` +}) +export class HeroDetailComponent { } diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/hero-detail.directive.ts b/public/docs/_examples/upgrade-module/ts/src/app/hero-detail.directive.ts similarity index 95% rename from public/docs/_examples/upgrade/ts/adapter/app/js/hero-detail.directive.ts rename to public/docs/_examples/upgrade-module/ts/src/app/hero-detail.directive.ts index 09af0685fa..e1b14d2dfc 100644 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/hero-detail.directive.ts +++ b/public/docs/_examples/upgrade-module/ts/src/app/hero-detail.directive.ts @@ -1,6 +1,7 @@ // #docregion export function heroDetailDirective() { return { + restrict: 'E', scope: {}, bindToController: { hero: '=', @@ -17,5 +18,5 @@ export function heroDetailDirective() { }; }, controllerAs: 'ctrl' - } + }; } diff --git a/public/docs/_examples/upgrade-module/ts/src/app/hero.ts b/public/docs/_examples/upgrade-module/ts/src/app/hero.ts new file mode 100644 index 0000000000..5dcb5664eb --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/hero.ts @@ -0,0 +1,5 @@ +export class Hero { + constructor(public id: number, + public name: string, + public description?: string) { } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/app.module.ts new file mode 100644 index 0000000000..599e711b5e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/app.module.ts @@ -0,0 +1,39 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { heroDetail, HeroDetailDirective } from './hero-detail.component'; +import { ContainerComponent } from './container.component'; + +// #docregion heroupgrade +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + ContainerComponent, + HeroDetailDirective + ], + entryComponents: [ + ContainerComponent + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion heroupgrade + +angular.module('heroApp', []) + .component('heroDetail', heroDetail) + .directive( + 'myContainer', + downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/container.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/container.component.ts new file mode 100644 index 0000000000..8d76085174 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/container.component.ts @@ -0,0 +1,19 @@ +// #docregion +import { Component } from '@angular/core'; +import { Hero } from '../hero'; + +@Component({ + selector: 'my-container', + template: ` +

    Tour of Heroes

    + + + ` +}) +export class ContainerComponent { + hero = new Hero(1, 'Windstorm'); + heroDeleted(hero: Hero) { + hero.name = 'Ex-' + hero.name; + } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/hero-detail.component.ts new file mode 100644 index 0000000000..90c3273010 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-io/hero-detail.component.ts @@ -0,0 +1,37 @@ +// #docregion +// #docregion hero-detail-io +export const heroDetail = { + bindings: { + hero: '<', + deleted: '&' + }, + template: ` +

    {{$ctrl.hero.name}} details!

    +
    {{$ctrl.hero.id}}
    + + `, + controller: function() { + this.onDelete = () => { + this.deleted(this.hero); + }; + } +}; +// #enddocregion hero-detail-io + +// #docregion hero-detail-io-upgrade +import { Directive, ElementRef, Injector, Input, Output, EventEmitter } from '@angular/core'; +import { UpgradeComponent } from '@angular/upgrade/static'; +import { Hero } from '../hero'; + +@Directive({ + selector: 'hero-detail' +}) +export class HeroDetailDirective extends UpgradeComponent { + @Input() hero: Hero; + @Output() deleted: EventEmitter; + + constructor(elementRef: ElementRef, injector: Injector) { + super('heroDetail', elementRef, injector); + } +} +// #enddocregion hero-detail-io-upgrade diff --git a/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/app.module.ts b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/app.module.ts new file mode 100644 index 0000000000..401963c35e --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/app.module.ts @@ -0,0 +1,41 @@ +declare var angular: angular.IAngularStatic; +import { NgModule } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static'; + +import { heroDetail, HeroDetailDirective } from './hero-detail.component'; +import { ContainerComponent } from './container.component'; + +// #docregion hero-detail-upgrade +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule + ], + declarations: [ + HeroDetailDirective, + // #enddocregion hero-detail-upgrade + ContainerComponent + ], + entryComponents: [ + ContainerComponent + // #docregion hero-detail-upgrade + ] +}) +export class AppModule { + ngDoBootstrap() {} +} +// #enddocregion hero-detail-upgrade + +angular.module('heroApp', []) + .component('heroDetail', heroDetail) + .directive( + 'myContainer', + downgradeComponent({component: ContainerComponent}) as angular.IDirectiveFactory + ); + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.body, ['heroApp'], {strictDi: true}); +}); diff --git a/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/container.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/container.component.ts new file mode 100644 index 0000000000..c28e5ea42d --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/container.component.ts @@ -0,0 +1,11 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-container', + template: ` +

    Tour of Heroes

    + + ` +}) +export class ContainerComponent { } diff --git a/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/hero-detail.component.ts new file mode 100644 index 0000000000..02ddd293eb --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/upgrade-static/hero-detail.component.ts @@ -0,0 +1,25 @@ +// #docregion +// #docregion hero-detail +export const heroDetail = { + template: ` +

    Windstorm details!

    +
    1
    + `, + controller: function() { + } +}; +// #enddocregion hero-detail + +// #docregion hero-detail-upgrade +import { Directive, ElementRef, Injector } from '@angular/core'; +import { UpgradeComponent } from '@angular/upgrade/static'; + +@Directive({ + selector: 'hero-detail' +}) +export class HeroDetailDirective extends UpgradeComponent { + constructor(elementRef: ElementRef, injector: Injector) { + super('heroDetail', elementRef, injector); + } +} +// #enddocregion hero-detail-upgrade diff --git a/public/docs/_examples/upgrade-module/ts/src/app/villain.ts b/public/docs/_examples/upgrade-module/ts/src/app/villain.ts new file mode 100644 index 0000000000..ef3d014f11 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/app/villain.ts @@ -0,0 +1,5 @@ +export class Villain { + constructor(public id: number, + public name: string, + public description?: string) { } +} diff --git a/public/docs/_examples/upgrade-module/ts/src/index-a-to-ajs-providers.html b/public/docs/_examples/upgrade-module/ts/src/index-a-to-ajs-providers.html new file mode 100644 index 0000000000..693655a53c --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-a-to-ajs-providers.html @@ -0,0 +1,31 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-a-to-ajs-transclusion.html b/public/docs/_examples/upgrade-module/ts/src/index-a-to-ajs-transclusion.html new file mode 100644 index 0000000000..43bc09c64b --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-a-to-ajs-transclusion.html @@ -0,0 +1,30 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-ajs-a-hybrid-bootstrap.html b/public/docs/_examples/upgrade-module/ts/src/index-ajs-a-hybrid-bootstrap.html new file mode 100644 index 0000000000..1115e931f5 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-ajs-a-hybrid-bootstrap.html @@ -0,0 +1,28 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + +
    {{ mainCtrl.message }}
    + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-ajs-to-a-projection.html b/public/docs/_examples/upgrade-module/ts/src/index-ajs-to-a-projection.html new file mode 100644 index 0000000000..3456957077 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-ajs-to-a-projection.html @@ -0,0 +1,37 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + +
    + + +

    {{mainCtrl.hero.description}}

    +
    +
    + +
    + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-ajs-to-a-providers.html b/public/docs/_examples/upgrade-module/ts/src/index-ajs-to-a-providers.html new file mode 100644 index 0000000000..7d1f2b7a05 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-ajs-to-a-providers.html @@ -0,0 +1,31 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-bootstrap.html b/public/docs/_examples/upgrade-module/ts/src/index-bootstrap.html new file mode 100644 index 0000000000..bc4614e562 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-bootstrap.html @@ -0,0 +1,13 @@ + + + + + + + + + + +
    {{ mainCtrl.message }}
    + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-divide-routes.html b/public/docs/_examples/upgrade-module/ts/src/index-divide-routes.html new file mode 100644 index 0000000000..ee9a56ab36 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-divide-routes.html @@ -0,0 +1,31 @@ + + + + Angular 2 Upgrade + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-downgrade-io.html b/public/docs/_examples/upgrade-module/ts/src/index-downgrade-io.html new file mode 100644 index 0000000000..71e55db355 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-downgrade-io.html @@ -0,0 +1,44 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + +
    + + +
    + + +
    + + +
    + +
    + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-downgrade-static.html b/public/docs/_examples/upgrade-module/ts/src/index-downgrade-static.html new file mode 100644 index 0000000000..47ec27e8f4 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-downgrade-static.html @@ -0,0 +1,32 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-ng-app.html b/public/docs/_examples/upgrade-module/ts/src/index-ng-app.html new file mode 100644 index 0000000000..0bd661faae --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-ng-app.html @@ -0,0 +1,15 @@ + + + + + + + + + + +
    + {{ mainCtrl.message }} +
    + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-upgrade-io.html b/public/docs/_examples/upgrade-module/ts/src/index-upgrade-io.html new file mode 100644 index 0000000000..2dca0d44d4 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-upgrade-io.html @@ -0,0 +1,30 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/index-upgrade-static.html b/public/docs/_examples/upgrade-module/ts/src/index-upgrade-static.html new file mode 100644 index 0000000000..9134cfbc32 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/index-upgrade-static.html @@ -0,0 +1,30 @@ + + + + Angular Upgrade + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-module/ts/src/systemjs.config.1.js b/public/docs/_examples/upgrade-module/ts/src/systemjs.config.1.js new file mode 100644 index 0000000000..a8c57d1792 --- /dev/null +++ b/public/docs/_examples/upgrade-module/ts/src/systemjs.config.1.js @@ -0,0 +1,43 @@ +/** + * System configuration for Angular samples + * Adjust as necessary for your application needs. + */ +(function (global) { + System.config({ + paths: { + // paths serve as alias + 'npm:': 'node_modules/' + }, + // map tells the System loader where to look for things + map: { + // our app is within the app folder + app: 'app', + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + // #docregion upgrade-static-umd + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', + // #enddocregion upgrade-static-umd + + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js' + }, + // packages tells the System loader how to load when no filename and/or no extension + packages: { + app: { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + } + } + }); +})(this); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/README.md b/public/docs/_examples/upgrade-phonecat-1-typescript/README.md new file mode 100644 index 0000000000..f3433b901a --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/README.md @@ -0,0 +1,34 @@ +This is the Angular Phonecat application adjusted to fit our boilerplate project +structure. + +The following changes from vanilla Phonecat are applied: + +* The TypeScript config file shown in the guide is `tsconfig.ajs.json` instead + of the default, because we don't want to enable `noImplicitAny` for migration. +* Karma config for unit tests is in karma.conf.ajs.js because the boilerplate + Karma config is not compatible with the way AngularJS tests need to be run. + The shell script run-unit-tests.sh can be used to run the unit tests. +* Instead of using Bower, AngularJS and its dependencies are fetched from a CDN + in index.html and karma.conf.ajs.js. +* E2E tests have been moved to the parent directory, where `gulp run-e2e-tests` can + discover and run them along with all the other examples. +* Most of the phone JSON and image data removed in the interest of keeping + repo weight down. Keeping enough to retain testability of the app. + +## Running the app + +Start like any example + + npm run start + +You'll find the app under the /app path: http://localhost:3002/app/index.html + +## Running unit tests + + ./run-unit-tests.sh + +## Running E2E tests + +Like for any example (at the project root): + + gulp run-e2e-tests --filter=phonecat-1 diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts new file mode 100644 index 0000000000..4598a7f6dc --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/e2e-spec.ts @@ -0,0 +1,107 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, ElementFinder } from 'protractor'; +import { setProtractorToNg1Mode } from '../protractor-helpers'; + +// Angular E2E Testing Guide: +// https://docs.angularjs.org/guide/e2e-testing + +describe('PhoneCat Application', function() { + + beforeAll(function() { + browser.baseUrl = 'http://localhost:8080/app/'; + setProtractorToNg1Mode(); + }); + + it('should redirect `index.html` to `index.html#!/phones', function() { + browser.get('index.html'); + expect(browser.getLocationAbsUrl()).toBe('/phones'); + }); + + describe('View: Phone list', function() { + + beforeEach(function() { + browser.get('index.html#!/phones'); + }); + + it('should filter the phone list as a user types into the search box', function() { + let phoneList = element.all(by.repeater('phone in $ctrl.phones')); + let query = element(by.model('$ctrl.query')); + + expect(phoneList.count()).toBe(20); + + query.sendKeys('nexus'); + expect(phoneList.count()).toBe(1); + + query.clear(); + query.sendKeys('motorola'); + expect(phoneList.count()).toBe(8); + }); + + it('should be possible to control phone order via the drop-down menu', function() { + let queryField = element(by.model('$ctrl.query')); + let orderSelect = element(by.model('$ctrl.orderProp')); + let nameOption = orderSelect.element(by.css('option[value="name"]')); + let phoneNameColumn = element.all(by.repeater('phone in $ctrl.phones').column('phone.name')); + + function getNames() { + return phoneNameColumn.map(function(elem: ElementFinder) { + return elem.getText(); + }); + } + + queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter + + expect(getNames()).toEqual([ + 'Motorola XOOM\u2122 with Wi-Fi', + 'MOTOROLA XOOM\u2122' + ]); + + nameOption.click(); + + expect(getNames()).toEqual([ + 'MOTOROLA XOOM\u2122', + 'Motorola XOOM\u2122 with Wi-Fi' + ]); + }); + + it('should render phone specific links', function() { + let query = element(by.model('$ctrl.query')); + query.sendKeys('nexus'); + + element.all(by.css('.phones li a')).first().click(); + expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s'); + }); + + }); + + describe('View: Phone detail', function() { + + beforeEach(function() { + browser.get('index.html#!/phones/nexus-s'); + }); + + it('should display the `nexus-s` page', function() { + expect(element(by.binding('$ctrl.phone.name')).getText()).toBe('Nexus S'); + }); + + it('should display the first phone image as the main phone image', function() { + let mainImage = element(by.css('img.phone.selected')); + + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + it('should swap the main image when clicking on a thumbnail image', function() { + let mainImage = element(by.css('img.phone.selected')); + let thumbnails = element.all(by.css('.phone-thumbs img')); + + thumbnails.get(2).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); + + thumbnails.get(0).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/.gitignore b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/.gitignore new file mode 100644 index 0000000000..448efbe632 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/.gitignore @@ -0,0 +1 @@ +!karma.conf.ajs.js diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.animations.css b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.animations.css new file mode 100644 index 0000000000..175320b509 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.animations.css @@ -0,0 +1,67 @@ +/* Animate `ngRepeat` in `phoneList` component */ +.phone-list-item.ng-enter, +.phone-list-item.ng-leave, +.phone-list-item.ng-move { + overflow: hidden; + transition: 0.5s linear all; +} + +.phone-list-item.ng-enter, +.phone-list-item.ng-leave.ng-leave-active, +.phone-list-item.ng-move { + height: 0; + margin-bottom: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; +} + +.phone-list-item.ng-enter.ng-enter-active, +.phone-list-item.ng-leave, +.phone-list-item.ng-move.ng-move-active { + height: 120px; + margin-bottom: 20px; + opacity: 1; + padding-bottom: 4px; + padding-top: 15px; +} + +/* Animate view transitions with `ngView` */ +.view-container { + position: relative; +} + +.view-frame { + margin-top: 20px; +} + +.view-frame.ng-enter, +.view-frame.ng-leave { + background: white; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.view-frame.ng-enter { + animation: 1s fade-in; + z-index: 100; +} + +.view-frame.ng-leave { + animation: 1s fade-out; + z-index: 99; +} + +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} + +/* Older browsers might need vendor-prefixes for keyframes and animation! */ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.animations.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.animations.ts new file mode 100644 index 0000000000..f0739b6405 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.animations.ts @@ -0,0 +1,43 @@ +'use strict'; + +angular. + module('phonecatApp'). + animation('.phone', function phoneAnimationFactory() { + return { + addClass: animateIn, + removeClass: animateOut + }; + + function animateIn(element: JQuery, className: string, done: () => void) { + if (className !== 'selected') { return; } + + element.css({ + display: 'block', + position: 'absolute', + top: 500, + left: 0 + }).animate({ + top: 0 + }, done); + + return function animateInEnd(wasCanceled: boolean) { + if (wasCanceled) { element.stop(); } + }; + } + + function animateOut(element: JQuery, className: string, done: () => void) { + if (className !== 'selected') { return; } + + element.css({ + position: 'absolute', + top: 0, + left: 0 + }).animate({ + top: -500 + }, done); + + return function animateOutEnd(wasCanceled: boolean) { + if (wasCanceled) { element.stop(); } + }; + } + }); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.config.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.config.ts new file mode 100644 index 0000000000..1d16f67fbe --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.config.ts @@ -0,0 +1,18 @@ +// #docregion +angular. + module('phonecatApp'). + config(['$locationProvider', '$routeProvider', + function config($locationProvider: angular.ILocationProvider, + $routeProvider: angular.route.IRouteProvider) { + $locationProvider.hashPrefix('!'); + + $routeProvider. + when('/phones', { + template: '' + }). + when('/phones/:phoneId', { + template: '' + }). + otherwise('/phones'); + } + ]); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.css b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.css new file mode 100644 index 0000000000..f4b45b02a5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.css @@ -0,0 +1,93 @@ +body { + padding: 20px; +} + +h1 { + border-bottom: 1px solid gray; + margin-top: 0; +} + +/* View: Phone list */ +.phones { + list-style: none; +} + +.phones li { + clear: both; + height: 115px; + padding-top: 15px; +} + +.thumb { + float: left; + height: 100px; + margin: -0.5em 1em 1.5em 0; + padding-bottom: 1em; + width: 100px; +} + +/* View: Phone detail */ +.phone { + background-color: white; + display: none; + float: left; + height: 400px; + margin-bottom: 2em; + margin-right: 3em; + padding: 2em; + width: 400px; +} + +.phone:first-child { + display: block; +} + +.phone-images { + background-color: white; + float: left; + height: 450px; + overflow: hidden; + position: relative; + width: 450px; +} + +.phone-thumbs { + list-style: none; + margin: 0; +} + +.phone-thumbs img { + height: 100px; + padding: 1em; + width: 100px; +} + +.phone-thumbs li { + background-color: white; + border: 1px solid black; + cursor: pointer; + display: inline-block; + margin: 1em; +} + +.specs { + clear: both; + list-style: none; + margin: 0; + padding: 0; +} + +.specs dt { + font-weight: bold; +} + +.specs > li { + display: inline-block; + vertical-align: top; + width: 200px; +} + +.specs > li > span { + font-size: 1.2em; + font-weight: bold; +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.module.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.module.ts new file mode 100644 index 0000000000..ab6d353eeb --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/app.module.ts @@ -0,0 +1,10 @@ +'use strict'; + +// Define the `phonecatApp` module +angular.module('phonecatApp', [ + 'ngAnimate', + 'ngRoute', + 'core', + 'phoneDetail', + 'phoneList', +]); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.spec.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.spec.ts new file mode 100644 index 0000000000..1b2d77c30c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.spec.ts @@ -0,0 +1,14 @@ +'use strict'; + +describe('checkmark', () => { + + beforeEach(angular.mock.module('core')); + + it('should convert boolean values to unicode checkmark or cross', + inject(function(checkmarkFilter: (v: boolean) => string) { + expect(checkmarkFilter(true)).toBe('\u2713'); + expect(checkmarkFilter(false)).toBe('\u2718'); + }) + ); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.ts new file mode 100644 index 0000000000..3114dc9681 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/checkmark/checkmark.filter.ts @@ -0,0 +1,8 @@ +// #docregion +angular. + module('core'). + filter('checkmark', function() { + return function(input: boolean) { + return input ? '\u2713' : '\u2718'; + }; + }); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/core.module.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/core.module.ts new file mode 100644 index 0000000000..84a91dc7a6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/core.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `core` module +angular.module('core', ['core.phone']); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.module.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.module.ts new file mode 100644 index 0000000000..0b6b348899 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `core.phone` module +angular.module('core.phone', ['ngResource']); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.spec.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.spec.ts new file mode 100644 index 0000000000..312036d71d --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.spec.ts @@ -0,0 +1,43 @@ +'use strict'; + +describe('Phone', () => { + let $httpBackend: angular.IHttpBackendService; + let Phone: any; + let phonesData = [ + {name: 'Phone X'}, + {name: 'Phone Y'}, + {name: 'Phone Z'} + ]; + + // Add a custom equality tester before each test + beforeEach(function() { + jasmine.addCustomEqualityTester(angular.equals); + }); + + // Load the module that contains the `Phone` service before each test + beforeEach(angular.mock.module('core.phone')); + + // Instantiate the service and "train" `$httpBackend` before each test + beforeEach(inject(function(_$httpBackend_: angular.IHttpBackendService, _Phone_: any) { + $httpBackend = _$httpBackend_; + $httpBackend.expectGET('phones/phones.json').respond(phonesData); + + Phone = _Phone_; + })); + + // Verify that there are no outstanding expectations or requests after each test + afterEach(() => { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + it('should fetch the phones data from `/phones/phones.json`', () => { + let phones = Phone.query(); + + expect(phones).toEqual([]); + + $httpBackend.flush(); + expect(phones).toEqual(phonesData); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts new file mode 100644 index 0000000000..c6204bc896 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/core/phone/phone.service.ts @@ -0,0 +1,14 @@ +// #docregion +angular. + module('core.phone'). + factory('Phone', ['$resource', + function($resource: angular.resource.IResourceService) { + return $resource('phones/:phoneId.json', {}, { + query: { + method: 'GET', + params: {phoneId: 'phones'}, + isArray: true + } + }); + } + ]); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/.gitkeep b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.0.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.0.jpg new file mode 100644 index 0000000000..7ce0dce4ee Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.1.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.1.jpg new file mode 100644 index 0000000000..ed8cad89fb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.2.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.2.jpg new file mode 100644 index 0000000000..c83529e0f9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.3.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.3.jpg new file mode 100644 index 0000000000..cd2c30280d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.4.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.4.jpg new file mode 100644 index 0000000000..b4d8472da8 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/dell-streak-7.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.0.jpg new file mode 100644 index 0000000000..2446159e93 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.1.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.1.jpg new file mode 100644 index 0000000000..867f207459 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.2.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.2.jpg new file mode 100644 index 0000000000..27d78338c4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.3.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.3.jpg new file mode 100644 index 0000000000..29459a68a4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-atrix-4g.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg new file mode 100644 index 0000000000..a6c993291e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg new file mode 100644 index 0000000000..400b89e2df Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg new file mode 100644 index 0000000000..86b55d28dd Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg new file mode 100644 index 0000000000..85ec293ae5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg new file mode 100644 index 0000000000..75ef1464cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg new file mode 100644 index 0000000000..4d42db4330 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.0.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.0.jpg new file mode 100644 index 0000000000..bf6954bbd5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.1.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.1.jpg new file mode 100644 index 0000000000..659688a47d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.2.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.2.jpg new file mode 100644 index 0000000000..ce0ff1002e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/motorola-xoom.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.0.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.0.jpg new file mode 100644 index 0000000000..0952bc79c2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.1.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.1.jpg new file mode 100644 index 0000000000..f33004dd7f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.2.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.2.jpg new file mode 100644 index 0000000000..c5c63621f1 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.3.jpg b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.3.jpg new file mode 100644 index 0000000000..e51f75b0ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/img/phones/nexus-s.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/index.html b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/index.html new file mode 100644 index 0000000000..82717fb7ee --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/index.html @@ -0,0 +1,35 @@ + + + + + Google Phone Gallery + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts new file mode 100644 index 0000000000..0998b638f0 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.spec.ts @@ -0,0 +1,38 @@ +// #docregion +describe('phoneDetail', () => { + + // Load the module that contains the `phoneDetail` component before each test + beforeEach(angular.mock.module('phoneDetail')); + + // Test the controller + describe('PhoneDetailController', () => { + let $httpBackend: angular.IHttpBackendService; + let ctrl: any; + let xyzPhoneData = { + name: 'phone xyz', + images: ['image/url1.png', 'image/url2.png'] + }; + + beforeEach(inject(($componentController: any, + _$httpBackend_: angular.IHttpBackendService, + $routeParams: angular.route.IRouteParamsService) => { + $httpBackend = _$httpBackend_; + $httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData); + + $routeParams['phoneId'] = 'xyz'; + + ctrl = $componentController('phoneDetail'); + })); + + it('should fetch the phone details', () => { + jasmine.addCustomEqualityTester(angular.equals); + + expect(ctrl.phone).toEqual({}); + + $httpBackend.flush(); + expect(ctrl.phone).toEqual(xyzPhoneData); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts new file mode 100644 index 0000000000..079b31e2c2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.component.ts @@ -0,0 +1,24 @@ +// #docregion +class PhoneDetailController { + phone: any; + mainImageUrl: string; + + static $inject = ['$routeParams', 'Phone']; + constructor($routeParams: angular.route.IRouteParamsService, Phone: any) { + let phoneId = $routeParams['phoneId']; + this.phone = Phone.get({phoneId}, (phone: any) => { + this.setImage(phone.images[0]); + }); + } + + setImage(imageUrl: string) { + this.mainImageUrl = imageUrl; + } +} + +angular. + module('phoneDetail'). + component('phoneDetail', { + templateUrl: 'phone-detail/phone-detail.template.html', + controller: PhoneDetailController + }); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.module.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.module.ts new file mode 100644 index 0000000000..fd7cb3b920 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.module.ts @@ -0,0 +1,7 @@ +'use strict'; + +// Define the `phoneDetail` module +angular.module('phoneDetail', [ + 'ngRoute', + 'core.phone' +]); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.template.html b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.template.html new file mode 100644 index 0000000000..f48657803c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-detail/phone-detail.template.html @@ -0,0 +1,117 @@ +
    + +
    + +

    {{$ctrl.phone.name}}

    + +

    {{$ctrl.phone.description}}

    + +
      +
    • + +
    • +
    + +
      +
    • + Availability and Networks +
      +
      Availability
      +
      {{availability}}
      +
      +
    • +
    • + Battery +
      +
      Type
      +
      {{$ctrl.phone.battery.type}}
      +
      Talk Time
      +
      {{$ctrl.phone.battery.talkTime}}
      +
      Standby time (max)
      +
      {{$ctrl.phone.battery.standbyTime}}
      +
      +
    • +
    • + Storage and Memory +
      +
      RAM
      +
      {{$ctrl.phone.storage.ram}}
      +
      Internal Storage
      +
      {{$ctrl.phone.storage.flash}}
      +
      +
    • +
    • + Connectivity +
      +
      Network Support
      +
      {{$ctrl.phone.connectivity.cell}}
      +
      WiFi
      +
      {{$ctrl.phone.connectivity.wifi}}
      +
      Bluetooth
      +
      {{$ctrl.phone.connectivity.bluetooth}}
      +
      Infrared
      +
      {{$ctrl.phone.connectivity.infrared | checkmark}}
      +
      GPS
      +
      {{$ctrl.phone.connectivity.gps | checkmark}}
      +
      +
    • +
    • + Android +
      +
      OS Version
      +
      {{$ctrl.phone.android.os}}
      +
      UI
      +
      {{$ctrl.phone.android.ui}}
      +
      +
    • +
    • + Size and Weight +
      +
      Dimensions
      +
      {{dim}}
      +
      Weight
      +
      {{$ctrl.phone.sizeAndWeight.weight}}
      +
      +
    • +
    • + Display +
      +
      Screen size
      +
      {{$ctrl.phone.display.screenSize}}
      +
      Screen resolution
      +
      {{$ctrl.phone.display.screenResolution}}
      +
      Touch screen
      +
      {{$ctrl.phone.display.touchScreen | checkmark}}
      +
      +
    • +
    • + Hardware +
      +
      CPU
      +
      {{$ctrl.phone.hardware.cpu}}
      +
      USB
      +
      {{$ctrl.phone.hardware.usb}}
      +
      Audio / headphone jack
      +
      {{$ctrl.phone.hardware.audioJack}}
      +
      FM Radio
      +
      {{$ctrl.phone.hardware.fmRadio | checkmark}}
      +
      Accelerometer
      +
      {{$ctrl.phone.hardware.accelerometer | checkmark}}
      +
      +
    • +
    • + Camera +
      +
      Primary
      +
      {{$ctrl.phone.camera.primary}}
      +
      Features
      +
      {{$ctrl.phone.camera.features.join(', ')}}
      +
      +
    • +
    • + Additional Features +
      {{$ctrl.phone.additionalFeatures}}
      +
    • +
    diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.spec.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.spec.ts new file mode 100644 index 0000000000..19e1890817 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.spec.ts @@ -0,0 +1,36 @@ +'use strict'; + +describe('phoneList', () => { + + // Load the module that contains the `phoneList` component before each test + beforeEach(angular.mock.module('phoneList')); + + // Test the controller + describe('PhoneListController', () => { + let $httpBackend: angular.IHttpBackendService; + let ctrl: any; + + beforeEach(inject(($componentController: any, _$httpBackend_: angular.IHttpBackendService) => { + $httpBackend = _$httpBackend_; + $httpBackend.expectGET('phones/phones.json') + .respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]); + + ctrl = $componentController('phoneList'); + })); + + it('should create a `phones` property with 2 phones fetched with `$http`', () => { + jasmine.addCustomEqualityTester(angular.equals); + + expect(ctrl.phones).toEqual([]); + + $httpBackend.flush(); + expect(ctrl.phones).toEqual([{name: 'Nexus S'}, {name: 'Motorola DROID'}]); + }); + + it('should set a default value for the `orderProp` property', () => { + expect(ctrl.orderProp).toBe('age'); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.ts new file mode 100644 index 0000000000..e2f2855ae6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.component.ts @@ -0,0 +1,20 @@ +// #docregion +class PhoneListController { + phones: any[]; + orderProp: string; + query: string; + + static $inject = ['Phone']; + constructor(Phone: any) { + this.phones = Phone.query(); + this.orderProp = 'age'; + } + +} + +angular. + module('phoneList'). + component('phoneList', { + templateUrl: 'phone-list/phone-list.template.html', + controller: PhoneListController + }); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.module.ts b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.module.ts new file mode 100644 index 0000000000..8ade7c5b88 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `phoneList` module +angular.module('phoneList', ['core.phone']); diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.template.html b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.template.html new file mode 100644 index 0000000000..90548f9f91 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phone-list/phone-list.template.html @@ -0,0 +1,36 @@ +
    +
    +
    + + +

    + Search: + +

    + +

    + Sort by: + +

    + +
    +
    + + + + +
    +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/dell-streak-7.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/dell-streak-7.json new file mode 100644 index 0000000000..a32eb6ff98 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/dell-streak-7.json @@ -0,0 +1,64 @@ +{ + "additionalFeatures": "Front Facing 1.3MP Camera", + "android": { + "os": "Android 2.2", + "ui": "Dell Stage" + }, + "availability": [ + "T-Mobile" + ], + "battery": { + "standbyTime": "", + "talkTime": "", + "type": "Lithium Ion (Li-Ion) (2780 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "T-mobile HSPA+ @ 2100/1900/AWS/850 MHz", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g" + }, + "description": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around. Android\u2122 2.2-based tablet with over-the-air upgrade capability for future OS releases. A vibrant 7-inch, multitouch display with full Adobe\u00ae Flash 10.1 pre-installed. Includes a 1.3 MP front-facing camera for face-to-face chats on popular services such as Qik or Skype. 16 GB of internal storage, plus Wi-Fi, Bluetooth and built-in GPS keeps you in touch with the world around you. Connect on your terms. Save with 2-year contract or flexibility with prepaid pay-as-you-go plans", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "7.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "nVidia Tegra T20", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "dell-streak-7", + "images": [ + "img/phones/dell-streak-7.0.jpg", + "img/phones/dell-streak-7.1.jpg", + "img/phones/dell-streak-7.2.jpg", + "img/phones/dell-streak-7.3.jpg", + "img/phones/dell-streak-7.4.jpg" + ], + "name": "Dell Streak 7", + "sizeAndWeight": { + "dimensions": [ + "199.9 mm (w)", + "119.8 mm (h)", + "12.4 mm (d)" + ], + "weight": "450.0 grams" + }, + "storage": { + "flash": "16000MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-atrix-4g.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-atrix-4g.json new file mode 100644 index 0000000000..ccca00e3b2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-atrix-4g.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "", + "android": { + "os": "Android 2.2", + "ui": "MOTOBLUR" + }, + "availability": [ + "AT&T" + ], + "battery": { + "standbyTime": "400 hours", + "talkTime": "5 hours", + "type": "Lithium Ion (Li-Ion) (1930 mAH)" + }, + "camera": { + "features": [ + "" + ], + "primary": "" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "WCDMA 850/1900/2100, GSM 850/900/1800/1900, HSDPA 14Mbps (Category 10) Edge Class 12, GPRS Class 12, eCompass, AGPS", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA ATRIX 4G gives you dual-core processing power and the revolutionary webtop application. With webtop and a compatible Motorola docking station, sold separately, you can surf the Internet with a full Firefox browser, create and edit docs, or access multimedia on a large screen almost anywhere.", + "display": { + "screenResolution": "QHD (960 x 540)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-atrix-4g", + "images": [ + "img/phones/motorola-atrix-4g.0.jpg", + "img/phones/motorola-atrix-4g.1.jpg", + "img/phones/motorola-atrix-4g.2.jpg", + "img/phones/motorola-atrix-4g.3.jpg" + ], + "name": "MOTOROLA ATRIX\u2122 4G", + "sizeAndWeight": { + "dimensions": [ + "63.5 mm (w)", + "117.75 mm (h)", + "10.95 mm (d)" + ], + "weight": "135.0 grams" + }, + "storage": { + "flash": "", + "ram": "" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-xoom-with-wi-fi.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-xoom-with-wi-fi.json new file mode 100644 index 0000000000..4ba9c8d5b5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-xoom-with-wi-fi.json @@ -0,0 +1,65 @@ +{ + "additionalFeatures": "Sensors: proximity, ambient light, barometer, gyroscope", + "android": { + "os": "Android 3.0", + "ui": "Honeycomb" + }, + "availability": [ + "" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other ( mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Motorola XOOM with Wi-Fi has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom-with-wi-fi", + "images": [ + "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "img/phones/motorola-xoom-with-wi-fi.1.jpg", + "img/phones/motorola-xoom-with-wi-fi.2.jpg", + "img/phones/motorola-xoom-with-wi-fi.3.jpg", + "img/phones/motorola-xoom-with-wi-fi.4.jpg", + "img/phones/motorola-xoom-with-wi-fi.5.jpg" + ], + "name": "Motorola XOOM\u2122 with Wi-Fi", + "sizeAndWeight": { + "dimensions": [ + "249.1 mm (w)", + "167.8 mm (h)", + "12.9 mm (d)" + ], + "weight": "708.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-xoom.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-xoom.json new file mode 100644 index 0000000000..f0f0c8711d --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/motorola-xoom.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "Front-facing camera. Sensors: proximity, ambient light, barometer, gyroscope.", + "android": { + "os": "Android 3.0", + "ui": "Android" + }, + "availability": [ + "Verizon" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other (3250 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "CDMA 800 /1900 LTE 700, Rx diversity in all bands", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA XOOM has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom", + "images": [ + "img/phones/motorola-xoom.0.jpg", + "img/phones/motorola-xoom.1.jpg", + "img/phones/motorola-xoom.2.jpg" + ], + "name": "MOTOROLA XOOM\u2122", + "sizeAndWeight": { + "dimensions": [ + "249.0 mm (w)", + "168.0 mm (h)", + "12.7 mm (d)" + ], + "weight": "726.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/nexus-s.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/nexus-s.json new file mode 100644 index 0000000000..5e712e2ff8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/nexus-s.json @@ -0,0 +1,69 @@ +{ + "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope, Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", + "android": { + "os": "Android 2.3", + "ui": "Android" + }, + "availability": [ + "M1,", + "O2,", + "Orange,", + "Singtel,", + "StarHub,", + "T-Mobile,", + "Vodafone" + ], + "battery": { + "standbyTime": "428 hours", + "talkTime": "6 hours", + "type": "Lithium Ion (Li-Ion) (1500 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "Quad-band GSM: 850, 900, 1800, 1900\r\nTri-band HSPA: 900, 2100, 1700\r\nHSPA type: HSDPA (7.2Mbps) HSUPA (5.76Mbps)", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Nexus S is the next generation of Nexus devices, co-developed by Google and Samsung. The latest Android platform (Gingerbread), paired with a 1 GHz Hummingbird processor and 16GB of memory, makes Nexus S one of the fastest phones on the market. It comes pre-installed with the best of Google apps and enabled with new and popular features like true multi-tasking, Wi-Fi hotspot, Internet Calling, NFC support, and full web browsing. With this device, users will also be the first to receive software upgrades and new Google mobile apps as soon as they become available. For more details, visit http://www.google.com/nexus.", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1GHz Cortex A8 (Hummingbird) processor", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "nexus-s", + "images": [ + "img/phones/nexus-s.0.jpg", + "img/phones/nexus-s.1.jpg", + "img/phones/nexus-s.2.jpg", + "img/phones/nexus-s.3.jpg" + ], + "name": "Nexus S", + "sizeAndWeight": { + "dimensions": [ + "63.0 mm (w)", + "123.9 mm (h)", + "10.88 mm (d)" + ], + "weight": "129.0 grams" + }, + "storage": { + "flash": "16384MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/phones.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/phones.json new file mode 100644 index 0000000000..339b94fbb5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/app/phones/phones.json @@ -0,0 +1,155 @@ +[ + { + "age": 0, + "id": "motorola-xoom-with-wi-fi", + "imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "name": "Motorola XOOM\u2122 with Wi-Fi", + "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 1, + "id": "motorola-xoom", + "imageUrl": "img/phones/motorola-xoom.0.jpg", + "name": "MOTOROLA XOOM\u2122", + "snippet": "The Next, Next Generation\n\nExperience the future with MOTOROLA XOOM, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 2, + "carrier": "AT&T", + "id": "motorola-atrix-4g", + "imageUrl": "img/phones/motorola-atrix-4g.0.jpg", + "name": "MOTOROLA ATRIX\u2122 4G", + "snippet": "MOTOROLA ATRIX 4G the world's most powerful smartphone." + }, + { + "age": 3, + "id": "dell-streak-7", + "imageUrl": "img/phones/dell-streak-7.0.jpg", + "name": "Dell Streak 7", + "snippet": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around." + }, + { + "age": 4, + "carrier": "Cellular South", + "id": "samsung-gem", + "imageUrl": "img/phones/samsung-gem.0.jpg", + "name": "Samsung Gem\u2122", + "snippet": "The Samsung Gem\u2122 brings you everything that you would expect and more from a touch display smart phone \u2013 more apps, more features and a more affordable price." + }, + { + "age": 5, + "carrier": "Dell", + "id": "dell-venue", + "imageUrl": "img/phones/dell-venue.0.jpg", + "name": "Dell Venue", + "snippet": "The Dell Venue; Your Personal Express Lane to Everything" + }, + { + "age": 6, + "carrier": "Best Buy", + "id": "nexus-s", + "imageUrl": "img/phones/nexus-s.0.jpg", + "name": "Nexus S", + "snippet": "Fast just got faster with Nexus S. A pure Google experience, Nexus S is the first phone to run Gingerbread (Android 2.3), the fastest version of Android yet." + }, + { + "age": 7, + "carrier": "Cellular South", + "id": "lg-axis", + "imageUrl": "img/phones/lg-axis.0.jpg", + "name": "LG Axis", + "snippet": "Android Powered, Google Maps Navigation, 5 Customizable Home Screens" + }, + { + "age": 8, + "id": "samsung-galaxy-tab", + "imageUrl": "img/phones/samsung-galaxy-tab.0.jpg", + "name": "Samsung Galaxy Tab\u2122", + "snippet": "Feel Free to Tab\u2122. The Samsung Galaxy Tab\u2122 brings you an ultra-mobile entertainment experience through its 7\u201d display, high-power processor and Adobe\u00ae Flash\u00ae Player compatibility." + }, + { + "age": 9, + "carrier": "Cellular South", + "id": "samsung-showcase-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg", + "name": "Samsung Showcase\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Showcase\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance, even outdoors" + }, + { + "age": 10, + "carrier": "Verizon", + "id": "droid-2-global-by-motorola", + "imageUrl": "img/phones/droid-2-global-by-motorola.0.jpg", + "name": "DROID\u2122 2 Global by Motorola", + "snippet": "The first smartphone with a 1.2 GHz processor and global capabilities." + }, + { + "age": 11, + "carrier": "Verizon", + "id": "droid-pro-by-motorola", + "imageUrl": "img/phones/droid-pro-by-motorola.0.jpg", + "name": "DROID\u2122 Pro by Motorola", + "snippet": "The next generation of DOES." + }, + { + "age": 12, + "carrier": "AT&T", + "id": "motorola-bravo-with-motoblur", + "imageUrl": "img/phones/motorola-bravo-with-motoblur.0.jpg", + "name": "MOTOROLA BRAVO\u2122 with MOTOBLUR\u2122", + "snippet": "An experience to cheer about." + }, + { + "age": 13, + "carrier": "T-Mobile", + "id": "motorola-defy-with-motoblur", + "imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg", + "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", + "snippet": "Are you ready for everything life throws your way?" + }, + { + "age": 14, + "carrier": "T-Mobile", + "id": "t-mobile-mytouch-4g", + "imageUrl": "img/phones/t-mobile-mytouch-4g.0.jpg", + "name": "T-Mobile myTouch 4G", + "snippet": "The T-Mobile myTouch 4G is a premium smartphone designed to deliver blazing fast 4G speeds so that you can video chat from practically anywhere, with or without Wi-Fi." + }, + { + "age": 15, + "carrier": "US Cellular", + "id": "samsung-mesmerize-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg", + "name": "Samsung Mesmerize\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Mesmerize\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance,even outdoors" + }, + { + "age": 16, + "carrier": "Sprint", + "id": "sanyo-zio", + "imageUrl": "img/phones/sanyo-zio.0.jpg", + "name": "SANYO ZIO", + "snippet": "The Sanyo Zio by Kyocera is an Android smartphone with a combination of ultra-sleek styling, strong performance and unprecedented value." + }, + { + "age": 17, + "id": "samsung-transform", + "imageUrl": "img/phones/samsung-transform.0.jpg", + "name": "Samsung Transform\u2122", + "snippet": "The Samsung Transform\u2122 brings you a fun way to customize your Android powered touch screen phone to just the way you like it through your favorite themed \u201cSprint ID Service Pack\u201d." + }, + { + "age": 18, + "id": "t-mobile-g2", + "imageUrl": "img/phones/t-mobile-g2.0.jpg", + "name": "T-Mobile G2", + "snippet": "The T-Mobile G2 with Google is the first smartphone built for 4G speeds on T-Mobile's new network. Get the information you need, faster than you ever thought possible." + }, + { + "age": 19, + "id": "motorola-charm-with-motoblur", + "imageUrl": "img/phones/motorola-charm-with-motoblur.0.jpg", + "name": "Motorola CHARM\u2122 with MOTOBLUR\u2122", + "snippet": "Motorola CHARM fits easily in your pocket or palm. Includes MOTOBLUR service." + } +] diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/example-config.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/example-config.json new file mode 100644 index 0000000000..a8781b9a31 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/example-config.json @@ -0,0 +1,4 @@ +{ + "build": "build:upgrade", + "run": "serve:upgrade" +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/karma.conf.ajs.js b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/karma.conf.ajs.js new file mode 100644 index 0000000000..dc829d1983 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/karma.conf.ajs.js @@ -0,0 +1,32 @@ +//jshint strict: false +module.exports = function(config) { + config.set({ + + basePath: './app', + + files: [ + 'https://code.angularjs.org/1.5.5/angular.js', + 'https://code.angularjs.org/1.5.5/angular-animate.js', + 'https://code.angularjs.org/1.5.5/angular-resource.js', + 'https://code.angularjs.org/1.5.5/angular-route.js', + 'https://code.angularjs.org/1.5.5/angular-mocks.js', + '**/*.module.js', + '*!(.module|.spec).js', + '!(bower_components)/**/*!(.module|.spec).js', + '**/*.spec.js' + ], + + autoWatch: true, + + frameworks: ['jasmine'], + + browsers: ['Chrome', 'Firefox'], + + plugins: [ + 'karma-chrome-launcher', + 'karma-firefox-launcher', + 'karma-jasmine' + ] + + }); +}; diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/run-unit-tests.sh b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/run-unit-tests.sh new file mode 100755 index 0000000000..239e5ff7d7 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/run-unit-tests.sh @@ -0,0 +1,7 @@ +## The boilerplate Karma configuration won't work with AngularJS tests since +## a specific loading configuration is needed for them. +## We keep one in karma.conf.ajs.js. This scripts runs the AngularJS tests with +## that config. + +PATH=$(npm bin):$PATH +tsc && karma start karma.conf.ajs.js diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/tsconfig.ajs.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/tsconfig.ajs.json new file mode 100644 index 0000000000..53da36ca95 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/tsconfig.ajs.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "removeComments": false, + "noImplicitAny": false, + "suppressImplicitAnyIndexErrors": true + } +} diff --git a/public/docs/_examples/upgrade-phonecat-1-typescript/ts/tsconfig.json b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/tsconfig.json new file mode 100644 index 0000000000..be11d1eb49 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-1-typescript/ts/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*", + "**/*-aot.ts", + "aot/**/*" + ] +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/README.md b/public/docs/_examples/upgrade-phonecat-2-hybrid/README.md new file mode 100644 index 0000000000..b005739148 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/README.md @@ -0,0 +1,34 @@ +This is the Angular Phonecat application adjusted to fit our boilerplate project +structure. + +The following changes from vanilla Phonecat are applied: + +* Karma config for unit tests is in karma.conf.ajs.js because the boilerplate + Karma config is not compatible with the way AngularJS tests need to be run. + The shell script run-unit-tests.sh can be used to run the unit tests. +* There's a `package.ajs.json`, which is not used to run anything but only to + show an example of changing the PhoneCat http-server root path. +* Also for the Karma shim, there is a `karma-test-shim.1.js` file which isn't + used but is shown in the test appendix. +* Instead of using Bower, AngularJS and its dependencies are fetched from a CDN + in index.html and karma.conf.ajs.js. +* E2E tests have been moved to the parent directory, where `run-e2e-tests` can + discover and run them along with all the other examples. +* Most of the phone JSON and image data removed in the interest of keeping + repo weight down. Keeping enough to retain testability of the app. + +## Running the app + +Start like any example + + npm run start + +## Running unit tests + + ./run-unit-tests.sh + +## Running E2E tests + +Like for any example (at the project root): + + gulp run-e2e-tests --filter=phonecat-2 diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts new file mode 100644 index 0000000000..2ec8e37977 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/e2e-spec.ts @@ -0,0 +1,107 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; +import { setProtractorToHybridMode } from '../protractor-helpers'; + +// Angular E2E Testing Guide: +// https://docs.angularjs.org/guide/e2e-testing + +describe('PhoneCat Application', function() { + + beforeAll(function () { + setProtractorToHybridMode(); + }); + + it('should redirect `index.html` to `index.html#!/phones', function() { + browser.get('index.html'); + expect(browser.getLocationAbsUrl()).toBe('/phones'); + }); + + describe('View: Phone list', function() { + + beforeEach(function() { + browser.get('index.html#!/phones'); + }); + + it('should filter the phone list as a user types into the search box', function() { + let phoneList = element.all(by.css('.phones li')); + let query = element(by.css('input')); + + expect(phoneList.count()).toBe(20); + + query.sendKeys('nexus'); + expect(phoneList.count()).toBe(1); + + query.clear(); + query.sendKeys('motorola'); + expect(phoneList.count()).toBe(8); + }); + + it('should be possible to control phone order via the drop-down menu', function() { + let queryField = element(by.css('input')); + let orderSelect = element(by.css('select')); + let nameOption = orderSelect.element(by.css('option[value="name"]')); + let phoneNameColumn = element.all(by.css('.phones .name')); + + function getNames() { + return phoneNameColumn.map(function(elem) { + return elem.getText(); + }); + } + + queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter + + expect(getNames()).toEqual([ + 'Motorola XOOM\u2122 with Wi-Fi', + 'MOTOROLA XOOM\u2122' + ]); + + nameOption.click(); + + expect(getNames()).toEqual([ + 'MOTOROLA XOOM\u2122', + 'Motorola XOOM\u2122 with Wi-Fi' + ]); + }); + + it('should render phone specific links', function() { + let query = element(by.css('input')); + query.sendKeys('nexus'); + + element.all(by.css('.phones li a')).first().click(); + browser.sleep(200); // Not sure why this is needed but it is. The route change works fine. + expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s'); + }); + + }); + + describe('View: Phone detail', function() { + + beforeEach(function() { + browser.get('index.html#!/phones/nexus-s'); + }); + + it('should display the `nexus-s` page', function() { + expect(element(by.css('h1')).getText()).toBe('Nexus S'); + }); + + it('should display the first phone image as the main phone image', function() { + let mainImage = element(by.css('img.phone.selected')); + + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + it('should swap the main image when clicking on a thumbnail image', function() { + let mainImage = element(by.css('img.phone.selected')); + let thumbnails = element.all(by.css('.phone-thumbs img')); + + thumbnails.get(2).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); + + thumbnails.get(0).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/.gitignore b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/.gitignore new file mode 100644 index 0000000000..927d62d641 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/.gitignore @@ -0,0 +1,8 @@ +aot/**/* +!aot/index.html +dist +!app/tsconfig.json +!rollup-config.js +!karma.conf.ajs.js +!copy-dist-files.js +!systemjs.config.1.js diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot/index.html b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot/index.html new file mode 100644 index 0000000000..fdc9584928 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/aot/index.html @@ -0,0 +1,40 @@ + + + + + + + + + Google Phone Gallery + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/ajs-upgraded-providers.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/ajs-upgraded-providers.ts new file mode 100644 index 0000000000..f6e1654d74 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/ajs-upgraded-providers.ts @@ -0,0 +1,14 @@ +// #docregion +export abstract class RouteParams { + [key: string]: string; +} + +export function routeParamsFactory(i: any) { + return i.get('$routeParams'); +} + +export const routeParamsProvider = { + provide: RouteParams, + useFactory: routeParamsFactory, + deps: ['$injector'] +}; diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.animations.css b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.animations.css new file mode 100644 index 0000000000..175320b509 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.animations.css @@ -0,0 +1,67 @@ +/* Animate `ngRepeat` in `phoneList` component */ +.phone-list-item.ng-enter, +.phone-list-item.ng-leave, +.phone-list-item.ng-move { + overflow: hidden; + transition: 0.5s linear all; +} + +.phone-list-item.ng-enter, +.phone-list-item.ng-leave.ng-leave-active, +.phone-list-item.ng-move { + height: 0; + margin-bottom: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; +} + +.phone-list-item.ng-enter.ng-enter-active, +.phone-list-item.ng-leave, +.phone-list-item.ng-move.ng-move-active { + height: 120px; + margin-bottom: 20px; + opacity: 1; + padding-bottom: 4px; + padding-top: 15px; +} + +/* Animate view transitions with `ngView` */ +.view-container { + position: relative; +} + +.view-frame { + margin-top: 20px; +} + +.view-frame.ng-enter, +.view-frame.ng-leave { + background: white; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.view-frame.ng-enter { + animation: 1s fade-in; + z-index: 100; +} + +.view-frame.ng-leave { + animation: 1s fade-out; + z-index: 99; +} + +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} + +/* Older browsers might need vendor-prefixes for keyframes and animation! */ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.animations.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.animations.ts new file mode 100644 index 0000000000..f0739b6405 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.animations.ts @@ -0,0 +1,43 @@ +'use strict'; + +angular. + module('phonecatApp'). + animation('.phone', function phoneAnimationFactory() { + return { + addClass: animateIn, + removeClass: animateOut + }; + + function animateIn(element: JQuery, className: string, done: () => void) { + if (className !== 'selected') { return; } + + element.css({ + display: 'block', + position: 'absolute', + top: 500, + left: 0 + }).animate({ + top: 0 + }, done); + + return function animateInEnd(wasCanceled: boolean) { + if (wasCanceled) { element.stop(); } + }; + } + + function animateOut(element: JQuery, className: string, done: () => void) { + if (className !== 'selected') { return; } + + element.css({ + position: 'absolute', + top: 0, + left: 0 + }).animate({ + top: -500 + }, done); + + return function animateOutEnd(wasCanceled: boolean) { + if (wasCanceled) { element.stop(); } + }; + } + }); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.config.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.config.ts new file mode 100644 index 0000000000..458ed94250 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.config.ts @@ -0,0 +1,19 @@ +'use strict'; + +angular. + module('phonecatApp'). + config(['$locationProvider', '$routeProvider', + function config($locationProvider: angular.ILocationProvider, + $routeProvider: angular.route.IRouteProvider) { + $locationProvider.hashPrefix('!'); + + $routeProvider. + when('/phones', { + template: '' + }). + when('/phones/:phoneId', { + template: '' + }). + otherwise('/phones'); + } + ]); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.css b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.css new file mode 100644 index 0000000000..f4b45b02a5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.css @@ -0,0 +1,93 @@ +body { + padding: 20px; +} + +h1 { + border-bottom: 1px solid gray; + margin-top: 0; +} + +/* View: Phone list */ +.phones { + list-style: none; +} + +.phones li { + clear: both; + height: 115px; + padding-top: 15px; +} + +.thumb { + float: left; + height: 100px; + margin: -0.5em 1em 1.5em 0; + padding-bottom: 1em; + width: 100px; +} + +/* View: Phone detail */ +.phone { + background-color: white; + display: none; + float: left; + height: 400px; + margin-bottom: 2em; + margin-right: 3em; + padding: 2em; + width: 400px; +} + +.phone:first-child { + display: block; +} + +.phone-images { + background-color: white; + float: left; + height: 450px; + overflow: hidden; + position: relative; + width: 450px; +} + +.phone-thumbs { + list-style: none; + margin: 0; +} + +.phone-thumbs img { + height: 100px; + padding: 1em; + width: 100px; +} + +.phone-thumbs li { + background-color: white; + border: 1px solid black; + cursor: pointer; + display: inline-block; + margin: 1em; +} + +.specs { + clear: both; + list-style: none; + margin: 0; + padding: 0; +} + +.specs dt { + font-weight: bold; +} + +.specs > li { + display: inline-block; + vertical-align: top; + width: 200px; +} + +.specs > li > span { + font-size: 1.2em; + font-weight: bold; +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ajs.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ajs.ts new file mode 100644 index 0000000000..089c3c7d85 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ajs.ts @@ -0,0 +1,11 @@ +// #docregion +'use strict'; + +// Define the `phonecatApp` AngularJS module +angular.module('phonecatApp', [ + 'ngAnimate', + 'ngRoute', + 'core', + 'phoneDetail', + 'phoneList', +]); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts new file mode 100644 index 0000000000..ea570e3cbf --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/app.module.ts @@ -0,0 +1,73 @@ +// #docplaster +// #docregion bare +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +// #enddocregion bare +// #docregion upgrademodule +import { UpgradeModule } from '@angular/upgrade/static'; +// #enddocregion upgrademodule +// #docregion httpmodule +import { HttpModule } from '@angular/http'; +// #enddocregion httpmodule +// #docregion phonelist +import { FormsModule } from '@angular/forms'; +// #enddocregion phonelist +// #docregion phone +import { Phone } from './core/phone/phone.service'; +// #enddocregion phone +// #docregion checkmarkpipe +import { CheckmarkPipe } from './core/checkmark/checkmark.pipe'; +// #enddocregion checkmarkpipe +// #docregion phonelist +import { PhoneListComponent } from './phone-list/phone-list.component'; +// #enddocregion phonelist +// #docregion routeparams +import { routeParamsProvider } from './ajs-upgraded-providers'; +// #enddocregion routeparams +// #docregion phonedetail +import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; +// #enddocregion phonedetail + +// #docregion bare, upgrademodule, httpmodule, phone, phonelist, phonedetail, checkmarkpipe + +@NgModule({ + imports: [ + BrowserModule, + // #enddocregion bare + UpgradeModule, + // #enddocregion upgrademodule + HttpModule, + // #enddocregion httpmodule, phone + FormsModule, + // #docregion bare, upgrademodule, httpmodule, phone + ], + // #enddocregion bare, upgrademodule, httpmodule, phone + declarations: [ + PhoneListComponent, + // #enddocregion phonelist + PhoneDetailComponent, + // #enddocregion phonedetail + CheckmarkPipe + // #docregion phonelist, phonedetail + ], + entryComponents: [ + PhoneListComponent, + // #enddocregion phonelist + PhoneDetailComponent + ], + // #docregion phone, routeparams + providers: [ + Phone, + // #enddocregion phone + routeParamsProvider + // #docregion phone + ] + // #enddocregion routeparams +// #docregion bare, upgrademodule, httpmodule, phonelist +}) +export class AppModule { + // #enddocregion bare + ngDoBootstrap() {} + // #docregion bare +} +// #enddocregion bare, upgrademodule, httpmodule, phone, phonelist, phonedetail, checkmarkpipe diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts new file mode 100644 index 0000000000..f7485ec2ba --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.spec.ts @@ -0,0 +1,11 @@ +// #docregion +import { CheckmarkPipe } from './checkmark.pipe'; + +describe('CheckmarkPipe', function() { + + it('should convert boolean values to unicode checkmark or cross', function () { + const checkmarkPipe = new CheckmarkPipe(); + expect(checkmarkPipe.transform(true)).toBe('\u2713'); + expect(checkmarkPipe.transform(false)).toBe('\u2718'); + }); +}); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts new file mode 100644 index 0000000000..888017e15c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/checkmark/checkmark.pipe.ts @@ -0,0 +1,9 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'checkmark'}) +export class CheckmarkPipe implements PipeTransform { + transform(input: boolean) { + return input ? '\u2713' : '\u2718'; + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/core.module.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/core.module.ts new file mode 100644 index 0000000000..84a91dc7a6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/core.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `core` module +angular.module('core', ['core.phone']); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.module.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.module.ts new file mode 100644 index 0000000000..0b6b348899 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `core.phone` module +angular.module('core.phone', ['ngResource']); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts new file mode 100644 index 0000000000..a0c1655c20 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.spec.ts @@ -0,0 +1,51 @@ +// #docregion +import { inject, TestBed } from '@angular/core/testing'; +import { + Http, + BaseRequestOptions, + ResponseOptions, + Response +} from '@angular/http'; +import { MockBackend, MockConnection } from '@angular/http/testing'; +import { Phone, PhoneData } from './phone.service'; + +describe('Phone', function() { + let phone: Phone; + let phonesData: PhoneData[] = [ + {name: 'Phone X', snippet: '', images: []}, + {name: 'Phone Y', snippet: '', images: []}, + {name: 'Phone Z', snippet: '', images: []} + ]; + let mockBackend: MockBackend; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + Phone, + MockBackend, + BaseRequestOptions, + { provide: Http, + useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options), + deps: [MockBackend, BaseRequestOptions] + } + ] + }); + }); + + beforeEach(inject([MockBackend, Phone], (_mockBackend_: MockBackend, _phone_: Phone) => { + mockBackend = _mockBackend_; + phone = _phone_; + })); + + it('should fetch the phones data from `/phones/phones.json`', (done: () => void) => { + mockBackend.connections.subscribe((conn: MockConnection) => { + conn.mockRespond(new Response(new ResponseOptions({body: JSON.stringify(phonesData)}))); + }); + phone.query().subscribe(result => { + expect(result).toEqual(phonesData); + done(); + }); + }); + +}); + diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts new file mode 100644 index 0000000000..c4673475fb --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/core/phone/phone.service.ts @@ -0,0 +1,42 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +// #docregion downgrade-injectable +declare var angular: angular.IAngularStatic; +import { downgradeInjectable } from '@angular/upgrade/static'; +// #enddocregion downgrade-injectable + +import 'rxjs/add/operator/map'; + +// #docregion phonedata-interface +export interface PhoneData { + name: string; + snippet: string; + images: string[]; +} +// #enddocregion phonedata-interface + +// #docregion fullclass +// #docregion classdef, downgrade-injectable +@Injectable() +export class Phone { +// #enddocregion classdef, downgrade-injectable + constructor(private http: Http) { } + query(): Observable { + return this.http.get(`phones/phones.json`) + .map((res: Response) => res.json()); + } + get(id: string): Observable { + return this.http.get(`phones/${id}.json`) + .map((res: Response) => res.json()); + } +// #docregion classdef, downgrade-injectable +} +// #enddocregion classdef +// #enddocregion fullclass + +angular.module('core.phone') + .factory('phone', downgradeInjectable(Phone)); +// #enddocregion downgrade-injectable diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/.gitkeep b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.0.jpg new file mode 100644 index 0000000000..7ce0dce4ee Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.1.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.1.jpg new file mode 100644 index 0000000000..ed8cad89fb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.2.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.2.jpg new file mode 100644 index 0000000000..c83529e0f9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.3.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.3.jpg new file mode 100644 index 0000000000..cd2c30280d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.4.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.4.jpg new file mode 100644 index 0000000000..b4d8472da8 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-streak-7.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-venue.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-venue.0.jpg new file mode 100644 index 0000000000..b4cb4eb25f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/dell-venue.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/droid-2-global-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/droid-2-global-by-motorola.0.jpg new file mode 100644 index 0000000000..60700a2ab3 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/droid-2-global-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/droid-pro-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/droid-pro-by-motorola.0.jpg new file mode 100644 index 0000000000..c7710de986 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/droid-pro-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/lg-axis.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/lg-axis.0.jpg new file mode 100644 index 0000000000..55e5a23bb2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/lg-axis.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.0.jpg new file mode 100644 index 0000000000..2446159e93 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.1.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.1.jpg new file mode 100644 index 0000000000..867f207459 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.2.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.2.jpg new file mode 100644 index 0000000000..27d78338c4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.3.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.3.jpg new file mode 100644 index 0000000000..29459a68a4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-atrix-4g.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg new file mode 100644 index 0000000000..e452ae7e7c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg new file mode 100644 index 0000000000..21e4b8d741 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg new file mode 100644 index 0000000000..c7c5e3ba0c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg new file mode 100644 index 0000000000..a6c993291e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg new file mode 100644 index 0000000000..400b89e2df Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg new file mode 100644 index 0000000000..86b55d28dd Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg new file mode 100644 index 0000000000..85ec293ae5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg new file mode 100644 index 0000000000..75ef1464cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg new file mode 100644 index 0000000000..4d42db4330 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.0.jpg new file mode 100644 index 0000000000..bf6954bbd5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.1.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.1.jpg new file mode 100644 index 0000000000..659688a47d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.2.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.2.jpg new file mode 100644 index 0000000000..ce0ff1002e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/motorola-xoom.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.0.jpg new file mode 100644 index 0000000000..0952bc79c2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.1.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.1.jpg new file mode 100644 index 0000000000..f33004dd7f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.2.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.2.jpg new file mode 100644 index 0000000000..c5c63621f1 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.3.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.3.jpg new file mode 100644 index 0000000000..e51f75b0ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/nexus-s.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-galaxy-tab.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-galaxy-tab.0.jpg new file mode 100644 index 0000000000..3750377ad9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-galaxy-tab.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-gem.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-gem.0.jpg new file mode 100644 index 0000000000..0d5024a026 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-gem.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-transform.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-transform.0.jpg new file mode 100644 index 0000000000..0e3107caf5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/samsung-transform.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/sanyo-zio.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/sanyo-zio.0.jpg new file mode 100644 index 0000000000..9eeb9b96ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/sanyo-zio.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/t-mobile-g2.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/t-mobile-g2.0.jpg new file mode 100644 index 0000000000..6b6c09e058 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/t-mobile-g2.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg new file mode 100644 index 0000000000..beba1f6827 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main-aot.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main-aot.ts new file mode 100644 index 0000000000..23a741c684 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main-aot.ts @@ -0,0 +1,10 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.documentElement, ['phonecatApp']); +}); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts new file mode 100644 index 0000000000..886e8ffac8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/main.ts @@ -0,0 +1,11 @@ +// #docregion bootstrap +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.documentElement, ['phonecatApp']); +}); +// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ajs.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ajs.ts new file mode 100644 index 0000000000..80282858c4 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ajs.ts @@ -0,0 +1,28 @@ +// #docregion +declare var angular: angular.IAngularStatic; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +class PhoneDetailController { + phone: PhoneData; + mainImageUrl: string; + + static $inject = ['$routeParams', 'phone']; + constructor($routeParams: angular.route.IRouteParamsService, phone: Phone) { + let phoneId = $routeParams['phoneId']; + phone.get(phoneId).subscribe(data => { + this.phone = data; + this.setImage(data.images[0]); + }); + } + + setImage(imageUrl: string) { + this.mainImageUrl = imageUrl; + } +} + +angular. + module('phoneDetail'). + component('phoneDetail', { + templateUrl: 'phone-detail/phone-detail.template.html', + controller: PhoneDetailController + }); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts new file mode 100644 index 0000000000..e3b9143a94 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.spec.ts @@ -0,0 +1,59 @@ +// #docregion +// #docregion activatedroute +import { ActivatedRoute } from '@angular/router'; + +// #enddocregion activatedroute +import { Observable } from 'rxjs/Rx'; + +import { async, TestBed } from '@angular/core/testing'; + +import { PhoneDetailComponent } from './phone-detail.component'; +import { Phone, PhoneData } from '../core/phone/phone.service'; +import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe'; + +function xyzPhoneData(): PhoneData { + return { + name: 'phone xyz', + snippet: '', + images: ['image/url1.png', 'image/url2.png'] + }; +} + +class MockPhone { + get(id: string): Observable { + return Observable.of(xyzPhoneData()); + } +} + +// #docregion activatedroute + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +// #enddocregion activatedroute + +describe('PhoneDetailComponent', () => { + + // #docregion activatedroute + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CheckmarkPipe, PhoneDetailComponent ], + providers: [ + { provide: Phone, useClass: MockPhone }, + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) } + ] + }) + .compileComponents(); + })); + // #enddocregion activatedroute + + it('should fetch phone detail', () => { + const fixture = TestBed.createComponent(PhoneDetailComponent); + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts new file mode 100644 index 0000000000..aa20ebb801 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.component.ts @@ -0,0 +1,41 @@ +// #docplaster +// #docregion +declare var angular: angular.IAngularStatic; +import { downgradeComponent } from '@angular/upgrade/static'; + +// #docregion initialclass +import { Component } from '@angular/core'; + +import { Phone, PhoneData } from '../core/phone/phone.service'; +// #enddocregion initialclass +import { RouteParams } from '../ajs-upgraded-providers'; + +// #docregion initialclass +@Component({ + selector: 'phone-detail', + templateUrl: './phone-detail.template.html', + // #enddocregion initialclass + // #docregion initialclass +}) +export class PhoneDetailComponent { + phone: PhoneData; + mainImageUrl: string; + + constructor(routeParams: RouteParams, phone: Phone) { + phone.get(routeParams['phoneId']).subscribe(phone => { + this.phone = phone; + this.setImage(phone.images[0]); + }); + } + + setImage(imageUrl: string) { + this.mainImageUrl = imageUrl; + } +} +// #enddocregion initialclass + +angular.module('phoneDetail') + .directive( + 'phoneDetail', + downgradeComponent({component: PhoneDetailComponent}) as angular.IDirectiveFactory + ); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.module.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.module.ts new file mode 100644 index 0000000000..fd7cb3b920 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.module.ts @@ -0,0 +1,7 @@ +'use strict'; + +// Define the `phoneDetail` module +angular.module('phoneDetail', [ + 'ngRoute', + 'core.phone' +]); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.template.html b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.template.html new file mode 100644 index 0000000000..46a96d66c3 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-detail/phone-detail.template.html @@ -0,0 +1,120 @@ + +
    +
    + +
    + +

    {{phone.name}}

    + +

    {{phone.description}}

    + +
      +
    • + +
    • +
    + +
      +
    • + Availability and Networks +
      +
      Availability
      +
      {{availability}}
      +
      +
    • +
    • + Battery +
      +
      Type
      +
      {{phone.battery?.type}}
      +
      Talk Time
      +
      {{phone.battery?.talkTime}}
      +
      Standby time (max)
      +
      {{phone.battery?.standbyTime}}
      +
      +
    • +
    • + Storage and Memory +
      +
      RAM
      +
      {{phone.storage?.ram}}
      +
      Internal Storage
      +
      {{phone.storage?.flash}}
      +
      +
    • +
    • + Connectivity +
      +
      Network Support
      +
      {{phone.connectivity?.cell}}
      +
      WiFi
      +
      {{phone.connectivity?.wifi}}
      +
      Bluetooth
      +
      {{phone.connectivity?.bluetooth}}
      +
      Infrared
      +
      {{phone.connectivity?.infrared | checkmark}}
      +
      GPS
      +
      {{phone.connectivity?.gps | checkmark}}
      +
      +
    • +
    • + Android +
      +
      OS Version
      +
      {{phone.android?.os}}
      +
      UI
      +
      {{phone.android?.ui}}
      +
      +
    • +
    • + Size and Weight +
      +
      Dimensions
      +
      {{dim}}
      +
      Weight
      +
      {{phone.sizeAndWeight?.weight}}
      +
      +
    • +
    • + Display +
      +
      Screen size
      +
      {{phone.display?.screenSize}}
      +
      Screen resolution
      +
      {{phone.display?.screenResolution}}
      +
      Touch screen
      +
      {{phone.display?.touchScreen | checkmark}}
      +
      +
    • +
    • + Hardware +
      +
      CPU
      +
      {{phone.hardware?.cpu}}
      +
      USB
      +
      {{phone.hardware?.usb}}
      +
      Audio / headphone jack
      +
      {{phone.hardware?.audioJack}}
      +
      FM Radio
      +
      {{phone.hardware?.fmRadio | checkmark}}
      +
      Accelerometer
      +
      {{phone.hardware?.accelerometer | checkmark}}
      +
      +
    • +
    • + Camera +
      +
      Primary
      +
      {{phone.camera?.primary}}
      +
      Features
      +
      {{phone.camera?.features?.join(', ')}}
      +
      +
    • +
    • + Additional Features +
      {{phone.additionalFeatures}}
      +
    • +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ajs.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ajs.ts new file mode 100644 index 0000000000..81eac1cd81 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ajs.ts @@ -0,0 +1,24 @@ +// #docregion +declare var angular: angular.IAngularStatic; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +class PhoneListController { + phones: PhoneData[]; + orderProp: string; + + static $inject = ['phone']; + constructor(phone: Phone) { + phone.query().subscribe(phones => { + this.phones = phones; + }); + this.orderProp = 'age'; + } + +} + +angular. + module('phoneList'). + component('phoneList', { + templateUrl: 'app/phone-list/phone-list.template.html', + controller: PhoneListController + }); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts new file mode 100644 index 0000000000..2bb9d2b62f --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.spec.ts @@ -0,0 +1,66 @@ +/* tslint:disable */ +// #docregion +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Rx'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SpyLocation } from '@angular/common/testing'; + +import { PhoneListComponent } from './phone-list.component'; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +class MockPhone { + query(): Observable { + return Observable.of([ + {name: 'Nexus S', snippet: '', images: []}, + {name: 'Motorola DROID', snippet: '', images: []} + ]); + } +} + +let fixture: ComponentFixture; + +describe('PhoneList', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PhoneListComponent ], + providers: [ + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) }, + { provide: Location, useClass: SpyLocation }, + { provide: Phone, useClass: MockPhone }, + ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PhoneListComponent); + }); + + it('should create "phones" model with 2 phones fetched from xhr', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2); + expect( + compiled.querySelector('.phone-list-item:nth-child(1)').textContent + ).toContain('Motorola DROID'); + expect( + compiled.querySelector('.phone-list-item:nth-child(2)').textContent + ).toContain('Nexus S'); + }); + + xit('should set the default value of orderProp model', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect( + compiled.querySelector('select option:last-child').selected + ).toBe(true); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts new file mode 100644 index 0000000000..1f51c6faa2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.component.ts @@ -0,0 +1,72 @@ +// #docregion downgrade-component +declare var angular: angular.IAngularStatic; +import { downgradeComponent } from '@angular/upgrade/static'; + +// #enddocregion downgrade-component + +// #docregion initialclass +import { Component } from '@angular/core'; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +// #docregion downgrade-component +@Component({ + selector: 'phone-list', + templateUrl: 'phone-list.template.html' +}) +export class PhoneListComponent { + // #enddocregion downgrade-component + phones: PhoneData[]; + query: string; + orderProp: string; + + constructor(phone: Phone) { + phone.query().subscribe(phones => { + this.phones = phones; + }); + this.orderProp = 'age'; + } + // #enddocregion initialclass + + // #docregion getphones + getPhones(): PhoneData[] { + return this.sortPhones(this.filterPhones(this.phones)); + } + + private filterPhones(phones: PhoneData[]) { + if (phones && this.query) { + return phones.filter(phone => { + let name = phone.name.toLowerCase(); + let snippet = phone.snippet.toLowerCase(); + return name.indexOf(this.query) >= 0 || snippet.indexOf(this.query) >= 0; + }); + } + return phones; + } + + private sortPhones(phones: PhoneData[]) { + if (phones && this.orderProp) { + return phones + .slice(0) // Make a copy + .sort((a, b) => { + if (a[this.orderProp] < b[this.orderProp]) { + return -1; + } else if ([b[this.orderProp] < a[this.orderProp]]) { + return 1; + } else { + return 0; + } + }); + } + return phones; + } + // #enddocregion getphones + // #docregion initialclass, downgrade-component +} +// #enddocregion initialclass + +angular.module('phoneList') + .directive( + 'phoneList', + downgradeComponent({component: PhoneListComponent}) as angular.IDirectiveFactory + ); +// #enddocregion downgrade-component diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.module.ts b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.module.ts new file mode 100644 index 0000000000..8ade7c5b88 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `phoneList` module +angular.module('phoneList', ['core.phone']); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html new file mode 100644 index 0000000000..8f02113985 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phone-list/phone-list.template.html @@ -0,0 +1,40 @@ +
    +
    +
    + + + +

    + Search: + +

    + +

    + Sort by: + +

    + + +
    +
    + + + + + + +
    +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/dell-streak-7.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/dell-streak-7.json new file mode 100644 index 0000000000..a32eb6ff98 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/dell-streak-7.json @@ -0,0 +1,64 @@ +{ + "additionalFeatures": "Front Facing 1.3MP Camera", + "android": { + "os": "Android 2.2", + "ui": "Dell Stage" + }, + "availability": [ + "T-Mobile" + ], + "battery": { + "standbyTime": "", + "talkTime": "", + "type": "Lithium Ion (Li-Ion) (2780 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "T-mobile HSPA+ @ 2100/1900/AWS/850 MHz", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g" + }, + "description": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around. Android\u2122 2.2-based tablet with over-the-air upgrade capability for future OS releases. A vibrant 7-inch, multitouch display with full Adobe\u00ae Flash 10.1 pre-installed. Includes a 1.3 MP front-facing camera for face-to-face chats on popular services such as Qik or Skype. 16 GB of internal storage, plus Wi-Fi, Bluetooth and built-in GPS keeps you in touch with the world around you. Connect on your terms. Save with 2-year contract or flexibility with prepaid pay-as-you-go plans", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "7.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "nVidia Tegra T20", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "dell-streak-7", + "images": [ + "img/phones/dell-streak-7.0.jpg", + "img/phones/dell-streak-7.1.jpg", + "img/phones/dell-streak-7.2.jpg", + "img/phones/dell-streak-7.3.jpg", + "img/phones/dell-streak-7.4.jpg" + ], + "name": "Dell Streak 7", + "sizeAndWeight": { + "dimensions": [ + "199.9 mm (w)", + "119.8 mm (h)", + "12.4 mm (d)" + ], + "weight": "450.0 grams" + }, + "storage": { + "flash": "16000MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-atrix-4g.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-atrix-4g.json new file mode 100644 index 0000000000..ccca00e3b2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-atrix-4g.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "", + "android": { + "os": "Android 2.2", + "ui": "MOTOBLUR" + }, + "availability": [ + "AT&T" + ], + "battery": { + "standbyTime": "400 hours", + "talkTime": "5 hours", + "type": "Lithium Ion (Li-Ion) (1930 mAH)" + }, + "camera": { + "features": [ + "" + ], + "primary": "" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "WCDMA 850/1900/2100, GSM 850/900/1800/1900, HSDPA 14Mbps (Category 10) Edge Class 12, GPRS Class 12, eCompass, AGPS", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA ATRIX 4G gives you dual-core processing power and the revolutionary webtop application. With webtop and a compatible Motorola docking station, sold separately, you can surf the Internet with a full Firefox browser, create and edit docs, or access multimedia on a large screen almost anywhere.", + "display": { + "screenResolution": "QHD (960 x 540)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-atrix-4g", + "images": [ + "img/phones/motorola-atrix-4g.0.jpg", + "img/phones/motorola-atrix-4g.1.jpg", + "img/phones/motorola-atrix-4g.2.jpg", + "img/phones/motorola-atrix-4g.3.jpg" + ], + "name": "MOTOROLA ATRIX\u2122 4G", + "sizeAndWeight": { + "dimensions": [ + "63.5 mm (w)", + "117.75 mm (h)", + "10.95 mm (d)" + ], + "weight": "135.0 grams" + }, + "storage": { + "flash": "", + "ram": "" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-xoom-with-wi-fi.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-xoom-with-wi-fi.json new file mode 100644 index 0000000000..4ba9c8d5b5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-xoom-with-wi-fi.json @@ -0,0 +1,65 @@ +{ + "additionalFeatures": "Sensors: proximity, ambient light, barometer, gyroscope", + "android": { + "os": "Android 3.0", + "ui": "Honeycomb" + }, + "availability": [ + "" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other ( mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Motorola XOOM with Wi-Fi has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom-with-wi-fi", + "images": [ + "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "img/phones/motorola-xoom-with-wi-fi.1.jpg", + "img/phones/motorola-xoom-with-wi-fi.2.jpg", + "img/phones/motorola-xoom-with-wi-fi.3.jpg", + "img/phones/motorola-xoom-with-wi-fi.4.jpg", + "img/phones/motorola-xoom-with-wi-fi.5.jpg" + ], + "name": "Motorola XOOM\u2122 with Wi-Fi", + "sizeAndWeight": { + "dimensions": [ + "249.1 mm (w)", + "167.8 mm (h)", + "12.9 mm (d)" + ], + "weight": "708.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-xoom.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-xoom.json new file mode 100644 index 0000000000..f0f0c8711d --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/motorola-xoom.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "Front-facing camera. Sensors: proximity, ambient light, barometer, gyroscope.", + "android": { + "os": "Android 3.0", + "ui": "Android" + }, + "availability": [ + "Verizon" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other (3250 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "CDMA 800 /1900 LTE 700, Rx diversity in all bands", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA XOOM has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom", + "images": [ + "img/phones/motorola-xoom.0.jpg", + "img/phones/motorola-xoom.1.jpg", + "img/phones/motorola-xoom.2.jpg" + ], + "name": "MOTOROLA XOOM\u2122", + "sizeAndWeight": { + "dimensions": [ + "249.0 mm (w)", + "168.0 mm (h)", + "12.7 mm (d)" + ], + "weight": "726.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/nexus-s.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/nexus-s.json new file mode 100644 index 0000000000..5e712e2ff8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/nexus-s.json @@ -0,0 +1,69 @@ +{ + "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope, Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", + "android": { + "os": "Android 2.3", + "ui": "Android" + }, + "availability": [ + "M1,", + "O2,", + "Orange,", + "Singtel,", + "StarHub,", + "T-Mobile,", + "Vodafone" + ], + "battery": { + "standbyTime": "428 hours", + "talkTime": "6 hours", + "type": "Lithium Ion (Li-Ion) (1500 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "Quad-band GSM: 850, 900, 1800, 1900\r\nTri-band HSPA: 900, 2100, 1700\r\nHSPA type: HSDPA (7.2Mbps) HSUPA (5.76Mbps)", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Nexus S is the next generation of Nexus devices, co-developed by Google and Samsung. The latest Android platform (Gingerbread), paired with a 1 GHz Hummingbird processor and 16GB of memory, makes Nexus S one of the fastest phones on the market. It comes pre-installed with the best of Google apps and enabled with new and popular features like true multi-tasking, Wi-Fi hotspot, Internet Calling, NFC support, and full web browsing. With this device, users will also be the first to receive software upgrades and new Google mobile apps as soon as they become available. For more details, visit http://www.google.com/nexus.", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1GHz Cortex A8 (Hummingbird) processor", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "nexus-s", + "images": [ + "img/phones/nexus-s.0.jpg", + "img/phones/nexus-s.1.jpg", + "img/phones/nexus-s.2.jpg", + "img/phones/nexus-s.3.jpg" + ], + "name": "Nexus S", + "sizeAndWeight": { + "dimensions": [ + "63.0 mm (w)", + "123.9 mm (h)", + "10.88 mm (d)" + ], + "weight": "129.0 grams" + }, + "storage": { + "flash": "16384MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/phones.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/phones.json new file mode 100644 index 0000000000..339b94fbb5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/app/phones/phones.json @@ -0,0 +1,155 @@ +[ + { + "age": 0, + "id": "motorola-xoom-with-wi-fi", + "imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "name": "Motorola XOOM\u2122 with Wi-Fi", + "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 1, + "id": "motorola-xoom", + "imageUrl": "img/phones/motorola-xoom.0.jpg", + "name": "MOTOROLA XOOM\u2122", + "snippet": "The Next, Next Generation\n\nExperience the future with MOTOROLA XOOM, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 2, + "carrier": "AT&T", + "id": "motorola-atrix-4g", + "imageUrl": "img/phones/motorola-atrix-4g.0.jpg", + "name": "MOTOROLA ATRIX\u2122 4G", + "snippet": "MOTOROLA ATRIX 4G the world's most powerful smartphone." + }, + { + "age": 3, + "id": "dell-streak-7", + "imageUrl": "img/phones/dell-streak-7.0.jpg", + "name": "Dell Streak 7", + "snippet": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around." + }, + { + "age": 4, + "carrier": "Cellular South", + "id": "samsung-gem", + "imageUrl": "img/phones/samsung-gem.0.jpg", + "name": "Samsung Gem\u2122", + "snippet": "The Samsung Gem\u2122 brings you everything that you would expect and more from a touch display smart phone \u2013 more apps, more features and a more affordable price." + }, + { + "age": 5, + "carrier": "Dell", + "id": "dell-venue", + "imageUrl": "img/phones/dell-venue.0.jpg", + "name": "Dell Venue", + "snippet": "The Dell Venue; Your Personal Express Lane to Everything" + }, + { + "age": 6, + "carrier": "Best Buy", + "id": "nexus-s", + "imageUrl": "img/phones/nexus-s.0.jpg", + "name": "Nexus S", + "snippet": "Fast just got faster with Nexus S. A pure Google experience, Nexus S is the first phone to run Gingerbread (Android 2.3), the fastest version of Android yet." + }, + { + "age": 7, + "carrier": "Cellular South", + "id": "lg-axis", + "imageUrl": "img/phones/lg-axis.0.jpg", + "name": "LG Axis", + "snippet": "Android Powered, Google Maps Navigation, 5 Customizable Home Screens" + }, + { + "age": 8, + "id": "samsung-galaxy-tab", + "imageUrl": "img/phones/samsung-galaxy-tab.0.jpg", + "name": "Samsung Galaxy Tab\u2122", + "snippet": "Feel Free to Tab\u2122. The Samsung Galaxy Tab\u2122 brings you an ultra-mobile entertainment experience through its 7\u201d display, high-power processor and Adobe\u00ae Flash\u00ae Player compatibility." + }, + { + "age": 9, + "carrier": "Cellular South", + "id": "samsung-showcase-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg", + "name": "Samsung Showcase\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Showcase\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance, even outdoors" + }, + { + "age": 10, + "carrier": "Verizon", + "id": "droid-2-global-by-motorola", + "imageUrl": "img/phones/droid-2-global-by-motorola.0.jpg", + "name": "DROID\u2122 2 Global by Motorola", + "snippet": "The first smartphone with a 1.2 GHz processor and global capabilities." + }, + { + "age": 11, + "carrier": "Verizon", + "id": "droid-pro-by-motorola", + "imageUrl": "img/phones/droid-pro-by-motorola.0.jpg", + "name": "DROID\u2122 Pro by Motorola", + "snippet": "The next generation of DOES." + }, + { + "age": 12, + "carrier": "AT&T", + "id": "motorola-bravo-with-motoblur", + "imageUrl": "img/phones/motorola-bravo-with-motoblur.0.jpg", + "name": "MOTOROLA BRAVO\u2122 with MOTOBLUR\u2122", + "snippet": "An experience to cheer about." + }, + { + "age": 13, + "carrier": "T-Mobile", + "id": "motorola-defy-with-motoblur", + "imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg", + "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", + "snippet": "Are you ready for everything life throws your way?" + }, + { + "age": 14, + "carrier": "T-Mobile", + "id": "t-mobile-mytouch-4g", + "imageUrl": "img/phones/t-mobile-mytouch-4g.0.jpg", + "name": "T-Mobile myTouch 4G", + "snippet": "The T-Mobile myTouch 4G is a premium smartphone designed to deliver blazing fast 4G speeds so that you can video chat from practically anywhere, with or without Wi-Fi." + }, + { + "age": 15, + "carrier": "US Cellular", + "id": "samsung-mesmerize-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg", + "name": "Samsung Mesmerize\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Mesmerize\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance,even outdoors" + }, + { + "age": 16, + "carrier": "Sprint", + "id": "sanyo-zio", + "imageUrl": "img/phones/sanyo-zio.0.jpg", + "name": "SANYO ZIO", + "snippet": "The Sanyo Zio by Kyocera is an Android smartphone with a combination of ultra-sleek styling, strong performance and unprecedented value." + }, + { + "age": 17, + "id": "samsung-transform", + "imageUrl": "img/phones/samsung-transform.0.jpg", + "name": "Samsung Transform\u2122", + "snippet": "The Samsung Transform\u2122 brings you a fun way to customize your Android powered touch screen phone to just the way you like it through your favorite themed \u201cSprint ID Service Pack\u201d." + }, + { + "age": 18, + "id": "t-mobile-g2", + "imageUrl": "img/phones/t-mobile-g2.0.jpg", + "name": "T-Mobile G2", + "snippet": "The T-Mobile G2 with Google is the first smartphone built for 4G speeds on T-Mobile's new network. Get the information you need, faster than you ever thought possible." + }, + { + "age": 19, + "id": "motorola-charm-with-motoblur", + "imageUrl": "img/phones/motorola-charm-with-motoblur.0.jpg", + "name": "Motorola CHARM\u2122 with MOTOBLUR\u2122", + "snippet": "Motorola CHARM fits easily in your pocket or palm. Includes MOTOBLUR service." + } +] diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/bs-config.aot.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/bs-config.aot.json new file mode 100644 index 0000000000..e59a7403a0 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/bs-config.aot.json @@ -0,0 +1,14 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": { + "0": null + } + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/copy-dist-files.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/copy-dist-files.js new file mode 100644 index 0000000000..a857af085c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/copy-dist-files.js @@ -0,0 +1,25 @@ +// #docregion +var fsExtra = require('fs-extra'); +var resources = [ + // polyfills + 'node_modules/core-js/client/shim.min.js', + 'node_modules/zone.js/dist/zone.min.js', + // css + 'app/app.css', + 'app/app.animations.css', + // images and json files + 'app/img/', + 'app/phones/', + // app files + 'app/app.module.ajs.js', + 'app/app.config.js', + 'app/app.animations.js', + 'app/core/core.module.js', + 'app/core/phone/phone.module.js', + 'app/phone-list/phone-list.module.js', + 'app/phone-detail/phone-detail.module.js' +]; +resources.map(function(sourcePath) { + var destPath = `aot/${sourcePath}`; + fsExtra.copySync(sourcePath, destPath); +}); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/example-config.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/example-config.json new file mode 100644 index 0000000000..401c14f835 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/example-config.json @@ -0,0 +1,5 @@ +{ + "build": "build:upgrade", + "run": "serve:upgrade", + "unittesting": true +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/index.html b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/index.html new file mode 100644 index 0000000000..f747e641e0 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/index.html @@ -0,0 +1,51 @@ + + + + + + + + + Google Phone Gallery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js new file mode 100644 index 0000000000..19fcc89fe9 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma-test-shim.1.js @@ -0,0 +1,89 @@ +// #docregion +// /*global jasmine, __karma__, window*/ +Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. + +// Uncomment to get full stacktrace output. Sometimes helpful, usually not. +// Error.stackTraceLimit = Infinity; // + +jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000; + +var builtPath = '/base/app/'; + +__karma__.loaded = function () { }; + +function isJsFile(path) { + return path.slice(-3) == '.js'; +} + +function isSpecFile(path) { + return /\.spec\.(.*\.)?js$/.test(path); +} + +function isBuiltFile(path) { + return isJsFile(path) && (path.substr(0, builtPath.length) == builtPath); +} + +var allSpecFiles = Object.keys(window.__karma__.files) + .filter(isSpecFile) + .filter(isBuiltFile); + +System.config({ + baseURL: '/base', + // Extend usual application package list with test folder + packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, + + // Assume npm: is set in `paths` in systemjs.config + // Map the angular testing umd bundles + map: { + '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', + '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', + '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', + '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', + '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', + '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', + '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', + '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', + }, +}); + +System.import('systemjs.config.js') + .then(importSystemJsExtras) + .then(initTestBed) + .then(initTesting); + +/** Optional SystemJS configuration extras. Keep going w/o it */ +function importSystemJsExtras(){ + return System.import('systemjs.config.extras.js') + .catch(function(reason) { + console.log( + 'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.' + ); + console.log(reason); + }); +} + +function initTestBed(){ + return Promise.all([ + System.import('@angular/core/testing'), + System.import('@angular/platform-browser-dynamic/testing') + ]) + + .then(function (providers) { + var coreTesting = providers[0]; + var browserTesting = providers[1]; + + coreTesting.TestBed.initTestEnvironment( + browserTesting.BrowserDynamicTestingModule, + browserTesting.platformBrowserDynamicTesting()); + }) +} + +// Import all spec files and start karma +function initTesting () { + return Promise.all( + allSpecFiles.map(function (moduleName) { + return System.import(moduleName); + }) + ) + .then(__karma__.start, __karma__.error); +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ajs.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ajs.js new file mode 100644 index 0000000000..a52abf73ce --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/karma.conf.ajs.js @@ -0,0 +1,73 @@ +//jshint strict: false +module.exports = function(config) { + config.set({ + + // #docregion basepath + basePath: './', + // #enddocregion basepath + + files: [ + 'https://code.angularjs.org/1.5.5/angular.js', + 'https://code.angularjs.org/1.5.5/angular-animate.js', + 'https://code.angularjs.org/1.5.5/angular-resource.js', + 'https://code.angularjs.org/1.5.5/angular-route.js', + 'https://code.angularjs.org/1.5.5/angular-mocks.js', + + // #docregion files + // System.js for module loading + 'node_modules/systemjs/dist/system.src.js', + + // Polyfills + 'node_modules/core-js/client/shim.js', + + // zone.js + 'node_modules/zone.js/dist/zone.js', + 'node_modules/zone.js/dist/long-stack-trace-zone.js', + 'node_modules/zone.js/dist/proxy.js', + 'node_modules/zone.js/dist/sync-test.js', + 'node_modules/zone.js/dist/jasmine-patch.js', + 'node_modules/zone.js/dist/async-test.js', + 'node_modules/zone.js/dist/fake-async-test.js', + + // RxJs. + { pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false }, + { pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false }, + + // Angular itself and the testing library + {pattern: 'node_modules/@angular/**/*.js', included: false, watched: false}, + {pattern: 'node_modules/@angular/**/*.js.map', included: false, watched: false}, + + {pattern: 'systemjs.config.js', included: false, watched: false}, + 'karma-test-shim.js', + + {pattern: 'app/**/*.module.js', included: false, watched: true}, + {pattern: 'app/*!(.module|.spec).js', included: false, watched: true}, + {pattern: 'app/!(bower_components)/**/*!(.module|.spec).js', included: false, watched: true}, + {pattern: 'app/**/*.spec.js', included: false, watched: true}, + + {pattern: '**/*.html', included: false, watched: true}, + // #enddocregion files + ], + + // #docregion html + // proxied base paths for loading assets + proxies: { + // required for component assets fetched by Angular's compiler + "/phone-detail": '/base/app/phone-detail', + "/phone-list": '/base/app/phone-list' + }, + // #enddocregion html + + autoWatch: true, + + frameworks: ['jasmine'], + + browsers: ['Chrome'], + + plugins: [ + 'karma-chrome-launcher', + 'karma-jasmine' + ] + + }); +}; diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/package.ajs.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/package.ajs.json new file mode 100644 index 0000000000..54f73776dd --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/package.ajs.json @@ -0,0 +1,37 @@ +{ + "name": "angular-phonecat", + "private": true, + "version": "0.0.0", + "description": "A tutorial application for AngularJS", + "repository": "https://github.com/angular/angular-phonecat", + "license": "MIT", + "devDependencies": { + "bower": "^1.7.7", + "http-server": "^0.9.0", + "jasmine-core": "^2.4.1", + "karma": "^0.13.22", + "karma-chrome-launcher": "^0.2.3", + "karma-firefox-launcher": "^0.1.7", + "karma-jasmine": "^0.3.8", + "protractor": "^3.2.2", + "shelljs": "^0.6.0" + }, + "scripts": { + "postinstall": "bower install", + + "prestart": "npm install", + "start": "http-server -a localhost -p 8000 -c-1 ./", + + "pretest": "npm install", + "test": "karma start karma.conf.js", + "test-single-run": "karma start karma.conf.js --single-run", + + "preupdate-webdriver": "npm install", + "update-webdriver": "webdriver-manager update", + + "preprotractor": "npm run update-webdriver", + "protractor": "protractor e2e-tests/protractor.conf.js", + + "update-index-async": "node -e \"require('shelljs/global'); sed('-i', /\\/\\/@@NG_LOADER_START@@[\\s\\S]*\\/\\/@@NG_LOADER_END@@/, '//@@NG_LOADER_START@@\\n' + sed(/sourceMappingURL=angular-loader.min.js.map/,'sourceMappingURL=bower_components/angular-loader/angular-loader.min.js.map','app/bower_components/angular-loader/angular-loader.min.js') + '\\n//@@NG_LOADER_END@@', 'app/index-async.html');\"" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/rollup-config.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/rollup-config.js new file mode 100644 index 0000000000..aeb227689c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/rollup-config.js @@ -0,0 +1,21 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +//paths are relative to the execution path +export default { + entry: 'app/main-aot.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + plugins: [ + nodeResolve({jsnext: true, module: true}), + commonjs({ + include: ['node_modules/rxjs/**'] + }), + uglify() + ] +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/run-unit-tests.sh b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/run-unit-tests.sh new file mode 100755 index 0000000000..239e5ff7d7 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/run-unit-tests.sh @@ -0,0 +1,7 @@ +## The boilerplate Karma configuration won't work with AngularJS tests since +## a specific loading configuration is needed for them. +## We keep one in karma.conf.ajs.js. This scripts runs the AngularJS tests with +## that config. + +PATH=$(npm bin):$PATH +tsc && karma start karma.conf.ajs.js diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js new file mode 100644 index 0000000000..8197c44a89 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/systemjs.config.1.js @@ -0,0 +1,50 @@ +/** + * System configuration for Angular samples + * Adjust as necessary for your application needs. + */ +(function (global) { + // #docregion paths + System.config({ + paths: { + // paths serve as alias + 'npm:': '/node_modules/' + }, + map: { + app: '/app', + // #enddocregion paths + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + // #docregion paths + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', + // #enddocregion paths + + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api', + // #docregion paths + }, + // #enddocregion paths + // packages tells the System loader how to load when no filename and/or no extension + packages: { + 'app': { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + }, + 'angular-in-memory-web-api': { + main: './index.js', + defaultExtension: 'js' + } + } + }); +})(this); diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig-aot.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig-aot.json new file mode 100644 index 0000000000..58f9de3309 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig-aot.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "removeComments": false, + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "app/app.module.ts", + "app/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig.json b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig.json new file mode 100644 index 0000000000..f267800f14 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-2-hybrid/ts/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*", + "**/*-aot.ts" + ] +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/README.md b/public/docs/_examples/upgrade-phonecat-3-router/README.md new file mode 100644 index 0000000000..4f8e4928af --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/README.md @@ -0,0 +1,34 @@ +This is the Angular Phonecat application adjusted to fit our boilerplate project +structure. + +The following changes from vanilla Phonecat are applied: + +* Karma config for unit tests is in karma.conf.ng1.js because the boilerplate + Karma config is not compatible with the way Angular 1 tests need to be run. + The shell script run-unit-tests.sh can be used to run the unit tests. +* There's a `package.ng1.json`, which is not used to run anything but only to + show an example of changing the PhoneCat http-server root path. +* Also for the Karma shim, there is a `karma-test-shim.1.js` file which isn't + used but is shown in the test appendix. +* Instead of using Bower, Angular 1 and its dependencies are fetched from a CDN + in index.html and karma.conf.ng1.js. +* E2E tests have been moved to the parent directory, where `run-e2e-tests` can + discover and run them along with all the other examples. +* Most of the phone JSON and image data removed in the interest of keeping + repo weight down. Keeping enough to retain testability of the app. + +## Running the app + +Start like any example + + npm run start + +## Running unit tests + + ./run-unit-tests.sh + +## Running E2E tests + +Like for any example (at the project root): + + gulp run-e2e-tests --filter=phonecat-2 diff --git a/public/docs/_examples/upgrade-phonecat-3-router/e2e-spec.ts b/public/docs/_examples/upgrade-phonecat-3-router/e2e-spec.ts new file mode 100644 index 0000000000..2ec8e37977 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/e2e-spec.ts @@ -0,0 +1,107 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; +import { setProtractorToHybridMode } from '../protractor-helpers'; + +// Angular E2E Testing Guide: +// https://docs.angularjs.org/guide/e2e-testing + +describe('PhoneCat Application', function() { + + beforeAll(function () { + setProtractorToHybridMode(); + }); + + it('should redirect `index.html` to `index.html#!/phones', function() { + browser.get('index.html'); + expect(browser.getLocationAbsUrl()).toBe('/phones'); + }); + + describe('View: Phone list', function() { + + beforeEach(function() { + browser.get('index.html#!/phones'); + }); + + it('should filter the phone list as a user types into the search box', function() { + let phoneList = element.all(by.css('.phones li')); + let query = element(by.css('input')); + + expect(phoneList.count()).toBe(20); + + query.sendKeys('nexus'); + expect(phoneList.count()).toBe(1); + + query.clear(); + query.sendKeys('motorola'); + expect(phoneList.count()).toBe(8); + }); + + it('should be possible to control phone order via the drop-down menu', function() { + let queryField = element(by.css('input')); + let orderSelect = element(by.css('select')); + let nameOption = orderSelect.element(by.css('option[value="name"]')); + let phoneNameColumn = element.all(by.css('.phones .name')); + + function getNames() { + return phoneNameColumn.map(function(elem) { + return elem.getText(); + }); + } + + queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter + + expect(getNames()).toEqual([ + 'Motorola XOOM\u2122 with Wi-Fi', + 'MOTOROLA XOOM\u2122' + ]); + + nameOption.click(); + + expect(getNames()).toEqual([ + 'MOTOROLA XOOM\u2122', + 'Motorola XOOM\u2122 with Wi-Fi' + ]); + }); + + it('should render phone specific links', function() { + let query = element(by.css('input')); + query.sendKeys('nexus'); + + element.all(by.css('.phones li a')).first().click(); + browser.sleep(200); // Not sure why this is needed but it is. The route change works fine. + expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s'); + }); + + }); + + describe('View: Phone detail', function() { + + beforeEach(function() { + browser.get('index.html#!/phones/nexus-s'); + }); + + it('should display the `nexus-s` page', function() { + expect(element(by.css('h1')).getText()).toBe('Nexus S'); + }); + + it('should display the first phone image as the main phone image', function() { + let mainImage = element(by.css('img.phone.selected')); + + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + it('should swap the main image when clicking on a thumbnail image', function() { + let mainImage = element(by.css('img.phone.selected')); + let thumbnails = element.all(by.css('.phone-thumbs img')); + + thumbnails.get(2).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); + + thumbnails.get(0).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/.gitignore b/public/docs/_examples/upgrade-phonecat-3-router/ts/.gitignore new file mode 100644 index 0000000000..7f5c313a3e --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/.gitignore @@ -0,0 +1,7 @@ +**/*.js +aot/**/* +!aot/bs-config.json +!aot/index.html +!copy-dist-files.js +!rollup-config.js +!systemjs.config.1.js diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/aot/bs-config.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/aot/bs-config.json new file mode 100644 index 0000000000..7c85d6eddd --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/aot/bs-config.json @@ -0,0 +1,5 @@ +{ + "port": 8000, + "files": ["./aot/**/*.{html,htm,css,js}"], + "server": { "baseDir": "./aot" } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/aot/index.html b/public/docs/_examples/upgrade-phonecat-3-router/ts/aot/index.html new file mode 100644 index 0000000000..0d6cf5946e --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/aot/index.html @@ -0,0 +1,38 @@ + + + + + + + + + Google Phone Gallery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/ajs-upgraded-providers.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/ajs-upgraded-providers.ts new file mode 100644 index 0000000000..f6e1654d74 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/ajs-upgraded-providers.ts @@ -0,0 +1,14 @@ +// #docregion +export abstract class RouteParams { + [key: string]: string; +} + +export function routeParamsFactory(i: any) { + return i.get('$routeParams'); +} + +export const routeParamsProvider = { + provide: RouteParams, + useFactory: routeParamsFactory, + deps: ['$injector'] +}; diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app-routing.module.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app-routing.module.ts new file mode 100644 index 0000000000..0485b1848d --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app-routing.module.ts @@ -0,0 +1,30 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { Routes, RouterModule, UrlHandlingStrategy, UrlTree } from '@angular/router'; +import { APP_BASE_HREF, HashLocationStrategy, LocationStrategy } from '@angular/common'; + +import { PhoneListComponent } from './phone-list/phone-list.component'; + +export class Ng1Ng2UrlHandlingStrategy implements UrlHandlingStrategy { + shouldProcessUrl(url: UrlTree) { + return url.toString() === '/' || url.toString() === '/phones'; + } + extract(url: UrlTree) { return url; } + merge(url: UrlTree, whole: UrlTree) { return url; } +} + +const routes: Routes = [ + { path: '', redirectTo: 'phones', pathMatch: 'full' }, + { path: 'phones', component: PhoneListComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ], + providers: [ + { provide: APP_BASE_HREF, useValue: '!' }, + { provide: LocationStrategy, useClass: HashLocationStrategy }, + { provide: UrlHandlingStrategy, useClass: Ng1Ng2UrlHandlingStrategy } + ] +}) +export class AppRoutingModule { } diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.animations.css b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.animations.css new file mode 100644 index 0000000000..175320b509 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.animations.css @@ -0,0 +1,67 @@ +/* Animate `ngRepeat` in `phoneList` component */ +.phone-list-item.ng-enter, +.phone-list-item.ng-leave, +.phone-list-item.ng-move { + overflow: hidden; + transition: 0.5s linear all; +} + +.phone-list-item.ng-enter, +.phone-list-item.ng-leave.ng-leave-active, +.phone-list-item.ng-move { + height: 0; + margin-bottom: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; +} + +.phone-list-item.ng-enter.ng-enter-active, +.phone-list-item.ng-leave, +.phone-list-item.ng-move.ng-move-active { + height: 120px; + margin-bottom: 20px; + opacity: 1; + padding-bottom: 4px; + padding-top: 15px; +} + +/* Animate view transitions with `ngView` */ +.view-container { + position: relative; +} + +.view-frame { + margin-top: 20px; +} + +.view-frame.ng-enter, +.view-frame.ng-leave { + background: white; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.view-frame.ng-enter { + animation: 1s fade-in; + z-index: 100; +} + +.view-frame.ng-leave { + animation: 1s fade-out; + z-index: 99; +} + +@keyframes fade-in { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fade-out { + from { opacity: 1; } + to { opacity: 0; } +} + +/* Older browsers might need vendor-prefixes for keyframes and animation! */ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.animations.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.animations.ts new file mode 100644 index 0000000000..f0739b6405 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.animations.ts @@ -0,0 +1,43 @@ +'use strict'; + +angular. + module('phonecatApp'). + animation('.phone', function phoneAnimationFactory() { + return { + addClass: animateIn, + removeClass: animateOut + }; + + function animateIn(element: JQuery, className: string, done: () => void) { + if (className !== 'selected') { return; } + + element.css({ + display: 'block', + position: 'absolute', + top: 500, + left: 0 + }).animate({ + top: 0 + }, done); + + return function animateInEnd(wasCanceled: boolean) { + if (wasCanceled) { element.stop(); } + }; + } + + function animateOut(element: JQuery, className: string, done: () => void) { + if (className !== 'selected') { return; } + + element.css({ + position: 'absolute', + top: 0, + left: 0 + }).animate({ + top: -500 + }, done); + + return function animateOutEnd(wasCanceled: boolean) { + if (wasCanceled) { element.stop(); } + }; + } + }); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.component.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.component.ts new file mode 100644 index 0000000000..6ecd19ab80 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.component.ts @@ -0,0 +1,13 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'phonecat-app', + template: ` + +
    +
    +
    + ` +}) +export class AppComponent { } diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.config.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.config.ts new file mode 100644 index 0000000000..51a5d82422 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.config.ts @@ -0,0 +1,16 @@ +'use strict'; + +angular. + module('phonecatApp'). + config(['$locationProvider', '$routeProvider', + function config($locationProvider: angular.ILocationProvider, + $routeProvider: angular.route.IRouteProvider) { + $locationProvider.hashPrefix('!'); + // #docregion ajs-routes + $routeProvider + .when('/phones/:phoneId', { + template: '' + }); + // #enddocregion ajs-routes + } + ]); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.css b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.css new file mode 100644 index 0000000000..f4b45b02a5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.css @@ -0,0 +1,93 @@ +body { + padding: 20px; +} + +h1 { + border-bottom: 1px solid gray; + margin-top: 0; +} + +/* View: Phone list */ +.phones { + list-style: none; +} + +.phones li { + clear: both; + height: 115px; + padding-top: 15px; +} + +.thumb { + float: left; + height: 100px; + margin: -0.5em 1em 1.5em 0; + padding-bottom: 1em; + width: 100px; +} + +/* View: Phone detail */ +.phone { + background-color: white; + display: none; + float: left; + height: 400px; + margin-bottom: 2em; + margin-right: 3em; + padding: 2em; + width: 400px; +} + +.phone:first-child { + display: block; +} + +.phone-images { + background-color: white; + float: left; + height: 450px; + overflow: hidden; + position: relative; + width: 450px; +} + +.phone-thumbs { + list-style: none; + margin: 0; +} + +.phone-thumbs img { + height: 100px; + padding: 1em; + width: 100px; +} + +.phone-thumbs li { + background-color: white; + border: 1px solid black; + cursor: pointer; + display: inline-block; + margin: 1em; +} + +.specs { + clear: both; + list-style: none; + margin: 0; + padding: 0; +} + +.specs dt { + font-weight: bold; +} + +.specs > li { + display: inline-block; + vertical-align: top; + width: 200px; +} + +.specs > li > span { + font-size: 1.2em; + font-weight: bold; +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.module.ajs.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.module.ajs.ts new file mode 100644 index 0000000000..e493137966 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.module.ajs.ts @@ -0,0 +1,11 @@ +// #docregion +'use strict'; + +// Define the `phonecatApp` Angular 1 module +angular.module('phonecatApp', [ + 'ngAnimate', + 'ngRoute', + 'core', + 'phoneDetail', + 'phoneList', +]); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.module.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.module.ts new file mode 100644 index 0000000000..e0bb64f4e4 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/app.module.ts @@ -0,0 +1,42 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; +import { HttpModule } from '@angular/http'; +import { FormsModule } from '@angular/forms'; + +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { Phone } from './core/phone/phone.service'; +import { CheckmarkPipe } from './core/checkmark/checkmark.pipe'; +import { PhoneListComponent } from './phone-list/phone-list.component'; +import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; +import { routeParamsProvider } from './ajs-upgraded-providers'; + +@NgModule({ + imports: [ + BrowserModule, + UpgradeModule, + HttpModule, + FormsModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + PhoneListComponent, + PhoneDetailComponent, + CheckmarkPipe + ], + entryComponents: [ + PhoneListComponent, + PhoneDetailComponent + ], + providers: [ + Phone, + routeParamsProvider + ], + // #docregion bootstrap + bootstrap: [ AppComponent ] +}) +export class AppModule { } +// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/checkmark/checkmark.pipe.spec.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/checkmark/checkmark.pipe.spec.ts new file mode 100644 index 0000000000..f7485ec2ba --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/checkmark/checkmark.pipe.spec.ts @@ -0,0 +1,11 @@ +// #docregion +import { CheckmarkPipe } from './checkmark.pipe'; + +describe('CheckmarkPipe', function() { + + it('should convert boolean values to unicode checkmark or cross', function () { + const checkmarkPipe = new CheckmarkPipe(); + expect(checkmarkPipe.transform(true)).toBe('\u2713'); + expect(checkmarkPipe.transform(false)).toBe('\u2718'); + }); +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/checkmark/checkmark.pipe.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/checkmark/checkmark.pipe.ts new file mode 100644 index 0000000000..888017e15c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/checkmark/checkmark.pipe.ts @@ -0,0 +1,9 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'checkmark'}) +export class CheckmarkPipe implements PipeTransform { + transform(input: boolean) { + return input ? '\u2713' : '\u2718'; + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/core.module.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/core.module.ts new file mode 100644 index 0000000000..84a91dc7a6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/core.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `core` module +angular.module('core', ['core.phone']); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.module.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.module.ts new file mode 100644 index 0000000000..0b6b348899 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `core.phone` module +angular.module('core.phone', ['ngResource']); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.service.spec.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.service.spec.ts new file mode 100644 index 0000000000..a0c1655c20 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.service.spec.ts @@ -0,0 +1,51 @@ +// #docregion +import { inject, TestBed } from '@angular/core/testing'; +import { + Http, + BaseRequestOptions, + ResponseOptions, + Response +} from '@angular/http'; +import { MockBackend, MockConnection } from '@angular/http/testing'; +import { Phone, PhoneData } from './phone.service'; + +describe('Phone', function() { + let phone: Phone; + let phonesData: PhoneData[] = [ + {name: 'Phone X', snippet: '', images: []}, + {name: 'Phone Y', snippet: '', images: []}, + {name: 'Phone Z', snippet: '', images: []} + ]; + let mockBackend: MockBackend; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + Phone, + MockBackend, + BaseRequestOptions, + { provide: Http, + useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options), + deps: [MockBackend, BaseRequestOptions] + } + ] + }); + }); + + beforeEach(inject([MockBackend, Phone], (_mockBackend_: MockBackend, _phone_: Phone) => { + mockBackend = _mockBackend_; + phone = _phone_; + })); + + it('should fetch the phones data from `/phones/phones.json`', (done: () => void) => { + mockBackend.connections.subscribe((conn: MockConnection) => { + conn.mockRespond(new Response(new ResponseOptions({body: JSON.stringify(phonesData)}))); + }); + phone.query().subscribe(result => { + expect(result).toEqual(phonesData); + done(); + }); + }); + +}); + diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.service.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.service.ts new file mode 100644 index 0000000000..ccbd1fdd72 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/core/phone/phone.service.ts @@ -0,0 +1,32 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +declare var angular: angular.IAngularStatic; +import { downgradeInjectable } from '@angular/upgrade/static'; + +import 'rxjs/add/operator/map'; + +export interface PhoneData { + name: string; + snippet: string; + images: string[]; +} + +@Injectable() +export class Phone { + constructor(private http: Http) { } + query(): Observable { + return this.http.get(`phones/phones.json`) + .map((res: Response) => res.json()); + } + get(id: string): Observable { + return this.http.get(`phones/${id}.json`) + .map((res: Response) => res.json()); + } +} + +angular.module('core.phone') + .factory('phone', downgradeInjectable(Phone)); + diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/.gitkeep b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.0.jpg new file mode 100644 index 0000000000..7ce0dce4ee Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.1.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.1.jpg new file mode 100644 index 0000000000..ed8cad89fb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.2.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.2.jpg new file mode 100644 index 0000000000..c83529e0f9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.3.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.3.jpg new file mode 100644 index 0000000000..cd2c30280d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.4.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.4.jpg new file mode 100644 index 0000000000..b4d8472da8 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-streak-7.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-venue.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-venue.0.jpg new file mode 100644 index 0000000000..b4cb4eb25f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/dell-venue.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/droid-2-global-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/droid-2-global-by-motorola.0.jpg new file mode 100644 index 0000000000..60700a2ab3 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/droid-2-global-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/droid-pro-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/droid-pro-by-motorola.0.jpg new file mode 100644 index 0000000000..c7710de986 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/droid-pro-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/lg-axis.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/lg-axis.0.jpg new file mode 100644 index 0000000000..55e5a23bb2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/lg-axis.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.0.jpg new file mode 100644 index 0000000000..2446159e93 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.1.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.1.jpg new file mode 100644 index 0000000000..867f207459 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.2.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.2.jpg new file mode 100644 index 0000000000..27d78338c4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.3.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.3.jpg new file mode 100644 index 0000000000..29459a68a4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-atrix-4g.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg new file mode 100644 index 0000000000..e452ae7e7c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg new file mode 100644 index 0000000000..21e4b8d741 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg new file mode 100644 index 0000000000..c7c5e3ba0c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg new file mode 100644 index 0000000000..a6c993291e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg new file mode 100644 index 0000000000..400b89e2df Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg new file mode 100644 index 0000000000..86b55d28dd Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg new file mode 100644 index 0000000000..85ec293ae5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg new file mode 100644 index 0000000000..75ef1464cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg new file mode 100644 index 0000000000..4d42db4330 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.0.jpg new file mode 100644 index 0000000000..bf6954bbd5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.1.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.1.jpg new file mode 100644 index 0000000000..659688a47d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.2.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.2.jpg new file mode 100644 index 0000000000..ce0ff1002e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/motorola-xoom.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.0.jpg new file mode 100644 index 0000000000..0952bc79c2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.1.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.1.jpg new file mode 100644 index 0000000000..f33004dd7f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.2.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.2.jpg new file mode 100644 index 0000000000..c5c63621f1 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.3.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.3.jpg new file mode 100644 index 0000000000..e51f75b0ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/nexus-s.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-galaxy-tab.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-galaxy-tab.0.jpg new file mode 100644 index 0000000000..3750377ad9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-galaxy-tab.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-gem.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-gem.0.jpg new file mode 100644 index 0000000000..0d5024a026 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-gem.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-transform.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-transform.0.jpg new file mode 100644 index 0000000000..0e3107caf5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/samsung-transform.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/sanyo-zio.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/sanyo-zio.0.jpg new file mode 100644 index 0000000000..9eeb9b96ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/sanyo-zio.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/t-mobile-g2.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/t-mobile-g2.0.jpg new file mode 100644 index 0000000000..6b6c09e058 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/t-mobile-g2.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg new file mode 100644 index 0000000000..beba1f6827 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/main-aot.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/main-aot.ts new file mode 100644 index 0000000000..23a741c684 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/main-aot.ts @@ -0,0 +1,10 @@ +// #docregion +import { platformBrowser } from '@angular/platform-browser'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory'; + +platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.documentElement, ['phonecatApp']); +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/main.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/main.ts new file mode 100644 index 0000000000..51b8e4d2a8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/main.ts @@ -0,0 +1,10 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { UpgradeModule } from '@angular/upgrade/static'; + +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => { + const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule; + upgrade.bootstrap(document.documentElement, ['phonecatApp']); +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.component.spec.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.component.spec.ts new file mode 100644 index 0000000000..e3b9143a94 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.component.spec.ts @@ -0,0 +1,59 @@ +// #docregion +// #docregion activatedroute +import { ActivatedRoute } from '@angular/router'; + +// #enddocregion activatedroute +import { Observable } from 'rxjs/Rx'; + +import { async, TestBed } from '@angular/core/testing'; + +import { PhoneDetailComponent } from './phone-detail.component'; +import { Phone, PhoneData } from '../core/phone/phone.service'; +import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe'; + +function xyzPhoneData(): PhoneData { + return { + name: 'phone xyz', + snippet: '', + images: ['image/url1.png', 'image/url2.png'] + }; +} + +class MockPhone { + get(id: string): Observable { + return Observable.of(xyzPhoneData()); + } +} + +// #docregion activatedroute + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +// #enddocregion activatedroute + +describe('PhoneDetailComponent', () => { + + // #docregion activatedroute + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CheckmarkPipe, PhoneDetailComponent ], + providers: [ + { provide: Phone, useClass: MockPhone }, + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) } + ] + }) + .compileComponents(); + })); + // #enddocregion activatedroute + + it('should fetch phone detail', () => { + const fixture = TestBed.createComponent(PhoneDetailComponent); + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.component.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.component.ts new file mode 100644 index 0000000000..32a3d40790 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.component.ts @@ -0,0 +1,33 @@ +// #docplaster +// #docregion +declare var angular: angular.IAngularStatic; +import { downgradeComponent } from '@angular/upgrade/static'; +import { Component } from '@angular/core'; + +import { Phone, PhoneData } from '../core/phone/phone.service'; +import { RouteParams } from '../ajs-upgraded-providers'; + +@Component({ + templateUrl: 'phone-detail.template.html', +}) +export class PhoneDetailComponent { + phone: PhoneData; + mainImageUrl: string; + + constructor(routeParams: RouteParams, phone: Phone) { + phone.get(routeParams['phoneId']).subscribe(phone => { + this.phone = phone; + this.setImage(phone.images[0]); + }); + } + + setImage(imageUrl: string) { + this.mainImageUrl = imageUrl; + } +} + +angular.module('phoneDetail') + .directive( + 'phoneDetail', + downgradeComponent({component: PhoneDetailComponent}) as angular.IDirectiveFactory + ); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.module.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.module.ts new file mode 100644 index 0000000000..fd7cb3b920 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.module.ts @@ -0,0 +1,7 @@ +'use strict'; + +// Define the `phoneDetail` module +angular.module('phoneDetail', [ + 'ngRoute', + 'core.phone' +]); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.template.html b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.template.html new file mode 100644 index 0000000000..46a96d66c3 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-detail/phone-detail.template.html @@ -0,0 +1,120 @@ + +
    +
    + +
    + +

    {{phone.name}}

    + +

    {{phone.description}}

    + +
      +
    • + +
    • +
    + +
      +
    • + Availability and Networks +
      +
      Availability
      +
      {{availability}}
      +
      +
    • +
    • + Battery +
      +
      Type
      +
      {{phone.battery?.type}}
      +
      Talk Time
      +
      {{phone.battery?.talkTime}}
      +
      Standby time (max)
      +
      {{phone.battery?.standbyTime}}
      +
      +
    • +
    • + Storage and Memory +
      +
      RAM
      +
      {{phone.storage?.ram}}
      +
      Internal Storage
      +
      {{phone.storage?.flash}}
      +
      +
    • +
    • + Connectivity +
      +
      Network Support
      +
      {{phone.connectivity?.cell}}
      +
      WiFi
      +
      {{phone.connectivity?.wifi}}
      +
      Bluetooth
      +
      {{phone.connectivity?.bluetooth}}
      +
      Infrared
      +
      {{phone.connectivity?.infrared | checkmark}}
      +
      GPS
      +
      {{phone.connectivity?.gps | checkmark}}
      +
      +
    • +
    • + Android +
      +
      OS Version
      +
      {{phone.android?.os}}
      +
      UI
      +
      {{phone.android?.ui}}
      +
      +
    • +
    • + Size and Weight +
      +
      Dimensions
      +
      {{dim}}
      +
      Weight
      +
      {{phone.sizeAndWeight?.weight}}
      +
      +
    • +
    • + Display +
      +
      Screen size
      +
      {{phone.display?.screenSize}}
      +
      Screen resolution
      +
      {{phone.display?.screenResolution}}
      +
      Touch screen
      +
      {{phone.display?.touchScreen | checkmark}}
      +
      +
    • +
    • + Hardware +
      +
      CPU
      +
      {{phone.hardware?.cpu}}
      +
      USB
      +
      {{phone.hardware?.usb}}
      +
      Audio / headphone jack
      +
      {{phone.hardware?.audioJack}}
      +
      FM Radio
      +
      {{phone.hardware?.fmRadio | checkmark}}
      +
      Accelerometer
      +
      {{phone.hardware?.accelerometer | checkmark}}
      +
      +
    • +
    • + Camera +
      +
      Primary
      +
      {{phone.camera?.primary}}
      +
      Features
      +
      {{phone.camera?.features?.join(', ')}}
      +
      +
    • +
    • + Additional Features +
      {{phone.additionalFeatures}}
      +
    • +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.component.spec.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.component.spec.ts new file mode 100644 index 0000000000..2bb9d2b62f --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.component.spec.ts @@ -0,0 +1,66 @@ +/* tslint:disable */ +// #docregion +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Rx'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SpyLocation } from '@angular/common/testing'; + +import { PhoneListComponent } from './phone-list.component'; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +class MockPhone { + query(): Observable { + return Observable.of([ + {name: 'Nexus S', snippet: '', images: []}, + {name: 'Motorola DROID', snippet: '', images: []} + ]); + } +} + +let fixture: ComponentFixture; + +describe('PhoneList', () => { + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PhoneListComponent ], + providers: [ + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) }, + { provide: Location, useClass: SpyLocation }, + { provide: Phone, useClass: MockPhone }, + ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PhoneListComponent); + }); + + it('should create "phones" model with 2 phones fetched from xhr', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2); + expect( + compiled.querySelector('.phone-list-item:nth-child(1)').textContent + ).toContain('Motorola DROID'); + expect( + compiled.querySelector('.phone-list-item:nth-child(2)').textContent + ).toContain('Nexus S'); + }); + + xit('should set the default value of orderProp model', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect( + compiled.querySelector('select option:last-child').selected + ).toBe(true); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.component.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.component.ts new file mode 100644 index 0000000000..40f522bec8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.component.ts @@ -0,0 +1,60 @@ +// #docregion +declare var angular: angular.IAngularStatic; +import { downgradeComponent } from '@angular/upgrade/static'; + +import { Component } from '@angular/core'; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +@Component({ + templateUrl: 'phone-list.template.html' +}) +export class PhoneListComponent { + phones: PhoneData[]; + query: string; + orderProp: string; + + constructor(phone: Phone) { + phone.query().subscribe(phones => { + this.phones = phones; + }); + this.orderProp = 'age'; + } + + getPhones(): PhoneData[] { + return this.sortPhones(this.filterPhones(this.phones)); + } + + private filterPhones(phones: PhoneData[]) { + if (phones && this.query) { + return phones.filter(phone => { + let name = phone.name.toLowerCase(); + let snippet = phone.snippet.toLowerCase(); + return name.indexOf(this.query) >= 0 || snippet.indexOf(this.query) >= 0; + }); + } + return phones; + } + + private sortPhones(phones: PhoneData[]) { + if (phones && this.orderProp) { + return phones + .slice(0) // Make a copy + .sort((a, b) => { + if (a[this.orderProp] < b[this.orderProp]) { + return -1; + } else if ([b[this.orderProp] < a[this.orderProp]]) { + return 1; + } else { + return 0; + } + }); + } + return phones; + } +} + +angular.module('phoneList') + .directive( + 'phoneList', + downgradeComponent({component: PhoneListComponent}) as angular.IDirectiveFactory + ); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.module.ts b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.module.ts new file mode 100644 index 0000000000..8ade7c5b88 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.module.ts @@ -0,0 +1,4 @@ +'use strict'; + +// Define the `phoneList` module +angular.module('phoneList', ['core.phone']); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.template.html b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.template.html new file mode 100644 index 0000000000..2678d384c2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phone-list/phone-list.template.html @@ -0,0 +1,38 @@ +
    +
    +
    + + +

    + Search: + +

    + +

    + Sort by: + +

    + +
    +
    + + + + + + +
    +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/dell-streak-7.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/dell-streak-7.json new file mode 100644 index 0000000000..a32eb6ff98 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/dell-streak-7.json @@ -0,0 +1,64 @@ +{ + "additionalFeatures": "Front Facing 1.3MP Camera", + "android": { + "os": "Android 2.2", + "ui": "Dell Stage" + }, + "availability": [ + "T-Mobile" + ], + "battery": { + "standbyTime": "", + "talkTime": "", + "type": "Lithium Ion (Li-Ion) (2780 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "T-mobile HSPA+ @ 2100/1900/AWS/850 MHz", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g" + }, + "description": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around. Android\u2122 2.2-based tablet with over-the-air upgrade capability for future OS releases. A vibrant 7-inch, multitouch display with full Adobe\u00ae Flash 10.1 pre-installed. Includes a 1.3 MP front-facing camera for face-to-face chats on popular services such as Qik or Skype. 16 GB of internal storage, plus Wi-Fi, Bluetooth and built-in GPS keeps you in touch with the world around you. Connect on your terms. Save with 2-year contract or flexibility with prepaid pay-as-you-go plans", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "7.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "nVidia Tegra T20", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "dell-streak-7", + "images": [ + "img/phones/dell-streak-7.0.jpg", + "img/phones/dell-streak-7.1.jpg", + "img/phones/dell-streak-7.2.jpg", + "img/phones/dell-streak-7.3.jpg", + "img/phones/dell-streak-7.4.jpg" + ], + "name": "Dell Streak 7", + "sizeAndWeight": { + "dimensions": [ + "199.9 mm (w)", + "119.8 mm (h)", + "12.4 mm (d)" + ], + "weight": "450.0 grams" + }, + "storage": { + "flash": "16000MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-atrix-4g.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-atrix-4g.json new file mode 100644 index 0000000000..ccca00e3b2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-atrix-4g.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "", + "android": { + "os": "Android 2.2", + "ui": "MOTOBLUR" + }, + "availability": [ + "AT&T" + ], + "battery": { + "standbyTime": "400 hours", + "talkTime": "5 hours", + "type": "Lithium Ion (Li-Ion) (1930 mAH)" + }, + "camera": { + "features": [ + "" + ], + "primary": "" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "WCDMA 850/1900/2100, GSM 850/900/1800/1900, HSDPA 14Mbps (Category 10) Edge Class 12, GPRS Class 12, eCompass, AGPS", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA ATRIX 4G gives you dual-core processing power and the revolutionary webtop application. With webtop and a compatible Motorola docking station, sold separately, you can surf the Internet with a full Firefox browser, create and edit docs, or access multimedia on a large screen almost anywhere.", + "display": { + "screenResolution": "QHD (960 x 540)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-atrix-4g", + "images": [ + "img/phones/motorola-atrix-4g.0.jpg", + "img/phones/motorola-atrix-4g.1.jpg", + "img/phones/motorola-atrix-4g.2.jpg", + "img/phones/motorola-atrix-4g.3.jpg" + ], + "name": "MOTOROLA ATRIX\u2122 4G", + "sizeAndWeight": { + "dimensions": [ + "63.5 mm (w)", + "117.75 mm (h)", + "10.95 mm (d)" + ], + "weight": "135.0 grams" + }, + "storage": { + "flash": "", + "ram": "" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-xoom-with-wi-fi.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-xoom-with-wi-fi.json new file mode 100644 index 0000000000..4ba9c8d5b5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-xoom-with-wi-fi.json @@ -0,0 +1,65 @@ +{ + "additionalFeatures": "Sensors: proximity, ambient light, barometer, gyroscope", + "android": { + "os": "Android 3.0", + "ui": "Honeycomb" + }, + "availability": [ + "" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other ( mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Motorola XOOM with Wi-Fi has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom-with-wi-fi", + "images": [ + "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "img/phones/motorola-xoom-with-wi-fi.1.jpg", + "img/phones/motorola-xoom-with-wi-fi.2.jpg", + "img/phones/motorola-xoom-with-wi-fi.3.jpg", + "img/phones/motorola-xoom-with-wi-fi.4.jpg", + "img/phones/motorola-xoom-with-wi-fi.5.jpg" + ], + "name": "Motorola XOOM\u2122 with Wi-Fi", + "sizeAndWeight": { + "dimensions": [ + "249.1 mm (w)", + "167.8 mm (h)", + "12.9 mm (d)" + ], + "weight": "708.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-xoom.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-xoom.json new file mode 100644 index 0000000000..f0f0c8711d --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/motorola-xoom.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "Front-facing camera. Sensors: proximity, ambient light, barometer, gyroscope.", + "android": { + "os": "Android 3.0", + "ui": "Android" + }, + "availability": [ + "Verizon" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other (3250 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "CDMA 800 /1900 LTE 700, Rx diversity in all bands", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA XOOM has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom", + "images": [ + "img/phones/motorola-xoom.0.jpg", + "img/phones/motorola-xoom.1.jpg", + "img/phones/motorola-xoom.2.jpg" + ], + "name": "MOTOROLA XOOM\u2122", + "sizeAndWeight": { + "dimensions": [ + "249.0 mm (w)", + "168.0 mm (h)", + "12.7 mm (d)" + ], + "weight": "726.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/nexus-s.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/nexus-s.json new file mode 100644 index 0000000000..5e712e2ff8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/nexus-s.json @@ -0,0 +1,69 @@ +{ + "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope, Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", + "android": { + "os": "Android 2.3", + "ui": "Android" + }, + "availability": [ + "M1,", + "O2,", + "Orange,", + "Singtel,", + "StarHub,", + "T-Mobile,", + "Vodafone" + ], + "battery": { + "standbyTime": "428 hours", + "talkTime": "6 hours", + "type": "Lithium Ion (Li-Ion) (1500 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "Quad-band GSM: 850, 900, 1800, 1900\r\nTri-band HSPA: 900, 2100, 1700\r\nHSPA type: HSDPA (7.2Mbps) HSUPA (5.76Mbps)", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Nexus S is the next generation of Nexus devices, co-developed by Google and Samsung. The latest Android platform (Gingerbread), paired with a 1 GHz Hummingbird processor and 16GB of memory, makes Nexus S one of the fastest phones on the market. It comes pre-installed with the best of Google apps and enabled with new and popular features like true multi-tasking, Wi-Fi hotspot, Internet Calling, NFC support, and full web browsing. With this device, users will also be the first to receive software upgrades and new Google mobile apps as soon as they become available. For more details, visit http://www.google.com/nexus.", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1GHz Cortex A8 (Hummingbird) processor", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "nexus-s", + "images": [ + "img/phones/nexus-s.0.jpg", + "img/phones/nexus-s.1.jpg", + "img/phones/nexus-s.2.jpg", + "img/phones/nexus-s.3.jpg" + ], + "name": "Nexus S", + "sizeAndWeight": { + "dimensions": [ + "63.0 mm (w)", + "123.9 mm (h)", + "10.88 mm (d)" + ], + "weight": "129.0 grams" + }, + "storage": { + "flash": "16384MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/phones.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/phones.json new file mode 100644 index 0000000000..339b94fbb5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/app/phones/phones.json @@ -0,0 +1,155 @@ +[ + { + "age": 0, + "id": "motorola-xoom-with-wi-fi", + "imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "name": "Motorola XOOM\u2122 with Wi-Fi", + "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 1, + "id": "motorola-xoom", + "imageUrl": "img/phones/motorola-xoom.0.jpg", + "name": "MOTOROLA XOOM\u2122", + "snippet": "The Next, Next Generation\n\nExperience the future with MOTOROLA XOOM, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 2, + "carrier": "AT&T", + "id": "motorola-atrix-4g", + "imageUrl": "img/phones/motorola-atrix-4g.0.jpg", + "name": "MOTOROLA ATRIX\u2122 4G", + "snippet": "MOTOROLA ATRIX 4G the world's most powerful smartphone." + }, + { + "age": 3, + "id": "dell-streak-7", + "imageUrl": "img/phones/dell-streak-7.0.jpg", + "name": "Dell Streak 7", + "snippet": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around." + }, + { + "age": 4, + "carrier": "Cellular South", + "id": "samsung-gem", + "imageUrl": "img/phones/samsung-gem.0.jpg", + "name": "Samsung Gem\u2122", + "snippet": "The Samsung Gem\u2122 brings you everything that you would expect and more from a touch display smart phone \u2013 more apps, more features and a more affordable price." + }, + { + "age": 5, + "carrier": "Dell", + "id": "dell-venue", + "imageUrl": "img/phones/dell-venue.0.jpg", + "name": "Dell Venue", + "snippet": "The Dell Venue; Your Personal Express Lane to Everything" + }, + { + "age": 6, + "carrier": "Best Buy", + "id": "nexus-s", + "imageUrl": "img/phones/nexus-s.0.jpg", + "name": "Nexus S", + "snippet": "Fast just got faster with Nexus S. A pure Google experience, Nexus S is the first phone to run Gingerbread (Android 2.3), the fastest version of Android yet." + }, + { + "age": 7, + "carrier": "Cellular South", + "id": "lg-axis", + "imageUrl": "img/phones/lg-axis.0.jpg", + "name": "LG Axis", + "snippet": "Android Powered, Google Maps Navigation, 5 Customizable Home Screens" + }, + { + "age": 8, + "id": "samsung-galaxy-tab", + "imageUrl": "img/phones/samsung-galaxy-tab.0.jpg", + "name": "Samsung Galaxy Tab\u2122", + "snippet": "Feel Free to Tab\u2122. The Samsung Galaxy Tab\u2122 brings you an ultra-mobile entertainment experience through its 7\u201d display, high-power processor and Adobe\u00ae Flash\u00ae Player compatibility." + }, + { + "age": 9, + "carrier": "Cellular South", + "id": "samsung-showcase-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg", + "name": "Samsung Showcase\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Showcase\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance, even outdoors" + }, + { + "age": 10, + "carrier": "Verizon", + "id": "droid-2-global-by-motorola", + "imageUrl": "img/phones/droid-2-global-by-motorola.0.jpg", + "name": "DROID\u2122 2 Global by Motorola", + "snippet": "The first smartphone with a 1.2 GHz processor and global capabilities." + }, + { + "age": 11, + "carrier": "Verizon", + "id": "droid-pro-by-motorola", + "imageUrl": "img/phones/droid-pro-by-motorola.0.jpg", + "name": "DROID\u2122 Pro by Motorola", + "snippet": "The next generation of DOES." + }, + { + "age": 12, + "carrier": "AT&T", + "id": "motorola-bravo-with-motoblur", + "imageUrl": "img/phones/motorola-bravo-with-motoblur.0.jpg", + "name": "MOTOROLA BRAVO\u2122 with MOTOBLUR\u2122", + "snippet": "An experience to cheer about." + }, + { + "age": 13, + "carrier": "T-Mobile", + "id": "motorola-defy-with-motoblur", + "imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg", + "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", + "snippet": "Are you ready for everything life throws your way?" + }, + { + "age": 14, + "carrier": "T-Mobile", + "id": "t-mobile-mytouch-4g", + "imageUrl": "img/phones/t-mobile-mytouch-4g.0.jpg", + "name": "T-Mobile myTouch 4G", + "snippet": "The T-Mobile myTouch 4G is a premium smartphone designed to deliver blazing fast 4G speeds so that you can video chat from practically anywhere, with or without Wi-Fi." + }, + { + "age": 15, + "carrier": "US Cellular", + "id": "samsung-mesmerize-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg", + "name": "Samsung Mesmerize\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Mesmerize\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance,even outdoors" + }, + { + "age": 16, + "carrier": "Sprint", + "id": "sanyo-zio", + "imageUrl": "img/phones/sanyo-zio.0.jpg", + "name": "SANYO ZIO", + "snippet": "The Sanyo Zio by Kyocera is an Android smartphone with a combination of ultra-sleek styling, strong performance and unprecedented value." + }, + { + "age": 17, + "id": "samsung-transform", + "imageUrl": "img/phones/samsung-transform.0.jpg", + "name": "Samsung Transform\u2122", + "snippet": "The Samsung Transform\u2122 brings you a fun way to customize your Android powered touch screen phone to just the way you like it through your favorite themed \u201cSprint ID Service Pack\u201d." + }, + { + "age": 18, + "id": "t-mobile-g2", + "imageUrl": "img/phones/t-mobile-g2.0.jpg", + "name": "T-Mobile G2", + "snippet": "The T-Mobile G2 with Google is the first smartphone built for 4G speeds on T-Mobile's new network. Get the information you need, faster than you ever thought possible." + }, + { + "age": 19, + "id": "motorola-charm-with-motoblur", + "imageUrl": "img/phones/motorola-charm-with-motoblur.0.jpg", + "name": "Motorola CHARM\u2122 with MOTOBLUR\u2122", + "snippet": "Motorola CHARM fits easily in your pocket or palm. Includes MOTOBLUR service." + } +] diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/bs-config.aot.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/bs-config.aot.json new file mode 100644 index 0000000000..e59a7403a0 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/bs-config.aot.json @@ -0,0 +1,14 @@ +{ + "open": false, + "logLevel": "silent", + "port": 8080, + "server": { + "baseDir": "aot", + "routes": { + "/node_modules": "node_modules" + }, + "middleware": { + "0": null + } + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/copy-dist-files.js b/public/docs/_examples/upgrade-phonecat-3-router/ts/copy-dist-files.js new file mode 100644 index 0000000000..a857af085c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/copy-dist-files.js @@ -0,0 +1,25 @@ +// #docregion +var fsExtra = require('fs-extra'); +var resources = [ + // polyfills + 'node_modules/core-js/client/shim.min.js', + 'node_modules/zone.js/dist/zone.min.js', + // css + 'app/app.css', + 'app/app.animations.css', + // images and json files + 'app/img/', + 'app/phones/', + // app files + 'app/app.module.ajs.js', + 'app/app.config.js', + 'app/app.animations.js', + 'app/core/core.module.js', + 'app/core/phone/phone.module.js', + 'app/phone-list/phone-list.module.js', + 'app/phone-detail/phone-detail.module.js' +]; +resources.map(function(sourcePath) { + var destPath = `aot/${sourcePath}`; + fsExtra.copySync(sourcePath, destPath); +}); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/example-config.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/example-config.json new file mode 100644 index 0000000000..401c14f835 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/example-config.json @@ -0,0 +1,5 @@ +{ + "build": "build:upgrade", + "run": "serve:upgrade", + "unittesting": true +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/index.html b/public/docs/_examples/upgrade-phonecat-3-router/ts/index.html new file mode 100644 index 0000000000..572c80d315 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/index.html @@ -0,0 +1,44 @@ + + + + + + + + + Google Phone Gallery + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/rollup-config.js b/public/docs/_examples/upgrade-phonecat-3-router/ts/rollup-config.js new file mode 100644 index 0000000000..aeb227689c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/rollup-config.js @@ -0,0 +1,21 @@ +// #docregion +import rollup from 'rollup' +import nodeResolve from 'rollup-plugin-node-resolve' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' + +//paths are relative to the execution path +export default { + entry: 'app/main-aot.js', + dest: 'aot/dist/build.js', // output a single application bundle + sourceMap: true, + sourceMapFile: 'aot/dist/build.js.map', + format: 'iife', + plugins: [ + nodeResolve({jsnext: true, module: true}), + commonjs({ + include: ['node_modules/rxjs/**'] + }), + uglify() + ] +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-3-router/ts/systemjs.config.1.js new file mode 100644 index 0000000000..b801d42bad --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/systemjs.config.1.js @@ -0,0 +1,48 @@ +/** + * System configuration for Angular samples + * Adjust as necessary for your application needs. + */ +(function (global) { + // #docregion paths + System.config({ + paths: { + // paths serve as alias + 'npm:': '/node_modules/' + }, + map: { + app: '/app', + // #enddocregion paths + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', + + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api', + // #docregion paths + }, + // #enddocregion paths + // packages tells the System loader how to load when no filename and/or no extension + packages: { + 'app': { + main: './main.js', + defaultExtension: 'js' + }, + rxjs: { + defaultExtension: 'js' + }, + 'angular-in-memory-web-api': { + main: './index.js', + defaultExtension: 'js' + } + } + }); +})(this); diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/tsconfig-aot.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/tsconfig-aot.json new file mode 100644 index 0000000000..58f9de3309 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/tsconfig-aot.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "removeComments": false, + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + + "files": [ + "app/app.module.ts", + "app/main-aot.ts" + ], + + "angularCompilerOptions": { + "genDir": "aot", + "skipMetadataEmit" : true + } +} diff --git a/public/docs/_examples/upgrade-phonecat-3-router/ts/tsconfig.json b/public/docs/_examples/upgrade-phonecat-3-router/ts/tsconfig.json new file mode 100644 index 0000000000..f267800f14 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-3-router/ts/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*", + "**/*-aot.ts" + ] +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/README.md b/public/docs/_examples/upgrade-phonecat-4-final/README.md new file mode 100644 index 0000000000..7448da44e6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/README.md @@ -0,0 +1,24 @@ +This is the Angular Phonecat application adjusted to fit our boilerplate project +structure. + +The following changes from vanilla Phonecat are applied: + +* Karma config for unit tests is in karma.conf.ng1.js because the boilerplate + Karma config is not compatible with the way tests in this project need to be run. + The shell script run-unit-tests.sh can be used to run the unit tests. +* E2E tests have been moved to the parent directory, where `run-e2e-tests` can + discover and run them along with all the other examples. +* Most of the phone JSON and image data removed in the interest of keeping + repo weight down. Keeping enough to retain testability of the app. + +## Running the app + +Start like any example + + npm run start + +## Running E2E tests + +Like for any example (at the project root): + + gulp run-e2e-tests --filter=phonecat-3 diff --git a/public/docs/_examples/upgrade-phonecat-4-final/e2e-spec.ts b/public/docs/_examples/upgrade-phonecat-4-final/e2e-spec.ts new file mode 100644 index 0000000000..6f47c54d02 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/e2e-spec.ts @@ -0,0 +1,109 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +// Angular E2E Testing Guide: +// https://docs.angularjs.org/guide/e2e-testing + +describe('PhoneCat Application', function() { + + // #docregion redirect + it('should redirect `index.html` to `index.html#!/phones', function() { + browser.get('index.html'); + browser.waitForAngular(); + browser.getCurrentUrl().then(function(url: string) { + expect(url.endsWith('/phones')).toBe(true); + }); + }); + // #enddocregion redirect + + describe('View: Phone list', function() { + + beforeEach(function() { + browser.get('index.html#!/phones'); + }); + + it('should filter the phone list as a user types into the search box', function() { + let phoneList = element.all(by.css('.phones li')); + let query = element(by.css('input')); + + expect(phoneList.count()).toBe(20); + + query.sendKeys('nexus'); + expect(phoneList.count()).toBe(1); + + query.clear(); + query.sendKeys('motorola'); + expect(phoneList.count()).toBe(8); + }); + + it('should be possible to control phone order via the drop-down menu', function() { + let queryField = element(by.css('input')); + let orderSelect = element(by.css('select')); + let nameOption = orderSelect.element(by.css('option[value="name"]')); + let phoneNameColumn = element.all(by.css('.phones .name')); + + function getNames() { + return phoneNameColumn.map(function(elem) { + return elem.getText(); + }); + } + + queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter + + expect(getNames()).toEqual([ + 'Motorola XOOM\u2122 with Wi-Fi', + 'MOTOROLA XOOM\u2122' + ]); + + nameOption.click(); + + expect(getNames()).toEqual([ + 'MOTOROLA XOOM\u2122', + 'Motorola XOOM\u2122 with Wi-Fi' + ]); + }); + + // #docregion links + it('should render phone specific links', function() { + let query = element(by.css('input')); + query.sendKeys('nexus'); + element.all(by.css('.phones li a')).first().click(); + browser.getCurrentUrl().then(function(url: string) { + expect(url.endsWith('/phones/nexus-s')).toBe(true); + }); + }); + // #enddocregion links + + }); + + describe('View: Phone detail', function() { + + beforeEach(function() { + browser.get('index.html#!/phones/nexus-s'); + }); + + it('should display the `nexus-s` page', function() { + expect(element(by.css('h1')).getText()).toBe('Nexus S'); + }); + + it('should display the first phone image as the main phone image', function() { + let mainImage = element(by.css('img.phone.selected')); + + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + it('should swap the main image when clicking on a thumbnail image', function() { + let mainImage = element(by.css('img.phone.selected')); + let thumbnails = element.all(by.css('.phone-thumbs img')); + + thumbnails.get(2).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); + + thumbnails.get(0).click(); + expect(mainImage.getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); + }); + + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app-routing.module.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app-routing.module.ts new file mode 100644 index 0000000000..f64d82e253 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app-routing.module.ts @@ -0,0 +1,23 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { Routes, RouterModule } from '@angular/router'; +import { APP_BASE_HREF, HashLocationStrategy, LocationStrategy } from '@angular/common'; + +import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; +import { PhoneListComponent } from './phone-list/phone-list.component'; + +const routes: Routes = [ + { path: '', redirectTo: 'phones', pathMatch: 'full' }, + { path: 'phones', component: PhoneListComponent }, + { path: 'phones/:phoneId', component: PhoneDetailComponent } +]; + +@NgModule({ + imports: [ RouterModule.forRoot(routes) ], + exports: [ RouterModule ], + providers: [ + { provide: APP_BASE_HREF, useValue: '!' }, + { provide: LocationStrategy, useClass: HashLocationStrategy }, + ] +}) +export class AppRoutingModule { } diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.component.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.component.ts new file mode 100644 index 0000000000..c476614121 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'phonecat-app', + template: '' +}) +export class AppComponent { } diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.css b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.css new file mode 100644 index 0000000000..f4b45b02a5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.css @@ -0,0 +1,93 @@ +body { + padding: 20px; +} + +h1 { + border-bottom: 1px solid gray; + margin-top: 0; +} + +/* View: Phone list */ +.phones { + list-style: none; +} + +.phones li { + clear: both; + height: 115px; + padding-top: 15px; +} + +.thumb { + float: left; + height: 100px; + margin: -0.5em 1em 1.5em 0; + padding-bottom: 1em; + width: 100px; +} + +/* View: Phone detail */ +.phone { + background-color: white; + display: none; + float: left; + height: 400px; + margin-bottom: 2em; + margin-right: 3em; + padding: 2em; + width: 400px; +} + +.phone:first-child { + display: block; +} + +.phone-images { + background-color: white; + float: left; + height: 450px; + overflow: hidden; + position: relative; + width: 450px; +} + +.phone-thumbs { + list-style: none; + margin: 0; +} + +.phone-thumbs img { + height: 100px; + padding: 1em; + width: 100px; +} + +.phone-thumbs li { + background-color: white; + border: 1px solid black; + cursor: pointer; + display: inline-block; + margin: 1em; +} + +.specs { + clear: both; + list-style: none; + margin: 0; + padding: 0; +} + +.specs dt { + font-weight: bold; +} + +.specs > li { + display: inline-block; + vertical-align: top; + width: 200px; +} + +.specs > li > span { + font-size: 1.2em; + font-weight: bold; +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.module.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.module.ts new file mode 100644 index 0000000000..607ecab8c9 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/app.module.ts @@ -0,0 +1,34 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { FormsModule } from '@angular/forms'; +import { HttpModule } from '@angular/http'; + +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { CheckmarkPipe } from './core/checkmark/checkmark.pipe'; +import { Phone } from './core/phone/phone.service'; +import { PhoneDetailComponent } from './phone-detail/phone-detail.component'; +import { PhoneListComponent } from './phone-list/phone-list.component'; + +@NgModule({ + imports: [ + BrowserModule, + FormsModule, + HttpModule, + AppRoutingModule + ], + declarations: [ + AppComponent, + PhoneListComponent, + CheckmarkPipe, + PhoneDetailComponent + ], + providers: [ + Phone + ], + // #docregion bootstrap + bootstrap: [ AppComponent ] + // #enddocregion bootstrap +}) +export class AppModule {} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/checkmark/checkmark.pipe.spec.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/checkmark/checkmark.pipe.spec.ts new file mode 100644 index 0000000000..75150500a6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/checkmark/checkmark.pipe.spec.ts @@ -0,0 +1,10 @@ +import { CheckmarkPipe } from './checkmark.pipe'; + +describe('CheckmarkPipe', function() { + + it('should convert boolean values to unicode checkmark or cross', function () { + const checkmarkPipe = new CheckmarkPipe(); + expect(checkmarkPipe.transform(true)).toBe('\u2713'); + expect(checkmarkPipe.transform(false)).toBe('\u2718'); + }); +}); diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/checkmark/checkmark.pipe.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/checkmark/checkmark.pipe.ts new file mode 100644 index 0000000000..888017e15c --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/checkmark/checkmark.pipe.ts @@ -0,0 +1,9 @@ +// #docregion +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({name: 'checkmark'}) +export class CheckmarkPipe implements PipeTransform { + transform(input: boolean) { + return input ? '\u2713' : '\u2718'; + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/phone/phone.service.spec.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/phone/phone.service.spec.ts new file mode 100644 index 0000000000..e3a422965b --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/phone/phone.service.spec.ts @@ -0,0 +1,49 @@ +import { inject, TestBed } from '@angular/core/testing'; +import { + Http, + BaseRequestOptions, + ResponseOptions, + Response +} from '@angular/http'; +import { MockBackend, MockConnection } from '@angular/http/testing'; +import { Phone, PhoneData } from './phone.service'; + +describe('Phone', function() { + let phone: Phone; + let phonesData: PhoneData[] = [ + {name: 'Phone X', snippet: '', images: []}, + {name: 'Phone Y', snippet: '', images: []}, + {name: 'Phone Z', snippet: '', images: []} + ]; + let mockBackend: MockBackend; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + Phone, + MockBackend, + BaseRequestOptions, + { provide: Http, + useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options), + deps: [MockBackend, BaseRequestOptions] + } + ] + }); + }); + + beforeEach(inject([MockBackend, Phone], (_mockBackend_: MockBackend, _phone_: Phone) => { + mockBackend = _mockBackend_; + phone = _phone_; + })); + + it('should fetch the phones data from `/phones/phones.json`', (done: () => void) => { + mockBackend.connections.subscribe((conn: MockConnection) => { + conn.mockRespond(new Response(new ResponseOptions({body: JSON.stringify(phonesData)}))); + }); + phone.query().subscribe(result => { + expect(result).toEqual(phonesData); + done(); + }); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/phone/phone.service.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/phone/phone.service.ts new file mode 100644 index 0000000000..83a837afb7 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/core/phone/phone.service.ts @@ -0,0 +1,25 @@ +// #docregion +import { Injectable } from '@angular/core'; +import { Http, Response } from '@angular/http'; +import { Observable } from 'rxjs/Rx'; + +import 'rxjs/add/operator/map'; + +export interface PhoneData { + name: string; + snippet: string; + images: string[]; +} + +@Injectable() +export class Phone { + constructor(private http: Http) { } + query(): Observable { + return this.http.get(`phones/phones.json`) + .map((res: Response) => res.json()); + } + get(id: string): Observable { + return this.http.get(`phones/${id}.json`) + .map((res: Response) => res.json()); + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/.gitkeep b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.0.jpg new file mode 100644 index 0000000000..7ce0dce4ee Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.1.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.1.jpg new file mode 100644 index 0000000000..ed8cad89fb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.2.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.2.jpg new file mode 100644 index 0000000000..c83529e0f9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.3.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.3.jpg new file mode 100644 index 0000000000..cd2c30280d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.4.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.4.jpg new file mode 100644 index 0000000000..b4d8472da8 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-streak-7.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-venue.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-venue.0.jpg new file mode 100644 index 0000000000..b4cb4eb25f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/dell-venue.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/droid-2-global-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/droid-2-global-by-motorola.0.jpg new file mode 100644 index 0000000000..60700a2ab3 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/droid-2-global-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/droid-pro-by-motorola.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/droid-pro-by-motorola.0.jpg new file mode 100644 index 0000000000..c7710de986 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/droid-pro-by-motorola.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/lg-axis.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/lg-axis.0.jpg new file mode 100644 index 0000000000..55e5a23bb2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/lg-axis.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.0.jpg new file mode 100644 index 0000000000..2446159e93 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.1.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.1.jpg new file mode 100644 index 0000000000..867f207459 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.2.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.2.jpg new file mode 100644 index 0000000000..27d78338c4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.3.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.3.jpg new file mode 100644 index 0000000000..29459a68a4 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-atrix-4g.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg new file mode 100644 index 0000000000..e452ae7e7c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-bravo-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg new file mode 100644 index 0000000000..21e4b8d741 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-charm-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg new file mode 100644 index 0000000000..c7c5e3ba0c Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-defy-with-motoblur.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg new file mode 100644 index 0000000000..a6c993291e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg new file mode 100644 index 0000000000..400b89e2df Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg new file mode 100644 index 0000000000..86b55d28dd Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg new file mode 100644 index 0000000000..85ec293ae5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg new file mode 100644 index 0000000000..75ef1464cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.4.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg new file mode 100644 index 0000000000..4d42db4330 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom-with-wi-fi.5.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.0.jpg new file mode 100644 index 0000000000..bf6954bbd5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.1.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.1.jpg new file mode 100644 index 0000000000..659688a47d Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.2.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.2.jpg new file mode 100644 index 0000000000..ce0ff1002e Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/motorola-xoom.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.0.jpg new file mode 100644 index 0000000000..0952bc79c2 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.1.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.1.jpg new file mode 100644 index 0000000000..f33004dd7f Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.1.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.2.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.2.jpg new file mode 100644 index 0000000000..c5c63621f1 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.2.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.3.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.3.jpg new file mode 100644 index 0000000000..e51f75b0ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/nexus-s.3.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-galaxy-tab.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-galaxy-tab.0.jpg new file mode 100644 index 0000000000..3750377ad9 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-galaxy-tab.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-gem.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-gem.0.jpg new file mode 100644 index 0000000000..0d5024a026 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-gem.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg new file mode 100644 index 0000000000..11b8f860cb Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-transform.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-transform.0.jpg new file mode 100644 index 0000000000..0e3107caf5 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/samsung-transform.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/sanyo-zio.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/sanyo-zio.0.jpg new file mode 100644 index 0000000000..9eeb9b96ed Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/sanyo-zio.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/t-mobile-g2.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/t-mobile-g2.0.jpg new file mode 100644 index 0000000000..6b6c09e058 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/t-mobile-g2.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg new file mode 100644 index 0000000000..beba1f6827 Binary files /dev/null and b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/img/phones/t-mobile-mytouch-4g.0.jpg differ diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/main.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/main.ts new file mode 100644 index 0000000000..08be7a99ba --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/main.ts @@ -0,0 +1,10 @@ +// #docregion +// #docregion imports +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; +// #enddocregion imports + +// #docregion bootstrap +platformBrowserDynamic().bootstrapModule(AppModule); +// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.spec.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.spec.ts new file mode 100644 index 0000000000..e3b9143a94 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.spec.ts @@ -0,0 +1,59 @@ +// #docregion +// #docregion activatedroute +import { ActivatedRoute } from '@angular/router'; + +// #enddocregion activatedroute +import { Observable } from 'rxjs/Rx'; + +import { async, TestBed } from '@angular/core/testing'; + +import { PhoneDetailComponent } from './phone-detail.component'; +import { Phone, PhoneData } from '../core/phone/phone.service'; +import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe'; + +function xyzPhoneData(): PhoneData { + return { + name: 'phone xyz', + snippet: '', + images: ['image/url1.png', 'image/url2.png'] + }; +} + +class MockPhone { + get(id: string): Observable { + return Observable.of(xyzPhoneData()); + } +} + +// #docregion activatedroute + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +// #enddocregion activatedroute + +describe('PhoneDetailComponent', () => { + + // #docregion activatedroute + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ CheckmarkPipe, PhoneDetailComponent ], + providers: [ + { provide: Phone, useClass: MockPhone }, + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) } + ] + }) + .compileComponents(); + })); + // #enddocregion activatedroute + + it('should fetch phone detail', () => { + const fixture = TestBed.createComponent(PhoneDetailComponent); + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.ts new file mode 100644 index 0000000000..dd47f746f6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.component.ts @@ -0,0 +1,27 @@ +// #docplaster +// #docregion +import { Component } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +import { Phone, PhoneData } from '../core/phone/phone.service'; + +@Component({ + selector: 'phone-detail', + templateUrl: './phone-detail.template.html' +}) +export class PhoneDetailComponent { + phone: PhoneData; + mainImageUrl: string; + + constructor(activatedRoute: ActivatedRoute, phone: Phone) { + phone.get(activatedRoute.snapshot.params['phoneId']) + .subscribe((p: PhoneData) => { + this.phone = p; + this.setImage(p.images[0]); + }); + } + + setImage(imageUrl: string) { + this.mainImageUrl = imageUrl; + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.template.html b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.template.html new file mode 100644 index 0000000000..46a96d66c3 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-detail/phone-detail.template.html @@ -0,0 +1,120 @@ + +
    +
    + +
    + +

    {{phone.name}}

    + +

    {{phone.description}}

    + +
      +
    • + +
    • +
    + +
      +
    • + Availability and Networks +
      +
      Availability
      +
      {{availability}}
      +
      +
    • +
    • + Battery +
      +
      Type
      +
      {{phone.battery?.type}}
      +
      Talk Time
      +
      {{phone.battery?.talkTime}}
      +
      Standby time (max)
      +
      {{phone.battery?.standbyTime}}
      +
      +
    • +
    • + Storage and Memory +
      +
      RAM
      +
      {{phone.storage?.ram}}
      +
      Internal Storage
      +
      {{phone.storage?.flash}}
      +
      +
    • +
    • + Connectivity +
      +
      Network Support
      +
      {{phone.connectivity?.cell}}
      +
      WiFi
      +
      {{phone.connectivity?.wifi}}
      +
      Bluetooth
      +
      {{phone.connectivity?.bluetooth}}
      +
      Infrared
      +
      {{phone.connectivity?.infrared | checkmark}}
      +
      GPS
      +
      {{phone.connectivity?.gps | checkmark}}
      +
      +
    • +
    • + Android +
      +
      OS Version
      +
      {{phone.android?.os}}
      +
      UI
      +
      {{phone.android?.ui}}
      +
      +
    • +
    • + Size and Weight +
      +
      Dimensions
      +
      {{dim}}
      +
      Weight
      +
      {{phone.sizeAndWeight?.weight}}
      +
      +
    • +
    • + Display +
      +
      Screen size
      +
      {{phone.display?.screenSize}}
      +
      Screen resolution
      +
      {{phone.display?.screenResolution}}
      +
      Touch screen
      +
      {{phone.display?.touchScreen | checkmark}}
      +
      +
    • +
    • + Hardware +
      +
      CPU
      +
      {{phone.hardware?.cpu}}
      +
      USB
      +
      {{phone.hardware?.usb}}
      +
      Audio / headphone jack
      +
      {{phone.hardware?.audioJack}}
      +
      FM Radio
      +
      {{phone.hardware?.fmRadio | checkmark}}
      +
      Accelerometer
      +
      {{phone.hardware?.accelerometer | checkmark}}
      +
      +
    • +
    • + Camera +
      +
      Primary
      +
      {{phone.camera?.primary}}
      +
      Features
      +
      {{phone.camera?.features?.join(', ')}}
      +
      +
    • +
    • + Additional Features +
      {{phone.additionalFeatures}}
      +
    • +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.spec.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.spec.ts new file mode 100644 index 0000000000..834c93df8f --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.spec.ts @@ -0,0 +1,71 @@ +/* tslint:disable */ +// #docregion routestuff +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Observable } from 'rxjs/Rx'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SpyLocation } from '@angular/common/testing'; + +import { PhoneListComponent } from './phone-list.component'; +import { Phone, PhoneData } from '../core/phone/phone.service'; + +// #enddocregion routestuff + +class ActivatedRouteMock { + constructor(public snapshot: any) {} +} + +class MockPhone { + query(): Observable { + return Observable.of([ + {name: 'Nexus S', snippet: '', images: []}, + {name: 'Motorola DROID', snippet: '', images: []} + ]); + } +} + +let fixture: ComponentFixture; + +describe('PhoneList', () => { + + // #docregion routestuff + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PhoneListComponent ], + providers: [ + { provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) }, + { provide: Location, useClass: SpyLocation }, + { provide: Phone, useClass: MockPhone }, + ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PhoneListComponent); + }); + // #enddocregion routestuff + + it('should create "phones" model with 2 phones fetched from xhr', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2); + expect( + compiled.querySelector('.phone-list-item:nth-child(1)').textContent + ).toContain('Motorola DROID'); + expect( + compiled.querySelector('.phone-list-item:nth-child(2)').textContent + ).toContain('Nexus S'); + }); + + xit('should set the default value of orderProp model', () => { + fixture.detectChanges(); + let compiled = fixture.debugElement.nativeElement; + expect( + compiled.querySelector('select option:last-child').selected + ).toBe(true); + }); + +}); diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.ts b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.ts new file mode 100644 index 0000000000..6cfd172027 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.component.ts @@ -0,0 +1,53 @@ +// #docregion +import { Component } from '@angular/core'; + +import { Phone, PhoneData } from '../core/phone/phone.service'; + +@Component({ + selector: 'phone-list', + templateUrl: './phone-list.template.html', +}) +export class PhoneListComponent { + phones: PhoneData[]; + query: string; + orderProp: string; + + constructor(phone: Phone) { + phone.query().subscribe(phones => { + this.phones = phones; + }); + this.orderProp = 'age'; + } + + getPhones(): PhoneData[] { + return this.sortPhones(this.filterPhones(this.phones)); + } + + private filterPhones(phones: PhoneData[]) { + if (phones && this.query) { + return phones.filter(phone => { + let name = phone.name.toLowerCase(); + let snippet = phone.snippet.toLowerCase(); + return name.indexOf(this.query) >= 0 || snippet.indexOf(this.query) >= 0; + }); + } + return phones; + } + + private sortPhones(phones: PhoneData[]) { + if (phones && this.orderProp) { + return phones + .slice(0) // Make a copy + .sort((a, b) => { + if (a[this.orderProp] < b[this.orderProp]) { + return -1; + } else if ([b[this.orderProp] < a[this.orderProp]]) { + return 1; + } else { + return 0; + } + }); + } + return phones; + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.template.html b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.template.html new file mode 100644 index 0000000000..b4a994b297 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phone-list/phone-list.template.html @@ -0,0 +1,40 @@ +
    +
    +
    + + + +

    + Search: + +

    + +

    + Sort by: + +

    + + +
    +
    + + + + + + +
    +
    +
    diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/dell-streak-7.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/dell-streak-7.json new file mode 100644 index 0000000000..a32eb6ff98 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/dell-streak-7.json @@ -0,0 +1,64 @@ +{ + "additionalFeatures": "Front Facing 1.3MP Camera", + "android": { + "os": "Android 2.2", + "ui": "Dell Stage" + }, + "availability": [ + "T-Mobile" + ], + "battery": { + "standbyTime": "", + "talkTime": "", + "type": "Lithium Ion (Li-Ion) (2780 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "T-mobile HSPA+ @ 2100/1900/AWS/850 MHz", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g" + }, + "description": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around. Android\u2122 2.2-based tablet with over-the-air upgrade capability for future OS releases. A vibrant 7-inch, multitouch display with full Adobe\u00ae Flash 10.1 pre-installed. Includes a 1.3 MP front-facing camera for face-to-face chats on popular services such as Qik or Skype. 16 GB of internal storage, plus Wi-Fi, Bluetooth and built-in GPS keeps you in touch with the world around you. Connect on your terms. Save with 2-year contract or flexibility with prepaid pay-as-you-go plans", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "7.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "nVidia Tegra T20", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "dell-streak-7", + "images": [ + "img/phones/dell-streak-7.0.jpg", + "img/phones/dell-streak-7.1.jpg", + "img/phones/dell-streak-7.2.jpg", + "img/phones/dell-streak-7.3.jpg", + "img/phones/dell-streak-7.4.jpg" + ], + "name": "Dell Streak 7", + "sizeAndWeight": { + "dimensions": [ + "199.9 mm (w)", + "119.8 mm (h)", + "12.4 mm (d)" + ], + "weight": "450.0 grams" + }, + "storage": { + "flash": "16000MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-atrix-4g.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-atrix-4g.json new file mode 100644 index 0000000000..ccca00e3b2 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-atrix-4g.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "", + "android": { + "os": "Android 2.2", + "ui": "MOTOBLUR" + }, + "availability": [ + "AT&T" + ], + "battery": { + "standbyTime": "400 hours", + "talkTime": "5 hours", + "type": "Lithium Ion (Li-Ion) (1930 mAH)" + }, + "camera": { + "features": [ + "" + ], + "primary": "" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "WCDMA 850/1900/2100, GSM 850/900/1800/1900, HSDPA 14Mbps (Category 10) Edge Class 12, GPRS Class 12, eCompass, AGPS", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA ATRIX 4G gives you dual-core processing power and the revolutionary webtop application. With webtop and a compatible Motorola docking station, sold separately, you can surf the Internet with a full Firefox browser, create and edit docs, or access multimedia on a large screen almost anywhere.", + "display": { + "screenResolution": "QHD (960 x 540)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-atrix-4g", + "images": [ + "img/phones/motorola-atrix-4g.0.jpg", + "img/phones/motorola-atrix-4g.1.jpg", + "img/phones/motorola-atrix-4g.2.jpg", + "img/phones/motorola-atrix-4g.3.jpg" + ], + "name": "MOTOROLA ATRIX\u2122 4G", + "sizeAndWeight": { + "dimensions": [ + "63.5 mm (w)", + "117.75 mm (h)", + "10.95 mm (d)" + ], + "weight": "135.0 grams" + }, + "storage": { + "flash": "", + "ram": "" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-xoom-with-wi-fi.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-xoom-with-wi-fi.json new file mode 100644 index 0000000000..4ba9c8d5b5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-xoom-with-wi-fi.json @@ -0,0 +1,65 @@ +{ + "additionalFeatures": "Sensors: proximity, ambient light, barometer, gyroscope", + "android": { + "os": "Android 3.0", + "ui": "Honeycomb" + }, + "availability": [ + "" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other ( mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Motorola XOOM with Wi-Fi has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom-with-wi-fi", + "images": [ + "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "img/phones/motorola-xoom-with-wi-fi.1.jpg", + "img/phones/motorola-xoom-with-wi-fi.2.jpg", + "img/phones/motorola-xoom-with-wi-fi.3.jpg", + "img/phones/motorola-xoom-with-wi-fi.4.jpg", + "img/phones/motorola-xoom-with-wi-fi.5.jpg" + ], + "name": "Motorola XOOM\u2122 with Wi-Fi", + "sizeAndWeight": { + "dimensions": [ + "249.1 mm (w)", + "167.8 mm (h)", + "12.9 mm (d)" + ], + "weight": "708.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-xoom.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-xoom.json new file mode 100644 index 0000000000..f0f0c8711d --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/motorola-xoom.json @@ -0,0 +1,62 @@ +{ + "additionalFeatures": "Front-facing camera. Sensors: proximity, ambient light, barometer, gyroscope.", + "android": { + "os": "Android 3.0", + "ui": "Android" + }, + "availability": [ + "Verizon" + ], + "battery": { + "standbyTime": "336 hours", + "talkTime": "24 hours", + "type": "Other (3250 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "CDMA 800 /1900 LTE 700, Rx diversity in all bands", + "gps": true, + "infrared": false, + "wifi": "802.11 a/b/g/n" + }, + "description": "MOTOROLA XOOM has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.", + "display": { + "screenResolution": "WXGA (1200 x 800)", + "screenSize": "10.1 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1 GHz Dual Core Tegra 2", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "motorola-xoom", + "images": [ + "img/phones/motorola-xoom.0.jpg", + "img/phones/motorola-xoom.1.jpg", + "img/phones/motorola-xoom.2.jpg" + ], + "name": "MOTOROLA XOOM\u2122", + "sizeAndWeight": { + "dimensions": [ + "249.0 mm (w)", + "168.0 mm (h)", + "12.7 mm (d)" + ], + "weight": "726.0 grams" + }, + "storage": { + "flash": "32000MB", + "ram": "1000MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/nexus-s.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/nexus-s.json new file mode 100644 index 0000000000..5e712e2ff8 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/nexus-s.json @@ -0,0 +1,69 @@ +{ + "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope, Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)", + "android": { + "os": "Android 2.3", + "ui": "Android" + }, + "availability": [ + "M1,", + "O2,", + "Orange,", + "Singtel,", + "StarHub,", + "T-Mobile,", + "Vodafone" + ], + "battery": { + "standbyTime": "428 hours", + "talkTime": "6 hours", + "type": "Lithium Ion (Li-Ion) (1500 mAH)" + }, + "camera": { + "features": [ + "Flash", + "Video" + ], + "primary": "5.0 megapixels" + }, + "connectivity": { + "bluetooth": "Bluetooth 2.1", + "cell": "Quad-band GSM: 850, 900, 1800, 1900\r\nTri-band HSPA: 900, 2100, 1700\r\nHSPA type: HSDPA (7.2Mbps) HSUPA (5.76Mbps)", + "gps": true, + "infrared": false, + "wifi": "802.11 b/g/n" + }, + "description": "Nexus S is the next generation of Nexus devices, co-developed by Google and Samsung. The latest Android platform (Gingerbread), paired with a 1 GHz Hummingbird processor and 16GB of memory, makes Nexus S one of the fastest phones on the market. It comes pre-installed with the best of Google apps and enabled with new and popular features like true multi-tasking, Wi-Fi hotspot, Internet Calling, NFC support, and full web browsing. With this device, users will also be the first to receive software upgrades and new Google mobile apps as soon as they become available. For more details, visit http://www.google.com/nexus.", + "display": { + "screenResolution": "WVGA (800 x 480)", + "screenSize": "4.0 inches", + "touchScreen": true + }, + "hardware": { + "accelerometer": true, + "audioJack": "3.5mm", + "cpu": "1GHz Cortex A8 (Hummingbird) processor", + "fmRadio": false, + "physicalKeyboard": false, + "usb": "USB 2.0" + }, + "id": "nexus-s", + "images": [ + "img/phones/nexus-s.0.jpg", + "img/phones/nexus-s.1.jpg", + "img/phones/nexus-s.2.jpg", + "img/phones/nexus-s.3.jpg" + ], + "name": "Nexus S", + "sizeAndWeight": { + "dimensions": [ + "63.0 mm (w)", + "123.9 mm (h)", + "10.88 mm (d)" + ], + "weight": "129.0 grams" + }, + "storage": { + "flash": "16384MB", + "ram": "512MB" + } +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/phones.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/phones.json new file mode 100644 index 0000000000..339b94fbb5 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/app/phones/phones.json @@ -0,0 +1,155 @@ +[ + { + "age": 0, + "id": "motorola-xoom-with-wi-fi", + "imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", + "name": "Motorola XOOM\u2122 with Wi-Fi", + "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 1, + "id": "motorola-xoom", + "imageUrl": "img/phones/motorola-xoom.0.jpg", + "name": "MOTOROLA XOOM\u2122", + "snippet": "The Next, Next Generation\n\nExperience the future with MOTOROLA XOOM, the world's first tablet powered by Android 3.0 (Honeycomb)." + }, + { + "age": 2, + "carrier": "AT&T", + "id": "motorola-atrix-4g", + "imageUrl": "img/phones/motorola-atrix-4g.0.jpg", + "name": "MOTOROLA ATRIX\u2122 4G", + "snippet": "MOTOROLA ATRIX 4G the world's most powerful smartphone." + }, + { + "age": 3, + "id": "dell-streak-7", + "imageUrl": "img/phones/dell-streak-7.0.jpg", + "name": "Dell Streak 7", + "snippet": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around." + }, + { + "age": 4, + "carrier": "Cellular South", + "id": "samsung-gem", + "imageUrl": "img/phones/samsung-gem.0.jpg", + "name": "Samsung Gem\u2122", + "snippet": "The Samsung Gem\u2122 brings you everything that you would expect and more from a touch display smart phone \u2013 more apps, more features and a more affordable price." + }, + { + "age": 5, + "carrier": "Dell", + "id": "dell-venue", + "imageUrl": "img/phones/dell-venue.0.jpg", + "name": "Dell Venue", + "snippet": "The Dell Venue; Your Personal Express Lane to Everything" + }, + { + "age": 6, + "carrier": "Best Buy", + "id": "nexus-s", + "imageUrl": "img/phones/nexus-s.0.jpg", + "name": "Nexus S", + "snippet": "Fast just got faster with Nexus S. A pure Google experience, Nexus S is the first phone to run Gingerbread (Android 2.3), the fastest version of Android yet." + }, + { + "age": 7, + "carrier": "Cellular South", + "id": "lg-axis", + "imageUrl": "img/phones/lg-axis.0.jpg", + "name": "LG Axis", + "snippet": "Android Powered, Google Maps Navigation, 5 Customizable Home Screens" + }, + { + "age": 8, + "id": "samsung-galaxy-tab", + "imageUrl": "img/phones/samsung-galaxy-tab.0.jpg", + "name": "Samsung Galaxy Tab\u2122", + "snippet": "Feel Free to Tab\u2122. The Samsung Galaxy Tab\u2122 brings you an ultra-mobile entertainment experience through its 7\u201d display, high-power processor and Adobe\u00ae Flash\u00ae Player compatibility." + }, + { + "age": 9, + "carrier": "Cellular South", + "id": "samsung-showcase-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg", + "name": "Samsung Showcase\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Showcase\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance, even outdoors" + }, + { + "age": 10, + "carrier": "Verizon", + "id": "droid-2-global-by-motorola", + "imageUrl": "img/phones/droid-2-global-by-motorola.0.jpg", + "name": "DROID\u2122 2 Global by Motorola", + "snippet": "The first smartphone with a 1.2 GHz processor and global capabilities." + }, + { + "age": 11, + "carrier": "Verizon", + "id": "droid-pro-by-motorola", + "imageUrl": "img/phones/droid-pro-by-motorola.0.jpg", + "name": "DROID\u2122 Pro by Motorola", + "snippet": "The next generation of DOES." + }, + { + "age": 12, + "carrier": "AT&T", + "id": "motorola-bravo-with-motoblur", + "imageUrl": "img/phones/motorola-bravo-with-motoblur.0.jpg", + "name": "MOTOROLA BRAVO\u2122 with MOTOBLUR\u2122", + "snippet": "An experience to cheer about." + }, + { + "age": 13, + "carrier": "T-Mobile", + "id": "motorola-defy-with-motoblur", + "imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg", + "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", + "snippet": "Are you ready for everything life throws your way?" + }, + { + "age": 14, + "carrier": "T-Mobile", + "id": "t-mobile-mytouch-4g", + "imageUrl": "img/phones/t-mobile-mytouch-4g.0.jpg", + "name": "T-Mobile myTouch 4G", + "snippet": "The T-Mobile myTouch 4G is a premium smartphone designed to deliver blazing fast 4G speeds so that you can video chat from practically anywhere, with or without Wi-Fi." + }, + { + "age": 15, + "carrier": "US Cellular", + "id": "samsung-mesmerize-a-galaxy-s-phone", + "imageUrl": "img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg", + "name": "Samsung Mesmerize\u2122 a Galaxy S\u2122 phone", + "snippet": "The Samsung Mesmerize\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance,even outdoors" + }, + { + "age": 16, + "carrier": "Sprint", + "id": "sanyo-zio", + "imageUrl": "img/phones/sanyo-zio.0.jpg", + "name": "SANYO ZIO", + "snippet": "The Sanyo Zio by Kyocera is an Android smartphone with a combination of ultra-sleek styling, strong performance and unprecedented value." + }, + { + "age": 17, + "id": "samsung-transform", + "imageUrl": "img/phones/samsung-transform.0.jpg", + "name": "Samsung Transform\u2122", + "snippet": "The Samsung Transform\u2122 brings you a fun way to customize your Android powered touch screen phone to just the way you like it through your favorite themed \u201cSprint ID Service Pack\u201d." + }, + { + "age": 18, + "id": "t-mobile-g2", + "imageUrl": "img/phones/t-mobile-g2.0.jpg", + "name": "T-Mobile G2", + "snippet": "The T-Mobile G2 with Google is the first smartphone built for 4G speeds on T-Mobile's new network. Get the information you need, faster than you ever thought possible." + }, + { + "age": 19, + "id": "motorola-charm-with-motoblur", + "imageUrl": "img/phones/motorola-charm-with-motoblur.0.jpg", + "name": "Motorola CHARM\u2122 with MOTOBLUR\u2122", + "snippet": "Motorola CHARM fits easily in your pocket or palm. Includes MOTOBLUR service." + } +] diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/example-config.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/example-config.json new file mode 100644 index 0000000000..401c14f835 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/example-config.json @@ -0,0 +1,5 @@ +{ + "build": "build:upgrade", + "run": "serve:upgrade", + "unittesting": true +} diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/index.html b/public/docs/_examples/upgrade-phonecat-4-final/ts/index.html new file mode 100644 index 0000000000..fee59370e6 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/index.html @@ -0,0 +1,36 @@ + + + + + + + + + + Google Phone Gallery + + + + + + + + + + + + + + + + + + + diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/run-unit-tests.sh b/public/docs/_examples/upgrade-phonecat-4-final/ts/run-unit-tests.sh new file mode 100644 index 0000000000..00a5abb7bc --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/run-unit-tests.sh @@ -0,0 +1,7 @@ +## The boilerplate Karma configuration won't work with Angular 1 tests since +## a specific loading configuration is needed for them. +## We keep one in karma.conf.ng1.js. This scripts runs the ng1 tests with +## that config. + +PATH=$(npm bin):$PATH +tsc && karma start karma.conf.ng1.js diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/systemjs.config.1.js b/public/docs/_examples/upgrade-phonecat-4-final/ts/systemjs.config.1.js new file mode 100644 index 0000000000..c48bb7ca39 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/systemjs.config.1.js @@ -0,0 +1,55 @@ +/** + * System configuration for Angular samples + * Adjust as necessary for your application needs. + */ +(function (global) { + // #docregion paths + System.config({ + paths: { + // paths serve as alias + 'npm:': '/node_modules/' + }, + map: { + 'ng-loader': '../src/systemjs-angular-loader.js', + app: '/app', + // #enddocregion paths + // angular bundles + '@angular/core': 'npm:@angular/core/bundles/core.umd.js', + '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': 'npm:@angular/http/bundles/http.umd.js', + '@angular/router': 'npm:@angular/router/bundles/router.umd.js', + '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js', + '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', + '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js', + '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js', + + // other libraries + 'rxjs': 'npm:rxjs', + 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api', + // #docregion paths + }, + // #enddocregion paths + // packages tells the System loader how to load when no filename and/or no extension + packages: { + 'app': { + main: './main.js', + defaultExtension: 'js', + meta: { + './*.js': { + loader: 'ng-loader' + } + } + }, + rxjs: { + defaultExtension: 'js' + }, + 'angular-in-memory-web-api': { + main: './index.js', + defaultExtension: 'js' + } + } + }); +})(this); diff --git a/public/docs/_examples/upgrade-phonecat-4-final/ts/tsconfig.json b/public/docs/_examples/upgrade-phonecat-4-final/ts/tsconfig.json new file mode 100644 index 0000000000..f267800f14 --- /dev/null +++ b/public/docs/_examples/upgrade-phonecat-4-final/ts/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": [ "es2015", "dom" ], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "../../node_modules/@types/" + ] + }, + "compileOnSave": true, + "exclude": [ + "node_modules/*", + "**/*-aot.ts" + ] +} diff --git a/public/docs/_examples/upgrade/.gitignore b/public/docs/_examples/upgrade/.gitignore deleted file mode 100644 index 6e8b20ba28..0000000000 --- a/public/docs/_examples/upgrade/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -!karma.conf.js -!package.json -!tsconfig.json diff --git a/public/docs/_examples/upgrade/README.md b/public/docs/_examples/upgrade/README.md deleted file mode 100644 index 507c99f2b7..0000000000 --- a/public/docs/_examples/upgrade/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Each subdirectory here is a version of the PhoneCat app. - -Each version is fully functional, but omits the JSON data and image -files in the interest of keeping things clean. To run each app -in its full form, copy the `img` and `phones` directories from -https://github.com/angular/angular-phonecat/tree/master/app under `app`. diff --git a/public/docs/_examples/upgrade/ts/adapter/.gitignore b/public/docs/_examples/upgrade/ts/adapter/.gitignore deleted file mode 100644 index 0caf9d9ce2..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -app/**/*.js -app/**/*.js.map diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-1-2-hybrid-bootstrap.html b/public/docs/_examples/upgrade/ts/adapter/app/index-1-2-hybrid-bootstrap.html deleted file mode 100644 index 0c6ab1c17a..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-1-2-hybrid-bootstrap.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-1-2-hybrid-shared-adapter-bootstrap.html b/public/docs/_examples/upgrade/ts/adapter/app/index-1-2-hybrid-shared-adapter-bootstrap.html deleted file mode 100644 index 7d2f2748b7..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-1-2-hybrid-shared-adapter-bootstrap.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-1-to-2-projection.html b/public/docs/_examples/upgrade/ts/adapter/app/index-1-to-2-projection.html deleted file mode 100644 index 089a668b26..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-1-to-2-projection.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - -
    - - -

    {{mainCtrl.hero.description}}

    -
    -
    - -
    - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-1-to-2-providers.html b/public/docs/_examples/upgrade/ts/adapter/app/index-1-to-2-providers.html deleted file mode 100644 index 7a14dd0db9..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-1-to-2-providers.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-2-to-1-providers.html b/public/docs/_examples/upgrade/ts/adapter/app/index-2-to-1-providers.html deleted file mode 100644 index 6fa63fae06..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-2-to-1-providers.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-2-to-1-transclusion.html b/public/docs/_examples/upgrade/ts/adapter/app/index-2-to-1-transclusion.html deleted file mode 100644 index f99223054a..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-2-to-1-transclusion.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-bootstrap.html b/public/docs/_examples/upgrade/ts/adapter/app/index-bootstrap.html deleted file mode 100644 index aa89f22ced..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-bootstrap.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - -
    - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-downgrade-io.html b/public/docs/_examples/upgrade/ts/adapter/app/index-downgrade-io.html deleted file mode 100644 index caccf11655..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-downgrade-io.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - -
    - - -
    - - -
    - - -
    - -
    - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-downgrade-static.html b/public/docs/_examples/upgrade/ts/adapter/app/index-downgrade-static.html deleted file mode 100644 index dbbd02859f..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-downgrade-static.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-ng-app.html b/public/docs/_examples/upgrade/ts/adapter/app/index-ng-app.html deleted file mode 100644 index f83324ae4c..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-ng-app.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - -
    - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-upgrade-io.html b/public/docs/_examples/upgrade/ts/adapter/app/index-upgrade-io.html deleted file mode 100644 index aa8a57cc6a..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-upgrade-io.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/index-upgrade-static.html b/public/docs/_examples/upgrade/ts/adapter/app/index-upgrade-static.html deleted file mode 100644 index b0a85ce95c..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/index-upgrade-static.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-bootstrap/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-bootstrap/app.module.ts deleted file mode 100644 index fcf7a21bab..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-bootstrap/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -declare var angular:any; - -// #docregion bootstrap -import {UpgradeAdapter} from 'angular2/upgrade'; - -// #enddocregion bootstrap - -angular.module('heroApp', []) - .run(() => console.log('running')); - -// #docregion bootstrap - -const upgradeAdapter = new UpgradeAdapter(); - -upgradeAdapter.bootstrap(document.body, ['heroApp'], {strictDi: true}); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-shared-adapter-bootstrap/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-shared-adapter-bootstrap/app.module.ts deleted file mode 100644 index 5a85c9ea1b..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-shared-adapter-bootstrap/app.module.ts +++ /dev/null @@ -1,14 +0,0 @@ -// #docregion bootstrap -import {upgradeAdapter} from './upgrade_adapter'; - -// #enddocregion bootstrap - -declare var angular:any; - -angular.module('heroApp', []) - .run(() => console.log('running')); - -// #docregion bootstrap - -upgradeAdapter.bootstrap(document.body, ['heroApp'], {strictDi: true}); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts deleted file mode 100644 index 6fb544a2ce..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-2-hybrid-shared-adapter-bootstrap/upgrade_adapter.ts +++ /dev/null @@ -1,3 +0,0 @@ -// #docregion -import {UpgradeAdapter} from 'angular2/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-autobootstrap/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-autobootstrap/app.module.ts deleted file mode 100644 index aaf3a2ca85..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-autobootstrap/app.module.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare var angular:any; - -angular.module('heroApp', []); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-bootstrap/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-bootstrap/app.module.ts deleted file mode 100644 index cc58467d56..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-bootstrap/app.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -declare var angular:any; - -angular.module('heroApp', []) - .run(() => console.log('running')); - -// #docregion bootstrap -angular.bootstrap(document.body, ['heroApp'], {strictDi: true}); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-ng-app/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-ng-app/app.module.ts deleted file mode 100644 index 0e6c12fa7a..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-ng-app/app.module.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare var angular:any; - -angular.module('heroApp', []) - .run(() => console.log('running')); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/app.module.ts deleted file mode 100644 index 0f01999f79..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {UpgradeAdapter} from 'angular2/upgrade'; -import {MainController} from './main.controller'; -import {HeroDetailComponent} from './hero-detail.component'; - -declare var angular:any; -const upgradeAdapter = new UpgradeAdapter(); - -angular.module('heroApp', []) - .controller('MainController', MainController) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/hero-detail.component.ts deleted file mode 100644 index ba64327498..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/hero-detail.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {Component, Input} from 'angular2/core'; -import {Hero} from '../hero'; - -@Component({ - selector: 'hero-detail', - template: ` -

    {{hero.name}}

    -
    - -
    - ` -}) -export class HeroDetailComponent { - @Input() hero: Hero; -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/main.controller.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/main.controller.ts deleted file mode 100644 index 11a2c5b38b..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-projection/main.controller.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {Hero} from '../Hero'; - -export class MainController { - hero = new Hero(1, 'Windstorm', 'A descr'); -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/app.module.ts deleted file mode 100644 index 2d04886a8a..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/app.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {HeroDetailComponent} from './hero-detail.component'; -import {HeroesService} from './heroes.service'; -import {upgradeAdapter} from './upgrade_adapter'; - -declare var angular:any; - -// #docregion register -angular.module('heroApp', []) - .service('heroes', HeroesService) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -upgradeAdapter.upgradeNg1Provider('heroes'); - -// #enddocregion register - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/hero-detail.component.ts deleted file mode 100644 index 1811ad5bf6..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/hero-detail.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -import {Component, Inject} from 'angular2/core'; -import {HeroesService} from './heroes.service'; -import {Hero} from '../hero'; - -@Component({ - selector: 'hero-detail', - template: ` -

    {{hero.id}}: {{hero.name}}

    - ` -}) -export class HeroDetailComponent { - hero:Hero; - constructor(@Inject('heroes') heroes:HeroesService) { - this.hero = heroes.get()[0]; - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/heroes.service.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/heroes.service.ts deleted file mode 100644 index 416d1af639..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/heroes.service.ts +++ /dev/null @@ -1,11 +0,0 @@ -// #docregion -import {Hero} from '../hero'; - -export class HeroesService { - get() { - return [ - new Hero(1, 'Windstorm'), - new Hero(2, 'Spiderman') - ]; - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/upgrade_adapter.ts deleted file mode 100644 index 6fb544a2ce..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/1-to-2-providers/upgrade_adapter.ts +++ /dev/null @@ -1,3 +0,0 @@ -// #docregion -import {UpgradeAdapter} from 'angular2/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/app.module.ts deleted file mode 100644 index 43a7fcf250..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/app.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {heroDetailComponent} from './hero-detail.component'; -import {Heroes} from './heroes'; -import {upgradeAdapter} from './upgrade_adapter'; - -declare var angular:any; - -// #docregion register -upgradeAdapter.addProvider(Heroes); - -angular.module('heroApp', []) - .factory('heroes', upgradeAdapter.downgradeNg2Provider(Heroes)) - .component('heroDetail', heroDetailComponent) -// #enddocregion register - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/hero-detail.component.ts deleted file mode 100644 index 8658eb3fa4..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/hero-detail.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -export const heroDetailComponent = { - template: ` -

    {{heroDetail.hero.id}}: {{heroDetail.hero.name}}

    - `, - controller: ['heroes', function(heroes) { - this.hero = heroes.get()[0]; - }] -}; diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/heroes.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/heroes.ts deleted file mode 100644 index 475a30c38d..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/heroes.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import {Injectable} from 'angular2/core'; -import {Hero} from '../hero'; - -@Injectable() -export class Heroes { - get() { - return [ - new Hero(1, 'Windstorm'), - new Hero(2, 'Spiderman') - ]; - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/upgrade_adapter.ts deleted file mode 100644 index 6fb544a2ce..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-providers/upgrade_adapter.ts +++ /dev/null @@ -1,3 +0,0 @@ -// #docregion -import {UpgradeAdapter} from 'angular2/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/app.module.ts deleted file mode 100644 index 08605ceade..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {UpgradeAdapter} from 'angular2/upgrade'; -import {ContainerComponent} from './container.component'; -import {heroDetailComponent} from './hero-detail.component'; -import {upgradeAdapter} from './upgrade_adapter'; - -declare var angular:any; - -angular.module('heroApp', []) - .directive('myContainer', upgradeAdapter.downgradeNg2Component(ContainerComponent)) - .component('heroDetail', heroDetailComponent) - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/container.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/container.component.ts deleted file mode 100644 index 25921aea75..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/container.component.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {upgradeAdapter} from './upgrade_adapter'; -import {Hero} from '../Hero'; - -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - -@Component({ - selector: 'my-container', - template: ` - - -

    {{hero.description}}

    -
    - `, - directives: [HeroDetail] -}) -export class ContainerComponent { - hero = new Hero(1, 'Windstorm', 'a descr'); -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/hero-detail.component.ts deleted file mode 100644 index 65a28d049a..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/hero-detail.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -export const heroDetailComponent = { - bindings: { - hero: '=' - }, - template: ` -

    {{hero.name}}

    -
    - -
    - ` -}; diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/upgrade_adapter.ts deleted file mode 100644 index 6fb544a2ce..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/2-to-1-transclusion/upgrade_adapter.ts +++ /dev/null @@ -1,3 +0,0 @@ -// #docregion -import {UpgradeAdapter} from 'angular2/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/app.module.ts deleted file mode 100644 index 579c6cdcd3..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/app.module.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {MainController} from './main.controller'; -// #docregion downgradecomponent -import {HeroDetailComponent} from './hero-detail.component'; - -// #enddocregion downgradecomponent -import {UpgradeAdapter} from 'angular2/upgrade'; - -const upgradeAdapter = new UpgradeAdapter(); - -// #docregion downgradecomponent - -angular.module('heroApp', []) - .controller('MainController', MainController) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -// #enddocregion downgradecomponent - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/hero-detail.component.ts deleted file mode 100644 index 39556b6ae3..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/hero-detail.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import {Component, Input, Output, EventEmitter} from 'angular2/core'; -import {Hero} from '../hero'; - -@Component({ - selector: 'hero-detail', - template: ` -

    {{hero.name}} details!

    -
    {{hero.id}}
    - - ` -}) -export class HeroDetailComponent { - @Input() hero:Hero - @Output() deleted = new EventEmitter(); - onDelete() { - this.deleted.emit(this.hero); - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/main.controller.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/main.controller.ts deleted file mode 100644 index 382b11fc7c..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-io/main.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Hero} from '../Hero'; - -export class MainController { - hero = new Hero(1, 'Windstorm'); - heroes = [ - new Hero(2, 'Superman'), - new Hero(3, 'Spiderman') - ] - onDelete(hero:Hero) { - console.log('del', hero); - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-static/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-static/app.module.ts deleted file mode 100644 index f9d3aef905..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-static/app.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -// #docregion downgradecomponent -import {HeroDetailComponent} from './hero-detail.component'; - -// #enddocregion downgradecomponent -import {UpgradeAdapter} from 'angular2/upgrade'; - -const upgradeAdapter = new UpgradeAdapter(); - -// #docregion downgradecomponent - -angular.module('heroApp', []) - .directive('heroDetail', upgradeAdapter.downgradeNg2Component(HeroDetailComponent)); - -// #enddocregion downgradecomponent - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-static/hero-detail.component.ts deleted file mode 100644 index b796ccce3b..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/downgrade-static/hero-detail.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - selector: 'hero-detail', - template: ` -

    Windstorm details!

    -
    1
    - ` -}) -export class HeroDetailComponent { - -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/hero.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/hero.ts deleted file mode 100644 index 172d393139..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/hero.ts +++ /dev/null @@ -1,5 +0,0 @@ -export class Hero { - constructor(public id:number, - public name:string, - public description?:string) { } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/app.module.ts deleted file mode 100644 index 5599ea67f0..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {heroDetail} from './hero-detail.component'; -import {ContainerComponent} from './container.component'; -import {upgradeAdapter} from './upgrade_adapter'; - - -declare var angular:any; - -angular.module('heroApp', []) - .component('heroDetail', heroDetail) - .directive('myContainer', upgradeAdapter.downgradeNg2Component(ContainerComponent)); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/container.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/container.component.ts deleted file mode 100644 index 495a4d110f..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/container.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {upgradeAdapter} from './upgrade_adapter'; -import {Hero} from '../Hero'; - -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - -@Component({ - selector: 'my-container', - template: ` -

    Tour of Heroes

    - - - `, - directives: [HeroDetail] -}) -export class ContainerComponent { - hero = new Hero(1, 'Windstorm'); - heroDeleted(event) { - console.log(event); - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/hero-detail.component.ts deleted file mode 100644 index 5ebc958b18..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/hero-detail.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -export const heroDetail = { - bindings: { - hero: '=', - deleted: '&' - }, - template: ` -

    {{heroDetail.hero.name}} details!

    -
    {{heroDetail.hero.id}}
    - - `, - controller: function() { - this.onDelete = () => { - this.deleted({hero: this.hero}); - }; - } -}; diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/upgrade_adapter.ts deleted file mode 100644 index 6fb544a2ce..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-io/upgrade_adapter.ts +++ /dev/null @@ -1,3 +0,0 @@ -// #docregion -import {UpgradeAdapter} from 'angular2/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/app.module.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/app.module.ts deleted file mode 100644 index 5599ea67f0..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/app.module.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {heroDetail} from './hero-detail.component'; -import {ContainerComponent} from './container.component'; -import {upgradeAdapter} from './upgrade_adapter'; - - -declare var angular:any; - -angular.module('heroApp', []) - .component('heroDetail', heroDetail) - .directive('myContainer', upgradeAdapter.downgradeNg2Component(ContainerComponent)); - -upgradeAdapter.bootstrap( - document.querySelector('hero-app'), - ['heroApp'], - {strictDi: true} -); diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/container.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/container.component.ts deleted file mode 100644 index 20e5933642..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/container.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {upgradeAdapter} from './upgrade_adapter'; - -const HeroDetail = upgradeAdapter.upgradeNg1Component('heroDetail'); - -@Component({ - selector: 'my-container', - template: ` -

    Tour of Heroes

    - - `, - directives: [HeroDetail] -}) -export class ContainerComponent { - -} diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/hero-detail.component.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/hero-detail.component.ts deleted file mode 100644 index 862c904bbc..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/hero-detail.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -export const heroDetail = { - template: ` -

    Windstorm details!

    -
    1
    - `, - controller: function() { - } -}; diff --git a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/upgrade_adapter.ts deleted file mode 100644 index 6fb544a2ce..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/app/js/upgrade-static/upgrade_adapter.ts +++ /dev/null @@ -1,3 +0,0 @@ -// #docregion -import {UpgradeAdapter} from 'angular2/upgrade'; -export const upgradeAdapter = new UpgradeAdapter(); diff --git a/public/docs/_examples/upgrade/ts/adapter/package.json b/public/docs/_examples/upgrade/ts/adapter/package.json deleted file mode 100644 index 5e84bdf221..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "adapter", - "version": "1.0.0", - "description": "", - "main": "index.js", - "keywords": [], - "author": "", - "license": "ISC", - "devDependencies": { - "typescript": "1.8.2", - "typings": "^0.6.8" - }, - "dependencies": { - "angular2": "2.0.0-beta.7", - "es6-promise": "3.0.2", - "es6-shim": "0.33.13", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "systemjs": "0.19.22", - "zone.js": "0.5.15" - }, - "scripts": { - "tsc": "tsc -p . -w", - "typings": "typings" - } -} diff --git a/public/docs/_examples/upgrade/ts/adapter/tsconfig.json b/public/docs/_examples/upgrade/ts/adapter/tsconfig.json deleted file mode 100644 index c1216959ee..0000000000 --- a/public/docs/_examples/upgrade/ts/adapter/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "module": "system", - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true - }, - "exclude": [ - "node_modules", - "typings/main.d.ts", - "typings/main" - ] -} diff --git a/public/docs/_examples/upgrade/ts/classes/.bowerrc b/public/docs/_examples/upgrade/ts/classes/.bowerrc deleted file mode 100644 index 5773025bf9..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "app/bower_components" -} diff --git a/public/docs/_examples/upgrade/ts/classes/.gitignore b/public/docs/_examples/upgrade/ts/classes/.gitignore deleted file mode 100644 index 63d5d99a52..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -app/**/*.js -app/**/*.js.map -test/unit/**/*.js -test/unit/**/*.js.map diff --git a/public/docs/_examples/upgrade/ts/classes/app/css/animations.css b/public/docs/_examples/upgrade/ts/classes/app/css/animations.css deleted file mode 100644 index 46f3da6ecb..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/css/animations.css +++ /dev/null @@ -1,97 +0,0 @@ -/* - * animations css stylesheet - */ - -/* animate ngRepeat in phone listing */ - -.phone-listing.ng-enter, -.phone-listing.ng-leave, -.phone-listing.ng-move { - -webkit-transition: 0.5s linear all; - -moz-transition: 0.5s linear all; - -o-transition: 0.5s linear all; - transition: 0.5s linear all; -} - -.phone-listing.ng-enter, -.phone-listing.ng-move { - opacity: 0; - height: 0; - overflow: hidden; -} - -.phone-listing.ng-move.ng-move-active, -.phone-listing.ng-enter.ng-enter-active { - opacity: 1; - height: 120px; -} - -.phone-listing.ng-leave { - opacity: 1; - overflow: hidden; -} - -.phone-listing.ng-leave.ng-leave-active { - opacity: 0; - height: 0; - padding-top: 0; - padding-bottom: 0; -} - -/* cross fading between routes with ngView */ - -.view-container { - position: relative; -} - -.view-frame.ng-enter, -.view-frame.ng-leave { - background: white; - position: absolute; - top: 0; - left: 0; - right: 0; -} - -.view-frame.ng-enter { - -webkit-animation: 0.5s fade-in; - -moz-animation: 0.5s fade-in; - -o-animation: 0.5s fade-in; - animation: 0.5s fade-in; - z-index: 100; -} - -.view-frame.ng-leave { - -webkit-animation: 0.5s fade-out; - -moz-animation: 0.5s fade-out; - -o-animation: 0.5s fade-out; - animation: 0.5s fade-out; - z-index: 99; -} - -@keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-moz-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-webkit-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-moz-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-webkit-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} - diff --git a/public/docs/_examples/upgrade/ts/classes/app/css/app.css b/public/docs/_examples/upgrade/ts/classes/app/css/app.css deleted file mode 100644 index 951ea087cc..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/css/app.css +++ /dev/null @@ -1,99 +0,0 @@ -/* app css stylesheet */ - -body { - padding-top: 20px; -} - - -.phone-images { - background-color: white; - width: 450px; - height: 450px; - overflow: hidden; - position: relative; - float: left; -} - -.phones { - list-style: none; -} - -.thumb { - float: left; - margin: -0.5em 1em 1.5em 0; - padding-bottom: 1em; - height: 100px; - width: 100px; -} - -.phones li { - clear: both; - height: 115px; - padding-top: 15px; -} - -/** Detail View **/ -img.phone { - float: left; - margin-right: 3em; - margin-bottom: 2em; - background-color: white; - padding: 2em; - height: 400px; - width: 400px; - display: none; -} - -img.phone:first-child { - display: block; -} - - -ul.phone-thumbs { - margin: 0; - list-style: none; -} - -ul.phone-thumbs li { - border: 1px solid black; - display: inline-block; - margin: 1em; - background-color: white; -} - -ul.phone-thumbs img { - height: 100px; - width: 100px; - padding: 1em; -} - -ul.phone-thumbs img:hover { - cursor: pointer; -} - - -ul.specs { - clear: both; - margin: 0; - padding: 0; - list-style: none; -} - -ul.specs > li{ - display: inline-block; - width: 200px; - vertical-align: top; -} - -ul.specs > li > span{ - font-weight: bold; - font-size: 1.2em; -} - -ul.specs dt { - font-weight: bold; -} - -h1 { - border-bottom: 1px solid gray; -} diff --git a/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings-white.png deleted file mode 100644 index 3bf6484a29..0000000000 Binary files a/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings-white.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings.png deleted file mode 100644 index 5b67ffda5f..0000000000 Binary files a/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/classes/app/index.html b/public/docs/_examples/upgrade/ts/classes/app/index.html deleted file mode 100644 index 74c39250b6..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - Google Phone Gallery - - - - - - - - - - - - - - - -
    -
    -
    - - - diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/app.module.ts deleted file mode 100644 index 01e3328c1e..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/app.module.ts +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion pre-bootstrap - -import core from './core/core.module'; -import phoneList from './phone_list/phone_list.module'; -import phoneDetail from './phone_detail/phone_detail.module'; - -angular.module('phonecatApp', [ - 'ngRoute', - core.name, - phoneList.name, - phoneDetail.name -]).config(configure); - -configure.$inject = ['$routeProvider']; - -function configure($routeProvider) { - $routeProvider. - when('/phones', { - templateUrl: 'js/phone_list/phone_list.html', - controller: 'PhoneListCtrl', - controllerAs: 'vm' - }). - when('/phones/:phoneId', { - templateUrl: 'js/phone_detail/phone_detail.html', - controller: 'PhoneDetailCtrl', - controllerAs: 'vm' - }). - otherwise({ - redirectTo: '/phones' - }); -} -// #enddocregion pre-bootstrap -// #docregion bootstrap -angular.bootstrap(document.documentElement, ['phonecatApp']); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/core/checkmark.filter.ts b/public/docs/_examples/upgrade/ts/classes/app/js/core/checkmark.filter.ts deleted file mode 100644 index cd0215064f..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/core/checkmark.filter.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export default function checkmarkFilter() { - return function(input:boolean):string { - return input ? '\u2713' : '\u2718'; - }; -} diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/core/core.module.ts deleted file mode 100644 index c20ce33683..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/core/core.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import Phone from './phone.factory'; -import checkmarkFilter from './checkmark.filter'; - -export default angular.module('phonecat.core', [ - 'ngResource' - ]) - .factory('Phone', Phone) - .filter('checkmark', checkmarkFilter); diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/core/phone.factory.ts b/public/docs/_examples/upgrade/ts/classes/app/js/core/phone.factory.ts deleted file mode 100644 index a8492b29fc..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/core/phone.factory.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -Phone.$inject = ['$resource']; - -function Phone($resource) { - return $resource('phones/:phoneId.json', {}, { - query: {method:'GET', params:{phoneId:'phones'}, isArray:true} - }); -} - -export default Phone; diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.controller.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.controller.ts deleted file mode 100644 index c5b96b6f08..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.controller.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -interface PhoneRouteParams { - phoneId: string -} - -class PhoneDetailCtrl { - phone:any; - mainImageUrl:string; - constructor($routeParams:PhoneRouteParams, Phone) { - this.phone = Phone.get({phoneId: $routeParams.phoneId}, (phone) => - this.mainImageUrl = phone.images[0] - ); - } - - setImage(url:string) { - this.mainImageUrl = url; - } -} - -PhoneDetailCtrl.$inject = ['$routeParams', 'Phone']; - -export default PhoneDetailCtrl; diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.html deleted file mode 100644 index 954c65c2cd..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.html +++ /dev/null @@ -1,118 +0,0 @@ -
    - -
    - -

    {{vm.phone.name}}

    - -

    {{vm.phone.description}}

    - -
      -
    • - -
    • -
    - -
      -
    • - Availability and Networks -
      -
      Availability
      -
      {{availability}}
      -
      -
    • -
    • - Battery -
      -
      Type
      -
      {{vm.phone.battery.type}}
      -
      Talk Time
      -
      {{vm.phone.battery.talkTime}}
      -
      Standby time (max)
      -
      {{vm.phone.battery.standbyTime}}
      -
      -
    • -
    • - Storage and Memory -
      -
      RAM
      -
      {{vm.phone.storage.ram}}
      -
      Internal Storage
      -
      {{vm.phone.storage.flash}}
      -
      -
    • -
    • - Connectivity -
      -
      Network Support
      -
      {{vm.phone.connectivity.cell}}
      -
      WiFi
      -
      {{vm.phone.connectivity.wifi}}
      -
      Bluetooth
      -
      {{vm.phone.connectivity.bluetooth}}
      -
      Infrared
      -
      {{vm.phone.connectivity.infrared | checkmark}}
      -
      GPS
      -
      {{vm.phone.connectivity.gps | checkmark}}
      -
      -
    • -
    • - Android -
      -
      OS Version
      -
      {{vm.phone.android.os}}
      -
      UI
      -
      {{vm.phone.android.ui}}
      -
      -
    • -
    • - Size and Weight -
      -
      Dimensions
      -
      {{dim}}
      -
      Weight
      -
      {{vm.phone.sizeAndWeight.weight}}
      -
      -
    • -
    • - Display -
      -
      Screen size
      -
      {{vm.phone.display.screenSize}}
      -
      Screen resolution
      -
      {{vm.phone.display.screenResolution}}
      -
      Touch screen
      -
      {{vm.phone.display.touchScreen | checkmark}}
      -
      -
    • -
    • - Hardware -
      -
      CPU
      -
      {{vm.phone.hardware.cpu}}
      -
      USB
      -
      {{vm.phone.hardware.usb}}
      -
      Audio / headphone jack
      -
      {{vm.phone.hardware.audioJack}}
      -
      FM Radio
      -
      {{vm.phone.hardware.fmRadio | checkmark}}
      -
      Accelerometer
      -
      {{vm.phone.hardware.accelerometer | checkmark}}
      -
      -
    • -
    • - Camera -
      -
      Primary
      -
      {{vm.phone.camera.primary}}
      -
      Features
      -
      {{vm.phone.camera.features.join(', ')}}
      -
      -
    • -
    • - Additional Features -
      {{vm.phone.additionalFeatures}}
      -
    • -
    diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.module.ts deleted file mode 100644 index 16e7ac0baf..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import PhoneDetailCtrl from './phone_detail.controller'; - -export default angular.module('phonecat.detail', [ - 'ngRoute', - 'phonecat.core' - ]) - .controller('PhoneDetailCtrl', PhoneDetailCtrl); diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.controller.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.controller.ts deleted file mode 100644 index f1a5beb808..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.controller.ts +++ /dev/null @@ -1,14 +0,0 @@ -// #docregion -class PhoneListCtrl { - phones:any[]; - orderProp:string; - query:string; - constructor(Phone) { - this.phones = Phone.query(); - this.orderProp = 'age'; - } -} - -PhoneListCtrl.$inject = ['Phone']; - -export default PhoneListCtrl; diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.html deleted file mode 100644 index 471f474e89..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.html +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    -
    - - - Search: - Sort by: - - -
    -
    - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.module.ts deleted file mode 100644 index 758b937927..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.module.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import PhoneListCtrl from './phone_list.controller'; - -export default angular.module('phonecat.list', ['phonecat.core']) - .controller('PhoneListCtrl', PhoneListCtrl); diff --git a/public/docs/_examples/upgrade/ts/classes/bower.json b/public/docs/_examples/upgrade/ts/classes/bower.json deleted file mode 100644 index 3f8ec94656..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/bower.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "angular-phonecat", - "description": "A starter project for AngularJS", - "version": "0.0.0", - "homepage": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "private": true, - "dependencies": { - "angular": "1.5.0", - "angular-mocks": "1.5.0", - "jquery": "~2.1.1", - "bootstrap": "~3.1.1", - "angular-route": "1.5.0", - "angular-resource": "1.5.0", - "angular-animate": "1.5.0" - }, - "resolutions": { - "angular": "1.5.0" - } -} diff --git a/public/docs/_examples/upgrade/ts/classes/package.1.json b/public/docs/_examples/upgrade/ts/classes/package.1.json deleted file mode 100644 index 10fb943821..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/package.1.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "version": "0.0.0", - "private": true, - "name": "angular-phonecat", - "description": "A tutorial application for AngularJS", - "repository": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "dependencies": { - "systemjs": "0.19.22" - }, - "devDependencies": { - "karma": "^0.12.16", - "karma-chrome-launcher": "^0.1.4", - "karma-firefox-launcher": "^0.1.3", - "karma-jasmine": "~0.3.7", - "protractor": "^3.0.0", - "http-server": "^0.6.1", - "tmp": "0.0.23", - "bower": "^1.3.1", - "shelljs": "^0.2.6", - "typescript": "1.8.2", - "typings": "^0.6.8" - }, - "scripts": { - "postinstall": "bower install", - - "prestart": "npm install", - "start": "http-server -a 0.0.0.0 -p 8000", - - "pretest": "npm install", - "test": "node node_modules/karma/bin/karma start test/karma.conf.js", - "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run", - - "preupdate-webdriver": "npm install", - "update-webdriver": "webdriver-manager update", - - "preprotractor": "npm run update-webdriver", - "protractor": "protractor test/protractor-conf.js", - - "typings": "typings", - "tsc": "tsc -p . -w" - } -} diff --git a/public/docs/_examples/upgrade/ts/classes/test/e2e/scenarios.js b/public/docs/_examples/upgrade/ts/classes/test/e2e/scenarios.js deleted file mode 100644 index 5a505b5dae..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/e2e/scenarios.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ - -describe('PhoneCat App', function() { - - it('should redirect index.html to index.html#/phones', function() { - browser.get('app/index.html'); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones'); - }); - }); - - - describe('Phone list view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones'); - }); - - - it('should filter the phone list as a user types into the search box', function() { - var phoneList = element.all(by.repeater('phone in vm.phones')); - var query = element(by.model('vm.query')); - - expect(phoneList.count()).toBe(20); - - query.sendKeys('nexus'); - expect(phoneList.count()).toBe(1); - - query.clear(); - query.sendKeys('motorola'); - expect(phoneList.count()).toBe(8); - }); - - - it('should be possible to control phone order via the drop down select box', function() { - - var phoneNameColumn = element.all(by.repeater('phone in vm.phones').column('phone.name')); - var query = element(by.model('vm.query')); - - function getNames() { - return phoneNameColumn.map(function(elm) { - return elm.getText(); - }); - } - - query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter - - expect(getNames()).toEqual([ - "Motorola XOOM\u2122 with Wi-Fi", - "MOTOROLA XOOM\u2122" - ]); - - element(by.model('vm.orderProp')).element(by.css('option[value="name"]')).click(); - - expect(getNames()).toEqual([ - "MOTOROLA XOOM\u2122", - "Motorola XOOM\u2122 with Wi-Fi" - ]); - }); - - - it('should render phone specific links', function() { - var query = element(by.model('vm.query')); - query.sendKeys('nexus'); - element.all(by.css('.phones li a')).first().click(); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones/nexus-s'); - }); - }); - }); - - - describe('Phone detail view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones/nexus-s'); - }); - - - it('should display nexus-s page', function() { - expect(element(by.binding('vm.phone.name')).getText()).toBe('Nexus S'); - }); - - - it('should display the first phone image as the main phone image', function() { - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - - - it('should swap main image if a thumbnail image is clicked on', function() { - element(by.css('.phone-thumbs li:nth-child(3) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); - - element(by.css('.phone-thumbs li:nth-child(1) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/classes/test/jasmine_matchers.d.ts b/public/docs/_examples/upgrade/ts/classes/test/jasmine_matchers.d.ts deleted file mode 100644 index 6d24879775..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/jasmine_matchers.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -declare module jasmine { - interface Matchers { - toEqualData(expected: any):boolean; - } -} diff --git a/public/docs/_examples/upgrade/ts/classes/test/karma.conf.1.js b/public/docs/_examples/upgrade/ts/classes/test/karma.conf.1.js deleted file mode 100644 index 646cdeb55a..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/karma.conf.1.js +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = function(config){ - config.set({ - - basePath : '..', - - // #docregion files - files : [ - 'app/bower_components/angular/angular.js', - 'app/bower_components/angular-route/angular-route.js', - 'app/bower_components/angular-resource/angular-resource.js', - 'app/bower_components/angular-animate/angular-animate.js', - 'app/bower_components/angular-mocks/angular-mocks.js', - 'node_modules/systemjs/dist/system.src.js', - 'test/karma_test_shim.js', - {pattern: 'app/js/**/*.js', included: false, watched: true}, - {pattern: 'test/unit/**/*.js', included: false, watched: true} - ], - // #enddocregion files - - autoWatch : true, - - frameworks: ['jasmine'], - - browsers : ['Chrome', 'Firefox'], - - plugins : [ - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-jasmine' - ], - - junitReporter : { - outputFile: 'test_out/unit.xml', - suite: 'unit' - }, - - logLevel: 'LOG_DEBUG' - - }); -}; diff --git a/public/docs/_examples/upgrade/ts/classes/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/classes/test/karma_test_shim.js deleted file mode 100644 index 15cbee5d7d..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/karma_test_shim.js +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion -// Cancel Karma's synchronous start, -// we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function() {}; - -System.config({ - packages: { - 'base/app/js': { - defaultExtension: false, - format: 'register', - map: Object.keys(window.__karma__.files). - filter(onlyAppFiles). - reduce(function createPathRecords(pathsMapping, appPath) { - // creates local module name mapping to global path with karma's fingerprint in path, e.g.: - // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' - var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath] - return pathsMapping; - }, {}) - - } - } -}); - -Promise.all( - Object.keys(window.__karma__.files) // All files served by Karma. - .filter(onlySpecFiles) - .map(function(moduleName) { - // loads all spec files via their global module names - return System.import(moduleName); -})) -.then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); -}); - -function onlyAppFiles(filePath) { - return /^\/base\/app\/js\/.*\.js$/.test(filePath) -} - -function onlySpecFiles(path) { - return /\.spec\.js$/.test(path); -} diff --git a/public/docs/_examples/upgrade/ts/classes/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/classes/test/protractor-conf.js deleted file mode 100644 index 118c7b9ec2..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/protractor-conf.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.config = { - allScriptsTimeout: 11000, - - specs: [ - 'e2e/*.js' - ], - - capabilities: { - 'browserName': 'chrome' - }, - - chromeOnly: true, - - baseUrl: 'http://localhost:8000/', - - framework: 'jasmine', - - jasmineNodeOpts: { - defaultTimeoutInterval: 30000 - } -}; diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/checkmark.filter.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/checkmark.filter.spec.ts deleted file mode 100644 index bae35e6875..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/unit/checkmark.filter.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion top -import '../../app/js/core/core.module'; -// #enddocregion top - -describe('checkmarkFilter', function() { - - beforeEach(angular.mock.module('phonecat.core')); - - it('should convert boolean values to unicode checkmark or cross', - inject(function(checkmarkFilter) { - expect(checkmarkFilter(true)).toBe('\u2713'); - expect(checkmarkFilter(false)).toBe('\u2718'); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/phone.factory.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/phone.factory.spec.ts deleted file mode 100644 index d7c95d347e..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/unit/phone.factory.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion top -import '../../app/js/core/core.module'; -// #enddocregion top - -describe('phoneFactory', function() { - - // load modules - beforeEach(angular.mock.module('phonecat.core')); - - // Test service availability - it('check the existence of Phone factory', inject(function(Phone) { - expect(Phone).toBeDefined(); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/phone_detail.controller.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/phone_detail.controller.spec.ts deleted file mode 100644 index 02a3e20240..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/unit/phone_detail.controller.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion top -import '../../app/js/phone_detail/phone_detail.module'; -// #enddocregion top - -describe('PhoneDetailCtrl', function(){ - var scope, $httpBackend, ctrl, - xyzPhoneData = function() { - return { - name: 'phone xyz', - images: ['image/url1.png', 'image/url2.png'] - } - }; - - beforeEach(angular.mock.module('phonecat.detail')); - - beforeEach(function(){ - jasmine.addMatchers({ - toEqualData: function(util, customEqualityTesters) { - return { - compare: function(actual, expected) { - return {pass: angular.equals(actual, expected)}; - } - }; - } - }); - }); - - beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) { - $httpBackend = _$httpBackend_; - $httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData()); - - $routeParams.phoneId = 'xyz'; - scope = $rootScope.$new(); - ctrl = $controller('PhoneDetailCtrl', {$scope: scope}); - })); - - - it('should fetch phone detail', function() { - expect(ctrl.phone).toEqualData({}); - $httpBackend.flush(); - - expect(ctrl.phone).toEqualData(xyzPhoneData()); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/phone_list.controller.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/phone_list.controller.spec.ts deleted file mode 100644 index efec5d5f08..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/test/unit/phone_list.controller.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion top -import '../../app/js/phone_list/phone_list.module'; -// #enddocregion top - -describe('PhoneListCtrl', function(){ - var scope, ctrl, $httpBackend; - - beforeEach(angular.mock.module('phonecat.list')); - - beforeEach(function(){ - jasmine.addMatchers({ - toEqualData: function(util, customEqualityTesters) { - return { - compare: function(actual, expected) { - return {pass: angular.equals(actual, expected)}; - } - }; - } - }); - }); - - beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) { - $httpBackend = _$httpBackend_; - $httpBackend.expectGET('phones/phones.json'). - respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]); - - scope = $rootScope.$new(); - ctrl = $controller('PhoneListCtrl', {$scope: scope}); - })); - - - it('should create "phones" model with 2 phones fetched from xhr', function() { - expect(ctrl.phones).toEqualData([]); - $httpBackend.flush(); - - expect(ctrl.phones).toEqualData( - [{name: 'Nexus S'}, {name: 'Motorola DROID'}]); - }); - - - it('should set the default value of orderProp model', function() { - expect(ctrl.orderProp).toBe('age'); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/classes/tsconfig.1.json b/public/docs/_examples/upgrade/ts/classes/tsconfig.1.json deleted file mode 100644 index c3cf6bcddb..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/tsconfig.1.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "system", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "removeComments": false - }, - "exclude": [ - "node_modules", - "typings/main.d.ts", - "typings/main" - ] -} diff --git a/public/docs/_examples/upgrade/ts/classes/typings.json b/public/docs/_examples/upgrade/ts/classes/typings.json deleted file mode 100644 index 3925b59066..0000000000 --- a/public/docs/_examples/upgrade/ts/classes/typings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ambientDependencies": { - "angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#3bebbe1baee04846cc46ed7249e8117e4cd7c7ff", - "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts#77dd2668f85730372aa8e62152e652048e8b6b87", - "angular-resource": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-resource.d.ts#c6609aff88f2c59e4df9adb93df5c7932adfd7b4", - "angular-route": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-route.d.ts#cf172aab99c3139a718aa8e65398a22c53dd7ead", - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#26c98c8a9530c44f8c801ccc3b2057e2101187ee", - "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#cf2a968f0edd7d30773f7d23fe3708fa029d5ab7" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/.bowerrc b/public/docs/_examples/upgrade/ts/ng2_components/.bowerrc deleted file mode 100644 index 5773025bf9..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "app/bower_components" -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/.gitignore b/public/docs/_examples/upgrade/ts/ng2_components/.gitignore deleted file mode 100644 index 63d5d99a52..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -app/**/*.js -app/**/*.js.map -test/unit/**/*.js -test/unit/**/*.js.map diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/css/animations.css b/public/docs/_examples/upgrade/ts/ng2_components/app/css/animations.css deleted file mode 100644 index 46f3da6ecb..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/css/animations.css +++ /dev/null @@ -1,97 +0,0 @@ -/* - * animations css stylesheet - */ - -/* animate ngRepeat in phone listing */ - -.phone-listing.ng-enter, -.phone-listing.ng-leave, -.phone-listing.ng-move { - -webkit-transition: 0.5s linear all; - -moz-transition: 0.5s linear all; - -o-transition: 0.5s linear all; - transition: 0.5s linear all; -} - -.phone-listing.ng-enter, -.phone-listing.ng-move { - opacity: 0; - height: 0; - overflow: hidden; -} - -.phone-listing.ng-move.ng-move-active, -.phone-listing.ng-enter.ng-enter-active { - opacity: 1; - height: 120px; -} - -.phone-listing.ng-leave { - opacity: 1; - overflow: hidden; -} - -.phone-listing.ng-leave.ng-leave-active { - opacity: 0; - height: 0; - padding-top: 0; - padding-bottom: 0; -} - -/* cross fading between routes with ngView */ - -.view-container { - position: relative; -} - -.view-frame.ng-enter, -.view-frame.ng-leave { - background: white; - position: absolute; - top: 0; - left: 0; - right: 0; -} - -.view-frame.ng-enter { - -webkit-animation: 0.5s fade-in; - -moz-animation: 0.5s fade-in; - -o-animation: 0.5s fade-in; - animation: 0.5s fade-in; - z-index: 100; -} - -.view-frame.ng-leave { - -webkit-animation: 0.5s fade-out; - -moz-animation: 0.5s fade-out; - -o-animation: 0.5s fade-out; - animation: 0.5s fade-out; - z-index: 99; -} - -@keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-moz-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-webkit-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-moz-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-webkit-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} - diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/css/app.css b/public/docs/_examples/upgrade/ts/ng2_components/app/css/app.css deleted file mode 100644 index f41c420776..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/css/app.css +++ /dev/null @@ -1,99 +0,0 @@ -/* app css stylesheet */ - -body { - padding-top: 20px; -} - - -.phone-images { - background-color: white; - width: 450px; - height: 450px; - overflow: hidden; - position: relative; - float: left; -} - -.phones { - list-style: none; -} - -.thumb { - float: left; - margin: -0.5em 1em 1.5em 0; - padding-bottom: 1em; - height: 100px; - width: 100px; -} - -.phones li { - clear: both; - height: 115px; - padding-top: 15px; -} - -/** Detail View **/ -img.phone { - float: left; - margin-right: 3em; - margin-bottom: 2em; - background-color: white; - padding: 2em; - height: 400px; - width: 400px; - display: none; -} - -img.phone:first-of-type { - display: block; -} - - -ul.phone-thumbs { - margin: 0; - list-style: none; -} - -ul.phone-thumbs li { - border: 1px solid black; - display: inline-block; - margin: 1em; - background-color: white; -} - -ul.phone-thumbs img { - height: 100px; - width: 100px; - padding: 1em; -} - -ul.phone-thumbs img:hover { - cursor: pointer; -} - - -ul.specs { - clear: both; - margin: 0; - padding: 0; - list-style: none; -} - -ul.specs > li{ - display: inline-block; - width: 200px; - vertical-align: top; -} - -ul.specs > li > span{ - font-weight: bold; - font-size: 1.2em; -} - -ul.specs dt { - font-weight: bold; -} - -h1 { - border-bottom: 1px solid gray; -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings-white.png deleted file mode 100644 index 3bf6484a29..0000000000 Binary files a/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings-white.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings.png deleted file mode 100644 index 5b67ffda5f..0000000000 Binary files a/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/index.html b/public/docs/_examples/upgrade/ts/ng2_components/app/index.html deleted file mode 100644 index 785df36cd6..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Google Phone Gallery - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    - - - diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/app.module.ts deleted file mode 100644 index 1f6f20c104..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/app.module.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docregion adapter-import -import {UpgradeAdapter} from 'angular2/upgrade'; -// #enddocregion adapter-import -// #docregion adapter-state-import -import upgradeAdapter from './core/upgrade_adapter'; -// #enddocregion adapter-state-import -// #docregion http-import -import {HTTP_PROVIDERS} from 'angular2/http'; -// #enddocregion http-import -import core from './core/core.module'; -import phoneList from './phone_list/phone_list.module'; -import phoneDetail from './phone_detail/phone_detail.module'; - -upgradeAdapter.addProvider(HTTP_PROVIDERS); -// #docregion upgrade-route-params -upgradeAdapter.upgradeNg1Provider('$routeParams'); -// #enddocregion -angular.module('phonecatApp', [ - 'ngRoute', - core.name, - phoneList.name, - phoneDetail.name -]).config(configure); - -configure.$inject = ['$routeProvider']; - -function configure($routeProvider) { - // #docregion list-route - $routeProvider. - when('/phones', { - template: '' - }). - // #enddocregion list-route - // #docregion detail-route - when('/phones/:phoneId', { - template: '' - }). - // #enddocregion detail-route - otherwise({ - redirectTo: '/phones' - }); -} - -// #docregion app-bootstrap -upgradeAdapter.bootstrap(document.documentElement, ['phonecatApp']); -// #enddocregion app-bootstrap diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/checkmark.pipe.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/checkmark.pipe.ts deleted file mode 100644 index 5156f14b50..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/checkmark.pipe.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import {Pipe} from 'angular2/core'; - -@Pipe({name: 'checkmark'}) -export class CheckmarkPipe { - transform(input:string): string { - return input ? '\u2713' : '\u2718'; - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/core.module.ts deleted file mode 100644 index 5d80850593..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/core.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import {Phones} from './phones.service'; -import upgradeAdapter from './upgrade_adapter'; - -upgradeAdapter.addProvider(Phones); - -export default angular.module('phonecat.core', []) - .factory('phones', upgradeAdapter.downgradeNg2Provider(Phones)); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/phones.service.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/phones.service.ts deleted file mode 100644 index b01b83da90..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/phones.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -// #docregion full -import {Injectable} from 'angular2/core'; -import {Http, Response} from 'angular2/http'; -import {Observable} from 'rxjs/Rx'; -import 'rxjs/add/operator/map'; - -// #docregion phone-interface -export interface Phone { - name: string; - snippet?: string; - images?: string[]; -} -// #enddocregion phone-interface - -// #docregion fullclass -// #docregion class -@Injectable() -export class Phones { -// #enddocregion class - - constructor(private http: Http) { } - - query():Observable { - return this.http.get(`phones/phones.json`) - .map((res:Response) => res.json()); - } - - get(id: string):Observable { - return this.http.get(`phones/${id}.json`) - .map((res:Response) => res.json()); - } - -// #docregion class -} -// #enddocregion class -// #enddocregion fullclass -// #docregion full diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/upgrade_adapter.ts deleted file mode 100644 index e21be0e4d8..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/upgrade_adapter.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion full -import {UpgradeAdapter} from 'angular2/upgrade'; - -// #docregion adapter-init -const upgradeAdapter = new UpgradeAdapter(); -// #enddocregion adapter-init - -export default upgradeAdapter; -// #enddocregion full diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.component.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.component.ts deleted file mode 100644 index 3d05494a46..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -// #docregion -// #docregion top -import {Component, Inject} from 'angular2/core'; -import {Phones, Phone} from '../core/phones.service'; -import {CheckmarkPipe} from '../core/checkmark.pipe'; - -interface PhoneRouteParams { - phoneId: string -} - -@Component({ - selector: 'pc-phone-detail', - templateUrl: 'js/phone_detail/phone_detail.html', - pipes: [CheckmarkPipe] -}) -class PhoneDetail { -// #enddocregion top - phone:Phone = undefined; - mainImageUrl:string; - constructor(@Inject('$routeParams') $routeParams:PhoneRouteParams, - phones:Phones) { - phones.get($routeParams.phoneId) - .subscribe(phone => { - this.phone = phone; - this.mainImageUrl = phone.images[0]; - }); - } - - setImage(url:string) { - this.mainImageUrl = url; - } -} -export default PhoneDetail; diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.html deleted file mode 100644 index 51cc10aad5..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.html +++ /dev/null @@ -1,115 +0,0 @@ - -
    - -
    -

    {{phone?.name}}

    -

    {{phone?.description}}

    -
      -
    • - -
    • -
    -
      -
    • - Availability and Networks -
      -
      Availability
      -
      {{availability}}
      -
      -
    • -
    • - Battery -
      -
      Type
      -
      {{phone?.battery?.type}}
      -
      Talk Time
      -
      {{phone?.battery?.talkTime}}
      -
      Standby time (max)
      -
      {{phone?.battery?.standbyTime}}
      -
      -
    • -
    • - Storage and Memory -
      -
      RAM
      -
      {{phone?.storage?.ram}}
      -
      Internal Storage
      -
      {{phone?.storage?.flash}}
      -
      -
    • -
    • - Connectivity -
      -
      Network Support
      -
      {{phone?.connectivity?.cell}}
      -
      WiFi
      -
      {{phone?.connectivity?.wifi}}
      -
      Bluetooth
      -
      {{phone?.connectivity?.bluetooth}}
      -
      Infrared
      -
      {{phone?.connectivity?.infrared | checkmark}}
      -
      GPS
      -
      {{phone?.connectivity?.gps | checkmark}}
      -
      -
    • -
    • - Android -
      -
      OS Version
      -
      {{phone?.android?.os}}
      -
      UI
      -
      {{phone?.android?.ui}}
      -
      -
    • -
    • - Size and Weight -
      -
      Dimensions
      -
      {{dim}}
      -
      Weight
      -
      {{phone?.sizeAndWeight?.weight}}
      -
      -
    • -
    • - Display -
      -
      Screen size
      -
      {{phone?.display?.screenSize}}
      -
      Screen resolution
      -
      {{phone?.display?.screenResolution}}
      -
      Touch screen
      -
      {{phone?.display?.touchScreen | checkmark}}
      -
      -
    • -
    • - Hardware -
      -
      CPU
      -
      {{phone?.hardware?.cpu}}
      -
      USB
      -
      {{phone?.hardware?.usb}}
      -
      Audio / headphone jack
      -
      {{phone?.hardware?.audioJack}}
      -
      FM Radio
      -
      {{phone?.hardware?.fmRadio | checkmark}}
      -
      Accelerometer
      -
      {{phone?.hardware?.accelerometer | checkmark}}
      -
      -
    • -
    • - Camera -
      -
      Primary
      -
      {{phone?.camera?.primary}}
      -
      Features
      -
      {{phone?.camera?.features?.join(', ')}}
      -
      -
    • -
    • - Additional Features -
      {{phone?.additionalFeatures}}
      -
    • -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.module.ts deleted file mode 100644 index 2a31fb503d..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import PhoneDetail from './phone_detail.component'; -import upgradeAdapter from '../core/upgrade_adapter'; - -export default angular.module('phonecat.detail', [ - 'ngRoute', - 'phonecat.core' - ]) - .directive('pcPhoneDetail', - upgradeAdapter.downgradeNg2Component(PhoneDetail)) diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail_without_pipes.component.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail_without_pipes.component.ts deleted file mode 100644 index a4c7ed3250..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail_without_pipes.component.ts +++ /dev/null @@ -1,29 +0,0 @@ -// #docregion -import {Component, Inject} from 'angular2/core'; -import {Phones, Phone} from '../core/phones.service'; - -interface PhoneRouteParams { - phoneId: string -} - -@Component({ - selector: 'pc-phone-detail', - templateUrl: 'js/phone_detail/phone_detail.html' -}) -class PhoneDetail { - phone:Phone = undefined; - mainImageUrl:string; - constructor(@Inject('$routeParams') $routeParams:PhoneRouteParams, - phones:Phones) { - phones.get($routeParams.phoneId) - .subscribe(phone => { - this.phone = phone; - this.mainImageUrl = phone.images[0]; - }); - } - - setImage(url:string) { - this.mainImageUrl = url; - } -} -export default PhoneDetail; diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/order_by.pipe.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/order_by.pipe.ts deleted file mode 100644 index 3b82f03c9b..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/order_by.pipe.ts +++ /dev/null @@ -1,24 +0,0 @@ -// #docregion -import {Pipe} from 'angular2/core'; - -@Pipe({name: 'orderBy'}) -export default class OrderByPipe { - - transform(input:T[], args:string[]): T[] { - if (input) { - let property = args[0]; - return input.slice().sort((a, b) => { - if (a[property] < b[property]) { - return -1; - } else if (b[property] < a[property]) { - return 1; - } else { - return 0; - } - }); - } else { - return input; - } - } - -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_filter.pipe.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_filter.pipe.ts deleted file mode 100644 index 0b70c47773..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_filter.pipe.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import {Pipe} from 'angular2/core'; -import {Phone} from '../core/phones.service'; - -@Pipe({name: 'phoneFilter'}) -export default class PhoneFilterPipe { - - transform(input:Phone[], args:string[]): Phone[] { - let query = args[0]; - if (query) { - query = query.toLowerCase(); - return input.filter((phone) => { - const name = phone.name.toLowerCase(); - const snippet = phone.snippet.toLowerCase(); - return name.indexOf(query) >= 0 || snippet.indexOf(query) >= 0; - }); - } else { - return input; - } - } - -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.component.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.component.ts deleted file mode 100644 index 2c13ae12f4..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -// #docregion full -// #docregion top -import {Component} from 'angular2/core'; -import {Observable} from 'rxjs'; -import {Phones, Phone} from '../core/phones.service'; -import PhoneFilterPipe from './phone_filter.pipe'; -import OrderByPipe from './order_by.pipe'; - -@Component({ - selector: 'pc-phone-list', - templateUrl: 'js/phone_list/phone_list.html', - pipes: [PhoneFilterPipe, OrderByPipe], -}) -class PhoneList { -// #enddocregion top - - phones:Observable; - orderProp:string; - query:string; - constructor(phones:Phones) { - this.phones = phones.query(); - this.orderProp = 'age'; - } -} - -export default PhoneList; diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.html deleted file mode 100644 index 71b84a9e88..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.html +++ /dev/null @@ -1,32 +0,0 @@ -
    -
    -
    - - - - Search: - Sort by: - - - -
    -
    - - - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.module.ts deleted file mode 100644 index 4632cc90f5..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import PhoneList from './phone_list.component'; -import upgradeAdapter from '../core/upgrade_adapter'; - -export default angular.module('phonecat.list', [ - 'phonecat.core' - ]) - .directive('pcPhoneList', - upgradeAdapter.downgradeNg2Component(PhoneList)); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_async.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_async.html deleted file mode 100644 index ac9f18d67d..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_async.html +++ /dev/null @@ -1,32 +0,0 @@ -
    -
    -
    - - - - Search: - Sort by: - - - -
    -
    - - - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.component.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.component.ts deleted file mode 100644 index 2820966099..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion top -import {Component} from 'angular2/core'; -import {Observable} from 'rxjs'; -import {Phones, Phone} from '../core/phones.service'; - -@Component({ - selector: 'pc-phone-list', - templateUrl: 'js/phone_list/phone_list.html' -}) -class PhoneList { -// #enddocregion top - - phones:Observable; - orderProp:string; - query:string; - constructor(phones:Phones) { - this.phones = phones.query(); - this.orderProp = 'age'; - } -} - -export default PhoneList; diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.html deleted file mode 100644 index a19d9a5455..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.html +++ /dev/null @@ -1,32 +0,0 @@ -
    -
    -
    - - - - Search: - Sort by: - - - -
    -
    - - - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_components/bower.json b/public/docs/_examples/upgrade/ts/ng2_components/bower.json deleted file mode 100644 index 3f8ec94656..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/bower.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "angular-phonecat", - "description": "A starter project for AngularJS", - "version": "0.0.0", - "homepage": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "private": true, - "dependencies": { - "angular": "1.5.0", - "angular-mocks": "1.5.0", - "jquery": "~2.1.1", - "bootstrap": "~3.1.1", - "angular-route": "1.5.0", - "angular-resource": "1.5.0", - "angular-animate": "1.5.0" - }, - "resolutions": { - "angular": "1.5.0" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/package.1.json b/public/docs/_examples/upgrade/ts/ng2_components/package.1.json deleted file mode 100644 index 15e2d4cc87..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/package.1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "version": "0.0.0", - "private": true, - "name": "angular-phonecat", - "description": "A tutorial application for AngularJS", - "repository": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "dependencies": { - "angular2": "2.0.0-beta.7", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "zone.js": "0.5.15", - "systemjs": "0.19.22" - }, - "devDependencies": { - "karma": "^0.12.16", - "karma-chrome-launcher": "^0.1.4", - "karma-firefox-launcher": "^0.1.3", - "karma-jasmine": "~0.3.7", - "protractor": "^3.0.0", - "http-server": "^0.6.1", - "tmp": "0.0.23", - "bower": "^1.3.1", - "shelljs": "^0.2.6", - "typescript": "1.8.2", - "typings": "^0.6.8" - }, - "scripts": { - "postinstall": "bower install", - - "prestart": "npm install", - "start": "http-server -a 0.0.0.0 -p 8000", - - "pretest": "npm install", - "test": "node node_modules/karma/bin/karma start test/karma.conf.js", - "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run", - - "preupdate-webdriver": "npm install", - "update-webdriver": "webdriver-manager update", - - "preprotractor": "npm run update-webdriver", - "protractor": "protractor test/protractor-conf.js", - - "typings": "typings", - "tsc": "tsc -p . -w" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/e2e/scenarios.js b/public/docs/_examples/upgrade/ts/ng2_components/test/e2e/scenarios.js deleted file mode 100644 index 1da0896c0d..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/e2e/scenarios.js +++ /dev/null @@ -1,112 +0,0 @@ -'use strict'; - -/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ - -describe('PhoneCat App', function() { - - it('should redirect index.html to index.html#/phones', function() { - browser.get('app/index.html'); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones'); - }); - }); - - - describe('Phone list view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones'); - }); - - it('should filter the phone list as a user types into the search box', function() { - var phoneList = element.all(by.css('.phones li')); - var query = element(by.css('input')); - - expect(phoneList.count()).toBe(20); - - query.sendKeys('nexus'); - expect(phoneList.count()).toBe(1); - - query.clear(); - // https://github.com/angular/protractor/issues/2019 - var str = 'motorola'; - for (var i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } - - expect(phoneList.count()).toBe(8); - }); - - - it('should be possible to control phone order via the drop down select box', function() { - var phoneNameColumn = element.all(by.css('.phones .name')); - var query = element(by.css('input')); - - function getNames() { - return phoneNameColumn.map(function(elm) { - return elm.getText(); - }); - } - - //let's narrow the dataset to make the test assertions shorter - // https://github.com/angular/protractor/issues/2019 - var str = 'tablet'; - for (var i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } - - expect(getNames()).toEqual([ - "Motorola XOOM\u2122 with Wi-Fi", - "MOTOROLA XOOM\u2122" - ]); - - element(by.css('select')).element(by.css('option[value="name"]')).click(); - - expect(getNames()).toEqual([ - "MOTOROLA XOOM\u2122", - "Motorola XOOM\u2122 with Wi-Fi" - ]); - }); - - - it('should render phone specific links', function() { - var query = element(by.css('input')); - // https://github.com/angular/protractor/issues/2019 - var str = 'nexus'; - for (var i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } - element.all(by.css('.phones li a')).first().click(); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones/nexus-s'); - }); - }); - }); - - - describe('Phone detail view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones/nexus-s'); - }); - - - it('should display nexus-s page', function() { - expect(element(by.css('h1')).getText()).toBe('Nexus S'); - }); - - - it('should display the first phone image as the main phone image', function() { - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - - - it('should swap main image if a thumbnail image is clicked on', function() { - element(by.css('.phone-thumbs li:nth-of-type(3) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); - - element(by.css('.phone-thumbs li:nth-of-type(1) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/karma.conf.1.js b/public/docs/_examples/upgrade/ts/ng2_components/test/karma.conf.1.js deleted file mode 100644 index c3ca85ac46..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/karma.conf.1.js +++ /dev/null @@ -1,58 +0,0 @@ -module.exports = function(config){ - config.set({ - - basePath : '..', - - // #docregion html - files : [ - // #enddocregion html - 'app/bower_components/angular/angular.js', - 'app/bower_components/angular-route/angular-route.js', - 'app/bower_components/angular-resource/angular-resource.js', - 'app/bower_components/angular-animate/angular-animate.js', - 'app/bower_components/angular-mocks/angular-mocks.js', - // #docregion ng2 - 'node_modules/systemjs/dist/system.src.js', - 'node_modules/angular2/bundles/angular2-polyfills.js', - 'node_modules/angular2/bundles/angular2.dev.js', - 'node_modules/angular2/bundles/upgrade.dev.js', - // #enddocregion ng2 - // #docregion ng2-http - 'node_modules/rxjs/bundles/Rx.js', - 'node_modules/angular2/bundles/http.dev.js', - // #enddocregion ng2-http - // #docregion ng2-testing - 'node_modules/angular2/bundles/testing.dev.js', - // #enddocregion ng2-testing - 'test/karma_test_shim.js', - {pattern: 'app/js/**/*.js', included: false, watched: true}, - {pattern: 'test/unit/**/*.js', included: false, watched: true}, - // #docregion html - {pattern: 'app/js/**/*.html', included: false, watched: true} - ], - - proxies: { - // required for component assests fetched by Angular's compiler - "/js": "/base/app/js" - }, - // #enddocregion html - - autoWatch : true, - - frameworks: ['jasmine'], - - browsers : ['Chrome', 'Firefox'], - - plugins : [ - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-jasmine' - ], - - junitReporter : { - outputFile: 'test_out/unit.xml', - suite: 'unit' - } - - }); -}; diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/ng2_components/test/karma_test_shim.js deleted file mode 100644 index 392f1f2916..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/karma_test_shim.js +++ /dev/null @@ -1,51 +0,0 @@ -// #docregion -// Cancel Karma's synchronous start, -// we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function() {}; - -System.config({ - packages: { - 'base/app/js': { - defaultExtension: false, - format: 'register', - map: Object.keys(window.__karma__.files). - filter(onlyAppFiles). - reduce(function createPathRecords(pathsMapping, appPath) { - // creates local module name mapping to global path with karma's fingerprint in path, e.g.: - // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' - var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath] - return pathsMapping; - }, {}) - } - } -}); - -// #docregion ng2 -System.import('angular2/testing').then(function(testing) { - return System.import('angular2/platform/testing/browser').then(function(testing_platform_browser) { - testing.setBaseTestProviders(testing_platform_browser.TEST_BROWSER_PLATFORM_PROVIDERS, - testing_platform_browser.TEST_BROWSER_APPLICATION_PROVIDERS); - }); -}).then(function() { - return Promise.all( - Object.keys(window.__karma__.files) // All files served by Karma. - .filter(onlySpecFiles) - .map(function(moduleName) { - // loads all spec files via their global module names - return System.import(moduleName); - })); -}).then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); -}); -// #enddocregion ng2 - -function onlyAppFiles(filePath) { - return /^\/base\/app\/js\/.*\.js$/.test(filePath) -} - -function onlySpecFiles(path) { - return /\.spec\.js$/.test(path); -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/ng2_components/test/protractor-conf.js deleted file mode 100644 index 490e9bd078..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/protractor-conf.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.config = { - allScriptsTimeout: 11000, - - specs: [ - 'e2e/*.js' - ], - - capabilities: { - 'browserName': 'chrome' - }, - - directConnect: true, - - baseUrl: 'http://localhost:8000/', - - framework: 'jasmine', - - jasmineNodeOpts: { - defaultTimeoutInterval: 30000 - } -}; diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/checkmark.pipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/checkmark.pipe.spec.ts deleted file mode 100644 index 76dfe5fad9..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/checkmark.pipe.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject, expect} from 'angular2/testing'; -import {CheckmarkPipe} from '../../app/js/core/checkmark.pipe'; - -describe('CheckmarkPipe', function() { - - beforeEachProviders(() => [CheckmarkPipe]); - - it('should convert boolean values to unicode checkmark or cross', - inject([CheckmarkPipe], (checkmarkPipe) => { - expect(checkmarkPipe.transform(true)).toBe('\u2713'); - expect(checkmarkPipe.transform(false)).toBe('\u2718'); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/order_by.pipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/order_by.pipe.spec.ts deleted file mode 100644 index 87780a9535..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/order_by.pipe.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; - -import OrderByPipe from '../../app/js/phone_list/order_by.pipe'; - -describe('OrderByPipe', function() { - - let input:any[] = [ - {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []}, - {name: 'Motorola DROID', snippet: 'An Android-for-business smartphone', images: []} - ]; - - beforeEachProviders(() => [OrderByPipe]); - - it('should order by the given property', inject([OrderByPipe], (orderByPipe) => { - expect(orderByPipe.transform(input, ['name'])).toEqual([input[1], input[0]]); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_detail.component.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_detail.component.spec.ts deleted file mode 100644 index 9365fe9e5f..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_detail.component.spec.ts +++ /dev/null @@ -1,49 +0,0 @@ -// #docregion -import {provide} from 'angular2/core'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import {Observable} from 'rxjs/Rx'; -import 'rxjs/add/observable/fromArray'; - -import { - describe, - beforeEachProviders, - injectAsync, - it, - expect, - TestComponentBuilder -} from 'angular2/testing'; -import PhoneDetail from '../../app/js/phone_detail/phone_detail.component'; -import {Phones, Phone} from '../../app/js/core/phones.service'; - -function xyzPhoneData():Phone { - return { - name: 'phone xyz', - snippet: '', - images: ['image/url1.png', 'image/url2.png'] - } -} - -class MockPhones extends Phones { - get(id):Observable { - return Observable.fromArray([xyzPhoneData()]); - } -} - -describe('PhoneDetail', () => { - - beforeEachProviders(() => [ - provide(Phones, {useClass: MockPhones}), - provide('$routeParams', {useValue: {phoneId: 'xyz'}}), - HTTP_PROVIDERS - ]); - - it('should fetch phone detail', injectAsync([TestComponentBuilder], (tcb) => { - return tcb.createAsync(PhoneDetail).then((fixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - - expect(compiled.querySelector('h1')).toHaveText(xyzPhoneData().name); - }); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_filter.pipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_filter.pipe.spec.ts deleted file mode 100644 index c730b8c1fe..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_filter.pipe.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; - -import PhoneFilterPipe from '../../app/js/phone_list/phone_filter.pipe'; -import {Phone} from '../../app/js/core/phones.service'; - -describe('PhoneFilterPipe', function() { - - let phones:Phone[] = [ - {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []}, - {name: 'Motorola DROID', snippet: 'an Android-for-business smartphone', images: []} - ]; - - beforeEachProviders(() => [PhoneFilterPipe]); - - it('should return input when no query', inject([PhoneFilterPipe], (phoneFilterPipe) => { - expect(phoneFilterPipe.transform(phones, [])).toEqual(phones); - })); - - it('should match based on name', inject([PhoneFilterPipe], (phoneFilterPipe) => { - expect(phoneFilterPipe.transform(phones, ['nexus'])).toEqual([phones[0]]); - })); - - it('should match based on snippet', inject([PhoneFilterPipe], (phoneFilterPipe) => { - expect(phoneFilterPipe.transform(phones, ['android'])).toEqual([phones[1]]); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_list.component.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_list.component.spec.ts deleted file mode 100644 index 56327c0e9a..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phone_list.component.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -// #docregion -import {provide} from 'angular2/core'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import {Observable} from 'rxjs/Rx'; -import 'rxjs/add/observable/fromArray'; - -import { - describe, - beforeEachProviders, - injectAsync, - it, - expect, - TestComponentBuilder -} from 'angular2/testing'; -import PhoneList from '../../app/js/phone_list/phone_list.component'; -import {Phones, Phone} from '../../app/js/core/phones.service'; - -class MockPhones extends Phones { - query():Observable { - return Observable.fromArray([ - [{name: 'Nexus S'}, {name: 'Motorola DROID'}] - ]) - } -} - -describe('PhoneList', () => { - - beforeEachProviders(() => [ - provide(Phones, {useClass: MockPhones}), - HTTP_PROVIDERS - ]); - - - it('should create "phones" model with 2 phones fetched from xhr', - injectAsync([TestComponentBuilder], (tcb) => { - return tcb.createAsync(PhoneList).then((fixture) => { - fixture.detectChanges(); - - let compiled = fixture.debugElement.nativeElement; - - expect(compiled.querySelectorAll('.phone-listing').length).toBe(2); - expect(compiled.querySelector('.phone-listing:nth-child(1)').textContent).toContain('Nexus S'); - expect(compiled.querySelector('.phone-listing:nth-child(2)').textContent).toContain('Motorola DROID'); - }); - })); - - - it('should set the default value of orderProp model', - injectAsync([TestComponentBuilder], (tcb) => { - return tcb.createAsync(PhoneList).then((fixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('select option:last-child').selected).toBe(true); - }); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phones.service.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phones.service.spec.ts deleted file mode 100644 index f389722c46..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/phones.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import {Phones} from '../../app/js/core/phones.service'; - -describe('Phones', function() { - - // load providers - beforeEachProviders(() => [Phones, HTTP_PROVIDERS]); - - // Test service availability - it('check the existence of Phones', inject([Phones], (phones) => { - expect(phones).toBeDefined(); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_components/tsconfig.1.json b/public/docs/_examples/upgrade/ts/ng2_components/tsconfig.1.json deleted file mode 100644 index eef7e2be89..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/tsconfig.1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "system", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "removeComments": false - }, - "exclude": [ - "node_modules", - "typings/main.d.ts", - "typings/main" - ] -} diff --git a/public/docs/_examples/upgrade/ts/ng2_components/typings.json b/public/docs/_examples/upgrade/ts/ng2_components/typings.json deleted file mode 100644 index 8351ca2854..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_components/typings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ambientDependencies": { - "angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#3bebbe1baee04846cc46ed7249e8117e4cd7c7ff", - "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts#77dd2668f85730372aa8e62152e652048e8b6b87", - "angular-resource": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-resource.d.ts#c6609aff88f2c59e4df9adb93df5c7932adfd7b4", - "angular-route": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-route.d.ts#cf172aab99c3139a718aa8e65398a22c53dd7ead", - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#26c98c8a9530c44f8c801ccc3b2057e2101187ee", - "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#cf2a968f0edd7d30773f7d23fe3708fa029d5ab7", - "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/.bowerrc b/public/docs/_examples/upgrade/ts/ng2_final/.bowerrc deleted file mode 100644 index 5773025bf9..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "app/bower_components" -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/.gitignore b/public/docs/_examples/upgrade/ts/ng2_final/.gitignore deleted file mode 100644 index 63d5d99a52..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -app/**/*.js -app/**/*.js.map -test/unit/**/*.js -test/unit/**/*.js.map diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/css/animations.css b/public/docs/_examples/upgrade/ts/ng2_final/app/css/animations.css deleted file mode 100644 index 46f3da6ecb..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/css/animations.css +++ /dev/null @@ -1,97 +0,0 @@ -/* - * animations css stylesheet - */ - -/* animate ngRepeat in phone listing */ - -.phone-listing.ng-enter, -.phone-listing.ng-leave, -.phone-listing.ng-move { - -webkit-transition: 0.5s linear all; - -moz-transition: 0.5s linear all; - -o-transition: 0.5s linear all; - transition: 0.5s linear all; -} - -.phone-listing.ng-enter, -.phone-listing.ng-move { - opacity: 0; - height: 0; - overflow: hidden; -} - -.phone-listing.ng-move.ng-move-active, -.phone-listing.ng-enter.ng-enter-active { - opacity: 1; - height: 120px; -} - -.phone-listing.ng-leave { - opacity: 1; - overflow: hidden; -} - -.phone-listing.ng-leave.ng-leave-active { - opacity: 0; - height: 0; - padding-top: 0; - padding-bottom: 0; -} - -/* cross fading between routes with ngView */ - -.view-container { - position: relative; -} - -.view-frame.ng-enter, -.view-frame.ng-leave { - background: white; - position: absolute; - top: 0; - left: 0; - right: 0; -} - -.view-frame.ng-enter { - -webkit-animation: 0.5s fade-in; - -moz-animation: 0.5s fade-in; - -o-animation: 0.5s fade-in; - animation: 0.5s fade-in; - z-index: 100; -} - -.view-frame.ng-leave { - -webkit-animation: 0.5s fade-out; - -moz-animation: 0.5s fade-out; - -o-animation: 0.5s fade-out; - animation: 0.5s fade-out; - z-index: 99; -} - -@keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-moz-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-webkit-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-moz-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-webkit-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} - diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/css/app.css b/public/docs/_examples/upgrade/ts/ng2_final/app/css/app.css deleted file mode 100644 index f41c420776..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/css/app.css +++ /dev/null @@ -1,99 +0,0 @@ -/* app css stylesheet */ - -body { - padding-top: 20px; -} - - -.phone-images { - background-color: white; - width: 450px; - height: 450px; - overflow: hidden; - position: relative; - float: left; -} - -.phones { - list-style: none; -} - -.thumb { - float: left; - margin: -0.5em 1em 1.5em 0; - padding-bottom: 1em; - height: 100px; - width: 100px; -} - -.phones li { - clear: both; - height: 115px; - padding-top: 15px; -} - -/** Detail View **/ -img.phone { - float: left; - margin-right: 3em; - margin-bottom: 2em; - background-color: white; - padding: 2em; - height: 400px; - width: 400px; - display: none; -} - -img.phone:first-of-type { - display: block; -} - - -ul.phone-thumbs { - margin: 0; - list-style: none; -} - -ul.phone-thumbs li { - border: 1px solid black; - display: inline-block; - margin: 1em; - background-color: white; -} - -ul.phone-thumbs img { - height: 100px; - width: 100px; - padding: 1em; -} - -ul.phone-thumbs img:hover { - cursor: pointer; -} - - -ul.specs { - clear: both; - margin: 0; - padding: 0; - list-style: none; -} - -ul.specs > li{ - display: inline-block; - width: 200px; - vertical-align: top; -} - -ul.specs > li > span{ - font-weight: bold; - font-size: 1.2em; -} - -ul.specs dt { - font-weight: bold; -} - -h1 { - border-bottom: 1px solid gray; -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings-white.png deleted file mode 100644 index 3bf6484a29..0000000000 Binary files a/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings-white.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings.png deleted file mode 100644 index 5b67ffda5f..0000000000 Binary files a/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/index.html b/public/docs/_examples/upgrade/ts/ng2_final/app/index.html deleted file mode 100644 index 8893e668b2..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/index.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - Google Phone Gallery - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/app.component.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/app.component.ts deleted file mode 100644 index 00c46592bb..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/app.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; -import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; -import PhoneList from './phone_list/phone_list.component'; -import PhoneDetail from './phone_detail/phone_detail.component'; - -@RouteConfig([ - {path:'/phones', name: 'Phones', component: PhoneList}, - {path:'/phones/:phoneId', name: 'Phone', component: PhoneDetail}, - {path:'/', redirectTo: ['Phones']} -]) -@Component({ - selector: 'pc-app', - template: '', - directives: [ROUTER_DIRECTIVES] -}) -export default class AppComponent { -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/checkmark.pipe.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/checkmark.pipe.ts deleted file mode 100644 index 5156f14b50..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/checkmark.pipe.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import {Pipe} from 'angular2/core'; - -@Pipe({name: 'checkmark'}) -export class CheckmarkPipe { - transform(input:string): string { - return input ? '\u2713' : '\u2718'; - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/phones.service.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/phones.service.ts deleted file mode 100644 index b01b83da90..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/phones.service.ts +++ /dev/null @@ -1,37 +0,0 @@ -// #docregion full -import {Injectable} from 'angular2/core'; -import {Http, Response} from 'angular2/http'; -import {Observable} from 'rxjs/Rx'; -import 'rxjs/add/operator/map'; - -// #docregion phone-interface -export interface Phone { - name: string; - snippet?: string; - images?: string[]; -} -// #enddocregion phone-interface - -// #docregion fullclass -// #docregion class -@Injectable() -export class Phones { -// #enddocregion class - - constructor(private http: Http) { } - - query():Observable { - return this.http.get(`phones/phones.json`) - .map((res:Response) => res.json()); - } - - get(id: string):Observable { - return this.http.get(`phones/${id}.json`) - .map((res:Response) => res.json()); - } - -// #docregion class -} -// #enddocregion class -// #enddocregion fullclass -// #docregion full diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/upgrade_adapter.ts deleted file mode 100644 index e21be0e4d8..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/upgrade_adapter.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion full -import {UpgradeAdapter} from 'angular2/upgrade'; - -// #docregion adapter-init -const upgradeAdapter = new UpgradeAdapter(); -// #enddocregion adapter-init - -export default upgradeAdapter; -// #enddocregion full diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/main.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/main.ts deleted file mode 100644 index 3d999cf8b5..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/main.ts +++ /dev/null @@ -1,26 +0,0 @@ -// #docregion -// #docregion importbootstrap -import {provide} from 'angular2/core'; -import {bootstrap} from 'angular2/platform/browser'; -import { - LocationStrategy, - HashLocationStrategy, - ROUTER_PROVIDERS -} from 'angular2/router'; - -import {Phones} from './core/phones.service'; -import AppComponent from './app.component'; -// #enddocregion importbootstrap - -// #docregion http-import -import {HTTP_PROVIDERS} from 'angular2/http'; -// #enddocregion http-import - -// #docregion bootstrap -bootstrap(AppComponent, [ - HTTP_PROVIDERS, - ROUTER_PROVIDERS, - provide(LocationStrategy, {useClass: HashLocationStrategy}), - Phones -]); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.component.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.component.ts deleted file mode 100644 index 68952a6e5d..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -// #docregion -// #docregion top -import {Component, Inject} from 'angular2/core'; -import {RouteParams} from 'angular2/router'; -import {Phones, Phone} from '../core/phones.service'; -import {CheckmarkPipe} from '../core/checkmark.pipe'; - -@Component({ - selector: 'pc-phone-detail', - templateUrl: 'js/phone_detail/phone_detail.html', - pipes: [CheckmarkPipe] -}) -class PhoneDetail { -// #enddocregion top - phone:Phone = undefined; - mainImageUrl:string; - constructor(params:RouteParams, - phones:Phones) { - phones.get(params.get('phoneId')) - .subscribe(phone => { - this.phone = phone; - this.mainImageUrl = phone.images[0]; - }); - } - - setImage(url:string) { - this.mainImageUrl = url; - } -} -export default PhoneDetail; diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.html deleted file mode 100644 index 51cc10aad5..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.html +++ /dev/null @@ -1,115 +0,0 @@ - -
    - -
    -

    {{phone?.name}}

    -

    {{phone?.description}}

    -
      -
    • - -
    • -
    -
      -
    • - Availability and Networks -
      -
      Availability
      -
      {{availability}}
      -
      -
    • -
    • - Battery -
      -
      Type
      -
      {{phone?.battery?.type}}
      -
      Talk Time
      -
      {{phone?.battery?.talkTime}}
      -
      Standby time (max)
      -
      {{phone?.battery?.standbyTime}}
      -
      -
    • -
    • - Storage and Memory -
      -
      RAM
      -
      {{phone?.storage?.ram}}
      -
      Internal Storage
      -
      {{phone?.storage?.flash}}
      -
      -
    • -
    • - Connectivity -
      -
      Network Support
      -
      {{phone?.connectivity?.cell}}
      -
      WiFi
      -
      {{phone?.connectivity?.wifi}}
      -
      Bluetooth
      -
      {{phone?.connectivity?.bluetooth}}
      -
      Infrared
      -
      {{phone?.connectivity?.infrared | checkmark}}
      -
      GPS
      -
      {{phone?.connectivity?.gps | checkmark}}
      -
      -
    • -
    • - Android -
      -
      OS Version
      -
      {{phone?.android?.os}}
      -
      UI
      -
      {{phone?.android?.ui}}
      -
      -
    • -
    • - Size and Weight -
      -
      Dimensions
      -
      {{dim}}
      -
      Weight
      -
      {{phone?.sizeAndWeight?.weight}}
      -
      -
    • -
    • - Display -
      -
      Screen size
      -
      {{phone?.display?.screenSize}}
      -
      Screen resolution
      -
      {{phone?.display?.screenResolution}}
      -
      Touch screen
      -
      {{phone?.display?.touchScreen | checkmark}}
      -
      -
    • -
    • - Hardware -
      -
      CPU
      -
      {{phone?.hardware?.cpu}}
      -
      USB
      -
      {{phone?.hardware?.usb}}
      -
      Audio / headphone jack
      -
      {{phone?.hardware?.audioJack}}
      -
      FM Radio
      -
      {{phone?.hardware?.fmRadio | checkmark}}
      -
      Accelerometer
      -
      {{phone?.hardware?.accelerometer | checkmark}}
      -
      -
    • -
    • - Camera -
      -
      Primary
      -
      {{phone?.camera?.primary}}
      -
      Features
      -
      {{phone?.camera?.features?.join(', ')}}
      -
      -
    • -
    • - Additional Features -
      {{phone?.additionalFeatures}}
      -
    • -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/order_by.pipe.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/order_by.pipe.ts deleted file mode 100644 index 3b82f03c9b..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/order_by.pipe.ts +++ /dev/null @@ -1,24 +0,0 @@ -// #docregion -import {Pipe} from 'angular2/core'; - -@Pipe({name: 'orderBy'}) -export default class OrderByPipe { - - transform(input:T[], args:string[]): T[] { - if (input) { - let property = args[0]; - return input.slice().sort((a, b) => { - if (a[property] < b[property]) { - return -1; - } else if (b[property] < a[property]) { - return 1; - } else { - return 0; - } - }); - } else { - return input; - } - } - -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_filter.pipe.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_filter.pipe.ts deleted file mode 100644 index 0b70c47773..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_filter.pipe.ts +++ /dev/null @@ -1,22 +0,0 @@ -// #docregion -import {Pipe} from 'angular2/core'; -import {Phone} from '../core/phones.service'; - -@Pipe({name: 'phoneFilter'}) -export default class PhoneFilterPipe { - - transform(input:Phone[], args:string[]): Phone[] { - let query = args[0]; - if (query) { - query = query.toLowerCase(); - return input.filter((phone) => { - const name = phone.name.toLowerCase(); - const snippet = phone.snippet.toLowerCase(); - return name.indexOf(query) >= 0 || snippet.indexOf(query) >= 0; - }); - } else { - return input; - } - } - -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.component.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.component.ts deleted file mode 100644 index 3d729ead62..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docregion full -// #docregion top -import {Component} from 'angular2/core'; -import {RouterLink} from 'angular2/router'; -import {Observable} from 'rxjs'; -import {Phones, Phone} from '../core/phones.service'; -import PhoneFilterPipe from './phone_filter.pipe'; -import OrderByPipe from './order_by.pipe'; - -@Component({ - selector: 'pc-phone-list', - templateUrl: 'js/phone_list/phone_list.html', - pipes: [PhoneFilterPipe, OrderByPipe], - directives: [RouterLink] -}) -class PhoneList { -// #enddocregion top - - phones:Observable; - orderProp:string; - query:string; - constructor(phones:Phones) { - this.phones = phones.query(); - this.orderProp = 'age'; - } -} - -export default PhoneList; diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.html deleted file mode 100644 index d605ff1f85..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.html +++ /dev/null @@ -1,32 +0,0 @@ -
    -
    -
    - - - - Search: - Sort by: - - - -
    -
    - - - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_final/bower.json b/public/docs/_examples/upgrade/ts/ng2_final/bower.json deleted file mode 100644 index 3f8ec94656..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/bower.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "angular-phonecat", - "description": "A starter project for AngularJS", - "version": "0.0.0", - "homepage": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "private": true, - "dependencies": { - "angular": "1.5.0", - "angular-mocks": "1.5.0", - "jquery": "~2.1.1", - "bootstrap": "~3.1.1", - "angular-route": "1.5.0", - "angular-resource": "1.5.0", - "angular-animate": "1.5.0" - }, - "resolutions": { - "angular": "1.5.0" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/package.1.json b/public/docs/_examples/upgrade/ts/ng2_final/package.1.json deleted file mode 100644 index 15e2d4cc87..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/package.1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "version": "0.0.0", - "private": true, - "name": "angular-phonecat", - "description": "A tutorial application for AngularJS", - "repository": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "dependencies": { - "angular2": "2.0.0-beta.7", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "zone.js": "0.5.15", - "systemjs": "0.19.22" - }, - "devDependencies": { - "karma": "^0.12.16", - "karma-chrome-launcher": "^0.1.4", - "karma-firefox-launcher": "^0.1.3", - "karma-jasmine": "~0.3.7", - "protractor": "^3.0.0", - "http-server": "^0.6.1", - "tmp": "0.0.23", - "bower": "^1.3.1", - "shelljs": "^0.2.6", - "typescript": "1.8.2", - "typings": "^0.6.8" - }, - "scripts": { - "postinstall": "bower install", - - "prestart": "npm install", - "start": "http-server -a 0.0.0.0 -p 8000", - - "pretest": "npm install", - "test": "node node_modules/karma/bin/karma start test/karma.conf.js", - "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run", - - "preupdate-webdriver": "npm install", - "update-webdriver": "webdriver-manager update", - - "preprotractor": "npm run update-webdriver", - "protractor": "protractor test/protractor-conf.js", - - "typings": "typings", - "tsc": "tsc -p . -w" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/e2e/scenarios.js b/public/docs/_examples/upgrade/ts/ng2_final/test/e2e/scenarios.js deleted file mode 100644 index 2e4b884563..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/e2e/scenarios.js +++ /dev/null @@ -1,114 +0,0 @@ -'use strict'; - -/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ - -describe('PhoneCat App', function() { - - // #docregion redirect - it('should redirect index.html to index.html#/phones', function() { - browser.get('app/index.html'); - browser.waitForAngular(); - browser.getCurrentUrl().then(function(url) { - expect(url.endsWith('/phones')).toBe(true); - }); - }); - // #enddocregion redirect - - describe('Phone list view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones'); - }); - - it('should filter the phone list as a user types into the search box', function() { - var phoneList = element.all(by.css('.phones li')); - var query = element(by.css('input')); - - expect(phoneList.count()).toBe(20); - - query.sendKeys('nexus'); - expect(phoneList.count()).toBe(1); - - query.clear(); - // https://github.com/angular/protractor/issues/2019 - var str = 'motorola'; - for (var i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } - - expect(phoneList.count()).toBe(8); - }); - - - it('should be possible to control phone order via the drop down select box', function() { - var phoneNameColumn = element.all(by.css('.phones .name')); - var query = element(by.css('input')); - - function getNames() { - return phoneNameColumn.map(function(elm) { - return elm.getText(); - }); - } - - //let's narrow the dataset to make the test assertions shorter - // https://github.com/angular/protractor/issues/2019 - var str = 'tablet'; - for (var i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } - - expect(getNames()).toEqual([ - "Motorola XOOM\u2122 with Wi-Fi", - "MOTOROLA XOOM\u2122" - ]); - - element(by.css('select')).element(by.css('option[value="name"]')).click(); - expect(getNames()).toEqual([ - "MOTOROLA XOOM\u2122", - "Motorola XOOM\u2122 with Wi-Fi" - ]); - }); - - - // #docregion links - it('should render phone specific links', function() { - var query = element(by.css('input')); - // https://github.com/angular/protractor/issues/2019 - var str = 'nexus'; - for (var i = 0; i < str.length; i++) { - query.sendKeys(str.charAt(i)); - } - element.all(by.css('.phones li a')).first().click(); - browser.getCurrentUrl().then(function(url) { - expect(url.endsWith('/phones/nexus-s')).toBe(true); - }); - }); - }); - // #enddocregion links - - describe('Phone detail view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones/nexus-s'); - }); - - - it('should display nexus-s page', function() { - expect(element(by.css('h1')).getText()).toBe('Nexus S'); - }); - - - it('should display the first phone image as the main phone image', function() { - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - - - it('should swap main image if a thumbnail image is clicked on', function() { - element(by.css('.phone-thumbs li:nth-of-type(3) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); - - element(by.css('.phone-thumbs li:nth-of-type(1) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/karma.conf.1.js b/public/docs/_examples/upgrade/ts/ng2_final/test/karma.conf.1.js deleted file mode 100644 index 5fad1839c4..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/karma.conf.1.js +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion -module.exports = function(config){ - config.set({ - basePath : '..', - files : [ - 'node_modules/systemjs/dist/system.src.js', - 'node_modules/angular2/bundles/angular2-polyfills.js', - 'node_modules/angular2/bundles/angular2.dev.js', - 'node_modules/rxjs/bundles/Rx.js', - 'node_modules/angular2/bundles/http.dev.js', - 'node_modules/angular2/bundles/testing.dev.js', - 'node_modules/angular2/bundles/router.dev.js', - 'test/karma_test_shim.js', - {pattern: 'app/js/**/*.js', included: false, watched: true}, - {pattern: 'app/js/**/*.html', included: false, watched: true}, - {pattern: 'test/unit/**/*.js', included: false, watched: true} - ], - autoWatch : true, - frameworks: ['jasmine'], - browsers : ['Chrome', 'Firefox'], - plugins : [ - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-jasmine' - ], - junitReporter : { - outputFile: 'test_out/unit.xml', - suite: 'unit' - }, - proxies: { - // required for component assests fetched by Angular's compiler - "/js/": "/base/app/js/" - } - }); -}; diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/ng2_final/test/karma_test_shim.js deleted file mode 100644 index 392f1f2916..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/karma_test_shim.js +++ /dev/null @@ -1,51 +0,0 @@ -// #docregion -// Cancel Karma's synchronous start, -// we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function() {}; - -System.config({ - packages: { - 'base/app/js': { - defaultExtension: false, - format: 'register', - map: Object.keys(window.__karma__.files). - filter(onlyAppFiles). - reduce(function createPathRecords(pathsMapping, appPath) { - // creates local module name mapping to global path with karma's fingerprint in path, e.g.: - // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' - var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath] - return pathsMapping; - }, {}) - } - } -}); - -// #docregion ng2 -System.import('angular2/testing').then(function(testing) { - return System.import('angular2/platform/testing/browser').then(function(testing_platform_browser) { - testing.setBaseTestProviders(testing_platform_browser.TEST_BROWSER_PLATFORM_PROVIDERS, - testing_platform_browser.TEST_BROWSER_APPLICATION_PROVIDERS); - }); -}).then(function() { - return Promise.all( - Object.keys(window.__karma__.files) // All files served by Karma. - .filter(onlySpecFiles) - .map(function(moduleName) { - // loads all spec files via their global module names - return System.import(moduleName); - })); -}).then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); -}); -// #enddocregion ng2 - -function onlyAppFiles(filePath) { - return /^\/base\/app\/js\/.*\.js$/.test(filePath) -} - -function onlySpecFiles(path) { - return /\.spec\.js$/.test(path); -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/ng2_final/test/protractor-conf.js deleted file mode 100644 index a1ea324632..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/protractor-conf.js +++ /dev/null @@ -1,25 +0,0 @@ -exports.config = { - allScriptsTimeout: 11000, - - specs: [ - 'e2e/*.js' - ], - - capabilities: { - 'browserName': 'chrome' - }, - - directConnect: true, - - baseUrl: 'http://localhost:8000/', - - framework: 'jasmine', - - jasmineNodeOpts: { - defaultTimeoutInterval: 30000 - }, - - // #docregion ng2 - useAllAngular2AppRoots: true - // #enddocregion ng2 -}; diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/checkmark.pipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/checkmark.pipe.spec.ts deleted file mode 100644 index d4f7ea1558..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/checkmark.pipe.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject, expect} from 'angular2/testing'; -import {CheckmarkPipe} from '../../app/js/core/checkmark.pipe'; - -describe('CheckmarkPipe', () => { - - beforeEachProviders(() => [CheckmarkPipe]); - - it('should convert boolean values to unicode checkmark or cross', - inject([CheckmarkPipe], (checkmarkPipe) => { - expect(checkmarkPipe.transform(true)).toBe('\u2713'); - expect(checkmarkPipe.transform(false)).toBe('\u2718'); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/order_by.pipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/order_by.pipe.spec.ts deleted file mode 100644 index 5f1cc31303..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/order_by.pipe.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; - -import OrderByPipe from '../../app/js/phone_list/order_by.pipe'; - -describe('OrderByPipe', () => { - - let input:any[] = [ - {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []}, - {name: 'Motorola DROID', snippet: 'An Android-for-business smartphone', images: []} - ]; - - beforeEachProviders(() => [OrderByPipe]); - - it('should order by the given property', inject([OrderByPipe], (orderByPipe) => { - expect(orderByPipe.transform(input, ['name'])).toEqual([input[1], input[0]]); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_detail.component.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_detail.component.spec.ts deleted file mode 100644 index e0ff036453..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_detail.component.spec.ts +++ /dev/null @@ -1,53 +0,0 @@ -import {provide} from 'angular2/core'; -// #docregion routeparams -import {RouteParams} from 'angular2/router'; -// #enddocregion routeparams -import {HTTP_PROVIDERS} from 'angular2/http'; -import {Observable} from 'rxjs/Rx'; -import 'rxjs/add/observable/fromArray'; - -import { - describe, - beforeEachProviders, - injectAsync, - it, - expect, - TestComponentBuilder -} from 'angular2/testing'; -import PhoneDetail from '../../app/js/phone_detail/phone_detail.component'; -import {Phones, Phone} from '../../app/js/core/phones.service'; - -function xyzPhoneData():Phone { - return { - name: 'phone xyz', - snippet: '', - images: ['image/url1.png', 'image/url2.png'] - } -} - -class MockPhones extends Phones { - get(id):Observable { - return Observable.fromArray([xyzPhoneData()]); - } -} - -// #docregion routeparams -describe('PhoneDetail', () => { - - beforeEachProviders(() => [ - provide(Phones, {useClass: MockPhones}), - provide(RouteParams, {useValue: new RouteParams({phoneId: 'xyz'})}), - HTTP_PROVIDERS - ]); - // #enddocregion routeparams - - it('should fetch phone detail', injectAsync([TestComponentBuilder], (tcb) => { - return tcb.createAsync(PhoneDetail).then((fixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - - expect(compiled.querySelector('h1')).toHaveText(xyzPhoneData().name); - }); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_filter.pipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_filter.pipe.spec.ts deleted file mode 100644 index 8e2308f8a0..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_filter.pipe.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; - -import PhoneFilterPipe from '../../app/js/phone_list/phone_filter.pipe'; -import {Phone} from '../../app/js/core/phones.service'; - -describe('PhoneFilterPipe', () => { - - let phones:Phone[] = [ - {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []}, - {name: 'Motorola DROID', snippet: 'an Android-for-business smartphone', images: []} - ]; - - beforeEachProviders(() => [PhoneFilterPipe]); - - it('should return input when no query', inject([PhoneFilterPipe], (phoneFilterPipe) => { - expect(phoneFilterPipe.transform(phones, [])).toEqual(phones); - })); - - it('should match based on name', inject([PhoneFilterPipe], (phoneFilterPipe) => { - expect(phoneFilterPipe.transform(phones, ['nexus'])).toEqual([phones[0]]); - })); - - it('should match based on snippet', inject([PhoneFilterPipe], (phoneFilterPipe) => { - expect(phoneFilterPipe.transform(phones, ['android'])).toEqual([phones[1]]); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_list.component.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_list.component.spec.ts deleted file mode 100644 index a051e75baf..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phone_list.component.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -// #docregion -import {provide, ApplicationRef} from 'angular2/core'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import { - ROUTER_PROVIDERS - ROUTER_PRIMARY_COMPONENT, - LocationStrategy -} from 'angular2/router'; -import {MockApplicationRef} from 'angular2/testing'; -import {MockLocationStrategy} from 'angular2/router/testing'; -import {Observable} from 'rxjs/Rx'; -import 'rxjs/add/observable/fromArray'; -import { - describe, - beforeEachProviders, - injectAsync, - it, - expect, - TestComponentBuilder -} from 'angular2/testing'; -import AppComponent from '../../app/js/app.component'; -import PhoneList from '../../app/js/phone_list/phone_list.component'; -import {Phones, Phone} from '../../app/js/core/phones.service'; - -class MockPhones extends Phones { - query():Observable { - return Observable.fromArray([ - [{name: 'Nexus S'}, {name: 'Motorola DROID'}] - ]) - } -} - -describe('PhoneList', () => { - - beforeEachProviders(() => [ - HTTP_PROVIDERS, - ROUTER_PROVIDERS, - provide(ApplicationRef, {useClass: MockApplicationRef}), - provide(ROUTER_PRIMARY_COMPONENT, {useValue: AppComponent}), - provide(LocationStrategy, {useClass: MockLocationStrategy}), - provide(Phones, {useClass: MockPhones}) - ]); - - - it('should create "phones" model with 2 phones fetched from xhr', - injectAsync([TestComponentBuilder], (tcb) => { - return tcb.createAsync(PhoneList).then((fixture) => { - fixture.detectChanges(); - - let compiled = fixture.debugElement.nativeElement; - - expect(compiled.querySelectorAll('.phone-listing').length).toBe(2); - expect(compiled.querySelector('.phone-listing:nth-child(1)').textContent).toContain('Nexus S'); - expect(compiled.querySelector('.phone-listing:nth-child(2)').textContent).toContain('Motorola DROID'); - }); - })); - - - it('should set the default value of orderProp model', - injectAsync([TestComponentBuilder], (tcb) => { - return tcb.createAsync(PhoneList).then((fixture) => { - fixture.detectChanges(); - let compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('select option:last-child').selected).toBe(true); - }); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phones.service.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phones.service.spec.ts deleted file mode 100644 index 2540f687c6..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/phones.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import {Phones} from '../../app/js/core/phones.service'; - -describe('Phones', () => { - - // load providers - beforeEachProviders(() => [Phones, HTTP_PROVIDERS]); - - // Test service availability - it('check the existence of Phones', inject([Phones], (phones) => { - expect(phones).toBeDefined(); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_final/tsconfig.1.json b/public/docs/_examples/upgrade/ts/ng2_final/tsconfig.1.json deleted file mode 100644 index eef7e2be89..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/tsconfig.1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "system", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "removeComments": false - }, - "exclude": [ - "node_modules", - "typings/main.d.ts", - "typings/main" - ] -} diff --git a/public/docs/_examples/upgrade/ts/ng2_final/typings.json b/public/docs/_examples/upgrade/ts/ng2_final/typings.json deleted file mode 100644 index 3b324843f7..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_final/typings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ambientDependencies": { - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#26c98c8a9530c44f8c801ccc3b2057e2101187ee", - "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/.bowerrc b/public/docs/_examples/upgrade/ts/ng2_initial/.bowerrc deleted file mode 100644 index 5773025bf9..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "app/bower_components" -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/.gitignore b/public/docs/_examples/upgrade/ts/ng2_initial/.gitignore deleted file mode 100644 index 63d5d99a52..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -app/**/*.js -app/**/*.js.map -test/unit/**/*.js -test/unit/**/*.js.map diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/animations.css b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/animations.css deleted file mode 100644 index 46f3da6ecb..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/animations.css +++ /dev/null @@ -1,97 +0,0 @@ -/* - * animations css stylesheet - */ - -/* animate ngRepeat in phone listing */ - -.phone-listing.ng-enter, -.phone-listing.ng-leave, -.phone-listing.ng-move { - -webkit-transition: 0.5s linear all; - -moz-transition: 0.5s linear all; - -o-transition: 0.5s linear all; - transition: 0.5s linear all; -} - -.phone-listing.ng-enter, -.phone-listing.ng-move { - opacity: 0; - height: 0; - overflow: hidden; -} - -.phone-listing.ng-move.ng-move-active, -.phone-listing.ng-enter.ng-enter-active { - opacity: 1; - height: 120px; -} - -.phone-listing.ng-leave { - opacity: 1; - overflow: hidden; -} - -.phone-listing.ng-leave.ng-leave-active { - opacity: 0; - height: 0; - padding-top: 0; - padding-bottom: 0; -} - -/* cross fading between routes with ngView */ - -.view-container { - position: relative; -} - -.view-frame.ng-enter, -.view-frame.ng-leave { - background: white; - position: absolute; - top: 0; - left: 0; - right: 0; -} - -.view-frame.ng-enter { - -webkit-animation: 0.5s fade-in; - -moz-animation: 0.5s fade-in; - -o-animation: 0.5s fade-in; - animation: 0.5s fade-in; - z-index: 100; -} - -.view-frame.ng-leave { - -webkit-animation: 0.5s fade-out; - -moz-animation: 0.5s fade-out; - -o-animation: 0.5s fade-out; - animation: 0.5s fade-out; - z-index: 99; -} - -@keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-moz-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-webkit-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-moz-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-webkit-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} - diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/app.css b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/app.css deleted file mode 100644 index 951ea087cc..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/app.css +++ /dev/null @@ -1,99 +0,0 @@ -/* app css stylesheet */ - -body { - padding-top: 20px; -} - - -.phone-images { - background-color: white; - width: 450px; - height: 450px; - overflow: hidden; - position: relative; - float: left; -} - -.phones { - list-style: none; -} - -.thumb { - float: left; - margin: -0.5em 1em 1.5em 0; - padding-bottom: 1em; - height: 100px; - width: 100px; -} - -.phones li { - clear: both; - height: 115px; - padding-top: 15px; -} - -/** Detail View **/ -img.phone { - float: left; - margin-right: 3em; - margin-bottom: 2em; - background-color: white; - padding: 2em; - height: 400px; - width: 400px; - display: none; -} - -img.phone:first-child { - display: block; -} - - -ul.phone-thumbs { - margin: 0; - list-style: none; -} - -ul.phone-thumbs li { - border: 1px solid black; - display: inline-block; - margin: 1em; - background-color: white; -} - -ul.phone-thumbs img { - height: 100px; - width: 100px; - padding: 1em; -} - -ul.phone-thumbs img:hover { - cursor: pointer; -} - - -ul.specs { - clear: both; - margin: 0; - padding: 0; - list-style: none; -} - -ul.specs > li{ - display: inline-block; - width: 200px; - vertical-align: top; -} - -ul.specs > li > span{ - font-weight: bold; - font-size: 1.2em; -} - -ul.specs dt { - font-weight: bold; -} - -h1 { - border-bottom: 1px solid gray; -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings-white.png deleted file mode 100644 index 3bf6484a29..0000000000 Binary files a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings-white.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings.png deleted file mode 100644 index 5b67ffda5f..0000000000 Binary files a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/index.html b/public/docs/_examples/upgrade/ts/ng2_initial/app/index.html deleted file mode 100644 index 725ad82344..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/index.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - Google Phone Gallery - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    - - - diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/app.module.ts deleted file mode 100644 index 3172decdf3..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/app.module.ts +++ /dev/null @@ -1,46 +0,0 @@ -// #docregion adapter-import -import {UpgradeAdapter} from 'angular2/upgrade'; -// #enddocregion adapter-import -// #docregion adapter-state-import -import upgradeAdapter from './core/upgrade_adapter'; -// #enddocregion adapter-state-import -// #docregion http-import -import {HTTP_PROVIDERS} from 'angular2/http'; -// #enddocregion http-import -import core from './core/core.module'; -import phoneList from './phone_list/phone_list.module'; -import phoneDetail from './phone_detail/phone_detail.module'; - -// #docregion add-http-providers -upgradeAdapter.addProvider(HTTP_PROVIDERS); -// #enddocregion add-http-providers - -angular.module('phonecatApp', [ - 'ngRoute', - core.name, - phoneList.name, - phoneDetail.name -]).config(configure); - -configure.$inject = ['$routeProvider']; - -function configure($routeProvider) { - $routeProvider. - when('/phones', { - templateUrl: 'js/phone_list/phone_list.html', - controller: 'PhoneListCtrl', - controllerAs: 'vm' - }). - when('/phones/:phoneId', { - templateUrl: 'js/phone_detail/phone_detail.html', - controller: 'PhoneDetailCtrl', - controllerAs: 'vm' - }). - otherwise({ - redirectTo: '/phones' - }); -} - -// #docregion bootstrap -upgradeAdapter.bootstrap(document.documentElement, ['phonecatApp']); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/checkmark.filter.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/checkmark.filter.ts deleted file mode 100644 index 84544b80a1..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/checkmark.filter.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export default function checkmarkFilter() { - return function(input:string):string { - return input ? '\u2713' : '\u2718'; - }; -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/core.module.ts deleted file mode 100644 index d30604a807..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/core.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -import {Phones} from './phones.service'; -import checkmarkFilter from './checkmark.filter'; -import upgradeAdapter from './upgrade_adapter'; - -upgradeAdapter.addProvider(Phones); - -export default angular.module('phonecat.core', []) - .factory('phones', upgradeAdapter.downgradeNg2Provider(Phones)) - .filter('checkmark', checkmarkFilter); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/phones.service.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/phones.service.ts deleted file mode 100644 index 70cb8c328c..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/phones.service.ts +++ /dev/null @@ -1,38 +0,0 @@ -// #docregion full -import {Injectable} from 'angular2/core'; -import {Http, Response} from 'angular2/http'; -import {Observable} from 'rxjs/Rx'; - -import 'rxjs/add/operator/map'; - -// #docregion phone-interface -export interface Phone { - name: string; - snippet: string; - images: string[]; -} -// #enddocregion phone-interface - -// #docregion fullclass -// #docregion class -@Injectable() -export class Phones { -// #enddocregion class - - constructor(private http: Http) { } - - query():Observable { - return this.http.get(`phones/phones.json`) - .map((res:Response) => res.json()); - } - - get(id: string):Observable { - return this.http.get(`phones/${id}.json`) - .map((res:Response) => res.json()); - } - -// #docregion class -} -// #enddocregion class -// #enddocregion fullclass -// #docregion full diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/upgrade_adapter.ts deleted file mode 100644 index e21be0e4d8..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/upgrade_adapter.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion full -import {UpgradeAdapter} from 'angular2/upgrade'; - -// #docregion adapter-init -const upgradeAdapter = new UpgradeAdapter(); -// #enddocregion adapter-init - -export default upgradeAdapter; -// #enddocregion full diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.controller.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.controller.ts deleted file mode 100644 index 2dd8b25c9e..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.controller.ts +++ /dev/null @@ -1,25 +0,0 @@ -// #docregion -import {Phones, Phone} from '../core/phones.service'; - -interface PhoneRouteParams { - phoneId: string -} - -class PhoneDetailCtrl { - phone:Phone; - mainImageUrl:string; - constructor($routeParams:PhoneRouteParams, phones:Phones) { - phones.get($routeParams.phoneId) - .subscribe(phone => { - this.phone = phone; - this.mainImageUrl = phone.images[0]; - }); - } - setImage(url:string) { - this.mainImageUrl = url; - } -} - -PhoneDetailCtrl.$inject = ['$routeParams', 'phones']; - -export default PhoneDetailCtrl; diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.html deleted file mode 100644 index 954c65c2cd..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.html +++ /dev/null @@ -1,118 +0,0 @@ -
    - -
    - -

    {{vm.phone.name}}

    - -

    {{vm.phone.description}}

    - -
      -
    • - -
    • -
    - -
      -
    • - Availability and Networks -
      -
      Availability
      -
      {{availability}}
      -
      -
    • -
    • - Battery -
      -
      Type
      -
      {{vm.phone.battery.type}}
      -
      Talk Time
      -
      {{vm.phone.battery.talkTime}}
      -
      Standby time (max)
      -
      {{vm.phone.battery.standbyTime}}
      -
      -
    • -
    • - Storage and Memory -
      -
      RAM
      -
      {{vm.phone.storage.ram}}
      -
      Internal Storage
      -
      {{vm.phone.storage.flash}}
      -
      -
    • -
    • - Connectivity -
      -
      Network Support
      -
      {{vm.phone.connectivity.cell}}
      -
      WiFi
      -
      {{vm.phone.connectivity.wifi}}
      -
      Bluetooth
      -
      {{vm.phone.connectivity.bluetooth}}
      -
      Infrared
      -
      {{vm.phone.connectivity.infrared | checkmark}}
      -
      GPS
      -
      {{vm.phone.connectivity.gps | checkmark}}
      -
      -
    • -
    • - Android -
      -
      OS Version
      -
      {{vm.phone.android.os}}
      -
      UI
      -
      {{vm.phone.android.ui}}
      -
      -
    • -
    • - Size and Weight -
      -
      Dimensions
      -
      {{dim}}
      -
      Weight
      -
      {{vm.phone.sizeAndWeight.weight}}
      -
      -
    • -
    • - Display -
      -
      Screen size
      -
      {{vm.phone.display.screenSize}}
      -
      Screen resolution
      -
      {{vm.phone.display.screenResolution}}
      -
      Touch screen
      -
      {{vm.phone.display.touchScreen | checkmark}}
      -
      -
    • -
    • - Hardware -
      -
      CPU
      -
      {{vm.phone.hardware.cpu}}
      -
      USB
      -
      {{vm.phone.hardware.usb}}
      -
      Audio / headphone jack
      -
      {{vm.phone.hardware.audioJack}}
      -
      FM Radio
      -
      {{vm.phone.hardware.fmRadio | checkmark}}
      -
      Accelerometer
      -
      {{vm.phone.hardware.accelerometer | checkmark}}
      -
      -
    • -
    • - Camera -
      -
      Primary
      -
      {{vm.phone.camera.primary}}
      -
      Features
      -
      {{vm.phone.camera.features.join(', ')}}
      -
      -
    • -
    • - Additional Features -
      {{vm.phone.additionalFeatures}}
      -
    • -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.module.ts deleted file mode 100644 index 16e7ac0baf..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import PhoneDetailCtrl from './phone_detail.controller'; - -export default angular.module('phonecat.detail', [ - 'ngRoute', - 'phonecat.core' - ]) - .controller('PhoneDetailCtrl', PhoneDetailCtrl); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.controller.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.controller.ts deleted file mode 100644 index 05ea2907ad..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.controller.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -import {Phones, Phone} from '../core/phones.service'; - -class PhoneListCtrl { - phones:Phone[]; - orderProp:string; - query:string; - constructor(phones:Phones) { - phones.query() - .subscribe(phones => this.phones = phones); - this.orderProp = 'age'; - } -} - -PhoneListCtrl.$inject = ['phones']; - -export default PhoneListCtrl; diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.html deleted file mode 100644 index 471f474e89..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.html +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    -
    - - - Search: - Sort by: - - -
    -
    - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.module.ts deleted file mode 100644 index d2e7200778..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.module.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import PhoneListCtrl from './phone_list.controller'; - -export default angular.module('phonecat.list', []) - .controller('PhoneListCtrl', PhoneListCtrl); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/bower.json b/public/docs/_examples/upgrade/ts/ng2_initial/bower.json deleted file mode 100644 index 3f8ec94656..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/bower.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "angular-phonecat", - "description": "A starter project for AngularJS", - "version": "0.0.0", - "homepage": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "private": true, - "dependencies": { - "angular": "1.5.0", - "angular-mocks": "1.5.0", - "jquery": "~2.1.1", - "bootstrap": "~3.1.1", - "angular-route": "1.5.0", - "angular-resource": "1.5.0", - "angular-animate": "1.5.0" - }, - "resolutions": { - "angular": "1.5.0" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/package.1.json b/public/docs/_examples/upgrade/ts/ng2_initial/package.1.json deleted file mode 100644 index 15e2d4cc87..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/package.1.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "version": "0.0.0", - "private": true, - "name": "angular-phonecat", - "description": "A tutorial application for AngularJS", - "repository": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "dependencies": { - "angular2": "2.0.0-beta.7", - "es6-promise": "^3.0.2", - "es6-shim": "^0.33.3", - "reflect-metadata": "0.1.2", - "rxjs": "5.0.0-beta.2", - "zone.js": "0.5.15", - "systemjs": "0.19.22" - }, - "devDependencies": { - "karma": "^0.12.16", - "karma-chrome-launcher": "^0.1.4", - "karma-firefox-launcher": "^0.1.3", - "karma-jasmine": "~0.3.7", - "protractor": "^3.0.0", - "http-server": "^0.6.1", - "tmp": "0.0.23", - "bower": "^1.3.1", - "shelljs": "^0.2.6", - "typescript": "1.8.2", - "typings": "^0.6.8" - }, - "scripts": { - "postinstall": "bower install", - - "prestart": "npm install", - "start": "http-server -a 0.0.0.0 -p 8000", - - "pretest": "npm install", - "test": "node node_modules/karma/bin/karma start test/karma.conf.js", - "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run", - - "preupdate-webdriver": "npm install", - "update-webdriver": "webdriver-manager update", - - "preprotractor": "npm run update-webdriver", - "protractor": "protractor test/protractor-conf.js", - - "typings": "typings", - "tsc": "tsc -p . -w" - } -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/e2e/scenarios.js b/public/docs/_examples/upgrade/ts/ng2_initial/test/e2e/scenarios.js deleted file mode 100644 index f20d0a294c..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/e2e/scenarios.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ - -describe('PhoneCat App', function() { - - it('should redirect index.html to index.html#/phones', function() { - browser.get('app/index.html'); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones'); - }); - }); - - - describe('Phone list view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones'); - }); - - it('should filter the phone list as a user types into the search box', function() { - var phoneList = element.all(by.repeater('phone in vm.phones')); - var query = element(by.model('vm.query')); - - expect(phoneList.count()).toBe(20); - - query.sendKeys('nexus'); - expect(phoneList.count()).toBe(1); - - query.clear(); - query.sendKeys('motorola'); - expect(phoneList.count()).toBe(8); - }); - - - it('should be possible to control phone order via the drop down select box', function() { - - var phoneNameColumn = element.all(by.repeater('phone in vm.phones').column(0)); - var query = element(by.model('vm.query')); - - function getNames() { - return phoneNameColumn.map(function(elm) { - return elm.getText(); - }); - } - - query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter - - expect(getNames()).toEqual([ - "Motorola XOOM\u2122 with Wi-Fi", - "MOTOROLA XOOM\u2122" - ]); - - element(by.model('vm.orderProp')).element(by.css('option[value="name"]')).click(); - - expect(getNames()).toEqual([ - "MOTOROLA XOOM\u2122", - "Motorola XOOM\u2122 with Wi-Fi" - ]); - }); - - - it('should render phone specific links', function() { - var query = element(by.model('vm.query')); - query.sendKeys('nexus'); - element.all(by.css('.phones li a')).first().click(); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones/nexus-s'); - }); - }); - }); - - - describe('Phone detail view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones/nexus-s'); - }); - - - it('should display nexus-s page', function() { - expect(element(by.binding('vm.phone.name')).getText()).toBe('Nexus S'); - }); - - - it('should display the first phone image as the main phone image', function() { - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - - - it('should swap main image if a thumbnail image is clicked on', function() { - element(by.css('.phone-thumbs li:nth-child(3) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); - - element(by.css('.phone-thumbs li:nth-child(1) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/karma.conf.1.js b/public/docs/_examples/upgrade/ts/ng2_initial/test/karma.conf.1.js deleted file mode 100644 index 8ef2a4a0d0..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/karma.conf.1.js +++ /dev/null @@ -1,54 +0,0 @@ -module.exports = function(config){ - config.set({ - - basePath : '..', - - // #docregion ng2 - files : [ - // #enddocregion ng2 - 'app/bower_components/angular/angular.js', - 'app/bower_components/angular-route/angular-route.js', - 'app/bower_components/angular-resource/angular-resource.js', - 'app/bower_components/angular-animate/angular-animate.js', - 'app/bower_components/angular-mocks/angular-mocks.js', - // #docregion ng2 - 'node_modules/systemjs/dist/system.src.js', - 'node_modules/es6-shim/es6-shim.js', - 'node_modules/es6-promise/dist/es6-promise.js', - 'node_modules/angular2/bundles/angular2-polyfills.js', - 'node_modules/angular2/bundles/angular2.dev.js', - 'node_modules/angular2/bundles/upgrade.dev.js', - // #enddocregion ng2 - // #docregion ng2-http - 'node_modules/rxjs/bundles/Rx.js', - 'node_modules/angular2/bundles/http.dev.js', - // #enddocregion ng2-http - // #docregion ng2-testing - 'node_modules/angular2/bundles/testing.dev.js', - // #enddocregion ng2-testing - 'test/karma_test_shim.js', - {pattern: 'app/js/**/*.js', included: false, watched: true}, - {pattern: 'test/unit/**/*.js', included: false, watched: true} - // #docregion ng2 - ], - // #enddocregion ng2 - - autoWatch : true, - - frameworks: ['jasmine'], - - browsers : ['Chrome', 'Firefox'], - - plugins : [ - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-jasmine' - ], - - junitReporter : { - outputFile: 'test_out/unit.xml', - suite: 'unit' - } - - }); -}; diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/ng2_initial/test/karma_test_shim.js deleted file mode 100644 index 392f1f2916..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/karma_test_shim.js +++ /dev/null @@ -1,51 +0,0 @@ -// #docregion -// Cancel Karma's synchronous start, -// we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function() {}; - -System.config({ - packages: { - 'base/app/js': { - defaultExtension: false, - format: 'register', - map: Object.keys(window.__karma__.files). - filter(onlyAppFiles). - reduce(function createPathRecords(pathsMapping, appPath) { - // creates local module name mapping to global path with karma's fingerprint in path, e.g.: - // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' - var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath] - return pathsMapping; - }, {}) - } - } -}); - -// #docregion ng2 -System.import('angular2/testing').then(function(testing) { - return System.import('angular2/platform/testing/browser').then(function(testing_platform_browser) { - testing.setBaseTestProviders(testing_platform_browser.TEST_BROWSER_PLATFORM_PROVIDERS, - testing_platform_browser.TEST_BROWSER_APPLICATION_PROVIDERS); - }); -}).then(function() { - return Promise.all( - Object.keys(window.__karma__.files) // All files served by Karma. - .filter(onlySpecFiles) - .map(function(moduleName) { - // loads all spec files via their global module names - return System.import(moduleName); - })); -}).then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); -}); -// #enddocregion ng2 - -function onlyAppFiles(filePath) { - return /^\/base\/app\/js\/.*\.js$/.test(filePath) -} - -function onlySpecFiles(path) { - return /\.spec\.js$/.test(path); -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/ng2_initial/test/protractor-conf.js deleted file mode 100644 index 118c7b9ec2..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/protractor-conf.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.config = { - allScriptsTimeout: 11000, - - specs: [ - 'e2e/*.js' - ], - - capabilities: { - 'browserName': 'chrome' - }, - - chromeOnly: true, - - baseUrl: 'http://localhost:8000/', - - framework: 'jasmine', - - jasmineNodeOpts: { - defaultTimeoutInterval: 30000 - } -}; diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/checkmark.filter.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/checkmark.filter.spec.ts deleted file mode 100644 index bae35e6875..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/checkmark.filter.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion top -import '../../app/js/core/core.module'; -// #enddocregion top - -describe('checkmarkFilter', function() { - - beforeEach(angular.mock.module('phonecat.core')); - - it('should convert boolean values to unicode checkmark or cross', - inject(function(checkmarkFilter) { - expect(checkmarkFilter(true)).toBe('\u2713'); - expect(checkmarkFilter(false)).toBe('\u2718'); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_detail.controller.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_detail.controller.spec.ts deleted file mode 100644 index a140463720..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_detail.controller.spec.ts +++ /dev/null @@ -1,43 +0,0 @@ -// #docregion -import {Observable} from 'rxjs/Rx'; -import '../../app/js/phone_detail/phone_detail.module'; -import {Phones} from '../../app/js/core/phones.service'; - -import 'rxjs/add/observable/fromArray'; - -describe('PhoneDetailCtrl', () => { - var scope, phones, $controller, - xyzPhoneData = function() { - return { - name: 'phone xyz', - snippet: '', - images: ['image/url1.png', 'image/url2.png'] - } - }; - - beforeEach(angular.mock.module('phonecat.detail')); - - // Supply a hand-instantianted instance of the Phones service - beforeEach(angular.mock.module(function($provide) { - $provide.factory('phones', function() { - return new Phones(null); - }); - })); - - beforeEach(inject(function(_phones_, _$controller_, $rootScope, $routeParams) { - phones = _phones_; - $controller = _$controller_; - $routeParams.phoneId = 'xyz'; - scope = $rootScope.$new(); - })); - - - it('should fetch phone detail', function() { - spyOn(phones, 'get').and.returnValue(Observable.fromArray([xyzPhoneData()])); - - let ctrl = $controller('PhoneDetailCtrl', {$scope: scope}); - - expect(phones.get).toHaveBeenCalledWith('xyz'); - expect(ctrl.phone).toEqual(xyzPhoneData()); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_list.controller.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_list.controller.spec.ts deleted file mode 100644 index f9f467306c..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_list.controller.spec.ts +++ /dev/null @@ -1,38 +0,0 @@ -// #docregion -import {Observable} from 'rxjs/Rx'; -import '../../app/js/phone_list/phone_list.module'; -import {Phones} from '../../app/js/core/phones.service'; - -import 'rxjs/add/observable/fromArray'; - -describe('PhoneListCtrl', () => { - var scope, ctrl, $httpBackend; - - beforeEach(angular.mock.module('phonecat.list')); - - // Supply a hand-instantianted instance of the Phones service - beforeEach(angular.mock.module(function($provide) { - $provide.factory('phones', function() { - return new Phones(null); - }); - })); - - beforeEach(inject(function(phones, $rootScope, $controller) { - spyOn(phones, 'query').and.returnValue(Observable.fromArray([ - [{name: 'Nexus S'}, {name: 'Motorola DROID'}] - ])); - scope = $rootScope.$new(); - ctrl = $controller('PhoneListCtrl', {$scope: scope}); - })); - - - it('should create "phones" model with 2 phones fetched from xhr', function() { - expect(ctrl.phones).toEqual( - [{name: 'Nexus S'}, {name: 'Motorola DROID'}]); - }); - - - it('should set the default value of orderProp model', function() { - expect(ctrl.orderProp).toBe('age'); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phones.service.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phones.service.spec.ts deleted file mode 100644 index 2540f687c6..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phones.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -// #docregion -import {describe, beforeEachProviders, it, inject} from 'angular2/testing'; -import {HTTP_PROVIDERS} from 'angular2/http'; -import {Phones} from '../../app/js/core/phones.service'; - -describe('Phones', () => { - - // load providers - beforeEachProviders(() => [Phones, HTTP_PROVIDERS]); - - // Test service availability - it('check the existence of Phones', inject([Phones], (phones) => { - expect(phones).toBeDefined(); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/tsconfig.1.json b/public/docs/_examples/upgrade/ts/ng2_initial/tsconfig.1.json deleted file mode 100644 index eef7e2be89..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/tsconfig.1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "system", - "moduleResolution": "node", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "removeComments": false - }, - "exclude": [ - "node_modules", - "typings/main.d.ts", - "typings/main" - ] -} diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/typings.json b/public/docs/_examples/upgrade/ts/ng2_initial/typings.json deleted file mode 100644 index 8351ca2854..0000000000 --- a/public/docs/_examples/upgrade/ts/ng2_initial/typings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "ambientDependencies": { - "angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#3bebbe1baee04846cc46ed7249e8117e4cd7c7ff", - "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts#77dd2668f85730372aa8e62152e652048e8b6b87", - "angular-resource": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-resource.d.ts#c6609aff88f2c59e4df9adb93df5c7932adfd7b4", - "angular-route": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-route.d.ts#cf172aab99c3139a718aa8e65398a22c53dd7ead", - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#26c98c8a9530c44f8c801ccc3b2057e2101187ee", - "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#cf2a968f0edd7d30773f7d23fe3708fa029d5ab7", - "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#6697d6f7dadbf5773cb40ecda35a76027e0783b2" - } -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/.bowerrc b/public/docs/_examples/upgrade/ts/typescript-conversion/.bowerrc deleted file mode 100644 index 5773025bf9..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "app/bower_components" -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/.gitignore b/public/docs/_examples/upgrade/ts/typescript-conversion/.gitignore deleted file mode 100644 index 63d5d99a52..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -app/**/*.js -app/**/*.js.map -test/unit/**/*.js -test/unit/**/*.js.map diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/animations.css b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/animations.css deleted file mode 100644 index 46f3da6ecb..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/animations.css +++ /dev/null @@ -1,97 +0,0 @@ -/* - * animations css stylesheet - */ - -/* animate ngRepeat in phone listing */ - -.phone-listing.ng-enter, -.phone-listing.ng-leave, -.phone-listing.ng-move { - -webkit-transition: 0.5s linear all; - -moz-transition: 0.5s linear all; - -o-transition: 0.5s linear all; - transition: 0.5s linear all; -} - -.phone-listing.ng-enter, -.phone-listing.ng-move { - opacity: 0; - height: 0; - overflow: hidden; -} - -.phone-listing.ng-move.ng-move-active, -.phone-listing.ng-enter.ng-enter-active { - opacity: 1; - height: 120px; -} - -.phone-listing.ng-leave { - opacity: 1; - overflow: hidden; -} - -.phone-listing.ng-leave.ng-leave-active { - opacity: 0; - height: 0; - padding-top: 0; - padding-bottom: 0; -} - -/* cross fading between routes with ngView */ - -.view-container { - position: relative; -} - -.view-frame.ng-enter, -.view-frame.ng-leave { - background: white; - position: absolute; - top: 0; - left: 0; - right: 0; -} - -.view-frame.ng-enter { - -webkit-animation: 0.5s fade-in; - -moz-animation: 0.5s fade-in; - -o-animation: 0.5s fade-in; - animation: 0.5s fade-in; - z-index: 100; -} - -.view-frame.ng-leave { - -webkit-animation: 0.5s fade-out; - -moz-animation: 0.5s fade-out; - -o-animation: 0.5s fade-out; - animation: 0.5s fade-out; - z-index: 99; -} - -@keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-moz-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} -@-webkit-keyframes fade-in { - from { opacity: 0; } - to { opacity: 1; } -} - -@keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-moz-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} -@-webkit-keyframes fade-out { - from { opacity: 1; } - to { opacity: 0; } -} - diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/app.css b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/app.css deleted file mode 100644 index f41c420776..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/app.css +++ /dev/null @@ -1,99 +0,0 @@ -/* app css stylesheet */ - -body { - padding-top: 20px; -} - - -.phone-images { - background-color: white; - width: 450px; - height: 450px; - overflow: hidden; - position: relative; - float: left; -} - -.phones { - list-style: none; -} - -.thumb { - float: left; - margin: -0.5em 1em 1.5em 0; - padding-bottom: 1em; - height: 100px; - width: 100px; -} - -.phones li { - clear: both; - height: 115px; - padding-top: 15px; -} - -/** Detail View **/ -img.phone { - float: left; - margin-right: 3em; - margin-bottom: 2em; - background-color: white; - padding: 2em; - height: 400px; - width: 400px; - display: none; -} - -img.phone:first-of-type { - display: block; -} - - -ul.phone-thumbs { - margin: 0; - list-style: none; -} - -ul.phone-thumbs li { - border: 1px solid black; - display: inline-block; - margin: 1em; - background-color: white; -} - -ul.phone-thumbs img { - height: 100px; - width: 100px; - padding: 1em; -} - -ul.phone-thumbs img:hover { - cursor: pointer; -} - - -ul.specs { - clear: both; - margin: 0; - padding: 0; - list-style: none; -} - -ul.specs > li{ - display: inline-block; - width: 200px; - vertical-align: top; -} - -ul.specs > li > span{ - font-weight: bold; - font-size: 1.2em; -} - -ul.specs dt { - font-weight: bold; -} - -h1 { - border-bottom: 1px solid gray; -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings-white.png deleted file mode 100644 index 3bf6484a29..0000000000 Binary files a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings-white.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings.png deleted file mode 100644 index 5b67ffda5f..0000000000 Binary files a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings.png and /dev/null differ diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/index.html b/public/docs/_examples/upgrade/ts/typescript-conversion/app/index.html deleted file mode 100644 index 326cd44a44..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/index.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Google Phone Gallery - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    -
    - - - diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/app.module.ts deleted file mode 100644 index 835518a9c0..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/app.module.ts +++ /dev/null @@ -1,35 +0,0 @@ -// #docregion pre-bootstrap -import core from './core/core.module'; -import phoneList from './phone_list/phone_list.module'; -import phoneDetail from './phone_detail/phone_detail.module'; - -angular.module('phonecatApp', [ - 'ngAnimate', - 'ngRoute', - core.name, - phoneList.name, - phoneDetail.name -]).config(configure); - -configure.$inject = ['$routeProvider']; - -function configure($routeProvider) { - $routeProvider. - when('/phones', { - templateUrl: 'js/phone_list/phone_list.html', - controller: 'PhoneListCtrl', - controllerAs: 'vm' - }). - when('/phones/:phoneId', { - templateUrl: 'js/phone_detail/phone_detail.html', - controller: 'PhoneDetailCtrl', - controllerAs: 'vm' - }). - otherwise({ - redirectTo: '/phones' - }); -} -// #enddocregion pre-bootstrap -// #docregion bootstrap -angular.bootstrap(document.documentElement, ['phonecatApp']); -// #enddocregion bootstrap diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/checkmark.filter.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/checkmark.filter.ts deleted file mode 100644 index b2615f15e4..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/checkmark.filter.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -export default function checkmarkFilter() { - return function(input) { - return input ? '\u2713' : '\u2718'; - }; -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/core.module.ts deleted file mode 100644 index c20ce33683..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/core.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -// #docregion -import Phone from './phone.factory'; -import checkmarkFilter from './checkmark.filter'; - -export default angular.module('phonecat.core', [ - 'ngResource' - ]) - .factory('Phone', Phone) - .filter('checkmark', checkmarkFilter); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/phone.factory.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/phone.factory.ts deleted file mode 100644 index a8492b29fc..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/phone.factory.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -Phone.$inject = ['$resource']; - -function Phone($resource) { - return $resource('phones/:phoneId.json', {}, { - query: {method:'GET', params:{phoneId:'phones'}, isArray:true} - }); -} - -export default Phone; diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.controller.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.controller.ts deleted file mode 100644 index c8745c0cd2..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.controller.ts +++ /dev/null @@ -1,14 +0,0 @@ -// #docregion -PhoneDetailCtrl.$inject = ['$routeParams', 'Phone']; - -function PhoneDetailCtrl($routeParams, Phone) { - var vm = this; - vm.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) { - vm.mainImageUrl = phone.images[0]; - }); - vm.setImage = function(imageUrl) { - vm.mainImageUrl = imageUrl; - }; -} - -export default PhoneDetailCtrl; diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.html deleted file mode 100644 index 954c65c2cd..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.html +++ /dev/null @@ -1,118 +0,0 @@ -
    - -
    - -

    {{vm.phone.name}}

    - -

    {{vm.phone.description}}

    - -
      -
    • - -
    • -
    - -
      -
    • - Availability and Networks -
      -
      Availability
      -
      {{availability}}
      -
      -
    • -
    • - Battery -
      -
      Type
      -
      {{vm.phone.battery.type}}
      -
      Talk Time
      -
      {{vm.phone.battery.talkTime}}
      -
      Standby time (max)
      -
      {{vm.phone.battery.standbyTime}}
      -
      -
    • -
    • - Storage and Memory -
      -
      RAM
      -
      {{vm.phone.storage.ram}}
      -
      Internal Storage
      -
      {{vm.phone.storage.flash}}
      -
      -
    • -
    • - Connectivity -
      -
      Network Support
      -
      {{vm.phone.connectivity.cell}}
      -
      WiFi
      -
      {{vm.phone.connectivity.wifi}}
      -
      Bluetooth
      -
      {{vm.phone.connectivity.bluetooth}}
      -
      Infrared
      -
      {{vm.phone.connectivity.infrared | checkmark}}
      -
      GPS
      -
      {{vm.phone.connectivity.gps | checkmark}}
      -
      -
    • -
    • - Android -
      -
      OS Version
      -
      {{vm.phone.android.os}}
      -
      UI
      -
      {{vm.phone.android.ui}}
      -
      -
    • -
    • - Size and Weight -
      -
      Dimensions
      -
      {{dim}}
      -
      Weight
      -
      {{vm.phone.sizeAndWeight.weight}}
      -
      -
    • -
    • - Display -
      -
      Screen size
      -
      {{vm.phone.display.screenSize}}
      -
      Screen resolution
      -
      {{vm.phone.display.screenResolution}}
      -
      Touch screen
      -
      {{vm.phone.display.touchScreen | checkmark}}
      -
      -
    • -
    • - Hardware -
      -
      CPU
      -
      {{vm.phone.hardware.cpu}}
      -
      USB
      -
      {{vm.phone.hardware.usb}}
      -
      Audio / headphone jack
      -
      {{vm.phone.hardware.audioJack}}
      -
      FM Radio
      -
      {{vm.phone.hardware.fmRadio | checkmark}}
      -
      Accelerometer
      -
      {{vm.phone.hardware.accelerometer | checkmark}}
      -
      -
    • -
    • - Camera -
      -
      Primary
      -
      {{vm.phone.camera.primary}}
      -
      Features
      -
      {{vm.phone.camera.features.join(', ')}}
      -
      -
    • -
    • - Additional Features -
      {{vm.phone.additionalFeatures}}
      -
    • -
    diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.module.ts deleted file mode 100644 index 5ea1739577..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -// #docregion -import PhoneDetailCtrl from './phone_detail.controller'; - -export default angular.module('phonecat.detail', [ - 'phonecat.core', - 'ngRoute' - ]) - .controller('PhoneDetailCtrl', PhoneDetailCtrl); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.controller.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.controller.ts deleted file mode 100644 index 63dc2a6548..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.controller.ts +++ /dev/null @@ -1,10 +0,0 @@ -// #docregion -PhoneListCtrl.$inject = ['Phone']; - -function PhoneListCtrl(Phone) { - var vm = this; - vm.phones = Phone.query(); - vm.orderProp = 'age'; -} - -export default PhoneListCtrl; diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.html deleted file mode 100644 index 471f474e89..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.html +++ /dev/null @@ -1,28 +0,0 @@ -
    -
    -
    - - - Search: - Sort by: - - -
    -
    - - - - -
    -
    -
    diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.module.ts deleted file mode 100644 index 758b937927..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.module.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -import PhoneListCtrl from './phone_list.controller'; - -export default angular.module('phonecat.list', ['phonecat.core']) - .controller('PhoneListCtrl', PhoneListCtrl); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/bower.json b/public/docs/_examples/upgrade/ts/typescript-conversion/bower.json deleted file mode 100644 index 3f8ec94656..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/bower.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "angular-phonecat", - "description": "A starter project for AngularJS", - "version": "0.0.0", - "homepage": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "private": true, - "dependencies": { - "angular": "1.5.0", - "angular-mocks": "1.5.0", - "jquery": "~2.1.1", - "bootstrap": "~3.1.1", - "angular-route": "1.5.0", - "angular-resource": "1.5.0", - "angular-animate": "1.5.0" - }, - "resolutions": { - "angular": "1.5.0" - } -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/package.1.json b/public/docs/_examples/upgrade/ts/typescript-conversion/package.1.json deleted file mode 100644 index cbbef829f1..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/package.1.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "version": "0.0.0", - "private": true, - "name": "angular-phonecat", - "description": "A tutorial application for AngularJS", - "repository": "https://github.com/angular/angular-phonecat", - "license": "MIT", - "dependencies": { - "systemjs": "0.19.22" - }, - "devDependencies": { - "bower": "^1.3.1", - "http-server": "^0.6.1", - "karma": "^0.12.16", - "karma-chrome-launcher": "^0.1.4", - "karma-firefox-launcher": "^0.1.3", - "karma-jasmine": "~0.3.7", - "protractor": "^3.0.0", - "shelljs": "^0.2.6", - "tmp": "0.0.23", - "typescript": "^1.8.2", - "typings": "^0.6.8" - }, - "scripts": { - "postinstall": "bower install", - "prestart": "npm install", - "start": "http-server -a 0.0.0.0 -p 8000", - "pretest": "npm install", - "test": "node node_modules/karma/bin/karma start test/karma.conf.js", - "test-single-run": "node node_modules/karma/bin/karma start test/karma.conf.js --single-run", - "preupdate-webdriver": "npm install", - "update-webdriver": "webdriver-manager update", - "preprotractor": "npm run update-webdriver", - "protractor": "protractor test/protractor-conf.js", - "typings": "typings", - "tsc": "tsc -p . -w" - } -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/e2e/scenarios.js b/public/docs/_examples/upgrade/ts/typescript-conversion/test/e2e/scenarios.js deleted file mode 100644 index 5a505b5dae..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/e2e/scenarios.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ - -describe('PhoneCat App', function() { - - it('should redirect index.html to index.html#/phones', function() { - browser.get('app/index.html'); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones'); - }); - }); - - - describe('Phone list view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones'); - }); - - - it('should filter the phone list as a user types into the search box', function() { - var phoneList = element.all(by.repeater('phone in vm.phones')); - var query = element(by.model('vm.query')); - - expect(phoneList.count()).toBe(20); - - query.sendKeys('nexus'); - expect(phoneList.count()).toBe(1); - - query.clear(); - query.sendKeys('motorola'); - expect(phoneList.count()).toBe(8); - }); - - - it('should be possible to control phone order via the drop down select box', function() { - - var phoneNameColumn = element.all(by.repeater('phone in vm.phones').column('phone.name')); - var query = element(by.model('vm.query')); - - function getNames() { - return phoneNameColumn.map(function(elm) { - return elm.getText(); - }); - } - - query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter - - expect(getNames()).toEqual([ - "Motorola XOOM\u2122 with Wi-Fi", - "MOTOROLA XOOM\u2122" - ]); - - element(by.model('vm.orderProp')).element(by.css('option[value="name"]')).click(); - - expect(getNames()).toEqual([ - "MOTOROLA XOOM\u2122", - "Motorola XOOM\u2122 with Wi-Fi" - ]); - }); - - - it('should render phone specific links', function() { - var query = element(by.model('vm.query')); - query.sendKeys('nexus'); - element.all(by.css('.phones li a')).first().click(); - browser.getLocationAbsUrl().then(function(url) { - expect(url).toEqual('/phones/nexus-s'); - }); - }); - }); - - - describe('Phone detail view', function() { - - beforeEach(function() { - browser.get('app/index.html#/phones/nexus-s'); - }); - - - it('should display nexus-s page', function() { - expect(element(by.binding('vm.phone.name')).getText()).toBe('Nexus S'); - }); - - - it('should display the first phone image as the main phone image', function() { - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - - - it('should swap main image if a thumbnail image is clicked on', function() { - element(by.css('.phone-thumbs li:nth-child(3) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/); - - element(by.css('.phone-thumbs li:nth-child(1) img')).click(); - expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/); - }); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/jasmine_matchers.d.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/jasmine_matchers.d.ts deleted file mode 100644 index 6d24879775..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/jasmine_matchers.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -// #docregion -declare module jasmine { - interface Matchers { - toEqualData(expected: any):boolean; - } -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma.conf.1.js b/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma.conf.1.js deleted file mode 100644 index 8f2e7d178f..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma.conf.1.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = function(config){ - config.set({ - - basePath : '..', - - // #docregion files - files : [ - 'app/bower_components/angular/angular.js', - 'app/bower_components/angular-route/angular-route.js', - 'app/bower_components/angular-resource/angular-resource.js', - 'app/bower_components/angular-animate/angular-animate.js', - 'app/bower_components/angular-mocks/angular-mocks.js', - 'node_modules/systemjs/dist/system.src.js', - 'test/karma_test_shim.js', - {pattern: 'app/js/**/*.js', included: false, watched: true}, - {pattern: 'test/unit/**/*.js', included: false, watched: true} - ], - // #enddocregion files - - autoWatch : true, - - frameworks: ['jasmine'], - - browsers : ['Chrome', 'Firefox'], - - plugins : [ - 'karma-chrome-launcher', - 'karma-firefox-launcher', - 'karma-jasmine' - ], - - junitReporter : { - outputFile: 'test_out/unit.xml', - suite: 'unit' - } - - }); -}; diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma_test_shim.js deleted file mode 100644 index 15cbee5d7d..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma_test_shim.js +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion -// Cancel Karma's synchronous start, -// we will call `__karma__.start()` later, once all the specs are loaded. -__karma__.loaded = function() {}; - -System.config({ - packages: { - 'base/app/js': { - defaultExtension: false, - format: 'register', - map: Object.keys(window.__karma__.files). - filter(onlyAppFiles). - reduce(function createPathRecords(pathsMapping, appPath) { - // creates local module name mapping to global path with karma's fingerprint in path, e.g.: - // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e' - var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, ''); - pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath] - return pathsMapping; - }, {}) - - } - } -}); - -Promise.all( - Object.keys(window.__karma__.files) // All files served by Karma. - .filter(onlySpecFiles) - .map(function(moduleName) { - // loads all spec files via their global module names - return System.import(moduleName); -})) -.then(function() { - __karma__.start(); -}, function(error) { - __karma__.error(error.stack || error); -}); - -function onlyAppFiles(filePath) { - return /^\/base\/app\/js\/.*\.js$/.test(filePath) -} - -function onlySpecFiles(path) { - return /\.spec\.js$/.test(path); -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/typescript-conversion/test/protractor-conf.js deleted file mode 100644 index 118c7b9ec2..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/protractor-conf.js +++ /dev/null @@ -1,21 +0,0 @@ -exports.config = { - allScriptsTimeout: 11000, - - specs: [ - 'e2e/*.js' - ], - - capabilities: { - 'browserName': 'chrome' - }, - - chromeOnly: true, - - baseUrl: 'http://localhost:8000/', - - framework: 'jasmine', - - jasmineNodeOpts: { - defaultTimeoutInterval: 30000 - } -}; diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/checkmark.filter.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/checkmark.filter.spec.ts deleted file mode 100644 index bae35e6875..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/checkmark.filter.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion top -import '../../app/js/core/core.module'; -// #enddocregion top - -describe('checkmarkFilter', function() { - - beforeEach(angular.mock.module('phonecat.core')); - - it('should convert boolean values to unicode checkmark or cross', - inject(function(checkmarkFilter) { - expect(checkmarkFilter(true)).toBe('\u2713'); - expect(checkmarkFilter(false)).toBe('\u2718'); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone.factory.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone.factory.spec.ts deleted file mode 100644 index d7c95d347e..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone.factory.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -// #docregion top -import '../../app/js/core/core.module'; -// #enddocregion top - -describe('phoneFactory', function() { - - // load modules - beforeEach(angular.mock.module('phonecat.core')); - - // Test service availability - it('check the existence of Phone factory', inject(function(Phone) { - expect(Phone).toBeDefined(); - })); - -}); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_detail.controller.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_detail.controller.spec.ts deleted file mode 100644 index 02a3e20240..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_detail.controller.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion top -import '../../app/js/phone_detail/phone_detail.module'; -// #enddocregion top - -describe('PhoneDetailCtrl', function(){ - var scope, $httpBackend, ctrl, - xyzPhoneData = function() { - return { - name: 'phone xyz', - images: ['image/url1.png', 'image/url2.png'] - } - }; - - beforeEach(angular.mock.module('phonecat.detail')); - - beforeEach(function(){ - jasmine.addMatchers({ - toEqualData: function(util, customEqualityTesters) { - return { - compare: function(actual, expected) { - return {pass: angular.equals(actual, expected)}; - } - }; - } - }); - }); - - beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) { - $httpBackend = _$httpBackend_; - $httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData()); - - $routeParams.phoneId = 'xyz'; - scope = $rootScope.$new(); - ctrl = $controller('PhoneDetailCtrl', {$scope: scope}); - })); - - - it('should fetch phone detail', function() { - expect(ctrl.phone).toEqualData({}); - $httpBackend.flush(); - - expect(ctrl.phone).toEqualData(xyzPhoneData()); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_list.controller.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_list.controller.spec.ts deleted file mode 100644 index efec5d5f08..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_list.controller.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -// #docregion top -import '../../app/js/phone_list/phone_list.module'; -// #enddocregion top - -describe('PhoneListCtrl', function(){ - var scope, ctrl, $httpBackend; - - beforeEach(angular.mock.module('phonecat.list')); - - beforeEach(function(){ - jasmine.addMatchers({ - toEqualData: function(util, customEqualityTesters) { - return { - compare: function(actual, expected) { - return {pass: angular.equals(actual, expected)}; - } - }; - } - }); - }); - - beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) { - $httpBackend = _$httpBackend_; - $httpBackend.expectGET('phones/phones.json'). - respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]); - - scope = $rootScope.$new(); - ctrl = $controller('PhoneListCtrl', {$scope: scope}); - })); - - - it('should create "phones" model with 2 phones fetched from xhr', function() { - expect(ctrl.phones).toEqualData([]); - $httpBackend.flush(); - - expect(ctrl.phones).toEqualData( - [{name: 'Nexus S'}, {name: 'Motorola DROID'}]); - }); - - - it('should set the default value of orderProp model', function() { - expect(ctrl.orderProp).toBe('age'); - }); -}); diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/tsconfig.1.json b/public/docs/_examples/upgrade/ts/typescript-conversion/tsconfig.1.json deleted file mode 100644 index c3cf6bcddb..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/tsconfig.1.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES5", - "module": "system", - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "removeComments": false - }, - "exclude": [ - "node_modules", - "typings/main.d.ts", - "typings/main" - ] -} diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/typings.json b/public/docs/_examples/upgrade/ts/typescript-conversion/typings.json deleted file mode 100644 index 55b63ee44f..0000000000 --- a/public/docs/_examples/upgrade/ts/typescript-conversion/typings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ambientDependencies": { - "angular": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular.d.ts#3bebbe1baee04846cc46ed7249e8117e4cd7c7ff", - "angular-mocks": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-mocks.d.ts#77dd2668f85730372aa8e62152e652048e8b6b87", - "angular-resource": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-resource.d.ts#c6609aff88f2c59e4df9adb93df5c7932adfd7b4", - "angular-route": "github:DefinitelyTyped/DefinitelyTyped/angularjs/angular-route.d.ts#cf172aab99c3139a718aa8e65398a22c53dd7ead", - "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#26c98c8a9530c44f8c801ccc3b2057e2101187ee", - "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#470954c4f427e0805a2d633636a7c6aa7170def8" - } -} diff --git a/public/docs/_examples/user-input/dart/lib/app_component.dart b/public/docs/_examples/user-input/dart/lib/app_component.dart deleted file mode 100644 index 4a2f3fe6ff..0000000000 --- a/public/docs/_examples/user-input/dart/lib/app_component.dart +++ /dev/null @@ -1,23 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -import 'click_me_component.dart'; -import 'click_me_component_2.dart'; -import 'keyup_components.dart'; -import 'little_tour_component.dart'; -import 'loop_back_component.dart'; - -@Component( - selector: 'my-app', - templateUrl: 'app_component.html', - directives: const [ - ClickMeComponent, - ClickMeComponent2, - KeyUpComponentV1, - KeyUpComponentV2, - KeyUpComponentV3, - KeyUpComponentV4, - LoopBackComponent, - LittleTourComponent - ]) -class AppComponent {} diff --git a/public/docs/_examples/user-input/dart/lib/app_component.html b/public/docs/_examples/user-input/dart/lib/app_component.html deleted file mode 100644 index ecda463827..0000000000 --- a/public/docs/_examples/user-input/dart/lib/app_component.html +++ /dev/null @@ -1,28 +0,0 @@ - -

    - -

    - -

    - -

    - -

    Give me some keys!

    -
    - -

    keyup loop-back component

    -
    -

    - -

    Give me some more keys!

    -
    - -

    Type away! Press [enter] when done.

    -
    - -

    Type away! Press [enter] or click elsewhere when done.

    -
    - -

    Little Tour of Heroes

    -

    Add a new hero

    -
    diff --git a/public/docs/_examples/user-input/dart/lib/click_me_component.dart b/public/docs/_examples/user-input/dart/lib/click_me_component.dart deleted file mode 100644 index eaad88dd0c..0000000000 --- a/public/docs/_examples/user-input/dart/lib/click_me_component.dart +++ /dev/null @@ -1,19 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -// #docregion click-me-component -@Component( - selector: 'click-me', - template: ''' - // #docregion click-me-button - - // #enddocregion click-me-button - {{clickMessage}}''') -class ClickMeComponent { - String clickMessage = ''; - - onClickMe() { - clickMessage = 'You are my hero!'; - } -} -// #enddocregion click-me-component diff --git a/public/docs/_examples/user-input/dart/lib/click_me_component_2.dart b/public/docs/_examples/user-input/dart/lib/click_me_component_2.dart deleted file mode 100644 index e96399d943..0000000000 --- a/public/docs/_examples/user-input/dart/lib/click_me_component_2.dart +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -@Component( - selector: 'click-me2', - template: ''' - {{clickMessage}}''') -class ClickMeComponent2 { - String clickMessage = ''; - int clicks = 1; - - onClickMe2(dynamic event) { - var evtMsg = - event != null ? ' Event target is ' + event.target.tagName : ''; - clickMessage = ('Click #${clicks++}. ${evtMsg}'); - } -} diff --git a/public/docs/_examples/user-input/dart/lib/keyup_components.dart b/public/docs/_examples/user-input/dart/lib/keyup_components.dart deleted file mode 100644 index e48056a1aa..0000000000 --- a/public/docs/_examples/user-input/dart/lib/keyup_components.dart +++ /dev/null @@ -1,83 +0,0 @@ -// #docplaster -// #docregion -import 'dart:html'; - -import 'package:angular2/angular2.dart'; - -// #docregion key-up-component-1 -@Component( - selector: 'key-up1', -// #docregion key-up-component-1-template - template: ''' - -

    {{values}}

    - ''' -// #enddocregion key-up-component-1-template - ) -// #docregion key-up-component-1-class, key-up-component-1-class-no-type -class KeyUpComponentV1 { - String values = ''; - - // #enddocregion key-up-component-1-class, key-up-component-1-class-no-type - /* - // #docregion key-up-component-1-class-no-type - onKey(dynamic event) { - values += event.target.value + ' | '; - } - // #enddocregion key-up-component-1-class-no-type - */ - // #docregion key-up-component-1-class - onKey(KeyboardEvent event) { - InputElement el = event.target; - values += '${el.value} | '; - } -// #docregion key-up-component-1-class-no-type -} -// #enddocregion key-up-component-1,key-up-component-1-class, key-up-component-1-class-no-type - -////////////////////////////////////////// - -// #docregion key-up-component-2 -@Component( - selector: 'key-up2', - template: ''' - -

    {{values}}

    - ''') -class KeyUpComponentV2 { - String values = ''; - onKey(value) { - values += '$value | '; - } -} -// #enddocregion key-up-component-2 - -////////////////////////////////////////// - -// #docregion key-up-component-3 -@Component( - selector: 'key-up3', - template: ''' - -

    {{values}}

    - ''') -class KeyUpComponentV3 { - String values = ''; -} -// #enddocregion key-up-component-3 - -////////////////////////////////////////// - -// #docregion key-up-component-4 -@Component( - selector: 'key-up4', - template: ''' - -

    {{values}}

    - ''') -class KeyUpComponentV4 { - String values = ''; -} -// #enddocregion key-up-component-4 diff --git a/public/docs/_examples/user-input/dart/lib/little_tour_component.dart b/public/docs/_examples/user-input/dart/lib/little_tour_component.dart deleted file mode 100644 index ba98f37d68..0000000000 --- a/public/docs/_examples/user-input/dart/lib/little_tour_component.dart +++ /dev/null @@ -1,25 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -// #docregion little-tour -@Component( - selector: 'little-tour', - template: ''' - - - - -
    • {{hero}}
    - ''') -class LittleTourComponent { - List heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado']; - - void addHero(String newHero) { - if (newHero?.length > 0) { - heroes.add(newHero); - } - } -} -// #enddocregion little-tour diff --git a/public/docs/_examples/user-input/dart/lib/loop_back_component.dart b/public/docs/_examples/user-input/dart/lib/loop_back_component.dart deleted file mode 100644 index b79f3f5ac4..0000000000 --- a/public/docs/_examples/user-input/dart/lib/loop_back_component.dart +++ /dev/null @@ -1,12 +0,0 @@ -// #docregion -import 'package:angular2/angular2.dart'; - -// #docregion loop-back-component -@Component( - selector: 'loop-back', - template: ''' - -

    {{box.value}}

    - ''') -class LoopBackComponent {} -// #enddocregion loop-back-component diff --git a/public/docs/_examples/user-input/dart/pubspec.yaml b/public/docs/_examples/user-input/dart/pubspec.yaml deleted file mode 100644 index 9fdeb9f82b..0000000000 --- a/public/docs/_examples/user-input/dart/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# #docregion -name: user_input -description: User input example -version: 0.0.1 -environment: - sdk: '>=1.13.0 <2.0.0' -dependencies: - angular2: 2.0.0-beta.8 - browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0 -transformers: -- angular2: - platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES' - entry_points: web/main.dart -- dart_to_js_script_rewriter diff --git a/public/docs/_examples/user-input/dart/web/index.html b/public/docs/_examples/user-input/dart/web/index.html deleted file mode 100644 index 6081616684..0000000000 --- a/public/docs/_examples/user-input/dart/web/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - User Input - - - - - - - - Loading... - - diff --git a/public/docs/_examples/user-input/dart/web/main.dart b/public/docs/_examples/user-input/dart/web/main.dart deleted file mode 100644 index f74bf40a09..0000000000 --- a/public/docs/_examples/user-input/dart/web/main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// #docregion -import 'package:angular2/bootstrap.dart'; -import 'package:user_input/app_component.dart'; - -main() { - bootstrap(AppComponent); -} diff --git a/public/docs/_examples/user-input/e2e-spec.js b/public/docs/_examples/user-input/e2e-spec.js deleted file mode 100644 index c0d4fa0c1f..0000000000 --- a/public/docs/_examples/user-input/e2e-spec.js +++ /dev/null @@ -1,101 +0,0 @@ -describe('User Input Tests', function () { - - beforeAll(function () { - browser.get(''); - }); - - it('should support the click event', function () { - var mainEle = element(by.css('click-me')); - var buttonEle =element(by.css('click-me button')); - expect(mainEle.getText()).not.toContain('You are my hero!'); - buttonEle.click().then(function() { - expect(mainEle.getText()).toContain('You are my hero!'); - }); - }); - - it('should support the click event with an event payload', function () { - var mainEle = element(by.css('click-me2')); - var buttonEle =element(by.css('click-me2 button')); - expect(mainEle.getText()).not.toContain('Event target is '); - buttonEle.click().then(function() { - expect(mainEle.getText()).toContain('Event target is BUTTON'); - }) - }); - - it('should support the keyup event ', function () { - var mainEle = element(by.css('key-up1')); - var inputEle = mainEle.element(by.css('input')); - var outputTextEle = mainEle.element(by.css('p')); - expect(outputTextEle.getText()).toEqual(''); - return sendKeys(inputEle,'abc').then(function() { - expect(outputTextEle.getText()).toEqual('a | ab | abc |'); - }); - }); - - it('should support user input from a local template var (loopback)', function () { - var mainEle = element(by.css('loop-back')); - var inputEle = mainEle.element(by.css('input')); - var outputTextEle = mainEle.element(by.css('p')); - expect(outputTextEle.getText()).toEqual(''); - return sendKeys(inputEle,'abc').then(function() { - expect(outputTextEle.getText()).toEqual('abc'); - }); - }); - - it('should be able to combine click event with a local template var', function () { - var mainEle = element(by.css('key-up2')); - var inputEle = mainEle.element(by.css('input')); - var outputTextEle = mainEle.element(by.css('p')); - expect(outputTextEle.getText()).toEqual(''); - return sendKeys(inputEle,'abc').then(function() { - expect(outputTextEle.getText()).toEqual('a | ab | abc |'); - }); - }); - - it('should be able to filter key events', function () { - var mainEle = element(by.css('key-up3')); - var inputEle = mainEle.element(by.css('input')); - var outputTextEle = mainEle.element(by.css('p')); - expect(outputTextEle.getText()).toEqual(''); - return sendKeys(inputEle,'abc').then(function() { - expect(outputTextEle.getText()).toEqual('', 'should be blank - have not sent enter yet'); - return sendKeys(inputEle, protractor.Key.ENTER); - }).then(function() { - expect(outputTextEle.getText()).toEqual('abc'); - }); - }); - - it('should be able to filter blur events', function () { - var prevInputEle = element(by.css('key-up3 input')); - var mainEle = element(by.css('key-up4')); - var inputEle = mainEle.element(by.css('input')); - var outputTextEle = mainEle.element(by.css('p')); - expect(outputTextEle.getText()).toEqual(''); - return sendKeys(inputEle,'abc').then(function() { - expect(outputTextEle.getText()).toEqual('', 'should be blank - have not sent enter yet'); - // change the focus - return prevInputEle.click(); - }).then(function() { - expect(outputTextEle.getText()).toEqual('abc'); - }); - }); - - it('should be able to compose little tour of heroes', function () { - var mainEle = element(by.css('little-tour')); - var inputEle = mainEle.element(by.css('input')); - var addButtonEle = mainEle.element(by.css('button')); - var heroEles = mainEle.all(by.css('li')); - var numHeroes; - expect(heroEles.count()).toBeGreaterThan(0); - heroEles.count().then(function(count) { - numHeroes = count; - return sendKeys(inputEle, 'abc'); - }).then(function() { - return addButtonEle.click(); - }).then(function() { - expect(heroEles.count()).toEqual(numHeroes + 1, 'should be one more hero added'); - expect(heroEles.get(numHeroes).getText()).toContain('abc'); - }); - }); -}); - diff --git a/public/docs/_examples/user-input/e2e-spec.ts b/public/docs/_examples/user-input/e2e-spec.ts new file mode 100644 index 0000000000..3f178382c7 --- /dev/null +++ b/public/docs/_examples/user-input/e2e-spec.ts @@ -0,0 +1,99 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by, protractor } from 'protractor'; + +describe('User Input Tests', function () { + + beforeAll(function () { + browser.get(''); + }); + + it('should support the click event', function () { + let mainEle = element(by.css('click-me')); + let buttonEle = element(by.css('click-me button')); + expect(mainEle.getText()).not.toContain('You are my hero!'); + buttonEle.click().then(function() { + expect(mainEle.getText()).toContain('You are my hero!'); + }); + }); + + it('should support the click event with an event payload', function () { + let mainEle = element(by.css('click-me2')); + let buttonEle = element(by.css('click-me2 button')); + expect(mainEle.getText()).not.toContain('Event target is '); + buttonEle.click().then(function() { + expect(mainEle.getText()).toContain('Event target is BUTTON'); + }); + }); + + it('should support the keyup event ', function () { + let mainEle = element(by.css('key-up1')); + let inputEle = mainEle.element(by.css('input')); + let outputTextEle = mainEle.element(by.css('p')); + expect(outputTextEle.getText()).toEqual(''); + inputEle.sendKeys('abc'); + expect(outputTextEle.getText()).toEqual('a | ab | abc |'); + }); + + it('should support user input from a local template let (loopback)', function () { + let mainEle = element(by.css('loop-back')); + let inputEle = mainEle.element(by.css('input')); + let outputTextEle = mainEle.element(by.css('p')); + expect(outputTextEle.getText()).toEqual(''); + inputEle.sendKeys('abc'); + expect(outputTextEle.getText()).toEqual('abc'); + }); + + it('should be able to combine click event with a local template var', function () { + let mainEle = element(by.css('key-up2')); + let inputEle = mainEle.element(by.css('input')); + let outputTextEle = mainEle.element(by.css('p')); + expect(outputTextEle.getText()).toEqual(''); + inputEle.sendKeys('abc'); + expect(outputTextEle.getText()).toEqual('a | ab | abc |'); + }); + + it('should be able to filter key events', () => { + let mainEle = element(by.css('key-up3')); + let inputEle = mainEle.element(by.css('input')); + let outputTextEle = mainEle.element(by.css('p')); + expect(outputTextEle.getText()).toEqual(''); + inputEle.sendKeys('abc'); + expect(outputTextEle.getText()).toEqual('', 'should be blank - have not sent enter yet'); + // broken atm, see https://github.com/angular/angular/issues/9419 + inputEle.sendKeys(protractor.Key.ENTER); + expect(outputTextEle.getText()).toEqual('abc'); + }); + + it('should be able to filter blur events', function () { + let prevInputEle = element(by.css('key-up3 input')); + let mainEle = element(by.css('key-up4')); + let inputEle = mainEle.element(by.css('input')); + let outputTextEle = mainEle.element(by.css('p')); + expect(outputTextEle.getText()).toEqual(''); + inputEle.sendKeys('abc'); + expect(outputTextEle.getText()).toEqual('', 'should be blank - have not sent enter yet'); + // change the focus + prevInputEle.click().then(function() { + expect(outputTextEle.getText()).toEqual('abc'); + }); + }); + + it('should be able to compose little tour of heroes', function () { + let mainEle = element(by.css('little-tour')); + let inputEle = mainEle.element(by.css('input')); + let addButtonEle = mainEle.element(by.css('button')); + let heroEles = mainEle.all(by.css('li')); + let numHeroes: number; + expect(heroEles.count()).toBeGreaterThan(0); + heroEles.count().then(function(count: number) { + numHeroes = count; + inputEle.sendKeys('abc'); + return addButtonEle.click(); + }).then(function() { + expect(heroEles.count()).toEqual(numHeroes + 1, 'should be one more hero added'); + expect(heroEles.get(numHeroes).getText()).toContain('abc'); + }); + }); +}); + diff --git a/public/docs/_examples/user-input/ts/.gitignore b/public/docs/_examples/user-input/ts/.gitignore deleted file mode 100644 index 2cb7d2a2e9..0000000000 --- a/public/docs/_examples/user-input/ts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/*.js diff --git a/public/docs/_examples/user-input/ts/app/app.component.ts b/public/docs/_examples/user-input/ts/app/app.component.ts deleted file mode 100644 index 8cd10cc290..0000000000 --- a/public/docs/_examples/user-input/ts/app/app.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -import {ClickMeComponent} from './click-me.component'; -import {ClickMeComponent2} from './click-me2.component'; - -import {LoopbackComponent} from './loop-back.component'; - -import {KeyUpComponent_v1, - KeyUpComponent_v2, - KeyUpComponent_v3, - KeyUpComponent_v4} from './keyup.components'; - -import {LittleTourComponent} from './little-tour.component'; - -@Component({ - selector: 'my-app', - templateUrl: 'app/app.component.html', - directives: [ - ClickMeComponent, ClickMeComponent2, - LoopbackComponent, - KeyUpComponent_v1, KeyUpComponent_v2, KeyUpComponent_v3, KeyUpComponent_v4, - LittleTourComponent - ] -}) -export class AppComponent { } diff --git a/public/docs/_examples/user-input/ts/app/click-me2.component.ts b/public/docs/_examples/user-input/ts/app/click-me2.component.ts deleted file mode 100644 index 32f78d272e..0000000000 --- a/public/docs/_examples/user-input/ts/app/click-me2.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -@Component({ - selector: 'click-me2', - template: ` - - {{clickMessage}}` -}) -export class ClickMeComponent2 { - clickMessage = ''; - clicks = 1; - - onClickMe2(event:any){ - let evtMsg = event ? ' Event target is '+ event.target.tagName : ''; - this.clickMessage = (`Click #${this.clicks++}. ${evtMsg}`) - } -} diff --git a/public/docs/_examples/user-input/ts/app/keyup.components.ts b/public/docs/_examples/user-input/ts/app/keyup.components.ts deleted file mode 100644 index 728ea30b3a..0000000000 --- a/public/docs/_examples/user-input/ts/app/keyup.components.ts +++ /dev/null @@ -1,88 +0,0 @@ -// #docplaster -// #docregion -import {Component} from 'angular2/core'; - -// #docregion key-up-component-1 -@Component({ - selector: 'key-up1', -// #docregion key-up-component-1-template - template: ` - -

    {{values}}

    - ` -// #enddocregion key-up-component-1-template -}) -// #docregion key-up-component-1-class, key-up-component-1-class-no-type -export class KeyUpComponent_v1 { - values=''; - -// #enddocregion key-up-component-1-class, key-up-component-1-class-no-type - /* - // #docregion key-up-component-1-class-no-type - // without strong typing - onKey(event:any) { - this.values += event.target.value + ' | '; - } - // #enddocregion key-up-component-1-class-no-type - */ - // #docregion key-up-component-1-class - // with strong typing - onKey(event:KeyboardEvent) { - this.values += (event.target).value + ' | '; - } -// #docregion key-up-component-1-class-no-type -} -// #enddocregion key-up-component-1,key-up-component-1-class, key-up-component-1-class-no-type - -////////////////////////////////////////// - -// #docregion key-up-component-2 -@Component({ - selector: 'key-up2', - template: ` - -

    {{values}}

    - ` -}) -export class KeyUpComponent_v2 { - values=''; - onKey(value:string) { - this.values += value + ' | '; - } -} -// #enddocregion key-up-component-2 - - -////////////////////////////////////////// - -// #docregion key-up-component-3 -@Component({ - selector: 'key-up3', - template: ` - -

    {{values}}

    - ` -}) -export class KeyUpComponent_v3 { - values=''; -} -// #enddocregion key-up-component-3 - - -////////////////////////////////////////// - -// #docregion key-up-component-4 -@Component({ - selector: 'key-up4', - template: ` - - -

    {{values}}

    - ` -}) -export class KeyUpComponent_v4 { - values=''; -} -// #enddocregion key-up-component-4 diff --git a/public/docs/_examples/user-input/ts/app/little-tour.component.ts b/public/docs/_examples/user-input/ts/app/little-tour.component.ts deleted file mode 100644 index 800837f6c1..0000000000 --- a/public/docs/_examples/user-input/ts/app/little-tour.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -// #docregion -import {Component} from 'angular2/core'; - -// #docregion little-tour -@Component({ - selector: 'little-tour', - template: ` - - - - -
    • {{hero}}
    - ` -}) -export class LittleTourComponent { - heroes=['Windstorm', 'Bombasto', 'Magneta', 'Tornado']; - addHero(newHero:string) { - if (newHero) { - this.heroes.push(newHero); - } - } -} -// #enddocregion little-tour diff --git a/public/docs/_examples/user-input/ts/app/main.ts b/public/docs/_examples/user-input/ts/app/main.ts deleted file mode 100644 index acb4b6229e..0000000000 --- a/public/docs/_examples/user-input/ts/app/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {bootstrap} from 'angular2/platform/browser'; -import {AppComponent} from './app.component'; - -bootstrap(AppComponent); \ No newline at end of file diff --git a/public/docs/_examples/user-input/ts/index.html b/public/docs/_examples/user-input/ts/index.html deleted file mode 100644 index a4f6d0eb91..0000000000 --- a/public/docs/_examples/user-input/ts/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - User Input - - - - - - - - - - - - - - - - - - Loading... - - - \ No newline at end of file diff --git a/public/docs/_examples/user-input/ts/plnkr.json b/public/docs/_examples/user-input/ts/plnkr.json index 4c260fcf9a..dd8f063d37 100644 --- a/public/docs/_examples/user-input/ts/plnkr.json +++ b/public/docs/_examples/user-input/ts/plnkr.json @@ -1,8 +1,9 @@ { "description": "User Input", + "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js" ], "tags": ["input"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/user-input/ts/app/app.component.html b/public/docs/_examples/user-input/ts/src/app/app.component.html similarity index 100% rename from public/docs/_examples/user-input/ts/app/app.component.html rename to public/docs/_examples/user-input/ts/src/app/app.component.html diff --git a/public/docs/_examples/user-input/ts/src/app/app.component.ts b/public/docs/_examples/user-input/ts/src/app/app.component.ts new file mode 100644 index 0000000000..5f885d5105 --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/app/app.component.ts @@ -0,0 +1,8 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'my-app', + templateUrl: './app.component.html' +}) +export class AppComponent { } diff --git a/public/docs/_examples/user-input/ts/src/app/app.module.ts b/public/docs/_examples/user-input/ts/src/app/app.module.ts new file mode 100644 index 0000000000..41f13f9f11 --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/app/app.module.ts @@ -0,0 +1,37 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; +import { ClickMeComponent } from './click-me.component'; +import { ClickMe2Component } from './click-me2.component'; +import { + KeyUpComponent_v1, + KeyUpComponent_v2, + KeyUpComponent_v3, + KeyUpComponent_v4 +} from './keyup.components'; +import { LittleTourComponent } from './little-tour.component'; +import { LoopbackComponent } from './loop-back.component'; + + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent, + ClickMeComponent, + ClickMe2Component, + KeyUpComponent_v1, + KeyUpComponent_v2, + KeyUpComponent_v3, + KeyUpComponent_v4, + LittleTourComponent, + LoopbackComponent + ], + providers: [ + + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/user-input/ts/app/click-me.component.ts b/public/docs/_examples/user-input/ts/src/app/click-me.component.ts similarity index 81% rename from public/docs/_examples/user-input/ts/app/click-me.component.ts rename to public/docs/_examples/user-input/ts/src/app/click-me.component.ts index 50fc8feb84..45a4ca7e70 100644 --- a/public/docs/_examples/user-input/ts/app/click-me.component.ts +++ b/public/docs/_examples/user-input/ts/src/app/click-me.component.ts @@ -5,7 +5,7 @@ */ // #docregion -import {Component} from 'angular2/core'; +import { Component } from '@angular/core'; // #docregion click-me-component @Component({ @@ -17,8 +17,8 @@ import {Component} from 'angular2/core'; export class ClickMeComponent { clickMessage = ''; - onClickMe(){ - this.clickMessage ='You are my hero!'; + onClickMe() { + this.clickMessage = 'You are my hero!'; } } // #enddocregion click-me-component diff --git a/public/docs/_examples/user-input/ts/src/app/click-me2.component.ts b/public/docs/_examples/user-input/ts/src/app/click-me2.component.ts new file mode 100644 index 0000000000..1e35731a82 --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/app/click-me2.component.ts @@ -0,0 +1,18 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + selector: 'click-me2', + template: ` + + {{clickMessage}}` +}) +export class ClickMe2Component { + clickMessage = ''; + clicks = 1; + + onClickMe2(event: any) { + let evtMsg = event ? ' Event target is ' + event.target.tagName : ''; + this.clickMessage = (`Click #${this.clicks++}. ${evtMsg}`); + } +} diff --git a/public/docs/_examples/user-input/ts/src/app/keyup.components.ts b/public/docs/_examples/user-input/ts/src/app/keyup.components.ts new file mode 100644 index 0000000000..94ed1ae423 --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/app/keyup.components.ts @@ -0,0 +1,88 @@ +/* tslint:disable:class-name component-class-suffix */ +// #docplaster +// #docregion +import { Component } from '@angular/core'; + +// #docregion key-up-component-1 +@Component({ + selector: 'key-up1', +// #docregion key-up-component-1-template + template: ` + +

    {{values}}

    + ` +// #enddocregion key-up-component-1-template +}) +// #docregion key-up-component-1-class, key-up-component-1-class-no-type +export class KeyUpComponent_v1 { + values = ''; + +// #enddocregion key-up-component-1-class, key-up-component-1-class-no-type + /* + // #docregion key-up-component-1-class-no-type + onKey(event: any) { // without type info + this.values += event.target.value + ' | '; + } + // #enddocregion key-up-component-1-class-no-type + */ + // #docregion key-up-component-1-class + + onKey(event: KeyboardEvent) { // with type info + this.values += (event.target).value + ' | '; + } +// #docregion key-up-component-1-class-no-type +} +// #enddocregion key-up-component-1,key-up-component-1-class, key-up-component-1-class-no-type + +////////////////////////////////////////// + +// #docregion key-up-component-2 +@Component({ + selector: 'key-up2', + template: ` + +

    {{values}}

    + ` +}) +export class KeyUpComponent_v2 { + values = ''; + onKey(value: string) { + this.values += value + ' | '; + } +} +// #enddocregion key-up-component-2 + +////////////////////////////////////////// + +// #docregion key-up-component-3 +@Component({ + selector: 'key-up3', + template: ` + +

    {{value}}

    + ` +}) +export class KeyUpComponent_v3 { + value = ''; + onEnter(value: string) { this.value = value; } +} +// #enddocregion key-up-component-3 + +////////////////////////////////////////// + +// #docregion key-up-component-4 +@Component({ + selector: 'key-up4', + template: ` + + +

    {{value}}

    + ` +}) +export class KeyUpComponent_v4 { + value = ''; + update(value: string) { this.value = value; } +} +// #enddocregion key-up-component-4 diff --git a/public/docs/_examples/user-input/ts/src/app/little-tour.component.ts b/public/docs/_examples/user-input/ts/src/app/little-tour.component.ts new file mode 100644 index 0000000000..5862f033d6 --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/app/little-tour.component.ts @@ -0,0 +1,25 @@ +// #docregion +import { Component } from '@angular/core'; + +// #docregion little-tour +@Component({ + selector: 'little-tour', + template: ` + + + + +
    • {{hero}}
    + ` +}) +export class LittleTourComponent { + heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado']; + addHero(newHero: string) { + if (newHero) { + this.heroes.push(newHero); + } + } +} +// #enddocregion little-tour diff --git a/public/docs/_examples/user-input/ts/app/loop-back.component.ts b/public/docs/_examples/user-input/ts/src/app/loop-back.component.ts similarity index 79% rename from public/docs/_examples/user-input/ts/app/loop-back.component.ts rename to public/docs/_examples/user-input/ts/src/app/loop-back.component.ts index 34bb94d20a..6c9dad1da8 100644 --- a/public/docs/_examples/user-input/ts/app/loop-back.component.ts +++ b/public/docs/_examples/user-input/ts/src/app/loop-back.component.ts @@ -1,9 +1,9 @@ // #docregion -import {Component} from 'angular2/core'; +import { Component } from '@angular/core'; // #docregion loop-back-component @Component({ selector: 'loop-back', - template:` + template: `

    {{box.value}}

    ` diff --git a/public/docs/_examples/user-input/ts/src/index.html b/public/docs/_examples/user-input/ts/src/index.html new file mode 100644 index 0000000000..9728814107 --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/index.html @@ -0,0 +1,27 @@ + + + + User Input + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/user-input/ts/src/main.ts b/public/docs/_examples/user-input/ts/src/main.ts new file mode 100644 index 0000000000..311c44b76d --- /dev/null +++ b/public/docs/_examples/user-input/ts/src/main.ts @@ -0,0 +1,5 @@ +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/user-input/dart/web/user-input-styles.css b/public/docs/_examples/user-input/ts/src/user-input-styles.css similarity index 100% rename from public/docs/_examples/user-input/dart/web/user-input-styles.css rename to public/docs/_examples/user-input/ts/src/user-input-styles.css diff --git a/public/docs/_examples/user-input/ts/user-input-styles.css b/public/docs/_examples/user-input/ts/user-input-styles.css deleted file mode 100644 index b2133e5103..0000000000 --- a/public/docs/_examples/user-input/ts/user-input-styles.css +++ /dev/null @@ -1,9 +0,0 @@ -fieldset {border-style:none} -img {height: 100px;} -.box {border: 1px solid black; padding:3px} -.child-div {margin-left: 1em; font-weight: normal} -.hidden {display: none} -.parent-div {margin-top: 1em; font-weight: bold} -.special {font-weight:bold;} -.toe {margin-left: 1em; font-style: italic;} -little-hero {color:blue; font-size: smaller; background-color: Turquoise } \ No newline at end of file diff --git a/public/docs/_examples/webpack/e2e-spec.ts b/public/docs/_examples/webpack/e2e-spec.ts new file mode 100644 index 0000000000..9bca9810eb --- /dev/null +++ b/public/docs/_examples/webpack/e2e-spec.ts @@ -0,0 +1,21 @@ +'use strict'; // necessary for es6 output in node + +import { browser, element, by } from 'protractor'; + +describe('QuickStart E2E Tests', function () { + + let expectedMsg = 'Hello from Angular App with Webpack'; + + beforeEach(function () { + browser.get(''); + }); + + it(`should display: ${expectedMsg}`, function () { + expect(element(by.css('h1')).getText()).toEqual(expectedMsg); + }); + + it('should display an image', function () { + expect(element(by.css('img')).isPresent()).toBe(true); + }); + +}); diff --git a/public/docs/_examples/webpack/ts/.gitignore b/public/docs/_examples/webpack/ts/.gitignore new file mode 100644 index 0000000000..8628a5eef6 --- /dev/null +++ b/public/docs/_examples/webpack/ts/.gitignore @@ -0,0 +1,5 @@ +dist +!karma.webpack.conf.js +!webpack.config.js +!config/* +!public/css/styles.css diff --git a/public/docs/_examples/webpack/ts/config/helpers.js b/public/docs/_examples/webpack/ts/config/helpers.js new file mode 100644 index 0000000000..b760520f1c --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/helpers.js @@ -0,0 +1,12 @@ +// #docregion +var path = require('path'); + +var _root = path.resolve(__dirname, '..'); + +function root(args) { + args = Array.prototype.slice.call(arguments, 0); + return path.join.apply(path, [_root].concat(args)); +} + +exports.root = root; +// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/webpack/ts/config/karma-test-shim.js b/public/docs/_examples/webpack/ts/config/karma-test-shim.js new file mode 100644 index 0000000000..2ea37fbd72 --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/karma-test-shim.js @@ -0,0 +1,22 @@ +// #docregion +Error.stackTraceLimit = Infinity; + +require('core-js/es6'); +require('core-js/es7/reflect'); + +require('zone.js/dist/zone'); +require('zone.js/dist/long-stack-trace-zone'); +require('zone.js/dist/proxy'); +require('zone.js/dist/sync-test'); +require('zone.js/dist/jasmine-patch'); +require('zone.js/dist/async-test'); +require('zone.js/dist/fake-async-test'); + +var appContext = require.context('../src', true, /\.spec\.ts/); + +appContext.keys().forEach(appContext); + +var testing = require('@angular/core/testing'); +var browser = require('@angular/platform-browser-dynamic/testing'); + +testing.TestBed.initTestEnvironment(browser.BrowserDynamicTestingModule, browser.platformBrowserDynamicTesting()); diff --git a/public/docs/_examples/webpack/ts/config/karma.conf.js b/public/docs/_examples/webpack/ts/config/karma.conf.js new file mode 100644 index 0000000000..7bbb4617db --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/karma.conf.js @@ -0,0 +1,39 @@ +// #docregion +var webpackConfig = require('./webpack.test'); + +module.exports = function (config) { + var _config = { + basePath: '', + + frameworks: ['jasmine'], + + files: [ + {pattern: './config/karma-test-shim.js', watched: false} + ], + + preprocessors: { + './config/karma-test-shim.js': ['webpack', 'sourcemap'] + }, + + webpack: webpackConfig, + + webpackMiddleware: { + stats: 'errors-only' + }, + + webpackServer: { + noInfo: true + }, + + reporters: ['kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: false, + browsers: ['Chrome'], + singleRun: true + }; + + config.set(_config); +}; +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/config/webpack.common.js b/public/docs/_examples/webpack/ts/config/webpack.common.js new file mode 100644 index 0000000000..28be240e04 --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/webpack.common.js @@ -0,0 +1,81 @@ +// #docplaster +// #docregion +var webpack = require('webpack'); +var HtmlWebpackPlugin = require('html-webpack-plugin'); +var ExtractTextPlugin = require('extract-text-webpack-plugin'); +var helpers = require('./helpers'); + +module.exports = { + // #docregion entries, one-entry, two-entries + entry: { + // #enddocregion one-entry, two-entries + 'polyfills': './src/polyfills.ts', + // #docregion two-entries + 'vendor': './src/vendor.ts', + // #docregion one-entry + 'app': './src/main.ts' + }, + // #enddocregion entries, one-entry, two-entries + + // #docregion resolve + resolve: { + extensions: ['.ts', '.js'] + }, + // #enddocregion resolve + + // #docregion loaders + module: { + rules: [ + { + test: /\.ts$/, + loaders: [ + { + loader: 'awesome-typescript-loader', + options: { configFileName: helpers.root('src', 'tsconfig.json') } + } , 'angular2-template-loader' + ] + }, + { + test: /\.html$/, + loader: 'html-loader' + }, + { + test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, + loader: 'file-loader?name=assets/[name].[hash].[ext]' + }, + { + test: /\.css$/, + exclude: helpers.root('src', 'app'), + loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' }) + }, + { + test: /\.css$/, + include: helpers.root('src', 'app'), + loader: 'raw-loader' + } + ] + }, + // #enddocregion loaders + + // #docregion plugins + plugins: [ + // Workaround for angular/angular#11580 + new webpack.ContextReplacementPlugin( + // The (\\|\/) piece accounts for path separators in *nix and Windows + /angular(\\|\/)core(\\|\/)@angular/, + helpers.root('./src'), // location of your src + {} // a map of your routes + ), + + new webpack.optimize.CommonsChunkPlugin({ + name: ['app', 'vendor', 'polyfills'] + }), + + new HtmlWebpackPlugin({ + template: 'src/index.html' + }) + ] + // #enddocregion plugins +}; +// #enddocregion + diff --git a/public/docs/_examples/webpack/ts/config/webpack.dev.js b/public/docs/_examples/webpack/ts/config/webpack.dev.js new file mode 100644 index 0000000000..57d29560a0 --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/webpack.dev.js @@ -0,0 +1,26 @@ +// #docregion +var webpackMerge = require('webpack-merge'); +var ExtractTextPlugin = require('extract-text-webpack-plugin'); +var commonConfig = require('./webpack.common.js'); +var helpers = require('./helpers'); + +module.exports = webpackMerge(commonConfig, { + devtool: 'cheap-module-eval-source-map', + + output: { + path: helpers.root('dist'), + publicPath: '/', + filename: '[name].js', + chunkFilename: '[id].chunk.js' + }, + + plugins: [ + new ExtractTextPlugin('[name].css') + ], + + devServer: { + historyApiFallback: true, + stats: 'minimal' + } +}); +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/config/webpack.prod.js b/public/docs/_examples/webpack/ts/config/webpack.prod.js new file mode 100644 index 0000000000..d6c70119bc --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/webpack.prod.js @@ -0,0 +1,41 @@ +// #docregion +var webpack = require('webpack'); +var webpackMerge = require('webpack-merge'); +var ExtractTextPlugin = require('extract-text-webpack-plugin'); +var commonConfig = require('./webpack.common.js'); +var helpers = require('./helpers'); + +const ENV = process.env.NODE_ENV = process.env.ENV = 'production'; + +module.exports = webpackMerge(commonConfig, { + devtool: 'source-map', + + output: { + path: helpers.root('dist'), + publicPath: '/', + filename: '[name].[hash].js', + chunkFilename: '[id].[hash].chunk.js' + }, + + plugins: [ + new webpack.NoEmitOnErrorsPlugin(), + new webpack.optimize.UglifyJsPlugin({ // https://github.com/angular/angular/issues/10618 + mangle: { + keep_fnames: true + } + }), + new ExtractTextPlugin('[name].[hash].css'), + new webpack.DefinePlugin({ + 'process.env': { + 'ENV': JSON.stringify(ENV) + } + }), + new webpack.LoaderOptionsPlugin({ + htmlLoader: { + minimize: false // workaround for ng2 + } + }) + ] +}); + +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/config/webpack.test.js b/public/docs/_examples/webpack/ts/config/webpack.test.js new file mode 100644 index 0000000000..e668504c67 --- /dev/null +++ b/public/docs/_examples/webpack/ts/config/webpack.test.js @@ -0,0 +1,55 @@ +// #docregion +var webpack = require('webpack'); +var helpers = require('./helpers'); + +module.exports = { + devtool: 'inline-source-map', + + resolve: { + extensions: ['.ts', '.js'] + }, + + module: { + rules: [ + { + test: /\.ts$/, + loaders: [ + { + loader: 'awesome-typescript-loader', + options: { configFileName: helpers.root('src', 'tsconfig.json') } + } , 'angular2-template-loader' + ] + }, + { + test: /\.html$/, + loader: 'html-loader' + + }, + { + test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/, + loader: 'null-loader' + }, + { + test: /\.css$/, + exclude: helpers.root('src', 'app'), + loader: 'null-loader' + }, + { + test: /\.css$/, + include: helpers.root('src', 'app'), + loader: 'raw-loader' + } + ] + }, + + plugins: [ + new webpack.ContextReplacementPlugin( + // The (\\|\/) piece accounts for path separators in *nix and Windows + /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, + helpers.root('./src'), // location of your src + {} // a map of your routes + ) + ] +} + +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/example-config.json b/public/docs/_examples/webpack/ts/example-config.json new file mode 100644 index 0000000000..e405d0c01a --- /dev/null +++ b/public/docs/_examples/webpack/ts/example-config.json @@ -0,0 +1,4 @@ +{ + "build": "build:webpack", + "run": "serve:cli" +} diff --git a/public/docs/_examples/webpack/ts/karma.webpack.conf.js b/public/docs/_examples/webpack/ts/karma.webpack.conf.js new file mode 100644 index 0000000000..e2a663e8de --- /dev/null +++ b/public/docs/_examples/webpack/ts/karma.webpack.conf.js @@ -0,0 +1,2 @@ +// #docregion +module.exports = require('./config/karma.conf.js'); diff --git a/public/docs/_examples/webpack/ts/package.webpack.json b/public/docs/_examples/webpack/ts/package.webpack.json new file mode 100644 index 0000000000..8f9e3954c2 --- /dev/null +++ b/public/docs/_examples/webpack/ts/package.webpack.json @@ -0,0 +1,49 @@ +{ + "name": "angular2-webpack", + "version": "1.0.0", + "description": "A webpack starter for Angular", + "scripts": { + "start": "webpack-dev-server --inline --progress --port 8080", + "test": "karma start", + "build": "rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail" + }, + "license": "MIT", + "dependencies": { + "@angular/common": "~4.0.0", + "@angular/compiler": "~4.0.0", + "@angular/core": "~4.0.0", + "@angular/forms": "~4.0.0", + "@angular/http": "~4.0.0", + "@angular/platform-browser": "~4.0.0", + "@angular/platform-browser-dynamic": "~4.0.0", + "@angular/router": "~4.0.0", + "core-js": "^2.4.1", + "rxjs": "5.0.1", + "zone.js": "^0.8.4" + }, + "devDependencies": { + "@types/node": "^6.0.45", + "@types/jasmine": "2.5.36", + "angular2-template-loader": "^0.6.0", + "awesome-typescript-loader": "^3.0.4", + "css-loader": "^0.26.1", + "extract-text-webpack-plugin": "2.0.0-beta.5", + "file-loader": "^0.9.0", + "html-loader": "^0.4.3", + "html-webpack-plugin": "^2.16.1", + "jasmine-core": "^2.4.1", + "karma": "^1.2.0", + "karma-chrome-launcher": "^2.0.0", + "karma-jasmine": "^1.0.2", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^2.0.1", + "null-loader": "^0.1.1", + "raw-loader": "^0.5.1", + "rimraf": "^2.5.2", + "style-loader": "^0.13.1", + "typescript": "~2.0.10", + "webpack": "2.2.1", + "webpack-dev-server": "2.4.1", + "webpack-merge": "^3.0.0" + } +} diff --git a/public/docs/_examples/webpack/ts/src/app/app.component.css b/public/docs/_examples/webpack/ts/src/app/app.component.css new file mode 100644 index 0000000000..bb624c5aae --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/app/app.component.css @@ -0,0 +1,9 @@ +/* #docregion */ +main { + padding: 1em; + font-family: Arial, Helvetica, sans-serif; + text-align: center; + margin-top: 50px; + display: block; +} +/* #enddocregion */ diff --git a/public/docs/_examples/webpack/ts/src/app/app.component.html b/public/docs/_examples/webpack/ts/src/app/app.component.html new file mode 100644 index 0000000000..9e60cd2ad5 --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/app/app.component.html @@ -0,0 +1,7 @@ + +
    +

    Hello from Angular App with Webpack

    + + +
    + diff --git a/public/docs/_examples/webpack/ts/src/app/app.component.spec.ts b/public/docs/_examples/webpack/ts/src/app/app.component.spec.ts new file mode 100644 index 0000000000..a6512a11e7 --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/app/app.component.spec.ts @@ -0,0 +1,16 @@ +// #docregion +import { TestBed } from '@angular/core/testing'; + +import { AppComponent } from './app.component'; + +describe('App', () => { + beforeEach(() => { + TestBed.configureTestingModule({ declarations: [AppComponent]}); + }); + + it ('should work', () => { + let fixture = TestBed.createComponent(AppComponent); + expect(fixture.componentInstance instanceof AppComponent).toBe(true, 'should create AppComponent'); + }); +}); +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/src/app/app.component.ts b/public/docs/_examples/webpack/ts/src/app/app.component.ts new file mode 100644 index 0000000000..2c5eac0147 --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/app/app.component.ts @@ -0,0 +1,16 @@ +// #docplaster +// #docregion +// #docregion component +import { Component } from '@angular/core'; + +// #enddocregion component +import '../assets/css/styles.css'; + +// #docregion component +@Component({ + selector: 'my-app', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { } +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/src/app/app.module.ts b/public/docs/_examples/webpack/ts/src/app/app.module.ts new file mode 100644 index 0000000000..362f3401fa --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/app/app.module.ts @@ -0,0 +1,16 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ + BrowserModule + ], + declarations: [ + AppComponent + ], + bootstrap: [ AppComponent ] +}) +export class AppModule { } diff --git a/public/docs/_examples/webpack/ts/src/assets/css/styles.css b/public/docs/_examples/webpack/ts/src/assets/css/styles.css new file mode 100644 index 0000000000..2d404ff5b9 --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/assets/css/styles.css @@ -0,0 +1,6 @@ +/* #docregion */ +body { + background: #0147A7; + color: #fff; +} +/* #enddocregion */ diff --git a/public/docs/_examples/webpack/ts/src/assets/images/angular.png b/public/docs/_examples/webpack/ts/src/assets/images/angular.png new file mode 100644 index 0000000000..c510293918 Binary files /dev/null and b/public/docs/_examples/webpack/ts/src/assets/images/angular.png differ diff --git a/public/docs/_examples/webpack/ts/src/index.html b/public/docs/_examples/webpack/ts/src/index.html new file mode 100644 index 0000000000..503ea4a950 --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/index.html @@ -0,0 +1,14 @@ + + + + + + Angular With Webpack + + + + + Loading... + + + diff --git a/public/docs/_examples/webpack/ts/src/main.ts b/public/docs/_examples/webpack/ts/src/main.ts new file mode 100644 index 0000000000..e1d8cbc0fe --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/main.ts @@ -0,0 +1,14 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode } from '@angular/core'; + +import { AppModule } from './app/app.module'; + +// #docregion enable-prod +if (process.env.ENV === 'production') { + enableProdMode(); +} +// #enddocregion enable-prod + +platformBrowserDynamic().bootstrapModule(AppModule); +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/src/polyfills.ts b/public/docs/_examples/webpack/ts/src/polyfills.ts new file mode 100644 index 0000000000..118acd2b0c --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/polyfills.ts @@ -0,0 +1,12 @@ +// #docregion +import 'core-js/es6'; +import 'core-js/es7/reflect'; +require('zone.js/dist/zone'); + +if (process.env.ENV === 'production') { + // Production +} else { + // Development and test + Error['stackTraceLimit'] = Infinity; + require('zone.js/dist/long-stack-trace-zone'); +} diff --git a/public/docs/_examples/webpack/ts/src/tsconfig.1.json b/public/docs/_examples/webpack/ts/src/tsconfig.1.json new file mode 100644 index 0000000000..544e895bce --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/tsconfig.1.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015", "dom"], + "noImplicitAny": true, + "suppressImplicitAnyIndexErrors": true + } +} \ No newline at end of file diff --git a/public/docs/_examples/webpack/ts/src/vendor.ts b/public/docs/_examples/webpack/ts/src/vendor.ts new file mode 100644 index 0000000000..8ffd09240a --- /dev/null +++ b/public/docs/_examples/webpack/ts/src/vendor.ts @@ -0,0 +1,15 @@ +// #docregion +// Angular +import '@angular/platform-browser'; +import '@angular/platform-browser-dynamic'; +import '@angular/core'; +import '@angular/common'; +import '@angular/http'; +import '@angular/router'; + +// RxJS +import 'rxjs'; + +// Other vendors for example jQuery, Lodash or Bootstrap +// You can import js, ts, css, sass, ... +// #enddocregion diff --git a/public/docs/_examples/webpack/ts/webpack.config.js b/public/docs/_examples/webpack/ts/webpack.config.js new file mode 100644 index 0000000000..66141706fe --- /dev/null +++ b/public/docs/_examples/webpack/ts/webpack.config.js @@ -0,0 +1,3 @@ +// #docregion +module.exports = require('./config/webpack.dev.js'); +// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/webpack/ts/zipper.json b/public/docs/_examples/webpack/ts/zipper.json new file mode 100644 index 0000000000..73ea46a406 --- /dev/null +++ b/public/docs/_examples/webpack/ts/zipper.json @@ -0,0 +1,12 @@ +{ + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[0-9].*", + "config/**/*", + "webpack.config.js", + "karma.webpack.conf.js" + ], + "removeSystemJsConfig": true, + "type": "webpack" +} diff --git a/public/docs/_includes/_hover-card.jade b/public/docs/_includes/_hover-card.jade new file mode 100644 index 0000000000..a76f9948c2 --- /dev/null +++ b/public/docs/_includes/_hover-card.jade @@ -0,0 +1,12 @@ +- var hasIcon = icon ? 'has-icon' : '' +- var iconNumber = number ? number : '' +a(class="hover-card is-button #{hasIcon}" href="#{url}" md-button) + if icon + span(class="hover-card-icon #{icon}") #{iconNumber} + + h3 #{name} + + if cta + p #{cta} + else + p View #{name} Docs diff --git a/public/docs/_includes/_see-addr-bar.jade b/public/docs/_includes/_see-addr-bar.jade new file mode 100644 index 0000000000..523b72f67a --- /dev/null +++ b/public/docs/_includes/_see-addr-bar.jade @@ -0,0 +1,11 @@ +table + tr + td + :marked + To see the URL changes in the browser address bar of the live example, + open it again in the Plunker editor by clicking the icon in the upper right, + then pop out the preview window by clicking the blue 'X' button in the upper right corner. + td + img(src='/resources/images/devguide/plunker-switch-to-editor-button.png' width="200px" height="70px" alt="pop out the window" align="right" ) + br + img(src='/resources/images/devguide/plunker-separate-window-button.png' width="200px" height="47px" alt="pop out the window" align="right" ) diff --git a/public/docs/_includes/_side-nav.jade b/public/docs/_includes/_side-nav.jade index b63c021c1d..cf73ed27d0 100644 --- a/public/docs/_includes/_side-nav.jade +++ b/public/docs/_includes/_side-nav.jade @@ -3,7 +3,7 @@ - var dir = current.path[4] ? current.path[3] + '/' : ''; - var cur = current.path[4] || current.path[3]; - cur = cur === 'index' ? '' : cur + '.html'; -- cur = base + dir + cur; +- cur = base + dir + cur; - var sections = function(dir, selector) { - var secondaryPath = public.docs[current.path[1]][current.path[2]] @@ -17,89 +17,133 @@ - var item = data[prop]; - item.slug = prop; - if (prop[0] !== '_' && !item.hide && selector(item)) { -- var file = prop === 'index' ? '' : prop + '.html'; +- var file = pro +- var ext = prop.lastIndexOf('/') === prop.length-1 ? '' : '.html'; +- var file = prop === 'index' ? '' : prop + ext; - var href = prefix + file; - item.class = cur === href ? 'is-selected' : ''; - item.file = file; - item.href = href; - item.navTitle = item.navTitle || item.title; -- item.tooltip = item.description || item.intro || ''; +- item.tooltip = item.description || item.intro || item.title || ''; - section.push(item); - } - } - return section; - } - + - var tutorial = sections('tutorial'); - var cookbook = sections('cookbook'); - var basics = sections('guide', function(item) { return item.basics; }); - var guide = sections('guide', function(item) { return !item.basics; }); - var qs = sections('', function(item) { return item.slug === 'quickstart'; })[0] || {}; +- var cliqs = sections('', function(item) { return item.slug === 'cli-quickstart'; })[0] || {}; - var reference = sections('', function(item) { return item.reference; }); -- var resources = sections('', function(item) { return item.resources; }); +- var anyItemSelected = function(items) { +- var selectedCount = items.filter(function(item) { return !!item.class; }).length; +- return selectedCount > 0 ? 'is-selected' : ''; +- } +- var isQuickstartSelected = function() { +- var splitted = cur.split('/'); +- var bit = splitted[splitted.length - 1].replace('.html', ''); +- return bit === 'quickstart' ? 'is-selected' : ''; +-} +- var isCLIQuickstartSelected = function() { +- var split = cur.split('/'); +- var bit = split[split.length - 1].replace('.html', ''); +- return bit === 'cli-quickstart' ? 'is-selected' : ''; +-} +- var isApiReferenceSelected = function() { +- var splitted = cur.split('/'); +- var bit = splitted[splitted.length - 2]; +- return bit === 'api' ? 'is-selected' : ''; +-} +- var isCollapsed = function(titleStyle) { +- return titleStyle === 'is-selected' ? '' : 'is-hidden'; +- } + +- var language = current.path[1] || 'ts' +- if (language !== 'ts' || language !== 'js' || language !== 'dart') { language = 'ts'; } + -nav.side-nav.l-pinned-left.l-layer-4.l-offset-nav +nav(class="sidenav l-pinned-left l-layer-4 l-offset-nav" data-swiftype-index="false" ng-class="appCtrl.showDocsNav ? 'is-visible' : ''") // SEARCH BAR - header.side-nav-search.st-input-wrapper - form.st-input-inner + header.sidenav-search.st-input-wrapper + .st-input-inner label(for="search-io" class="is-hidden") Search Docs - input(type="search" id="search-io" placeholder="SEARCH DOCS...") + input(type="text" class="st-default-search-input" placeholder="SEARCH DOCS...") button(class="mobile-trigger button" aria-label="View Docs Menu" ng-click="appCtrl.toggleDocsMenu($event)" md-button) Docs - div(class="side-nav-secondary" ng-class="appCtrl.showDocsNav ? 'is-visible' : ''") - .nav-blocks - .nav-title Tutorial - .nav-primary-link(class="#{qs.class}") - a(href="#{qs.href}" title="#{qs.tooltip}") #{qs.navTitle} - .nav-sub-title Case Study: Tour of Heroes - .nav-ordered-lists - ol - each item in tutorial - li(class="#{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} - - .nav-blocks - .nav-title Basics - .nav-ordered-lists - ol - each item in basics - li(class="#{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} - - .nav-blocks - .nav-title Developer Guide - .nav-unordered-lists + ul(class="sidenav-links") + li.sidenav-section.no-border + a(class="nav-title" href="/https/github.com/docs/#{current.path[1]}/latest/") Docs Home + + // CORE DOCUMENTATION + li.sidenav-section-divider + h3 Core Documentation + + li.sidenav-section + a(class="nav-title #{isQuickstartSelected(cur)}" href="#{qs.href}" title="#{qs.tooltip}") Quickstart + + li.sidenav-section + a(class="nav-title #{isCLIQuickstartSelected(cur)}" href="#{cliqs.href}" title="#{cliqs.tooltip}") CLI Quickstart + + + li.sidenav-section + a(class="nav-title is-parent #{anyItemSelected(basics)}" href="#{basics[0].href}" title="#{basics[0].tooltip}") Guide + img(class="inline-arrow-down-svg" src="/https/github.com/resources/images/icons/ic_keyboard_arrow_down_black_24px.svg") + + .nav-ordered-lists(class="#{isCollapsed(anyItemSelected(basics))}") ul - each item in guide - li(class="#{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} + each item, index in basics + li(class="nav-list-item #{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{index + 1}. #{item.navTitle} + li.sidenav-section.no-border + a(class="nav-title #{isApiReferenceSelected()}" href="#{reference[0].href}" title="#{reference[0].tooltip}") API Reference + + // ADVANCED DOCUMENATION + li.sidenav-section-divider + h3 Additional Documentation - .nav-blocks - .nav-title Cookbook - .nav-unordered-lists + li.sidenav-section + a(class="nav-title is-parent #{anyItemSelected(tutorial)}" href="#{tutorial[0].href}" title="#{tutorial[0].tooltip}") Tutorial + img(class="inline-arrow-down-svg" src="/https/github.com/resources/images/icons/ic_keyboard_arrow_down_black_24px.svg") + .nav-ordered-lists(class="#{isCollapsed(anyItemSelected(tutorial))}") ul - each item in cookbook - li(class="#{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} + each item, index in tutorial + li(class="nav-list-item #{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{index + 1}. #{item.navTitle} + + li.sidenav-section + a(class="nav-title is-parent #{anyItemSelected(guide)}" href="#{guide[0].href}" title="#{guide[0].tooltip}") Advanced + img(class="inline-arrow-down-svg" src="/https/github.com/resources/images/icons/ic_keyboard_arrow_down_black_24px.svg") - .nav-blocks - .nav-title Reference - .nav-unordered-lists + .nav-unordered-lists(class="#{isCollapsed(anyItemSelected(guide))}") ul - each item in reference - li(class="#{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} - - .nav-blocks - .nav-title Resources - .nav-unordered-lists + each item in guide + li(class="nav-list-item #{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} + + li.sidenav-section + a(class="nav-title is-parent #{anyItemSelected(cookbook)}" href="#{cookbook[0].href}" title="#{cookbook[0].tooltip}") Cookbook + img(class="inline-arrow-down-svg" src="/https/github.com/resources/images/icons/ic_keyboard_arrow_down_black_24px.svg") + + .nav-unordered-lists(class="#{isCollapsed(anyItemSelected(cookbook))}") ul - each item in resources - li(class="#{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} + each item in cookbook + li(class="nav-list-item #{item.class}"): a(href="#{item.href}" title="#{item.tooltip}") #{item.navTitle} + + + + + if current.path[0] == "docs" + != partial("../../_includes/_version-dropdown") script. // Could put in appCtrl but only needed here and clear here (function scrollToSelectedLink() { - var sideNav = document.getElementsByClassName('side-nav')[0]; + var sideNav = document.getElementsByClassName('sidenav')[0]; var link = sideNav.getElementsByClassName('is-selected')[0]; if(link && link.offsetTop > window.innerHeight){ sideNav.scrollTop = link.offsetTop - (window.innerHeight/2); - //alert("offsetTop: " + link.offsetTop + " side-nav top is " + sideNav.scrollTop); - } + //alert("offsetTop: " + link.offsetTop + " side-nav top is " + sideNav.scrollTop); + } })() diff --git a/public/docs/_includes/_ts-temp.jade b/public/docs/_includes/_ts-temp.jade index b4a6b8ad8a..7c162672f4 100644 --- a/public/docs/_includes/_ts-temp.jade +++ b/public/docs/_includes/_ts-temp.jade @@ -8,26 +8,9 @@ if language == 'js' if language == 'ts' - lang = 'TypeScript' -- var page = '' -if current.path[4] - - var page = current.path[4] + '.html' - +- var page = current.path[4] ? current.path[4] + '.html' : '' +- if (page === 'index.html') page = '' - var path = '/docs/ts/latest/'+ current.path[3] + '/' + page - -- var name = 'it' -- var secondaryPath = public.docs[current.path[1]][current.path[2]][current.path[3]] -if secondaryPath - - var data = secondaryPath._data - - var listType = data._listtype - - var items = listType == 'api' ? secondaryPath : data - - for item, slug in items - if slug == current.path[4] - - name = 'the ' + item.title + ' chapter' - -p. - This chapter is not yet available in #{lang}. - We recommend reading the TypeScript version. -a(href=path, class='md-primary md-button md-ink-ripple'). - Read !{name} in TypeScript -// != partial(path) \ No newline at end of file +:marked + This page is not yet available in #{lang}. + We recommend reading [it in TypeScript](!{path}). \ No newline at end of file diff --git a/public/docs/_includes/styleguide/_aside.jade b/public/docs/_includes/styleguide/_aside.jade index d8675b2e99..dfc4fec6d3 100644 --- a/public/docs/_includes/styleguide/_aside.jade +++ b/public/docs/_includes/styleguide/_aside.jade @@ -11,7 +11,7 @@ h3 Adding an aside - aside.is-right Did you know that hipsum is a replacment for Lorem Ipsum? To find out more visit hipsum.co + aside.is-right Did you know that hipsum is a replacement for Lorem Ipsum? To find out more visit hipsum.co p. Etsy artisan Thundercats, authentic sustainable bitters wolf roof party meditation 90's asymmetrical XOXO hoodie. Twee umami cray iPhone. Chillwave shabby chic tilde occupy sriracha squid Brooklyn street art. Selvage heirloom kogi American Apparel bicycle rights. Carles Etsy Truffaut mlkshk trust fund. Jean shorts fashion axe Williamsburg wolf cardigan beard, twee blog locavore organic. Cred skateboard dreamcatcher, taxidermy Bushwick actually aesthetic normcore fanny pack. @@ -19,7 +19,7 @@ pre.prettyprint.linenums.lang-html code. - aside.is-right Did you know that hipsum is a replacment for Lorem Ipsum? To find out more visit hipsum.co + aside.is-right Did you know that hipsum is a replacement for Lorem Ipsum? To find out more visit hipsum.co p. Etsy artisan Thundercats, authentic sustainable bitters diff --git a/public/docs/_includes/styleguide/_code-examples.jade b/public/docs/_includes/styleguide/_code-examples.jade index 47dbb56c1b..c92cb84cd9 100644 --- a/public/docs/_includes/styleguide/_code-examples.jade +++ b/public/docs/_includes/styleguide/_code-examples.jade @@ -12,7 +12,7 @@ include ../../../_includes/_util-fns :marked ### Including a code example from the `_examples` folder - One of the design goals for this documention was that any code samples that appear within the documentation be 'testable'. + One of the design goals for this documentation was that any code samples that appear within the documentation be 'testable'. In practice this means that a set of standalone testable examples exist somewhere in the same repository as the rest of the documentation. These examples will each typically consist of a collection of html, javascript and css files. @@ -45,14 +45,14 @@ include ../../../_includes/_util-fns #### Example: code-example(format="linenums" language="js"). - +makeExample('styleguide/js/index.html', null, 'index.html') + +makeExample('styleguide/js/src/index.html', null, 'index.html') :marked - This will read the *_examples/styleguide/js/index.html* file and include it + This will read the *_examples/styleguide/js/src/index.html* file and include it with the heading 'index.html'. Note that the file will be properly escaped and color coded according to the extension on the file ( html in this case). - +makeExample('styleguide/js/index.html', null, 'index.html') + +makeExample('styleguide/js/src/index.html', null, 'index.html') :marked The second parameter with a value of 'null' will be described later in this document. @@ -69,12 +69,12 @@ include ../../../_includes/_util-fns #### Example: code-example(format="linenums" language="js"). - +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test') + +makeTabs('styleguide/js/src/index.html, styleguide/js/spec.js', null, 'index.html,unit test') :marked This will create two tabs, each with its own title and appropriately color coded. - +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test') + +makeTabs('styleguide/js/src/index.html, styleguide/js/spec.js', null, 'index.html,unit test') :marked @@ -113,12 +113,10 @@ include ../../../_includes/_util-fns var AppComponent = ng // #docregion component .Component({ - selector: 'my-app' - }) + selector: 'my-app', // #enddocregion component // #docregion view - .View({ - template: '

    My First Angular 2 App

    ' + template: '

    My First Angular App

    ' }) // #enddocregion view // #docregion class @@ -132,20 +130,20 @@ include ../../../_includes/_util-fns Multiple `#docregion` tags may be defined on a single line as shown below. In addition, anytime a file contains multiple `#docregion` tags with the same name they will automatically be combined. Each of the individually tagged sections of the combined document will be separated from one another by a comment consisting of '. . .'. This default separator, known - as 'plaster' can be overriden anywhere within the affected file via a `#docplaster` comment as shown below. This example creates + as 'plaster' can be overridden anywhere within the affected file via a `#docplaster` comment as shown below. This example creates a separator that consists of `/* more code here */` in the output file. code-example(format="linenums" language="js" escape="html"). // #docplaster more code here // #docregion import,twoparts - import {Component, View, bootstrap} from 'angular2/angular2'; + import { Component } from '@angular/core'; + import { bootstrap } from '@angular/platform-browser-dynamic'; + // #enddocregion twoparts, import @Component({ - selector: 'my-app' - }) - @View({ - template: '

    My first Angular 2 App

    ' + selector: 'my-app', + template: '

    My first Angular App

    ' }) class AppComponent { } @@ -162,7 +160,6 @@ include ../../../_includes/_util-fns code-example(format="linenums" language="html"). <!-- #docregion --> ... - <script src="https://code.angularjs.org/2.0.0-beta.7/angular2.sfx.dev.js"></script> <script src="app.js"></script> ... @@ -185,13 +182,13 @@ include ../../../_includes/_util-fns #### Example code-example(format="linenums" language="js"). - +makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region") + +makeExample('styleguide/js/src/app.js', 'class-w-annotations', "Extracted region") :marked is a request to include just the `class-w-annotations` region from the `app.js` file in the `_examples/styleguide` folder and results in the following: - +makeExample('styleguide/js/app.js', 'class-w-annotations', "Extracted region") + +makeExample('styleguide/js/src/app.js', 'class-w-annotations', "Extracted region") :marked @@ -211,7 +208,7 @@ include ../../../_includes/_util-fns #### Example code-example(format="linenums" language="js" escape="none"). - +makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*&quot;)/g}) + +makeExample('styleguide/js/src/index.html', null, 'index.html', {pnk: /script (src=.*&quot;)/g}) :marked Which will mark all of the quoted contents of each `script` tag within the index.html file in pink. @@ -220,20 +217,20 @@ include ../../../_includes/_util-fns Note that expression replacement occurs AFTER the fragment has been included and html escaped. This means that your regular expression must use escaped html text; i.e. the '&quot' in the regex above. - +makeExample('styleguide/js/index.html', null, 'index.html', {pnk: /script (src=.*")/g}) + +makeExample('styleguide/js/src/index.html', null, 'src/index.html', {pnk: /script (src=.*")/g}) :marked A more complicated example might be: code-example(format="linenums" language="js"). - var stylePattern = { pnk: /script (src=.*&quot;)/g, otl: /(\S*my-app.*$)/m }; - +makeExample('styleguide/js/index.html', null, 'index.html', stylePattern ) + +makeExample('styleguide/js/src/index.html', null, 'index.html', stylePattern ) :marked Which applies multiple styles and uses an intermediate javascript object as opposed to a literal. - var stylePattern = { pnk: /script (src=.*")/g, otl: /(\S*my-app.*$)/m }; - +makeExample('styleguide/js/index.html', null, 'index.html', stylePattern ) + +makeExample('styleguide/js/src/index.html', null, 'index.html', stylePattern ) :marked `makeTabs` support for `stylePatterns` is slightly different from the `makeExample` mixin in that you can also @@ -242,10 +239,10 @@ include ../../../_includes/_util-fns code-example(format="linenums" language="js"). -var stylePatterns = [{ pnk: /script (src=.*&quot;)/g }, {pnk: /(result)/ }]; - +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns) + +makeTabs('styleguide/js/src/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns) -var stylePatterns = [{ pnk: /script (src=.*")/g }, {pnk: /(result)/ }]; - +makeTabs('styleguide/js/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns) + +makeTabs('styleguide/js/src/index.html, styleguide/js/spec.js', null, 'index.html,unit test', stylePatterns) :marked @@ -287,19 +284,9 @@ include ../../../_includes/_util-fns Styling selected portions of the json is also supported. code-example(format="" language="js"). - +makeJson('styleguide/package.1.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*traceur.*)/, /(\Sangular2.*)/, /(\Ssystem.*)/ ]}) - - +makeJson('styleguide/package.1.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*traceur.*)/, /(\Sangular2.*)/, /(\Ssystem.*)/ ]}) - - :marked - As well as styling across multiple lines. - - code-example(format="" language="js"). - - var styles = { pnk: /(^.*dependencies[\s\S]* \})/gm }; - +makeJson('styleguide/package.1.json', {paths: 'name, version, dependencies '}, "Foo", styles ) + +makeJson('styleguide/package.1.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*zone.*)/, /(\Score-js.*)/, /(\Ssystem.*)/ ]}) - - var styles = { pnk: /(^.*dependencies[\s\S]* \})/gm }; - +makeJson('styleguide/package.1.json', {paths: 'name, version, dependencies '}, "Foo", styles ) + +makeJson('styleguide/package.1.json', {paths: 'dependencies'}, "package.json dependencies", { pnk: [/(\S*zone.*)/, /(\Score-js.*)/, /(\Ssystem.*)/ ]}) :marked ### Inline code and code examples provided directly i.e. not from an example file. @@ -310,10 +297,10 @@ include ../../../_includes/_util-fns This style has several named attributes #### code-example attributes - - *name:* Name displayed in Tab (required for tabs) - - *language:* javascript, html, etc. - - *escape:* html (escapes html, woot!) - - *format:* linenums (or linenums:4 specify starting line) + * *name:* Name displayed in Tab (required for tabs) + * *language:* javascript, html, etc. + * *escape:* html (escapes html, woot!) + * *format:* linenums (or linenums:4 specify starting line) #### Example @@ -396,20 +383,20 @@ include ../../../_includes/_util-fns #### Example code-example(). - +makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15") + +makeExample('styleguide/js/src/app.js', "class-w-annotations")(format="linenums:15") :marked Starts the numbering of the example at line 15. - +makeExample('styleguide/js/app.js', "class-w-annotations")(format="linenums:15") + +makeExample('styleguide/js/src/app.js', "class-w-annotations")(format="linenums:15") :marked Or to suppress line numbering completely you can use code-example(). - +makeExample('styleguide/js/app.js', 'class-w-annotations')(format=".") + +makeExample('styleguide/js/src/app.js', 'class-w-annotations')(format=".") - +makeExample('styleguide/js/app.js', 'class-w-annotations')(format=".") + +makeExample('styleguide/js/src/app.js', 'class-w-annotations')(format=".") :marked @@ -424,7 +411,7 @@ include ../../../_includes/_util-fns .alert.is-important. The '@example' and '@exampleTabs' inline tags MUST always appear at the beginning of a line. - Example files referenced by inline tags are all assumed to be in the 'modules/angular2' folder in the angular/angular repo. + Example files referenced by inline tags are all assumed to be in the 'modules/@angular' folder in the angular/angular repo. :marked #### @example inline tag parameters diff --git a/public/docs/_includes/styleguide/_images.jade b/public/docs/_includes/styleguide/_images.jade new file mode 100644 index 0000000000..9643229235 --- /dev/null +++ b/public/docs/_includes/styleguide/_images.jade @@ -0,0 +1,10 @@ +#sg-images.showcase.shadow-1 + header.showcase-header + h2 Images + p. + To maintain visual consistency across documentation chapters, please follow the best + practices for authors outlined in the Image + Guide. + p. + The browser background template used for outlining screenshots is here. diff --git a/public/docs/_includes/styleguide/_layouts.jade b/public/docs/_includes/styleguide/_layouts.jade index 904e8de0aa..7fc023ae0d 100644 --- a/public/docs/_includes/styleguide/_layouts.jade +++ b/public/docs/_includes/styleguide/_layouts.jade @@ -2,7 +2,7 @@ header.showcase-header h2 Basic Layouts p. - You will use the following layouts throughout your documenation + You will use the following layouts throughout your documentation to specify sections and sub-sections of content. .showcase-content @@ -23,4 +23,4 @@ code-example(language="html" format="linenums"). .l-sub-section h3 Sub Section Title - p sub section content... \ No newline at end of file + p sub section content... diff --git a/public/docs/_includes/styleguide/_styleguide.jade b/public/docs/_includes/styleguide/_styleguide.jade index b4db92940a..36684a8841 100644 --- a/public/docs/_includes/styleguide/_styleguide.jade +++ b/public/docs/_includes/styleguide/_styleguide.jade @@ -1,10 +1,11 @@ .grid-fluid .c10 - != partial("_layouts") - != partial("_code-examples") - != partial("_alerts") - != partial("_callouts") - != partial("_tables") - != partial("_aside") + include _layouts + include _code-examples + include _alerts + include _callouts + include _tables + include _aside + include _images -//!= partial("_jump-nav") +//include _jump-nav diff --git a/public/docs/_includes/styleguide/_tables.jade b/public/docs/_includes/styleguide/_tables.jade index e06e05559b..738a8dc873 100644 --- a/public/docs/_includes/styleguide/_tables.jade +++ b/public/docs/_includes/styleguide/_tables.jade @@ -2,7 +2,7 @@ header.showcase-header h2 Tables p. - Tables can be used to present tablular data as it relates + Tables can be used to present tabular data as it relates to each other. .showcase-content @@ -15,15 +15,15 @@ th Task th Speed tr - td Angular 1.3 + td AngularJS v.1.3 td Routing td fast tr - td Angular 1.4 + td AngularJS v.1.4 td Routing td faster tr - td Angular 2 + td Angular td Routing td fastest :) @@ -35,6 +35,6 @@ th Task th Speed tr - td Angular 1.3 + td AngularJS v.1.3 td Routing - td fast \ No newline at end of file + td fast diff --git a/public/docs/_layout-dart-api.jade b/public/docs/_layout-dart-api.jade new file mode 100644 index 0000000000..cded545a26 --- /dev/null +++ b/public/docs/_layout-dart-api.jade @@ -0,0 +1,52 @@ +//- WARNING: _layout.jade and _layout-dart-api.jade should match in terms of content +//- except that one uses Harp partial/yield and the other uses Jade extends/include. +if jade2ng + .side-nav--offset + link(rel="stylesheet" href="/https/github.com/assets/css/vendor/dartdoc/bootstrap.min.css") + link(rel="stylesheet" href="/https/github.com/assets/css/vendor/dartdoc/styles.css") + include ../_includes/_hero + include ../_includes/_banner + .l-content-small.grid-fluid.docs-content + block main-content +else + doctype + html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework") + // template: public/docs/_layout-dart-api + head + include ../_includes/_head-include + link(rel="stylesheet" href="/https/github.com/resources/css/vendor/dartdoc/bootstrap.min.css") + link(rel="stylesheet" href="/https/github.com/resources/css/vendor/dartdoc/styles.css") + block head-extra + + block var-def + body(class="l-offset-nav l-offset-side-nav" ng-controller="AppCtrl as appCtrl") + include ../_includes/_main-nav + if current.path[2] + include _includes/_side-nav + include ../_includes/_hero + include ../_includes/_banner + + if current.path[3] == 'api' + if current.path[4] == 'index' + block main-content + else + article(class="l-content-small grid-fluid docs-content") + block main-content + else if current.path.indexOf('cheatsheet') > 0 + block main-content + else + if current.path[3] == 'index' || current.path[3] == 'styleguide' + article(class="l-content-small grid-fluid docs-content") + block main-content + else + article(class="l-content-small grid-fluid docs-content") + div(class="c10") + .showcase + .showcase-content + block main-content + if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4] + include ../_includes/_next-item + + include ../_includes/_footer + include ../_includes/_scripts-include + include ../_includes/_scripts-minimum \ No newline at end of file diff --git a/public/docs/_layout.jade b/public/docs/_layout.jade index ba13f435a6..a59a28af1d 100644 --- a/public/docs/_layout.jade +++ b/public/docs/_layout.jade @@ -1,29 +1,64 @@ -doctype -html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework") - head - != partial("../_includes/_head-include") +//- WARNING: _layout.jade and _layout-dart-api.jade should match in terms of content +//- except that one uses Harp partial/yield and the other uses Jade extends/include. - body(class="l-offset-nav l-offset-side-nav" ng-controller="AppCtrl as appCtrl") - != partial("../_includes/_main-nav") - if current.path[2] - != partial("_includes/_side-nav") +- function tsApiHrefToDart(match, hrefApi, dontcare1, urlRest) { +- // Simple argument values: +- // hrefApi: href="../api/ +- // urlRest: core/index/ViewChild-var.html" +- // console.log(`got match on ${match}, 1: ${hrefApi}, 3: ${urlRest}`); +- var matches = urlRest.match(/^(\w*)\/index\/(\w*)-(\w*)(\.html")$/); +- // console.log(`urlRest matches ${matches}`); +- if (!matches) return match; // leave unchanged +- var i = 1; // matches[0] corresponds to the fully matched result +- var libName = matches[i++]; +- var apiPageEntryName = matches[i++]; +- var apiEntryKind = matches[i++]; +- var suffix = matches[i++]; +- return hrefApi + 'angular2.' + libName + '/' + apiPageEntryName + '-class' + suffix; +- } + +if jade2ng + .side-nav--offset != partial("../_includes/_hero") != partial("../_includes/_banner") + .l-content-small.grid-fluid.docs-content + != yield +else + doctype + html(lang="en" ng-app="angularIOApp" itemscope itemtype="http://schema.org/Framework") + // template: public/docs/_layout + head + != partial("../_includes/_head-include") + block head-extra - if current.path[3] == 'api' - if current.path[4] == 'index' - != yield - else - article(class="l-content-small grid-fluid docs-content") + //- + body(class="l-offset-nav l-offset-side-nav" ng-controller="AppCtrl as appCtrl") + != partial("../_includes/_main-nav") + if current.path[2] + != partial("_includes/_side-nav") + != partial("../_includes/_hero") + != partial("../_includes/_banner") + + if current.path[3] == 'api' + if current.path[4] == 'index' != yield - else if current.path.indexOf('cheatsheet') > 0 - != yield - else - article(class="l-content-small grid-fluid docs-content") + else + article(class="l-content-small grid-fluid docs-content") + != yield + else if current.path.indexOf('cheatsheet') > 0 != yield + else + if current.path[3] == 'index' || current.path[3] == 'styleguide' + article(class="l-content-small grid-fluid docs-content") + != yield + else + - var isDart = current.path[1] === 'dart'; + - var regex = /(href=\"(\.?\.\/)*api\/)(.*")/g; + article(class="l-content-small grid-fluid docs-content") + != !isDart ? yield : yield.replace(regex, tsApiHrefToDart) + if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4] + != partial("../_includes/_next-item") - if (current.path[3] == 'guide' || current.path[3] == 'tutorial') && current.path[4] - != partial("../_includes/_next-item") - - != partial("../_includes/_footer") - != partial("../_includes/_scripts-include") \ No newline at end of file + != partial("../_includes/_footer") + != partial("../_includes/_scripts-include") + != partial("../_includes/_scripts-minimum") \ No newline at end of file diff --git a/public/docs/dart/latest/_data.json b/public/docs/dart/latest/_data.json deleted file mode 100644 index 8dd7a5e313..0000000000 --- a/public/docs/dart/latest/_data.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "index": { - "icon": "home", - "title": "Angular Docs", - "menuTitle": "Docs Home", - "banner": "Angular 2 is currently in Beta." - }, - - "quickstart": { - "icon": "query-builder", - "title": "5 Min Quickstart", - "description": "Get up and running with Angular 2" - }, - - "tutorial": { - "icon": "list", - "title": "Tutorial", - "banner": "Angular 2 is currently in Beta." - }, - - "guide": { - "icon": "list", - "title": "Developer Guides", - "banner": "Angular 2 is currently in Beta." - }, - - "cookbook": { - "icon": "list", - "title": "Cookbook", - "banner": "How to solve common implementation challenges." - }, - - "api": { - "icon": "book", - "title": "API Preview", - "reference": true - }, - - "cheatsheet": { - "title": "Angular Cheat Sheet", - "intro": "A quick quide to Angular syntax.", - "reference": true - }, - - "glossary": { - "title": "Glossary", - "intro": "Brief definitions of the most important words in the Angular 2 vocabulary", - "reference": true - }, - - "resources": { - "icon": "play-circle-fill", - "title": "Angular Resources", - "banner": "Angular 2 is currently in Beta.", - "resources": true - }, - - "help": { - "icon": "chat", - "title": "Help & Support", - "resources": true - } -} diff --git a/public/docs/dart/latest/_util-fns.jade b/public/docs/dart/latest/_util-fns.jade deleted file mode 100644 index 63d13cdd4d..0000000000 --- a/public/docs/dart/latest/_util-fns.jade +++ /dev/null @@ -1 +0,0 @@ -include ../../../_includes/_util-fns \ No newline at end of file diff --git a/public/docs/dart/latest/api/_data.json b/public/docs/dart/latest/api/_data.json deleted file mode 100644 index 4b375156fc..0000000000 --- a/public/docs/dart/latest/api/_data.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "index" : { - "title" : "API 2.0 Preview" - } -} \ No newline at end of file diff --git a/public/docs/dart/latest/api/api-list.json b/public/docs/dart/latest/api/api-list.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/public/docs/dart/latest/api/api-list.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/public/docs/dart/latest/api/index.jade b/public/docs/dart/latest/api/index.jade deleted file mode 100644 index c0b081114d..0000000000 --- a/public/docs/dart/latest/api/index.jade +++ /dev/null @@ -1,10 +0,0 @@ -.l-main-section - h2 Beta - - p. - The proposed Angular 2 API does not yet have Dart-specific documentation. - However, because the Dart and JavaScript APIs are generated from the same source, - you might find the JavaScript API docs helpful: - - p.text-center - Angular 2 API Preview (JavaScript) diff --git a/public/docs/dart/latest/api/overview-dump.html b/public/docs/dart/latest/api/overview-dump.html deleted file mode 100644 index b26796f8ae..0000000000 --- a/public/docs/dart/latest/api/overview-dump.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - -

    Module Overview

    - - - - - diff --git a/public/docs/dart/latest/cheatsheet.jade b/public/docs/dart/latest/cheatsheet.jade deleted file mode 100644 index 4548cf52e0..0000000000 --- a/public/docs/dart/latest/cheatsheet.jade +++ /dev/null @@ -1,7 +0,0 @@ -- var base = current.path[4] ? '.' : './guide'; -.banner - p.text-body This cheat sheet is provisional and may change. Angular 2 is currently in Beta. - -article(class="l-content-small grid-fluid docs-content") - .cheatsheet - ngio-cheatsheet(src= base + '/cheatsheet.json') diff --git a/public/docs/dart/latest/cookbook/_data.json b/public/docs/dart/latest/cookbook/_data.json deleted file mode 100644 index 71d17069b1..0000000000 --- a/public/docs/dart/latest/cookbook/_data.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "index": { - "title": "Cookbook", - "navTitle": "Overview", - "description": "A collection of recipes for common Angular application scenarios" - }, - - "a1-a2-quick-reference": { - "title": "Angular 1 to 2 Quick Reference", - "navTitle": "Angular 1 to 2 Quick Ref", - "description": "Learn how Angular 1 concepts and techniques map to Angular 2", - "hide": true - }, - - "component-communication": { - "title": "Component Interaction", - "description": "Share information between different directives and components" - } -} \ No newline at end of file diff --git a/public/docs/dart/latest/cookbook/a1-a2-quick-reference.jade b/public/docs/dart/latest/cookbook/a1-a2-quick-reference.jade deleted file mode 100644 index 6778b6af28..0000000000 --- a/public/docs/dart/latest/cookbook/a1-a2-quick-reference.jade +++ /dev/null @@ -1 +0,0 @@ -!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/dart/latest/cookbook/component-communication.jade b/public/docs/dart/latest/cookbook/component-communication.jade deleted file mode 100644 index 6778b6af28..0000000000 --- a/public/docs/dart/latest/cookbook/component-communication.jade +++ /dev/null @@ -1 +0,0 @@ -!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/dart/latest/cookbook/index.jade b/public/docs/dart/latest/cookbook/index.jade deleted file mode 100644 index 6778b6af28..0000000000 --- a/public/docs/dart/latest/cookbook/index.jade +++ /dev/null @@ -1 +0,0 @@ -!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/dart/latest/glossary.jade b/public/docs/dart/latest/glossary.jade deleted file mode 100644 index 652c5d9a1a..0000000000 --- a/public/docs/dart/latest/glossary.jade +++ /dev/null @@ -1,14 +0,0 @@ -include _util-fns -+includeShared('{ts}', 'intro') -+includeShared('{ts}', 'a2') -+includeShared('{ts}', 'b-c') -+includeShared('{ts}', 'd1') -+includeShared('{ts}', 'd2') -+includeShared('{ts}', 'e1') -+includeShared('{ts}', 'e2') -+includeShared('{ts}', 'f-l') -+includeShared('{ts}', 'm1') -+includeShared('{ts}', 'n-s') -+includeShared('{ts}', 't1') - -+includeShared('{ts}', 'u-z') \ No newline at end of file diff --git a/public/docs/dart/latest/guide/_data.json b/public/docs/dart/latest/guide/_data.json deleted file mode 100644 index ad902928f1..0000000000 --- a/public/docs/dart/latest/guide/_data.json +++ /dev/null @@ -1,125 +0,0 @@ -{ - "index": { - "title": "Documentation Overview", - "navTitle": "Overview", - "description": "How to read and use this documentation", - "nextable": true, - "basics": true - }, - - "architecture": { - "title": "Architecture Overview", - "navTitle": "Architecture", - "intro": "The basic building blocks of Angular 2 applications", - "nextable": true, - "basics": true - }, - - "displaying-data": { - "title": "Displaying Data", - "intro": "Interpolation and other forms of property binding help us show app data in the UI.", - "nextable": true, - "basics": true - }, - - "user-input": { - "title": "User Input", - "intro": "User input triggers DOM events. We listen to those events with event bindings that funnel updated values back into our components and models.", - "nextable": true, - "basics": true - }, - - "forms": { - "title": "Forms", - "intro": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors.", - "nextable": true, - "basics": true - }, - - "dependency-injection": { - "title": "Dependency Injection", - "intro": "Angular's dependency injection system creates and delivers dependent services \"just-in-time\".", - "nextable": true, - "basics": true - }, - - "template-syntax": { - "title": "Template Syntax", - "intro": "Learn how to write templates that display data and consume user events with the help of data binding.", - "nextable": true, - "basics": true - }, - - "cheatsheet": { - "title": "Angular Cheat Sheet", - "intro": "A quick quide to Angular syntax.", - "nextable": true, - "basics": true - }, - - "attribute-directives": { - "title": "Attribute Directives", - "intro": "Attribute directives attach behavior to elements." - }, - - "hierarchical-dependency-injection": { - "title": "Hierarchical Dependency Injectors", - "navTitle": "Hierarchical Injectors", - "intro": "Angular's hierarchical dependency injection system supports nested injectors in parallel with the component tree." - }, - - "server-communication": { - "title": "Http Client", - "intro": "Talk to a remote server with the Angular Http Client." - }, - - "lifecycle-hooks": { - "title": "Lifecycle Hooks", - "intro": "Angular calls lifecycle hook methods on directives and components as it creates, changes, and destroys them." - }, - - "npm-packages": { - "title": "Npm Packages", - "intro": "Details of the recommended npm packages and the different kinds of package dependencies", - "hide": true - }, - - "pipes": { - "title": "Pipes", - "intro": "Pipes transform displayed values within a template." - }, - - "router": { - "title": "Routing & Navigation", - "intro": "Discover the basics of screen navigation with the Angular 2 router." - }, - - "structural-directives": { - "title": "Structural Directives", - "intro": "Angular has a powerful template engine that lets us easily manipulate the DOM structure of our elements." - }, - - "testing": { - "title": "Testing", - "intro": "Techniques and practices for testing an Angular 2 app", - "hide": true - }, - - "typescript-configuration": { - "title": "TypeScript Configuration", - "intro": "TypeScript configuration for Angular 2 developers", - "hide": true - }, - - "upgrade": { - "title": "Upgrading from 1.x", - "intro": "Angular 1 applications can be incrementally upgraded to Angular 2.", - "hide": true - }, - - "glossary": { - "title": "Glossary", - "intro": "Brief definitions of the most important words in the Angular 2 vocabulary", - "hide": true - } -} diff --git a/public/docs/dart/latest/guide/architecture.jade b/public/docs/dart/latest/guide/architecture.jade deleted file mode 100644 index 732bbc6c08..0000000000 --- a/public/docs/dart/latest/guide/architecture.jade +++ /dev/null @@ -1,451 +0,0 @@ -include ../_util-fns - -:marked - Angular 2 is a framework to help us build client applications in HTML and - either JavaScript or a language (like Dart or TypeScript) that compiles to JavaScript. - Angular 2 for Dart is published as the `angular2` package, which - (like many other Dart packages) is available via the Pub tool. - - With Angular, we write applications by composing HTML *templates* with Angularized markup, - writing *component* classes to manage those templates, adding application logic in *services*, - and handing the top root component to Angular's *bootstrapper*. - - Angular takes over, presenting our application content in a browser and responding to user interactions - according to the instructions we provided. - - -:marked - Of course there is more to it than this. - We're cruising at high altitude in this overview. - We're looking for landmarks. We should expect the object below to be fuzzy and obscured by occasional clouds. - Details become more clear and precise when we land in the chapters themselves. -
    - -:marked - An Angular 2 for Dart application rests on seven main building blocks: - 1. [Components](#component) - 1. [Templates](#template) - 1. [Metadata](#metadata) - 1. [Data binding](#data-binding) - 1. [Directives](#directive) - 1. [Services](#service) - 1. [Dependency injection](#dependency-injection) - -figure - img(src="/resources/images/devguide/architecture/overview.png" alt="overview" style="margin-left:-40px;" width="700") -:marked - Learn these seven and we're on our way. - -.l-main-section - -:marked - ## Components -figure - img(src="/resources/images/devguide/architecture/hero-component.png" alt="Component" align="left" style="width:200px; margin-left:-40px;margin-right:10px" ) -:marked - A **component** controls a patch of screen real estate that we could call a *view*. - A set of navigation links, a list of heroes, a hero editor ... - they're all views controlled by components. - - We define a component's application logic — what it does to support the view — inside a class. - The class interacts with the view through an API of properties and methods. - - - A `HeroListComponent`, for example, might have a `heroes` property that returns an array of heroes - that it acquired from a service. - It might have a `selectHero()` method that sets a `selectedHero` property when the user clicks to choose a hero from that list. - The component might be a class like this: - -+makeExample('architecture/dart/lib/hero_list_component.dart', 'class', 'lib/hero_list_component.dart') -:marked - Angular creates, updates, and destroys components as the user moves through the application. - The developer can take action at each moment in this lifecycle through optional lifecycle hooks. - - -.l-sub-section - :marked - We may wonder who is calling the component's constructor? Who provides the service parameter? - For the moment, have faith that Angular will call the constructor and deliver an - appropriate `HeroService` when we need it. - -.l-main-section - -:marked - ## Templates -figure - img(src="/resources/images/devguide/architecture/template.png" alt="Template" align="left" style="width:200px; margin-left:-40px;margin-right:10px" ) -:marked - We define a component's view with its companion **template**. A template is a form of HTML - that tells Angular how to render the component. - - A template looks like regular HTML much of the time ... and then it gets a bit strange. Here is a - template for our `HeroListComponent`: -+makeExample('architecture/dart/lib/hero_list_component.html', null, 'lib/hero_list_component.html') -:marked - This template features typical HTML elements like `

    ` and `
    `. - But what are `*ngFor`, {‌{hero.name}}, `(click)`, `[hero]`, and ``? - They're examples of Angular's template syntax. - We'll grow accustomed to that syntax and may even learn to love it. - - Take a look at the last line, - which has the `` tag. - That tag adds a custom element representing a component we haven't seen yet, - a `HeroDetailComponent`. - - The `HeroDetailComponent` is a *different* component than the `HeroListComponent` we've seen. - The `HeroDetailComponent` (code not shown) presents facts about a particular hero, the - hero that the user selects from the list presented by the the `HeroListComponent`. - The `HeroDetailComponent` is a **child** of the `HeroListComponent`. - -figure - img(src="/resources/images/devguide/architecture/component-tree.png" alt="Metadata" align="left" style="width:300px; margin-left:-40px;margin-right:10px" ) -:marked - Notice how `` rests comfortably among native HTML elements. - We can and _will_ mix our custom components with native HTML in the same layouts. - - In this manner we'll compose complex component trees to build out our richly featured application. -
    - -.l-main-section - -:marked - ## Metadata -figure - img(src="/resources/images/devguide/architecture/metadata.png" alt="Metadata" align="left" style="width:150px; margin-left:-40px;margin-right:10px" ) -:marked -

    Metadata tells Angular how to process a class.

    -
    -:marked - [Looking back at the code](#component-code) for `HeroListComponent`, we see that it's just a class. - There is no evidence of a framework, no "Angular" in it at all. - - In fact, it really is *just a class*. It's not a component until we *tell Angular about it*. - - We tell Angular that `HeroListComponent` is a component by attaching **metadata** to the class. - - In Dart, we attach metadata by using an **annotation**. - Here's some metadata for `HeroListComponent`: - -+makeExample('architecture/dart/lib/hero_list_component.dart', 'metadata', 'lib/hero_list_component.dart') -:marked - Here we see the `@Component` annotation, which (no surprise) identifies the class - immediately below it as a component class. - - Annotations often have configuration parameters. - The `@Component` annotation takes parameters to provide the - information Angular needs to create and present the component and its view. - - Here we see a few of the possible `@Component` parameters: - - * `selector`: A CSS selector that tells Angular to create and insert an instance of this component - where it finds a `` tag in *parent* HTML. - For example, if an app's HTML contains ``, then - Angular inserts an instance of the `HeroListComponent` view between those tags. - - * `templateUrl`: The address of this component's template, which we showed [above](#the-template). - - * `directives`: An array of the components or directives that *this* template requires. - We saw in the last line of our template that we expect Angular to insert a `HeroDetailComponent` - in the space indicated by `` tags. - Angular will do so only if we mention the `HeroDetailComponent` in this `directives` array. - - * `providers`: An array of **dependency injection providers** for services that the component requires. - This is one way to tell Angular that our component's constructor requires a `HeroService` - so it can get the list of heroes to display. We'll get to dependency injection later. -figure - img(src="/resources/images/devguide/architecture/template-metadata-component.png" alt="Metadata" align="left" style="height:200px; margin-left:-40px;margin-right:10px" ) - -:marked - At runtime, Angular discovers the metadata specified by the `@Component` - annotation. That's how Angular learns how to do "the right thing". - - The template, metadata, and component together describe the view. - - We apply other metadata annotations in a similar fashion to guide Angular behavior. - `@Injectable`, `@Input`, `@Output`, and `@RouterConfig` are a few of the more popular annotations - we'll master as our Angular knowledge grows. -
    -:marked - The architectural takeaway is that we must add metadata to our code - so that Angular knows what to do. - -.l-main-section - -:marked - ## Data binding - Without a framework, we would be responsible for pushing data values into the HTML controls and turning user responses - into actions and value updates. Writing such push/pull logic by hand is tedious, error-prone, and a nightmare to - read as any experienced jQuery programmer can attest. -figure - img(src="/resources/images/devguide/architecture/databinding.png" alt="Data Binding" style="width:220px; float:left; margin-left:-40px;margin-right:20px" ) -:marked - Angular supports **data binding**, - a mechanism for coordinating parts of a template with parts of a component. - We add binding markup to the template HTML to tell Angular how to connect both sides. - - There are four forms of data binding syntax. Each form has a direction — to the DOM, from the DOM, or in both directions — - as indicated by the arrows in the diagram. -
    -:marked - We saw three forms of data binding in our [example](#template) template: -+makeExample('architecture/dart/lib/hero_list_component_1.html', 'binding')(format=".") -:marked - * The {‌{hero.name}} [interpolation](displaying-data.html#interpolation) - displays the component's `hero.name` property value within the `
    ` tags. - - * The `[hero]` property binding - passes the value of `selectedHero` from - the parent `HeroListComponent` to the `hero` property of the child `HeroDetailComponent`. - - * The `(click)` [event binding](user-input.html#click) calls the component's `selectHero` method when the user clicks a hero's name. - - **Two-way data binding** is an important fourth form - that combines property and event binding in a single notation, using the `ngModel` directive. - We didn't have a two-way binding in the `HeroListComponent` template; - here's an example from the `HeroDetailComponent` template: - -+makeExample('architecture/dart/lib/hero_detail_component.html', 'ng-model', 'lib/hero_detail_component.html (excerpt)')(format=".") -:marked - In two-way binding, a data property value flows to the input box from the component as with property binding. - The user's changes also flow back to the component, resetting the property to the latest value, - as with event binding. - - Angular processes *all* data bindings once per JavaScript event cycle, - depth-first from the root of the application component tree. - -figure - img(src="/resources/images/devguide/architecture/component-databinding.png" alt="Data Binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" ) -:marked - We don't know all the details yet, - but it's clear from these examples that data binding plays an important role in communication - between a template and its component. -
    -figure - img(src="/resources/images/devguide/architecture/parent-child-binding.png" alt="Parent/Child binding" style="float:left; width:300px; margin-left:-40px;margin-right:10px" ) -:marked - Data binding is also important for communication between parent and child components. -
    - -.l-main-section - -:marked - ## Directives -figure - img(src="/resources/images/devguide/architecture/directive.png" alt="Parent child" style="float:left; width:150px; margin-left:-40px;margin-right:10px" ) -:marked - Angular templates are *dynamic*. When Angular renders them, it transforms the DOM - according to the instructions given by **directives**. - - A directive is a class with directive metadata. In Dart we apply the `@Directive` annotation - to attach metadata to the class. -
    -:marked - We already met one form of directive: the component. A component is a *directive-with-a-template*; - a `@Component` annotation is actually a `@Directive` annotation extended with template-oriented features. - -.l-sub-section - :marked - While **a component is technically a directive**, - components are so distinctive and central to Angular applications that we chose - to separate components from directives in this architectural overview. -:marked - Two *other* kinds of directives exist: _structural_ and _attribute_ directives. - - They tend to appear within an element tag like attributes, - sometimes by name but more often as the target of an assignment or a binding. - - **Structural** directives alter layout by adding, removing, and replacing elements in DOM. - - Our [example](#template) template uses two built-in structural directives: -+makeExample('architecture/dart/lib/hero_list_component_1.html', 'structural')(format=".") -:marked - * [`*ngFor`](displaying-data.html#ng-for) tells Angular to stamp out one `
    ` per hero in the `heroes` list. - * [`*ngIf`](displaying-data.html#ng-if) includes the `HeroDetail` component only if a selected hero exists. - -.l-sub-section - :marked - In Dart, **the only value that is true is the boolean value `true`**; all - other values are false. JavaScript and TypeScript, in contrast, treat values - such as 1 and most non-null objects as true. For this reason, the JavaScript - and TypeScript versions of this app can use just `selectedHero` as the value - of the `*ngIf` expression. The Dart version must use a boolean operator such - as `!=` instead. - -:marked - **Attribute** directives alter the appearance or behavior of an existing element. - In templates they look like regular HTML attributes, hence the name. - - The `ngModel` directive, which implements two-way data binding, is - an example of an attribute directive. `ngModel` modifies the behavior of - an existing element (typically an ``) - by setting its display value property and responding to change events. - -+makeExample('architecture/dart/lib/hero_detail_component.html', 'ng-model')(format=".") -:marked - Angular ships with a small number of other directives that either alter the layout structure - (for example, `ngSwitch`) - or modify aspects of DOM elements and components - (for example, `ngStyle` and `ngClass`). - - - Of course, we can also write our own directives. Components such as - `HeroListComponent` are one kind of custom directive. - - -.l-main-section - -:marked - ## Services -figure - img(src="/resources/images/devguide/architecture/service.png" alt="Service" style="float:left; margin-left:-40px;margin-right:10px" ) -:marked - _Services_ is a broad category encompassing any value, function, or feature that our application needs. - - Almost anything can be a service. - A service is typically a class with a narrow, well-defined purpose. It should do something specific and do it well. -
    -:marked - Examples include: - * logging service - * data service - * message bus - * tax calculator - * application configuration - - There is nothing specifically _Angular_ about services. Angular itself has no definition of a service. - There is no service base class, and no place to register a service. - - Yet services are fundamental to any Angular application. Our components are big consumers of services. - - We prefer our component classes lean. Our components don't fetch data from the server, - they don't validate user input, and they don't log directly to console. They delegate such tasks to services. - - A component's job is to enable the user experience and nothing more. It mediates between the view (rendered by the template) - and the application logic (which often includes some notion of a _model_). - A good component presents properties and methods for data binding. - It delegates everything nontrivial to services. - - Angular doesn't *enforce* these principles. - It won't complain if we write a "kitchen sink" component with 3000 lines. - - Angular does help us *follow* these principles by making it easy to factor our - application logic into services and make those services available to components through *dependency injection*. - -.l-main-section - -:marked - ## Dependency injection -figure - img(src="/resources/images/devguide/architecture/dependency-injection.png" alt="Service" style="float:left; width:200px; margin-left:-40px;margin-right:10px" ) -:marked - Dependency injection is a way to supply a new instance of a class - with the fully-formed dependencies it requires. Most dependencies are services. - Angular uses dependency injection to provide new components with the services they need. -
    -:marked - Angular can tell which services a component needs by looking at the types of its constructor parameters. - For example, the constructor of our `HeroListComponent` needs a `HeroService`: -+makeExample('architecture/dart/lib/hero_list_component.dart', 'ctor', 'lib/hero_list_component.dart (excerpt)')(format='.') -:marked - When Angular creates a component, it first asks an **injector** for - the services that the component requires. - - An injector maintains a container of service instances that it has previously created. - If a requested service instance is not in the container, the injector makes one and adds it to the container - before returning the service to Angular. - When all requested services have been resolved and returned, - Angular can call the component's constructor with those services as arguments. - This is what we mean by *dependency injection*. - - The process of `HeroService` injection looks a bit like this: -figure - img(src="/resources/images/devguide/architecture/injector-injects.png" alt="Service" ) -:marked - If the injector doesn't have a `HeroService`, how does it know how to make one? - - In brief, we must have previously registered a **provider** of the `HeroService` with the injector. - A provider is something that can create or return a service, typically the service class itself. - - We can register providers at any level of the application component tree. - We often do so at the root when we bootstrap the application so that - the same instance of a service is available everywhere. -+makeExample('architecture/dart/web/main.dart', 'bootstrap', 'web/main.dart (excerpt)')(format='.') -:marked - Alternatively, we might register at a component level: -+makeExample('architecture/dart/lib/hero_list_component.dart', 'providers', 'lib/hero_list_component.dart (excerpt)')(format='.') -:marked - Registering at a component level means we get a new instance of the - service with each new instance of that component. - - - - Points to remember about dependency injection: - - * Dependency injection is wired into the Angular framework and used everywhere. - - * The *injector* is the main mechanism. - * An injector maintains a *container* of service instances that it created. - * An injector can create a new service instance from a *provider*. - - * A *provider* is a recipe for creating a service. - - * We register *providers* with injectors. - - -.l-main-section -:marked - ## Other stuff - - We've learned just a bit about the seven main building blocks of an Angular application: - 1. [Components](#component) - 1. [Templates](#template) - 1. [Metadata](#metadata) - 1. [Data binding](#data-binding) - 1. [Directives](#directive) - 1. [Services](#service) - 1. [Dependency injection](#dependency-injection) - - That's a foundation for everything else in an Angular application, - and it's more than enough to get going. - But it doesn't include everything we'll need or want to know. - - Here is a brief, alphabetical list of other important Angular features and services. - Most of them are covered in this Developers Guide (or soon will be). - - >**Animations:** A forthcoming animation library makes it easy for developers to animate component behavior - without deep knowledge of animation techniques or CSS. - - >**Bootstrap:** A method to configure and launch the root application component. - - >**Change detection:** Learn how Angular decides that a component property value has changed and - when to update the screen. - Learn how it uses **zones** to intercept asynchronous activity and run its change detection strategies. - - >**Component router:** With the component Router service, users can navigate a multi-screen application - in a familiar web browsing style using URLs. - - >**Events:** The DOM raises events. So can components and services. Angular offers mechanisms for - publishing and subscribing to events including an implementation of the [RxJS Observable](https://github.com/zenparsing/es-observable) proposal. - - >**[Forms](forms.html):** Support complex data entry scenarios with HTML-based validation and dirty checking. - - >**HTTP:** Communicate with a server to get data, save data, and invoke server-side actions with this Angular HTTP client. - - >**Lifecycle hooks:** We can tap into key moments in the lifetime of a component, from its creation to its destruction, - by implementing the lifecycle hook interfaces. - - >**Pipes:** Services that transform values for display. - We can put pipes in our templates to improve the user experience. Consider - this `currency` pipe expression: -
    -code-example(language="javascript" linenumbers="."). - price | currency:'USD':true' -
    -:marked - >It displays a price of "42.33" as `$42.33`. - - >**Testing:** Angular provides a - [testing library](https://pub.dartlang.org/packages/angular2_testing) - to run unit tests on our application parts as they interact with the Angular framework. diff --git a/public/docs/dart/latest/guide/attribute-directives.jade b/public/docs/dart/latest/guide/attribute-directives.jade deleted file mode 100644 index 25afd1888d..0000000000 --- a/public/docs/dart/latest/guide/attribute-directives.jade +++ /dev/null @@ -1,12 +0,0 @@ -include ../_util-fns - -:marked - We're working on the Dart version of this chapter. - In the meantime, please see these resources: - - * [Attribute Directives](/docs/ts/latest/guide/attribute-directives.html): - The TypeScript version of this chapter - - * [Dart source code](https://github.com/angular/angular.io/tree/master/public/docs/_examples/attribute-directives/dart): - A preliminary version of the example code that will appear in this chapter - diff --git a/public/docs/dart/latest/guide/cheatsheet.jade b/public/docs/dart/latest/guide/cheatsheet.jade deleted file mode 100644 index ff8cc6085c..0000000000 --- a/public/docs/dart/latest/guide/cheatsheet.jade +++ /dev/null @@ -1 +0,0 @@ -!= partial("../cheatsheet") diff --git a/public/docs/dart/latest/guide/dependency-injection.jade b/public/docs/dart/latest/guide/dependency-injection.jade deleted file mode 100644 index 72fdaa1a49..0000000000 --- a/public/docs/dart/latest/guide/dependency-injection.jade +++ /dev/null @@ -1,11 +0,0 @@ -include ../_util-fns - -:marked - We're working on the Dart version of this chapter. - In the meantime, please see these resources: - - * [Dependency Injection](/docs/ts/latest/guide/dependency-injection.html): - The TypeScript version of this chapter - - * [Dart source code](https://github.com/angular/angular.io/tree/master/public/docs/_examples/dependency-injection/dart): - A preliminary version of the example code that will appear in this chapter diff --git a/public/docs/dart/latest/guide/displaying-data.jade b/public/docs/dart/latest/guide/displaying-data.jade deleted file mode 100644 index b69eb829ef..0000000000 --- a/public/docs/dart/latest/guide/displaying-data.jade +++ /dev/null @@ -1,263 +0,0 @@ -include ../_util-fns - -:marked - We typically display data in Angular by binding controls in an HTML template - to properties of an Angular component. - - In this chapter, we'll create a component with a list of heroes. Each hero has a name. - We'll display the list of hero names and - conditionally show a selected hero in a detail area below the list. - - The final UI looks like this: - -figure.image-display - img(src="/resources/images/devguide/displaying-data/final.png" alt="Final UI") - - - -.l-main-section -:marked - ## Showing component properties with interpolation - The easiest way to display a component property - is to bind the property name through interpolation. - With interpolation, we put the property name in the view template, enclosed in double curly braces: `{{myHero}}`. - - Let's build a small illustrative example together. - - - Create a new project folder (`displaying`) and create 3 files: - `pubspec.yaml`, `web/index.html`, and `web/main.dart`. - Put these contents in the files: - -- var stylePattern = [{ otl: /(platform_directives.*$)/gm }, null, null]; -+makeTabs('displaying-data/dart/pubspec.yaml, displaying-data/dart/web/index.html, displaying-data/dart/web/main.dart', ',,final', 'pubspec.yaml, web/index.html, web/main.dart', stylePattern) - -:marked - All of this code should look familiar from the - [QuickStart](../quickstart.html), - except for the `platform_directives` entry in `pubspec.yaml` - and the imports in `main.dart`. - - In `pubspec.yaml`, the `platform_directives` entry lets us use - core directives, such as the NgFor directive that we'll soon add to our app. - - In `main.dart`, importing `app_component.dart` lets us implement part - of the app in a different Dart file. The QuickStart version of `main.dart` - imported `angular2.dart`, but we don't need that import here because - this version of `main.dart` is so basic: it only bootstraps the app, - and doesn't implement any components or other injectable types. - - So that the code can run, - let's create a stub for the `` component. - - Create a new directory called `lib`. - In it, put a file called `app_component.dart` - with the following code: - -+makeExample('displaying-data/dart/lib/app_component_1.dart', null, 'lib/app_component.dart') - -:marked - We defined a component with two properties: `title` and `myHero`. - The template displays the two component properties using double curly brace - interpolation: - -+makeExample('displaying-data/dart/lib/app_component_1.dart', 'template')(format=".") - -:marked - Angular automatically pulls the value of the `title` and `myHero` properties from the component and - inserts those values into the browser. Angular updates the display - when these properties change. - - -.l-sub-section - :marked - More precisely, the redisplay occurs after some kind of asynchronous event related to - the view such as a keystroke, a timer completion, or an async `XHR` response. - We don't have those in this sample. - But then the properties aren't changing on their own either. For the moment we must operate on faith. -:marked - Notice that we haven't called **new** to create an instance of the `AppComponent` class. - Angular is creating an instance for us. How? - - Notice the CSS `selector` in the `@Component` decorator that specifies an element named "my-app". - Remember back in QuickStart that we added the `` element to the body of our `index.html` file: -+makeExample('displaying-data/dart/web/index.html', 'my-app')(format=".") - - -:marked - When we bootstrap with the `AppComponent` class (in `main.dart`), Angular looks for a `` - in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it - inside the `` tag. - - Try running the app. It should display the title and hero name: -figure.image-display - img(src="/resources/images/devguide/displaying-data/title-and-hero.png" alt="Title and Hero") -// TODO: Here the TS version says "Let's review some of the choices we made and consider alternatives." However, it's unclear where this review ends. Clarify the structure in the TS, and make sure this is the best place for the Dart version of this section. - -#performance.l-sub-section - :marked - ### Template inline or template file? - - We can store our component's template in one of two places. - We can define it *inline* using the `template` property, as we do here. - Or we can define the template in a separate HTML file and link to it in - the component metadata using the `@Component` decorator's `templateUrl` property. - - The choice between inline and separate HTML is a matter of taste, - circumstances, and organization policy. - Here we're using inline HTML because the template is small, and the demo - is simpler without the additional HTML file. - - In either style, the template data bindings have the same access to the component's properties. - - - -.l-main-section -:marked - ## Showing a list property with NgFor - - We want to display a list of heroes. We begin by adding a list of hero names to the component and redefine `myHero` to be the first name in the list. -+makeExample('displaying-data/dart/lib/app_component_2.dart', 'mock-heroes', 'lib/app_component.dart (excerpt)')(format=".") - -:marked - Now we use the Angular `NgFor` "repeater" directive in the template to display - each item in the `heroes` list. - -+makeExample('displaying-data/dart/lib/app_component_2.dart', 'template','lib/app_component.dart (excerpt)')(format=".") - - -:marked - Our presentation is the familiar HTML unordered list with `
      ` and `
    • ` tags. Let's focus on the `
    • ` tag. -+makeExample('displaying-data/dart/lib/app_component_2.dart', 'li-repeater')(format=".") - -:marked - We added a somewhat mysterious `*ngFor` to the `
    • ` element. - That's the Angular "repeater" directive. - Its presence on the `
    • ` tag marks that `
    • ` element (and its children) as the "repeater template". - -.alert.is-important - :marked - Don't forget the leading asterisk (\*) in `*ngFor`. - - -:marked - Notice the `#hero` in the `NgFor` double-quoted instruction. - The `#hero` is a local template variable - - declaration. - The `#` prefix declares a local variable name named `hero`. - - Angular duplicates the `
    • ` for each item in the list, setting the `hero` variable - to the item (the hero) in the current iteration. Angular uses that variable as the - context for the interpolation in the double curly braces. - -.l-sub-section - :marked - We happened to give `NgFor` a list to display. - In fact, `NgFor` can repeat items for any [Iterable](https://api.dartlang.org/stable/dart-core/Iterable-class.html) object. - -:marked - Now the heroes appear in an unordered list. - -figure.image-display - img(src="/resources/images/devguide/displaying-data/hero-names-list.png" alt="After ngfor") - -.callout.is-important - header Did the app break? - :marked - If the app stops working after adding `*ngFor`, - make sure `pubspec.yaml` has the [correct **platform_directives** entry](#platform_directives). - A missing or incorrect `platform_directives` entry results in template parse errors. - -.l-main-section -:marked - ## Creating a class for the data - - We are defining our data directly inside our component. - That's fine for a demo but certainly isn't a best practice. It's not even a good practice. - Although we won't do anything about that in this chapter, we'll make a mental note to fix this down the road. - - At the moment, we're binding to a list of strings. We do that occasionally in real applications, but - most of the time we're binding to more specialized objects. - - Let's turn our list of hero names into a list of `Hero` objects. For that we'll need a `Hero` class. - - Create a new file in the `lib/` folder called `hero.dart` with the following code. -+makeExample('displaying-data/dart/lib/hero.dart',null,'lib/hero.dart') - -:marked - We've defined a class with a constructor, a string description, and two properties: `id` and `name`. - -.l-main-section -:marked - ## Using the Hero class - Let's make the `heroes` property in our component return a list of these Hero objects. -- var stylePattern = { otl: /(import.*$)|(final)|(new Hero.*$)/gm }; -+makeExample('displaying-data/dart/lib/app_component_3.dart', 'heroes', 'app_component.dart (excerpt)', stylePattern)(format=".") - -:marked - We'll have to update the template. - At the moment it displays the string value of the `Hero` object. - Let's fix that so we display only the hero's `name` property. -- var stylePattern = { otl: /(myHero\.name)|(hero\.name)/gm }; -+makeExample('displaying-data/dart/lib/app_component_3.dart', 'template','app_component.dart (template)', stylePattern)(format=".") - - -:marked - Our display looks the same, but now we know much better what a hero really is. - - -.l-main-section -:marked - ## Conditional display with NgIf - - Sometimes the app should display a view or a portion of a view only under specific circumstances. - - In our example, we'd like to display a message if we have a large number of heroes — say, more than 3. - - The Angular `NgIf` directive inserts or removes an element based on a boolean condition. - We can see it in action by adding the following paragraph at the bottom of the template: -+makeExample('displaying-data/dart/lib/app_component.dart', 'message') -.alert.is-important - :marked - Don't forget the leading asterisk (\*) in `*ngIf`. - - - -:marked - The template expression - - inside the double quotes looks much like Dart, and it _is_ much like Dart. - When the component's list of heroes has more than 3 items, Angular adds the paragraph to the DOM and the message appears. - If there are 3 or fewer items, Angular omits the paragraph, so no message appears. - -.alert.is-helpful - :marked - Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. - That hardly matters here. But it would matter a great deal, from a performance perspective, if - we were conditionally including or excluding a big chunk of HTML with many data bindings. - -:marked - Try it out. Because the list has four items, the message should appear. - Go back into `app_component.dart` and delete or comment out one of the elements from the hero list. - The browser should refresh automatically and the message should disappear. - -.l-main-section -:marked - ## Summary - Now we know how to use: - - **interpolation** with double curly braces to display a component property - - **`NgFor`** to display a list of items - - a Dart class to shape the **model data** for our component and display properties of that model - - **`NgIf`** to conditionally display a chunk of HTML based on a boolean expression - - - Here's our final code: - -+makeTabs(`displaying-data/dart/lib/app_component.dart, - displaying-data/dart/lib/hero.dart, - displaying-data/dart/pubspec.yaml, - displaying-data/dart/web/index.html, - displaying-data/dart/web/main.dart`, - ',,,,final', - 'lib/app_component.dart, lib/hero.dart, pubspec.yaml, web/index.html, web/main.dart') diff --git a/public/docs/dart/latest/guide/forms.jade b/public/docs/dart/latest/guide/forms.jade deleted file mode 100644 index fa588e15cf..0000000000 --- a/public/docs/dart/latest/guide/forms.jade +++ /dev/null @@ -1,664 +0,0 @@ -include ../_util-fns - - -:marked - We’ve all used a form to log in, submit a help request, place an order, book a flight, - schedule a meeting, and perform countless other data entry tasks. - Forms are the mainstay of business applications. - - Any seasoned web developer can slap together an HTML form with all the right tags. - It's more challenging to create a cohesive data entry experience that guides the - user efficiently and effectively through the workflow behind the form. - - *That* takes design skills that are, to be frank, well out of scope for this chapter. - - It also takes framework support for - **two-way data binding, change tracking, validation, and error handling** - ... which we shall cover in this chapter on Angular forms. - - We will build a simple form from scratch, one step at a time. Along the way we'll learn: - - - How to build an Angular form with a component and template - - - The `ngModel` two-way data binding syntax for reading and writing values to input controls - - - The `ngControl` directive to track the change state and validity of form controls - - - The special CSS classes that `ngControl` adds to form controls and how to use them to provide strong visual feedback - - - How to display validation errors to users and enable/disable form controls - - - How to share information across controls with template local variables - -.l-main-section -:marked - ## Template-driven forms - - Many of us will build forms by writing templates in the Angular - template syntax - - with the form-specific directives and techniques described in this chapter. - -.l-sub-section - :marked - That's not the only way to create a form but it's the way we'll cover in this chapter. -:marked - We can build almost any form we need with an Angular template—login forms, contact forms, pretty much any business form. - We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors, - conditionally enable or disable specific controls, trigger built-in visual feedback, and much more. - - It will be pretty easy because Angular handles many of the repetitive, boilerplate tasks we'd - otherwise wrestle with ourselves. - - We'll discuss and learn to build a template-driven form that looks like this: - -figure.image-display - img(src="/resources/images/devguide/forms/hero-form-1.png" width="400px" alt="Clean Form") - -:marked - Here at the *Hero Employment Agency* we use this form to maintain personal information about the - heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis! - - Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot. - - If we delete the hero name, the form displays a validation error in an attention-grabbing style: - -figure.image-display - img(src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="Invalid, Name Required") - -:marked - Note that the submit button is disabled, and the "required" bar to the left of the input control changed from green to red. - -.l-sub-section - :marked - We'll customize the colors and location of the "required" bar with standard CSS. - -:marked - We'll build this form in small steps: - - 1. Create the `Hero` model class. - 1. Create the component that controls the form. - 1. Create a template with the initial form layout. - 1. Add the **ngModel** directive to each form input control. - 1. Add the **ngControl** directive to each form input control. - 1. Add custom CSS to provide visual feedback. - 1. Show and hide validation error messages. - 1. Handle form submission with **ngSubmit**. - 1. Change the form's display after submission. - -:marked - ## Setup - Create a new project folder (`angular2_forms`) and create 3 files: - `pubspec.yaml`, `web/index.html`, and `web/main.dart`. - (These files should be familiar from the - [QuickStart](../quickstart.html).) Put these contents in the files: - -+makeTabs('forms/dart/pubspec.yaml, forms/dart/web/index.html, forms/dart/web/main.dart', ',initial,', 'pubspec.yaml, web/index.html, web/main.dart') - -.l-sub-section - :marked - Note the `platform_directives` entry in `pubspec.yaml`. - It imports core directives and, more importantly for this chapter, - **form directives**. - -:marked - So that the code can run, - let's create a stub for the `` component. - - Create a new directory called `lib`. - In it, put a file called `hero_form_component.dart` - with the following code: - -+makeExample('forms/dart/lib/hero_form_component_initial.dart', null, 'lib/hero_form_component.dart') - -:marked - The app should now run, but it won't do anything interesting. - Let's add some data. - - - ## Create the Hero model class - - As users enter form data, we'll capture their changes and update an instance of a model. - We can't lay out the form until we know what the model looks like. - - A model can be as simple as a "property bag" that holds facts about a thing of application importance. - That describes well our `Hero` class with its three required fields (`id`, `name`, `power`) - and one optional field (`alterEgo`). - - In the `lib` directory, add a file called `hero.dart` - with the following code: - -+makeExample('forms/dart/lib/hero.dart', 'all', 'lib/hero.dart') - -:marked - It's an anemic model with few requirements and no behavior. Perfect for our demo. - - The `alterEgo` is optional, so the constructor lets us omit it: note the - `[]` in `[this.alterEgo]`. - - We can create a new hero like this: - -+makeExample('forms/dart/lib/hero.dart', 'newhero')(format=".") - -:marked - -.l-main-section -:marked - ## Create a form component - - An Angular form has two parts: an HTML-based template and a code-based component to handle data and user interactions. - - We begin with the component because it states, in brief, what the Hero editor can do. - - Edit `hero_form_component.dart`, replacing all of its contents - with the following code: - -+makeExample('forms/dart/lib/hero_form_component.dart', null, 'lib/hero_form_component.dart') - -:marked - There’s nothing special about this component, nothing form-specific, - nothing to distinguish it from any component we've written before. - - Understanding this component requires only the Angular 2 concepts covered in previous chapters. - - 1. The code imports a standard set of symbols from the Angular library. - - 1. The `@Component` selector value of "hero-form" means we can drop this form in a parent template with a `` tag. - - 1. The `templateUrl` property points to a separate file for template HTML called `hero_form_component.html`. - - 1. We defined dummy data for `model` and `powers`, as befits a demo. - Down the road, we can inject a data service to get and save real data - or perhaps expose these properties as inputs and outputs - for binding to a - parent component. None of this concerns us now, and these future changes won't affect our form. - - 1. We threw in a `diagnostic` property to return a - string describing our model. - It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later. - - Why isn't the template inline in the component file? - - Inline templates can be nice when they are short, - but most form templates aren't short. Dart files generally aren't the best place to - write (or read) large stretches of HTML, and few editors are much help with files that have a mix of HTML and code. - It's also nice to have short files with a clear and obvious purpose. - - We made a good choice to put the HTML template elsewhere. Let's write it. - - - - - -.l-main-section -:marked - ## Create an initial HTML form template - - Create a new file under `lib` called `hero_form_component.html`, - and put the following template code in it: - -+makeExample('forms/dart/lib/hero_form_component_initial.html', null, 'lib/hero_form_component.html') - -:marked - That is plain old HTML 5. We're presenting two of the `Hero` fields, `name` and `alterEgo`, and - opening them up for user input in input boxes. - - The Name `` control has the HTML5 `required` attribute; - the Alter Ego `` control does not because `alterEgo` is optional. - - We've got a Submit button at the bottom with some classes on it. - - **We are not using Angular yet**. There are no bindings. No extra directives. Just layout. - - - The `container`,`form-group`, `form-control`, and `btn` classes are [Bootstrap](http://getbootstrap.com/) CSS. Purely cosmetic. - We're using Bootstrap to gussy up our form. - Hey, what's a form without a little style! - -.callout.is-important - header Angular forms do not require a style library - :marked - Angular makes no use of the `container`, `form-group`, `form-control`, and `btn` classes or - the styles of any external library. Angular apps can use any CSS library - ... or none at all. - -:marked - Let's add the stylesheet. - - 1. Download the Bootstrap stylesheet from - https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css, - and put it in the `web` directory. - - 2. Edit `web/index.html`, adding a link to `bootstrap.min.css`: - -- var stylePattern = { otl: /(<link rel.*$)/gm }; -+makeExample('forms/dart/web/index.html', 'bootstrap-and-script', 'web/index.html (excerpt)', stylePattern)(format=".") - - [PENDING: runnable now? Remind about pub get? remind them to look in the browser console] - - -.l-main-section -:marked - ## Add powers with ***ngFor** - Our hero must choose one super power from a fixed list of Agency-approved powers. - We maintain that list internally (in `HeroFormComponent`). - - We'll add a `select` to our - form and bind the options to the `powers` list using `NgFor`, - a technique used before in [Displaying Data](./displaying-data.html). - - Add the following HTML *immediately below* the Alter Ego group. -+makeExample('forms/dart/lib/hero_form_component_ngmodel_ngfor.html', 'powers', 'lib/hero_form_component.html (excerpt)')(format=".") - -:marked - This code repeats the `