Merge branch 'pr/2' into fix-styleguide-trigger-positioning

This commit is contained in:
Jacob Müller 2016-09-21 16:21:50 +02:00
commit 0bae5fca69
1088 changed files with 22114 additions and 19593 deletions

30
.eslintrc.js Normal file
View File

@ -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"
]
}
};

6
.firebaserc Normal file
View File

@ -0,0 +1,6 @@
{
"projects": {
"live": "angular-io",
"ngdocsdev": "ngdocsdev"
}
}

4
.gitignore vendored
View File

@ -21,10 +21,12 @@ _.*
**/resources/zips **/resources/zips
public/docs/xref-*.* public/docs/xref-*.*
_zip-output _zip-output
www www*
npm-debug*.log* npm-debug*.log*
*.plnkr.html *.plnkr.html
plnkr.html plnkr.html
*.eplnkr.html
eplnkr.html
*plnkr.no-link.html *plnkr.no-link.html
public/docs/*/latest/guide/cheatsheet.json public/docs/*/latest/guide/cheatsheet.json
protractor-results.txt protractor-results.txt

2
.nvmrc
View File

@ -1 +1 @@
5 6

View File

@ -2,7 +2,7 @@ dist: trusty
sudo: required sudo: required
language: node_js language: node_js
node_js: node_js:
- "5" - "6"
os: os:
- linux - linux
env: env:
@ -10,20 +10,20 @@ env:
- DBUS_SESSION_BUS_ADDRESS=/dev/null - DBUS_SESSION_BUS_ADDRESS=/dev/null
- DISPLAY=:99.0 - DISPLAY=:99.0
- CHROME_BIN=chromium-browser - CHROME_BIN=chromium-browser
- LATEST_RELEASE=2.0.0-rc.4 # using SHA instead of version to fix build-compile issue
- LATEST_RELEASE=cfc12c653970c9ad6d807a6a8ebff58edbc568a0
- TASK_FLAGS="--dgeni-log=warn" - TASK_FLAGS="--dgeni-log=warn"
# - TASK_FLAGS=""
matrix: matrix:
- TASK=lint - TASK=lint
- TASK="run-e2e-tests --fast" SCRIPT=examples-install.sh - TASK="run-e2e-tests --fast" SCRIPT=examples-install.sh
- TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh - TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh
- TASK=build-compile SCRIPT=deploy-install.sh WAIT="travis_wait 50" - TASK=build-compile SCRIPT=deploy-install.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v"
- TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50" - TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v"
matrix: matrix:
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- env: TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh - env: TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh
- env: TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50" - env: TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v"
before_install: before_install:
- source ./scripts/env-set.sh - source ./scripts/env-set.sh
- ./scripts/before-install.sh - ./scripts/before-install.sh
@ -34,3 +34,4 @@ before_script:
- sh -e /etc/init.d/xvfb start - sh -e /etc/init.d/xvfb start
script: script:
- $WAIT gulp $TASK $TASK_FLAGS - $WAIT gulp $TASK $TASK_FLAGS
- if [[ -n "$POST_SCRIPT" ]]; then ./scripts/$POST_SCRIPT; fi

View File

@ -1,7 +1,7 @@
# Angular.io # Angular.io
[![Build Status][travis-badge]][travis-badge-url] [![Build Status][travis-badge]][travis-badge-url]
Angular.io is site for Angular 2 **documentation** . Angular.io is site for Angular **documentation** .
This site also includes links to other helpful angular resources including This site also includes links to other helpful angular resources including
Angular 2, Angular 1, Angular Material, and AngularFire. Angular 2, Angular 1, Angular Material, and AngularFire.
@ -21,16 +21,18 @@ Filing issues is helpful but **pull requests** that improve the docs are even be
Learn how to [contribute to Angular.io](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md). Learn how to [contribute to Angular.io](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
> **IMPORTANT**: Do _NOT_ make changes to cached files under `public/docs/ts/_cache`. Cached files are updated through a separate workflow.
## Development Setup ## Development Setup
This site relies heavily on node and npm. This site relies heavily on node and npm.
1. Make sure you are using at least node v.5+ and latest 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. if not install [nvm](https://github.com/creationix/nvm) to get node going on your machine.
1. install these npm packages *globally*: `npm install -g harp gulp` 1. Install these npm packages *globally*: `npm install -g harp gulp`
1. clone this repo and the [angular source code repo](https://github.com/angular/angular) to the same parent directory. 1. Clone this repo, the [angular/angular source code repo](https://github.com/angular/angular), and the [dart-lang/angular2 source code repo](https://github.com/dart-lang/angular2) to the same parent directory.
The two cloned repo directories must be sibling. The three cloned repo directories must be siblings, with the latter two repo directories named **angular** and **angular-dart**, respectively.
1. cd into root directory `angular.io/` 1. cd into root directory `angular.io/`
@ -71,11 +73,11 @@ If you are only going to work on a specific part of the docs, such as the dev gu
## Code Sample Development ## Code Sample Development
All documentation is supported by sample code and plunkers. All documentation is supported by sample code and plunkers.
Such code resides in the `public/docs/_examples` directory, under chapter-specific directories, further divided by language track. 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`. 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 2. 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. This consistency is possible in part thanks to gulp-driven tooling.
To run the samples locally and confirm that they work properly, To run the samples locally and confirm that they work properly,
take the following extra steps to prepare the environment: take the following extra steps to prepare the environment:

View File

@ -45,7 +45,8 @@ var STYLES_SOURCE_PATH = path.join(TOOLS_PATH, 'styles-builder/less');
var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder')); var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder'));
var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper')); var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper'));
var plunkerBuilder = require(path.resolve(TOOLS_PATH, 'plunker-builder/plunkerBuilder')); 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')); var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils'));
const isSilent = !!argv.silent; const isSilent = !!argv.silent;
@ -72,9 +73,10 @@ var _apiShredOptions = {
logLevel: _dgeniLogLevel logLevel: _dgeniLogLevel
}; };
const relDartDocApiDir = path.join('doc', 'api');
var _apiShredOptionsForDart = { var _apiShredOptionsForDart = {
lang: 'dart', lang: 'dart',
examplesDir: path.resolve(ngPathFor('dart'), 'examples'), examplesDir: path.resolve(ngPathFor('dart'), 'example'),
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'), fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
zipDir: path.join(RESOURCES_PATH, 'zips/api'), zipDir: path.join(RESOURCES_PATH, 'zips/api'),
logLevel: _dgeniLogLevel logLevel: _dgeniLogLevel
@ -89,15 +91,12 @@ var _excludeMatchers = _excludePatterns.map(function(excludePattern){
var _exampleBoilerplateFiles = [ var _exampleBoilerplateFiles = [
'.editorconfig', '.editorconfig',
'a2docs.css', 'a2docs.css',
'karma.conf.js',
'karma-test-shim.js',
'package.json', 'package.json',
'styles.css', 'styles.css',
'systemjs.config.js', 'systemjs.config.js',
'tsconfig.json', 'tsconfig.json',
'tslint.json', 'tslint.json',
'typings.json', 'typings.json'
'wallaby.js'
]; ];
var _exampleDartWebBoilerPlateFiles = ['a2docs.css', 'styles.css']; var _exampleDartWebBoilerPlateFiles = ['a2docs.css', 'styles.css'];
@ -118,22 +117,35 @@ var _styleLessName = 'a2docs.less';
// or a regex pattern to match any one of 'ts', 'js', or 'dart'. // 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), // Default: 'ts|js' except for the "full site build" tasks (see below),
// for which it is 'all'. // for which it is 'all'.
//
var lang, langs, buildDartApiDocs = false; // langs and skipLangs partition ['ts', 'js', 'dart'].
var lang, langs, skipLangs, buildDartApiDocs = false;
function configLangs(langOption) { function configLangs(langOption) {
const fullSiteBuildTasks = ['build-compile', 'check-serve', 'check-deploy']; const fullSiteBuildTasks = ['build-compile', 'check-deploy', 'harp-compile'];
const buildAllDocs = argv['_'] && const buildAllDocs = argv['_'] &&
fullSiteBuildTasks.some((task) => argv['_'].indexOf(task) >= 0); fullSiteBuildTasks.some((task) => argv['_'].indexOf(task) >= 0);
const langDefault = buildAllDocs ? 'all' : 'ts|js'; const langDefault = buildAllDocs ? 'all' : 'ts|js';
if (langOption === '') {
lang = '';
langs = [];
} else {
lang = (langOption || langDefault).toLowerCase(); lang = (langOption || langDefault).toLowerCase();
if (lang === 'all') lang = 'ts|js|dart'; if (lang === 'all') lang = 'ts|js|dart';
langs = lang.match(/\w+/g); // the languages in `lang` as an array langs = lang.match(/\w+/g); // the languages in `lang` as an array
gutil.log('Building docs for: ' + lang); }
gutil.log(`Building docs for: [${langs}]`);
if (langs.indexOf('dart') >= 0) { if (langs.indexOf('dart') >= 0) {
buildDartApiDocs = true; buildDartApiDocs = true;
// For Dart, be proactive about checking for the repo // For Dart, be proactive about checking for the repo
checkAngularProjectPath(ngPathFor('dart')); 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); configLangs(argv.lang);
@ -344,10 +356,15 @@ function runE2eDartTests(appDir, outputFile) {
gutil.log('http-server failed to launch over ' + deployDir); gutil.log('http-server failed to launch over ' + deployDir);
return false; 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 pubUpgradeSpawnInfo = spawnExt('pub', ['upgrade'], { cwd: appDir });
var prepPromise = pubUpgradeSpawnInfo.promise.then(function (data) { var prepPromise = pubUpgradeSpawnInfo.promise.then(function (data) {
return spawnExt('pub', ['build'], { cwd: appDir }).promise; return spawnExt('pub', ['build'], { cwd: appDir }).promise;
}); });
}
return runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile); return runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile);
} }
@ -441,10 +458,10 @@ gulp.task('add-example-boilerplate', function(done) {
// copies boilerplate files to locations // copies boilerplate files to locations
// where an example app is found // where an example app is found
gulp.task('_copy-example-boilerplate', function (done) { gulp.task('_copy-example-boilerplate', function (done) {
if (!argv.fast) buildStyles(copyExampleBoilerplate, done); return argv.fast ? done() : buildStyles(copyExampleBoilerplate, done);
}); });
//Builds Angular 2 Docs CSS file from Bootstrap npm LESS source //Builds Angular Docs CSS file from Bootstrap npm LESS source
//and copies the result to the _examples folder to be included as //and copies the result to the _examples folder to be included as
//part of the example boilerplate. //part of the example boilerplate.
function buildStyles(cb, done){ function buildStyles(cb, done){
@ -504,23 +521,42 @@ gulp.task('remove-example-boilerplate', function() {
// either release or current build packages // either release or current build packages
// Examples: // Examples:
// gulp install-example-angular --build // use current build packages // 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 // gulp install-example-angular // restore release packages
//
// Find the tags here: https://github.com/angular/core-builds/releases
gulp.task('install-example-angular', installExampleAngular); gulp.task('install-example-angular', installExampleAngular);
function installExampleAngular() { function installExampleAngular() {
var sources; var sources;
var template; var template;
var libs = [ var libs = [
'core', 'common', 'compiler', 'core', 'common', 'compiler', 'compiler-cli',
'platform-browser', 'platform-browser-dynamic', 'platform-browser', 'platform-browser-dynamic',
'forms', 'http', 'router', 'upgrade']; '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" // Like: "angular/core-builds" or "@angular/core"
sources = libs.map( lib => argv.build ? `angular/${lib}-builds` : `@angular/${lib}`); 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('@angular/router-deprecated'); sources.push('@angular/router-deprecated');
gutil.log(`Installing Angular npm packages from ${argv.build ? 'BUILD' : 'RELEASE'}`); gutil.log(`Installing Angular packages from ${build === 'npm' ? 'NPM' : 'BUILD ' + build}`);
var spawnInfo = spawnExt('rm', ['-rf', 'node_modules/@angular'], { cwd: EXAMPLES_PATH}); var spawnInfo = spawnExt('rm', ['-rf', 'node_modules/@angular'], { cwd: EXAMPLES_PATH});
return spawnInfo.promise return spawnInfo.promise
@ -594,8 +630,10 @@ gulp.task('build-dart-api-docs', ['_shred-api-examples', 'dartdoc'], function()
return buildApiDocsForDart(); return buildApiDocsForDart();
}); });
// Using the --build flag will use systemjs.config.plunker.build.js (for preview builds)
gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() { gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() {
return plunkerBuilder.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build }); 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('build-dart-cheatsheet', [], function() { gulp.task('build-dart-cheatsheet', [], function() {
@ -604,20 +642,20 @@ gulp.task('build-dart-cheatsheet', [], function() {
gulp.task('dartdoc', ['pub upgrade'], function() { gulp.task('dartdoc', ['pub upgrade'], function() {
const ngRepoPath = ngPathFor('dart'); const ngRepoPath = ngPathFor('dart');
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'doc'))) { if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, relDartDocApiDir))) {
gutil.log('Skipping dartdoc: --fast flag enabled and "doc" dir exists'); gutil.log(`Skipping dartdoc: --fast flag enabled and api dir exists (${relDartDocApiDir})`);
return true; return true;
} }
checkAngularProjectPath(ngRepoPath); checkAngularProjectPath(ngRepoPath);
const topLevelLibFilePath = path.resolve(ngRepoPath, 'lib', 'angular2.dart'); const topLevelLibFilePath = path.resolve(ngRepoPath, 'lib', 'angular2.dart');
const tmpPath = topLevelLibFilePath + '.disabled'; const tmpPath = topLevelLibFilePath + '.disabled';
if (!fs.existsSync(topLevelLibFilePath)) throw new Error(`Missing file: ${topLevelLibFilePath}`); renameIfExistsSync(topLevelLibFilePath, tmpPath);
fs.renameSync(topLevelLibFilePath, tmpPath);
gutil.log(`Hiding top-level angular2 library: ${topLevelLibFilePath}`); gutil.log(`Hiding top-level angular2 library: ${topLevelLibFilePath}`);
const dartdoc = spawnExt('dartdoc', ['--output', 'doc/api', '--add-crossdart'], { cwd: ngRepoPath}); // Remove dartdoc '--add-crossdart' flag while we are fixing links to API pages.
const dartdoc = spawnExt('dartdoc', ['--output', relDartDocApiDir], { cwd: ngRepoPath});
return dartdoc.promise.finally(() => { return dartdoc.promise.finally(() => {
gutil.log(`Restoring top-level angular2 library: ${topLevelLibFilePath}`); gutil.log(`Restoring top-level angular2 library: ${topLevelLibFilePath}`);
fs.renameSync(tmpPath, topLevelLibFilePath); renameIfExistsSync(tmpPath, topLevelLibFilePath);
}) })
}); });
@ -678,12 +716,12 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
}); });
}); });
gulp.task('harp-compile', [], function() { gulp.task('harp-compile', () => {
return harpCompile() return harpCompile()
}); });
gulp.task('serve', [], function() { gulp.task('harp-serve', () => {
// Harp will serve files from workspace. // Harp will watch and serve workspace files.
const cmd = 'npm run harp -- server .'; const cmd = 'npm run harp -- server .';
gutil.log('Launching harp server (over project files)'); gutil.log('Launching harp server (over project files)');
gutil.log(` > ${cmd}`); gutil.log(` > ${cmd}`);
@ -691,7 +729,7 @@ gulp.task('serve', [], function() {
return execPromise(cmd); return execPromise(cmd);
}); });
gulp.task('serve-www', [], function() { gulp.task('serve-www', () => {
// Serve generated site. // Serve generated site.
return execPromise('npm run live-server ./www'); return execPromise('npm run live-server ./www');
}); });
@ -700,13 +738,6 @@ gulp.task('build-compile', ['build-docs'], function() {
return harpCompile(); return harpCompile();
}); });
gulp.task('check-serve', ['build-docs'], function() {
return harpCompile().then(function() {
gutil.log('Launching live-server over ./www');
return execPromise('npm run live-server ./www');
});
});
gulp.task('check-deploy', ['build-docs'], function() { gulp.task('check-deploy', ['build-docs'], function() {
return harpCompile().then(function() { return harpCompile().then(function() {
gutil.log('compile ok'); gutil.log('compile ok');
@ -802,7 +833,7 @@ gulp.task('_shred-clean-devguide', function(cb) {
gulp.task('_shred-api-examples', ['_shred-clean-api'], function() { gulp.task('_shred-api-examples', ['_shred-clean-api'], function() {
const promises = []; const promises = [];
gutil.log('Shredding API examples for languages: ' + langs.join(', ')); gutil.log('Shredding API examples for languages: ' + langs.join(', '));
langs.forEach((lang) => { langs.forEach(lang => {
if (lang === 'js') return; // JS is handled via TS. if (lang === 'js') return; // JS is handled via TS.
checkAngularProjectPath(ngPathFor(lang)); checkAngularProjectPath(ngPathFor(lang));
const options = lang == 'dart' ? _apiShredOptionsForDart : _apiShredOptions; const options = lang == 'dart' ? _apiShredOptionsForDart : _apiShredOptions;
@ -852,26 +883,40 @@ gulp.task('lint', function() {
function harpCompile() { function harpCompile() {
// Supposedly running in production makes harp faster // Supposedly running in production makes harp faster
// and less likely to drown in node_modules. // and less likely to drown in node_modules.
env({ env({ vars: { NODE_ENV: "production" } });
vars: { NODE_ENV: "production" }
});
gutil.log("NODE_ENV: " + process.env.NODE_ENV); gutil.log("NODE_ENV: " + process.env.NODE_ENV);
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.`)
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(); var deferred = Q.defer();
gutil.log('running harp compile...'); gutil.log('running harp compile...');
showHideExampleNodeModules('hide'); showHideExampleNodeModules('hide');
showHideApiDir('hide');
var spawnInfo = spawnExt('npm',['run','harp', '--', 'compile', '.', './www' ]); var spawnInfo = spawnExt('npm',['run','harp', '--', 'compile', '.', './www' ]);
spawnInfo.promise.then(function(x) { spawnInfo.promise.then(function(x) {
gutil.log("NODE_ENV: " + process.env.NODE_ENV); gutil.log("NODE_ENV: " + process.env.NODE_ENV);
showHideExampleNodeModules('show'); showHideExampleNodeModules('show');
showHideApiDir('show');
if (x !== 0) { if (x !== 0) {
deferred.reject(x) deferred.reject(x)
} else { } else {
restoreApiHtml();
deferred.resolve(x); deferred.resolve(x);
} }
}).catch(function(e) { }).catch(function(e) {
gutil.log("NODE_ENV: " + process.env.NODE_ENV); gutil.log("NODE_ENV: " + process.env.NODE_ENV);
showHideExampleNodeModules('show'); showHideExampleNodeModules('show');
showHideApiDir('show');
deferred.reject(e); deferred.reject(e);
}); });
return deferred.promise; return deferred.promise;
@ -970,6 +1015,54 @@ 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 wwwApiSubdir = path.join('www', relApiDir);
const backupApiSubdir = path.join('www-backup', relApiDir);
if (fs.existsSync(backupApiSubdir) || argv.forceSkipApi !== true) {
gutil.log(`cp ${backupApiSubdir} ${wwwApiSubdir}`)
fs.copySync(backupApiSubdir, wwwApiSubdir);
}
});
}
// For each lang in skipLangs, ensure API dir exists in www-backup
function backupApiHtmlFilesExist(folderName) {
const vers = 'latest';
var result = 1;
skipLangs.forEach(lang => {
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;
}
// Copies fileNames into destPaths, setting the mode of the // Copies fileNames into destPaths, setting the mode of the
// files at the destination as optional_destFileMode if given. // files at the destination as optional_destFileMode if given.
// returns a promise // returns a promise
@ -1069,11 +1162,16 @@ function watchAndSync(options, cb) {
var browserSync = require('browser-sync').create(); var browserSync = require('browser-sync').create();
browserSync.init({proxy: 'localhost:9000'}); 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) { if (options.devGuide) {
devGuideExamplesWatch(_devguideShredOptions, browserSync.reload); devGuideExamplesWatch(_devguideShredOptions, browserSync.reload, focus);
} }
if (options.devGuideJade) { if (options.devGuideJade) {
devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload); devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload, focus);
} }
if (options.apiDocs) { if (options.apiDocs) {
apiSourceWatch(browserSync.reload); apiSourceWatch(browserSync.reload);
@ -1088,11 +1186,10 @@ function watchAndSync(options, cb) {
// returns a promise; // returns a promise;
function askDeploy() { function askDeploy() {
prompt.start(); prompt.start();
var schema = { var schema = {
name: 'shouldDeploy', name: 'shouldDeploy',
description: 'Deploy to Firebase? (y/n): ', description: 'Deploy to Firebase? (y/n)',
type: 'string', type: 'string',
pattern: /Y|N|y|n/, pattern: /Y|N|y|n/,
message: "Respond with either a 'y' or 'n'", message: "Respond with either a 'y' or 'n'",
@ -1114,7 +1211,7 @@ function filterOutExcludedPatterns(fileNames, excludeMatchers) {
} }
function apiSourceWatch(postBuildAction) { function apiSourceWatch(postBuildAction) {
var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/src/**/*.*')]; var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/**/*.*')];
gulp.watch(srcPattern, {readDelay: 500}, function (event, done) { gulp.watch(srcPattern, {readDelay: 500}, function (event, done) {
gutil.log('API source changed'); gutil.log('API source changed');
gutil.log('Event type: ' + event.event); // added, changed, or deleted gutil.log('Event type: ' + event.event); // added, changed, or deleted
@ -1141,8 +1238,9 @@ function apiExamplesWatch(postShredAction) {
}); });
} }
function devGuideExamplesWatch(shredOptions, postShredAction) { function devGuideExamplesWatch(shredOptions, postShredAction, focus) {
var includePattern = path.join(shredOptions.examplesDir, '**/*.*'); var watchPattern = focus ? '**/' + focus + '/**/*.*' : '**/*.*';
var includePattern = path.join(shredOptions.examplesDir, watchPattern);
// removed this version because gulp.watch has the same glob issue that dgeni has. // removed this version because gulp.watch has the same glob issue that dgeni has.
// var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*'); // var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*');
// gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) { // gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
@ -1158,8 +1256,9 @@ function devGuideExamplesWatch(shredOptions, postShredAction) {
}); });
} }
function devGuideSharedJadeWatch(shredOptions, postShredAction) { function devGuideSharedJadeWatch(shredOptions, postShredAction, focus) {
var includePattern = path.join(DOCS_PATH, '**/*.jade'); 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. // removed this version because gulp.watch has the same glob issue that dgeni has.
// var excludePattern = '!' + path.join(shredOptions.jadeDir, '**/node_modules/**/*.*'); // var excludePattern = '!' + path.join(shredOptions.jadeDir, '**/node_modules/**/*.*');
// gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) { // gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
@ -1235,15 +1334,14 @@ function buildDartCheatsheet() {
function buildApiDocsForDart() { function buildApiDocsForDart() {
const apiDir = 'api';
const vers = 'latest'; const vers = 'latest';
const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH); const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH);
const log = dab.log; const log = dab.log;
log.level = _dgeniLogLevel; log.level = _dgeniLogLevel;
const dabInfo = dab.dartPkgConfigInfo; const dabInfo = dab.dartPkgConfigInfo;
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, apiDir); dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, 'api');
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'doc', apiDir); dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), relDartDocApiDir);
// Exclude API entries for developer/internal libraries. Also exclude entries for // Exclude API entries for developer/internal libraries. Also exclude entries for
// the top-level catch all "angular2" library (otherwise every entry appears twice). // the top-level catch all "angular2" library (otherwise every entry appears twice).
dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|\.testing|_|codegen|^angular2$/); dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|\.testing|_|codegen|^angular2$/);
@ -1455,3 +1553,12 @@ function checkAngularProjectPath(_ngPath) {
if (fs.existsSync(ngPath)) return; if (fs.existsSync(ngPath)) return;
throw new Error('API related tasks require the angular2 repo to be at ' + ngPath); 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}`);
}
}

View File

@ -85,7 +85,7 @@
"picture": "/resources/images/bios/tobias.jpg", "picture": "/resources/images/bios/tobias.jpg",
"twitter": "tbosch1009", "twitter": "tbosch1009",
"website": "https://plus.google.com/+TobiasBosch", "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.", "bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular.",
"type": "Google" "type": "Google"
}, },
@ -184,7 +184,7 @@
"picture": "/resources/images/bios/hansl.jpg", "picture": "/resources/images/bios/hansl.jpg",
"twitter": "hanslatwork", "twitter": "hanslatwork",
"website": "http://www.codingatwork.com/", "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 Angular2, using Material Design components and the CLI tool.", "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" "type": "Google"
}, },
@ -316,6 +316,12 @@
"bio": "Max Sills is Angular's Open Source lawyer.", "bio": "Max Sills is Angular's Open Source lawyer.",
"type": "Google" "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": { "pawel": {
"name": "Pawel Kozlowski", "name": "Pawel Kozlowski",
@ -354,7 +360,7 @@
"picture": "/resources/images/bios/marclaval.jpg", "picture": "/resources/images/bios/marclaval.jpg",
"twitter": "marclaval", "twitter": "marclaval",
"website": "https://github.com/mlaval", "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" "type": "Community"
}, },
@ -372,7 +378,7 @@
"picture": "/resources/images/bios/patrick-stapleton.jpg", "picture": "/resources/images/bios/patrick-stapleton.jpg",
"twitter": "gdi2290", "twitter": "gdi2290",
"website": "https://angularclass.com", "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.", "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 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" "type": "Community"
}, },
@ -391,6 +397,7 @@
"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.", "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" "type": "Community"
}, },
"johnpapa": { "johnpapa": {
"name": "John Papa", "name": "John Papa",
"picture": "/resources/images/bios/john-papa.jpg", "picture": "/resources/images/bios/john-papa.jpg",
@ -399,6 +406,7 @@
"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.", "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" "type": "Community"
}, },
"martinstaffa": { "martinstaffa": {
"name": "Martin Staffa", "name": "Martin Staffa",
"picture": "/resources/images/bios/martinstaffa.jpg", "picture": "/resources/images/bios/martinstaffa.jpg",
@ -406,6 +414,7 @@
"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 Angular 1 team since 2014. If you can't find him roaming the Github issue queues, he's probably out with his camera somewhere.",
"type": "Community" "type": "Community"
}, },
"topherfangio": { "topherfangio": {
"name": "Topher Fangio", "name": "Topher Fangio",
"picture": "/resources/images/bios/topherfangio.jpg", "picture": "/resources/images/bios/topherfangio.jpg",
@ -414,6 +423,7 @@
"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.", "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" "type": "Community"
}, },
"filipesilva": { "filipesilva": {
"name": "Filipe Silva", "name": "Filipe Silva",
"picture": "/resources/images/bios/filipe-silva.jpg", "picture": "/resources/images/bios/filipe-silva.jpg",
@ -422,6 +432,7 @@
"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.", "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" "type": "Community"
}, },
"teropa": { "teropa": {
"name": "Tero Parviainen", "name": "Tero Parviainen",
"picture": "/resources/images/bios/teropa.jpg", "picture": "/resources/images/bios/teropa.jpg",
@ -430,6 +441,7 @@
"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.", "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" "type": "Community"
}, },
"deborah": { "deborah": {
"name": "Deborah Kurata", "name": "Deborah Kurata",
"picture": "/resources/images/bios/deborah.jpg", "picture": "/resources/images/bios/deborah.jpg",
@ -438,6 +450,7 @@
"bio": "Deborah is an independent software developer and author. She is author of several Pluralsight courses including: 'Angular 2: Getting Started'", "bio": "Deborah is an independent software developer and author. She is author of several Pluralsight courses including: 'Angular 2: Getting Started'",
"type": "Community" "type": "Community"
}, },
"jesusrodriguez": { "jesusrodriguez": {
"name": "Jesús Rodríguez", "name": "Jesús Rodríguez",
"picture": "/resources/images/bios/jesus-rodriguez.jpg", "picture": "/resources/images/bios/jesus-rodriguez.jpg",
@ -446,6 +459,7 @@
"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.", "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" "type": "Community"
}, },
"torgeirhelgevold": { "torgeirhelgevold": {
"name": "Torgeir Helgevold", "name": "Torgeir Helgevold",
"picture": "/resources/images/bios/torgeirhelgevold.jpg", "picture": "/resources/images/bios/torgeirhelgevold.jpg",
@ -454,6 +468,7 @@
"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.", "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" "type": "Community"
}, },
"fatimaremtullah": { "fatimaremtullah": {
"name": "Fatima Remtullah", "name": "Fatima Remtullah",
"picture": "/resources/images/bios/fatima.jpg", "picture": "/resources/images/bios/fatima.jpg",
@ -462,6 +477,7 @@
"bio": "Fatima is a Product Designer and Front-End Developer. When she is not nerding out she is probably eating an abundance of cookies.", "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" "type": "Community"
}, },
"eric": { "eric": {
"name": "Eric Jimenez", "name": "Eric Jimenez",
"picture": "/resources/images/bios/eric.jpg", "picture": "/resources/images/bios/eric.jpg",
@ -470,6 +486,7 @@
"bio": "Eric is a gamer, writer, and programmer.", "bio": "Eric is a gamer, writer, and programmer.",
"type": "Community" "type": "Community"
}, },
"mikeryan": { "mikeryan": {
"name": "Mike Ryan", "name": "Mike Ryan",
"picture": "/resources/images/bios/mikeryan.jpg", "picture": "/resources/images/bios/mikeryan.jpg",
@ -478,6 +495,7 @@
"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.", "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" "type": "Community"
}, },
"rex": { "rex": {
"name": "Rex Ye", "name": "Rex Ye",
"picture": "/resources/images/bios/rex.jpg", "picture": "/resources/images/bios/rex.jpg",
@ -485,6 +503,7 @@
"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.", "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" "type": "Community"
}, },
"ralph": { "ralph": {
"name": "Ralph Wang", "name": "Ralph Wang",
"picture": "/resources/images/bios/ralph.jpg", "picture": "/resources/images/bios/ralph.jpg",
@ -492,6 +511,7 @@
"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.", "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" "type": "Community"
}, },
"brandonroberts": { "brandonroberts": {
"name": "Brandon Roberts", "name": "Brandon Roberts",
"picture": "/resources/images/bios/brandonroberts.jpg", "picture": "/resources/images/bios/brandonroberts.jpg",
@ -500,12 +520,28 @@
"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.", "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" "type": "Community"
}, },
"crisbeto": { "crisbeto": {
"name": "Kristiyan Kostadinov", "name": "Kristiyan Kostadinov",
"picture": "/resources/images/bios/crisbeto.jpg", "picture": "/resources/images/bios/crisbeto.jpg",
"website": "http://crisbeto.com/", "website": "http://crisbeto.com/",
"bio": "Kristiyan is a front-end developer, passionate open-source contributor and a core team member on Angular Material.", "bio": "Kristiyan is a front-end developer, passionate open-source contributor and a core team member on Angular Material.",
"type": "Community" "type": "Community"
},
"gkalpak": {
"name": "Georgios Kalpakas",
"picture": "/resources/images/bios/gkalpak.jpg",
"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",
"bio": "Kapunahele is a front-end developer at Capital One. 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"
} }
} }
} }

View File

@ -2,7 +2,7 @@
"name": "angular.io", "name": "angular.io",
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"description": "Angular 2 documentation", "description": "Angular documentation",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
@ -36,20 +36,19 @@
"cross-spawn": "^4.0.0", "cross-spawn": "^4.0.0",
"del": "^2.2.0", "del": "^2.2.0",
"dgeni": "^0.4.0", "dgeni": "^0.4.0",
"dgeni-packages": "^0.13.1", "dgeni-packages": "^0.16.0",
"diff": "^2.1.3", "diff": "^2.1.3",
"fs-extra": "^0.30.0", "fs-extra": "^0.30.0",
"globby": "^4.0.0", "globby": "^4.0.0",
"grunt-sass": "^1.2.0",
"gulp": "^3.5.6", "gulp": "^3.5.6",
"gulp-env": "0.4.0", "gulp-env": "0.4.0",
"gulp-sass": "^2.3.2",
"gulp-less": "^3.1.0", "gulp-less": "^3.1.0",
"gulp-sass": "^2.3.2",
"gulp-task-listing": "^1.0.1", "gulp-task-listing": "^1.0.1",
"gulp-tslint": "^5.0.0", "gulp-tslint": "^5.0.0",
"gulp-util": "^3.0.6", "gulp-util": "^3.0.6",
"gulp-watch": "^4.3.4", "gulp-watch": "^4.3.4",
"harp": "^0.20.3", "harp": "0.21.0-pre.1",
"html2jade": "^0.8.4", "html2jade": "^0.8.4",
"indent-string": "^2.1.0", "indent-string": "^2.1.0",
"jasmine-core": "^2.3.4", "jasmine-core": "^2.3.4",
@ -71,7 +70,7 @@
"protractor": "^3.0.0", "protractor": "^3.0.0",
"q": "^1.4.1", "q": "^1.4.1",
"tree-kill": "^1.0.0", "tree-kill": "^1.0.0",
"tslint": "^3.2.2", "tslint": "^3.15.1",
"yargs": "^4.7.1" "yargs": "^4.7.1"
}, },
"dependencies": { "dependencies": {

View File

@ -2,7 +2,7 @@
"index": { "index": {
"hero": "home", "hero": "home",
"title": "One framework.", "title": "One framework.",
"subtitle": "Mobile and desktop." "subtitle": "Mobile & desktop."
}, },
"features": { "features": {

View File

@ -8,7 +8,7 @@ else
- var styleguide = "/docs/ts/latest/styleguide.html" - var styleguide = "/docs/ts/latest/styleguide.html"
.main-footer .main-footer
nav.background-blue-grey-900.grid-fluid nav.background-midnight.grid-fluid
.c3.main-footer-branding .c3.main-footer-branding
.logo-inverse-large .logo-inverse-large
@ -17,7 +17,7 @@ else
h3.text-headline RESOURCES h3.text-headline RESOURCES
ul.text-body ul.text-body
// TODO: (ericjim) make a libraries page to showcase all angular 2 libraries // TODO: (ericjim) make a libraries page to showcase all angular libraries
//li <a href="/libraries.html">Libraries</a> //li <a href="/libraries.html">Libraries</a>
li <a href="/about/">About</a> li <a href="/about/">About</a>
li <a href="/resources/">Books & Training</a> li <a href="/resources/">Books & Training</a>
@ -51,7 +51,7 @@ else
ul.text-body ul.text-body
li <a href="https://angular.cn/">中文版</a> li <a href="https://angular.cn/">中文版</a>
footer(class="background-steel") footer(class="background-midnight")
small.text-caption Powered by Google ©2010-2016. Code licensed under an <a href="/license" class="text-snow">MIT-style License</a>. Documentation licensed under <a class="text-snow" href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>. small.text-caption Powered by Google ©2010-2016. Code licensed under an <a href="/license">MIT-style License</a>. Documentation licensed under <a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
a(aria-label="View Style Guide" href=styleguide title="Style Guide" class="styleguide-trigger text-snow") a(aria-label="View Style Guide" href=styleguide title="Style Guide" class="styleguide-trigger")
span.icon-favorite span.icon-favorite

View File

@ -12,7 +12,7 @@ if title == "Angular"
else if language else if language
title #{title} - #{language} title #{title} - #{language}
else else
title #{title} - Angular 2 title #{title} - Angular
meta(charset="utf-8") meta(charset="utf-8")
meta(http-equiv="X-UA-Compatible" content="IE=edge") meta(http-equiv="X-UA-Compatible" content="IE=edge")
@ -22,14 +22,14 @@ meta(name="robots" content="all")
meta(name="referrer" content="origin") meta(name="referrer" content="origin")
meta(name="viewport" id="viewport" content="width=device-width, initial-scale=1") 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" content="/resources/images/logos/standard/shield-large.png")
meta(property="og:image:type" content="image/png") meta(property="og:image:type" content="image/png")
meta(property="og:image:width" content="184") meta(property="og:image:width" content="184")
meta(property="og:image:height" content="200") meta(property="og:image:height" content="200")
meta(property="og:description" content="#{description}") meta(property="og:description" content="#{description}")
meta(itemprop="name" content="Angular 2") meta(itemprop="name" content="Angular")
meta(itemprop="description" content="#{description}") meta(itemprop="description" content="#{description}")
meta(itemprop="image" content="https://angular.io/resources/images/logos/standard/shield-large.png") meta(itemprop="image" content="https://angular.io/resources/images/logos/standard/shield-large.png")

View File

@ -1,13 +1,18 @@
header(class="background-sky") header(class="background-sky l-relative")
.hero.background-superhero-paper.is-large .hero.background-superhero-paper.is-large
h1.text-headline.hero-logo #{title}<br>#{subtitle} img(class="hero-logo" src='/resources/images/logos/angular2/angular.svg')
h1.text-headline #{title}<br>#{subtitle}
a(href="/docs/ts/latest/quickstart.html" class="hero-cta md-raised button button-large button-plain" md-button) Get Started
.hero-cta
a(href="/docs/ts/latest/quickstart.html" class="md-raised button button-large button-plain" md-button) Get Started
.banner.banner-floaty announcement-bar
.banner-ng-annoucement .announcement-bar-slide.clearfix
div(class="banner-text" align="center") img(src="/resources/images/logos/angular2/angular-logo-banner.png")
p Join us for AngularConnect in London, UK this September! p Angular 2.0 Final Release Now Live!
div(class="banner-button") a(href="http://angularjs.blogspot.com/2016/09/angular2-final.html" target="_blank" class="button " + "md-button") Learn More
a(href="http://angularconnect.com/?utm_source=angular&utm_medium=banner&utm_campaign=angular-banner" target="_blank" class="button md-button") Register now
.announcement-bar-slide.clearfix
img(src="/resources/images/logos/ng-europe/ng-europe-logo.png")
p Join us for <strong>ng-europe in Paris</strong>, France this October!
a(href="https://ngeurope.org/?utm_source=angular&utm_medium=banner&utm_campaign=angular-banner" target="_blank" class="button md-button") Register now

View File

@ -13,27 +13,27 @@
if current.path[4] && current.path[3] == 'api' if current.path[4] && current.path[3] == 'api'
- var textFormat = 'is-standard-case' - var textFormat = 'is-standard-case'
header(class="hero background-sky", style=fixHeroCss ? "height:auto" : "") header.hero.background-sky
div(class="inner-header") h1(class="hero-title #{textFormat}") #{headerTitle}
h1(class="hero-title text-display-1 #{textFormat}") #{headerTitle}
if useBadges if useBadges
span(class="badges")
if docType
span(class="status-badge").
#{renamer(capitalize(docType))}
if stability if stability
span(layout="row" class="status-badge") span(class="badge is-#{stability}").
// badge circle is filled based on stability by matching a css selector in _hero.scss #{capitalize(stability)}
span(class="status-circle status-#{stability}")
span Stability: #{capitalize(stability)}
if security if security
span(class="status-badge security-risk-badge"). span(class="badge is-deprecated").
Security Risk Security Risk
if subtitle //CLEAR FLOAT ELEMENTS
h2.hero-subtitle.text-subhead #{subtitle} .clear
else if current.path[3] == 'api' && current.path[1] == 'dart' if 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 block breadcrumbs
else if current.path[0] == "docs"
!= partial("_version-dropdown")

View File

@ -1,8 +1,7 @@
- var language = current.path[1] || 'ts' - var language = current.path[1] || 'ts'
- if (language !== 'ts' || language !== 'js' || language !== 'dart') { language = 'ts'; } - if (language !== 'ts' || language !== 'js' || language !== 'dart') { language = 'ts'; }
md-toolbar(class="main-nav background-regal l-pinned-top l-layer-5",scroll-y-offset-element) nav(class="main-nav l-pinned-top l-layer-5", scroll-y-offset-element)
nav
h1 <a href="/" md-button>Angular <sup>by Google</sup></a> h1 <a href="/" md-button>Angular <sup>by Google</sup></a>
button(class="main-nav-button main-nav-mobile-trigger l-right" aria-label="View Menu" ng-click="appCtrl.toggleMainMenu($event)" md-button) Site Menu <span class="icon icon-arrow-drop-down"></span> button(class="main-nav-button main-nav-mobile-trigger l-right" aria-label="View Menu" ng-click="appCtrl.toggleMainMenu($event)" md-button) Site Menu <span class="icon icon-arrow-drop-down"></span>

View File

@ -28,6 +28,7 @@ script(src="/resources/js/directives/cheatsheet.js")
script(src="/resources/js/directives/api-list.js") script(src="/resources/js/directives/api-list.js")
script(src="/resources/js/directives/bio.js") script(src="/resources/js/directives/bio.js")
script(src="/resources/js/directives/bold.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/code.js")
script(src="/resources/js/directives/copy.js") script(src="/resources/js/directives/copy.js")
script(src="/resources/js/directives/code-tabs.js") script(src="/resources/js/directives/code-tabs.js")

View File

@ -38,6 +38,15 @@
//- Location of sample code //- Location of sample code
- var _liveLink = 'live link'; - var _liveLink = 'live link';
//- NgModule related
- var _AppModuleVsAppComp = 'AppModule'
- var _appModuleTsVsAppCompTs = 'app/app.module.ts'
- var _appModuleTsVsMainTs = 'app/app.module.ts'
- var _bootstrapModule = 'bootstrapModule'
- var _moduleVsComp = 'module'
- var _moduleVsRootComp = 'module'
- var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic'
//- Other //- Other
- var _truthy = 'truthy'; - var _truthy = 'truthy';
- var _falsey = 'falsey'; - var _falsey = 'falsey';
@ -74,12 +83,12 @@ mixin makeExample(_filePath, region, _title, stylePatterns)
- var format = attributes.format || defaultFormat; - var format = attributes.format || defaultFormat;
- if (attributes.format === '.') format = ''; - if (attributes.format === '.') format = '';
- var avoid = !!attributes.avoid; - var avoid = !!attributes.avoid;
- var avoidClass = avoid ? 'is-anti-pattern' : '';
div(class="code-example #{avoidClass}")
if (title) if (title)
if (avoid) header
.example-title.avoid AVOID: #{title} h4 #{title}
else
.example-title #{title}
code-example(language="#{language}" format="#{format}") code-example(language="#{language}" format="#{format}")
!= styleString(frag, stylePatterns) != styleString(frag, stylePatterns)
@ -89,14 +98,14 @@ mixin makeExample(_filePath, region, _title, stylePatterns)
//- ending is given or is just (), then the title will be suffixed with //- ending is given or is just (), then the title will be suffixed with
//- either "(excerpt)", or "(#{_region})" when _region is defined. //- either "(excerpt)", or "(#{_region})" when _region is defined.
mixin makeExcerpt(_filePath, _region, _title, stylePatterns) mixin makeExcerpt(_filePath, _region, _title, stylePatterns)
- var matches = _filePath.match(/(.*)\s+\(([\w ]*)\)$/); - var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/);
- var parenText; - var parenText;
- if (matches) { _filePath = matches[1]; parenText = matches[2]; } - if (matches) { _filePath = matches[1]; parenText = matches[2]; }
- var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title}); - var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title});
- var filePath = adjustments.filePath; - var filePath = adjustments.filePath;
- var title = adjustments.title; - var title = adjustments.title;
- var region = _region || parenText; - var region = _region || (_region === '' ? '' : parenText);
- var excerpt = !region || parenText === '' ? 'excerpt' : parenText || region; - var excerpt = parenText || region || 'excerpt';
- if (title) title = title + ' (' + excerpt + ')'; - if (title) title = title + ' (' + excerpt + ')';
+makeExample(filePath, region, title, stylePatterns)(format='.') +makeExample(filePath, region, title, stylePatterns)(format='.')
@ -133,20 +142,21 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns)
- var json = unescapeHtml(frag); - var json = unescapeHtml(frag);
- var jsonExtract = extractJson(json, jsonConfig); - var jsonExtract = extractJson(json, jsonConfig);
- var avoid = !!attributes.avoid; - var avoid = !!attributes.avoid;
- var avoidClass = avoid ? 'is-anti-pattern' : '';
div(class="code-example #{avoidClass}")
if (title) if (title)
if (avoid) header
.example-title.avoid #{title} h4 #{title}
else
.example-title #{title}
code-example(language="#{language}" format="#{format}") code-example(language="#{language}" format="#{format}")
if (jsonExtract == 'ERROR') if (jsonExtract == 'ERROR')
err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}" err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}"
else else
!= styleString(jsonExtract, stylePatterns) != styleString(jsonExtract, stylePatterns)
- // Open (and close) an explanation <div>. See QuickStart if !jade2ng
script. //- Open (and close) an explanation <div>. See QuickStart
script.
function why(id, backTo) { function why(id, backTo) {
var id = "#"+id; var id = "#"+id;
var el = document.querySelector(id); var el = document.querySelector(id);
@ -158,7 +168,7 @@ script.
location.href = "#" + backTo; location.href = "#" + backTo;
} }
} }
script. script.
function verbose(isVerbose) { function verbose(isVerbose) {
isVerbose = !! isVerbose; isVerbose = !! isVerbose;
var el = document.querySelector('button.verbose.off'); var el = document.querySelector('button.verbose.off');
@ -170,7 +180,7 @@ script.
isVerbose ? 'block' : 'none'); isVerbose ? 'block' : 'none');
} }
script. script.
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){ function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
/* returns the value of the element style of the rule in the stylesheet /* returns the value of the element style of the rule in the stylesheet
* If no value is given, reads the value * If no value is given, reads the value
@ -203,6 +213,7 @@ script.
else else
return CCSstyle[style] = value return CCSstyle[style] = value
} }
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
//- Converts the given project-relative path (like 'app/main.ts') //- Converts the given project-relative path (like 'app/main.ts')
//- to a doc folder relative path (like 'quickstart/ts/app/main.ts') //- to a doc folder relative path (like 'quickstart/ts/app/main.ts')
@ -213,8 +224,8 @@ script.
- // E.g. of a project relative path is 'app/main.ts' - // E.g. of a project relative path is 'app/main.ts'
- if (ex.title === null || ex.title === undefined) { - if (ex.title === null || ex.title === undefined) {
- // Title is not given so take it to be ex.filePath. - // Title is not given so take it to be ex.filePath.
- // Is title like styles.1.css? Then drop the '.1' qualifier: - // Title like styles.1.css or foo_1.dart? Then drop the '.1' or '_1' qualifier:
- var matches = ex.filePath.match(/^(.*)\.\d(\.\w+)$/); - var matches = ex.filePath.match(/^(.*)[\._]\d(\.\w+)$/);
- ex.title = matches ? matches[1] + matches[2] : ex.filePath; - ex.title = matches ? matches[1] + matches[2] : ex.filePath;
- } - }
- ex.filePath = getExampleName() + '/' + _docsFor + '/' + ex.filePath; - ex.filePath = getExampleName() + '/' + _docsFor + '/' + ex.filePath;
@ -289,7 +300,7 @@ script.
- } else { - } else {
- // ``` gets translated to <pre><code>.....</code></pre> and we need - // ``` gets translated to <pre><code>.....</code></pre> and we need
- // to remove this from the fragment prefix is 11 long and suffix is 13 long - // to remove this from the fragment prefix is 11 long and suffix is 13 long
- frag = frag.substring(11, frag.length-13); - frag = jade2ng ? frag : frag.substring(11, frag.length-13);
- // Uncomment next line for debugging. - // Uncomment next line for debugging.
- // frag = "FileName: " + fullFileName + " Current path: " + current.path + " PathToDocs: " + getPathToDocs() + "\n" + frag; - // frag = "FileName: " + fullFileName + " Current path: " + current.path + " PathToDocs: " + getPathToDocs() + "\n" + frag;
- return frag; - return frag;

View File

@ -5,7 +5,7 @@
- var version = '' - var version = ''
- var page = '' - var page = ''
<!-- Replace _ underscores with . dots --> //- Replace _ underscores with . dots
if current.path[2] if current.path[2]
- var version = current.path[2].replace(/\_+/gm, ".") - var version = current.path[2].replace(/\_+/gm, ".")
@ -33,32 +33,31 @@ else if current.path[3]
else else
- var page = current.path[3] + '.html' - var page = current.path[3] + '.html'
<!-- VERSION TREE CREATOR MIXIN --> //- VERSION TREE CREATOR MIXIN
mixin tree(directory, urlPrefix, name, latest) mixin tree(directory, urlPrefix, name, latest)
ul
for val, semvar in directory for val, semvar in directory
if semvar !== '.git' && semvar !== '_data' if semvar !== '.git' && semvar !== '_data'
- var libVersion = (semvar == "latest") ? latest : semvar.replace(/\_+/gm, ".") - var libVersion = (semvar == "latest") ? latest : semvar.replace(/\_+/gm, ".")
li <a href="#{urlPrefix}/#{semvar}/#{page}" md-button>#{name} #{libVersion}</a> li <a href="#{urlPrefix}/#{semvar}/#{page}" md-button>#{name} #{libVersion}</a>
<!-- BUTTON TITLE GENERATION --> //- BUTTON TITLE GENERATION
if language == 'ts' if language == 'ts'
if version == "latest" if version == "latest"
- var title = 'Angular 2 for TypeScript' - var title = 'Angular for TypeScript'
else else
- var title = 'Angular ' + version + ' for TypeScript' - var title = 'Angular ' + version + ' for TypeScript'
if language == 'js' if language == 'js'
if version == "latest" if version == "latest"
- var title = 'Angular 2 for JavaScript' - var title = 'Angular for JavaScript'
else else
- var title = 'Angular ' + version + ' for JavaScript' - var title = 'Angular ' + version + ' for JavaScript'
if language == 'dart' if language == 'dart'
if version == "latest" if version == "latest"
- var title = 'Angular 2 for Dart' - var title = 'Angular for Dart'
else else
- var title = 'Angular ' + version + ' for Dart' - var title = 'Angular ' + version + ' for Dart'
@ -69,7 +68,9 @@ nav.dropdown
div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu") div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu")
<!-- DROPDOWN MENU --> <!-- DROPDOWN MENU -->
div(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''") ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''")
mixin tree(public.docs.ts, "/docs/ts", "Angular 2 for TypeScript") mixin tree(public.docs.ts, "/docs/ts", "Angular for TypeScript")
mixin tree(public.docs.js, "/docs/js", "Angular 2 for JavaScript") mixin tree(public.docs.js, "/docs/js", "Angular for JavaScript")
mixin tree(public.docs.dart, "/docs/dart", "Angular 2 for Dart") //- Disable cross-language link for API entry pages (but keep for top API search page):
if ! (current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]])
mixin tree(public.docs.dart, "/docs/dart", "Angular for Dart")

View File

@ -3,11 +3,11 @@
p We'd love for you to contribute to our source code and to make Angular projects even better. p We'd love for you to contribute to our source code and to make Angular projects even better.
.l-sub-section .l-sub-section
h3 Angular 2 h3 Angular
p Angular 2 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 .l-sub-section
h3 Angular for JavaScript or Dart h3 Angular for JavaScript or Dart

View File

@ -13,7 +13,9 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"protractor": "^3.3.0", "protractor": "^3.3.0",
"typings": "^1.0.4" "typings": "^1.0.4",
"ts-node": "^1.3.0",
"typescript": "^2.0.2"
}, },
"repository": {} "repository": {}
} }

View File

@ -26,7 +26,7 @@ exports.config = {
// Framework to use. Jasmine is recommended. // Framework to use. Jasmine is recommended.
framework: 'jasmine', framework: 'jasmine',
// For angular2 tests // For angular tests
useAllAngular2AppRoots: true, useAllAngular2AppRoots: true,
// Base URL for application server // Base URL for application server

View File

@ -4,7 +4,7 @@
* The tests here basically just checking that the end styles * The tests here basically just checking that the end styles
* of each animation are in effect. * of each animation are in effect.
* *
* Relies on the Angular 2 testability only becoming stable once * Relies on the Angular testability only becoming stable once
* animation(s) have finished. * animation(s) have finished.
* *
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations * Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
@ -289,6 +289,19 @@ describe('Animation Tests', () => {
}); });
}); });
describe('callbacks', () => {
it('fires a callback on start and done', () => {
addActiveHero();
browser.manage().logs().get('browser').then((logs) => {
const animationMessages = logs.filter((log) => {
return log.message.indexOf('Animation') !== -1 ? true : false;
});
expect(animationMessages.length).toBeGreaterThan(0);
});
});
});
function addActiveHero(sleep?: number) { function addActiveHero(sleep?: number) {
sleep = sleep || 500; sleep = sleep || 500;
element(by.buttonText('Add active hero')).click(); element(by.buttonText('Add active hero')).click();

View File

@ -17,7 +17,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@shrinkOut="'in'"> [@shrinkOut]="'in'">
{{hero.name}} {{hero.name}}
</li> </li>
</ul> </ul>

View File

@ -27,7 +27,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@heroState="hero.state" [@heroState]="hero.state"
(click)="hero.toggleState()"> (click)="hero.toggleState()">
{{hero.name}} {{hero.name}}
</li> </li>

View File

@ -20,7 +20,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@heroState="hero.state" [@heroState]="hero.state"
(click)="hero.toggleState()"> (click)="hero.toggleState()">
{{hero.name}} {{hero.name}}
</li> </li>

View File

@ -18,7 +18,7 @@ import { Heroes } from './hero.service';
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
(click)="hero.toggleState()" (click)="hero.toggleState()"
@heroState="hero.state"> [@heroState]="hero.state">
{{hero.name}} {{hero.name}}
</li> </li>
</ul> </ul>

View File

@ -17,7 +17,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@flyInOut="'in'"> [@flyInOut]="'in'">
{{hero.name}} {{hero.name}}
</li> </li>
</ul> </ul>

View File

@ -17,7 +17,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@flyInOut="'in'"> [@flyInOut]="'in'">
{{hero.name}} {{hero.name}}
</li> </li>
</ul> </ul>

View File

@ -19,7 +19,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@heroState="hero.state" [@heroState]="hero.state"
(click)="hero.toggleState()"> (click)="hero.toggleState()">
{{hero.name}} {{hero.name}}
</li> </li>

View File

@ -6,7 +6,8 @@ import {
style, style,
animate, animate,
transition, transition,
keyframes keyframes,
AnimationTransitionEvent
} from '@angular/core'; } from '@angular/core';
import { Heroes } from './hero.service'; import { Heroes } from './hero.service';
@ -14,14 +15,18 @@ import { Heroes } from './hero.service';
@Component({ @Component({
moduleId: module.id, moduleId: module.id,
selector: 'hero-list-multistep', selector: 'hero-list-multistep',
// #docregion template
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@flyInOut="'in'"> (@flyInOut.start)="animationStarted($event)"
(@flyInOut.done)="animationDone($event)"
[@flyInOut]="'in'">
{{hero.name}} {{hero.name}}
</li> </li>
</ul> </ul>
`, `,
// #enddocregion template
styleUrls: ['hero-list.component.css'], styleUrls: ['hero-list.component.css'],
/* The element here always has the state "in" when it /* The element here always has the state "in" when it
* is present. We animate two transitions: From void * is present. We animate two transitions: From void
@ -54,4 +59,12 @@ import { Heroes } from './hero.service';
}) })
export class HeroListMultistepComponent { export class HeroListMultistepComponent {
@Input() heroes: Heroes; @Input() heroes: Heroes;
animationStarted(event: AnimationTransitionEvent) {
console.warn('Animation started: ', event);
}
animationDone(event: AnimationTransitionEvent) {
console.warn('Animation done: ', event);
}
} }

View File

@ -16,7 +16,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@flyInOut="'in'" [@flyInOut]="'in'"
(click)="hero.toggleState()"> (click)="hero.toggleState()">
{{hero.name}} {{hero.name}}
</li> </li>

View File

@ -20,7 +20,7 @@ import { Heroes } from './hero.service';
template: ` template: `
<ul> <ul>
<li *ngFor="let hero of heroes" <li *ngFor="let hero of heroes"
@heroState="hero.state" [@heroState]="hero.state"
(click)="hero.toggleState()"> (click)="hero.toggleState()">
{{hero.name}} {{hero.name}}
</li> </li>

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<!-- Polyfill for Web Animations --> <!-- Polyfill for Web Animations -->
<script src="https://npmcdn.com/web-animations-js@2.2.1"></script> <script src="https://unpkg.com/web-animations-js@2.2.1"></script>
<!-- Polyfill(s) for older browsers --> <!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/core-js/client/shim.min.js"></script>

View File

@ -1,5 +1,5 @@
{ {
"description": "Angular 2 Animations", "description": "Angular Animations",
"files":[ "files":[
"!**/*.d.ts", "!**/*.d.ts",
"!**/*.js" "!**/*.js"

View File

@ -5,7 +5,7 @@ version: 0.0.1
environment: environment:
sdk: '>=1.13.0 <2.0.0' sdk: '>=1.13.0 <2.0.0'
dependencies: dependencies:
angular2: 2.0.0-beta.18 angular2: 2.0.0-beta.21
browser: ^0.10.0 browser: ^0.10.0
dart_to_js_script_rewriter: ^1.0.1 dart_to_js_script_rewriter: ^1.0.1
transformers: transformers:

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Architecture of Angular 2</title> <title>Architecture of Angular</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">

View File

@ -10,7 +10,7 @@ class Hero {
describe('Architecture', () => { describe('Architecture', () => {
const expectedTitle = 'Architecture of Angular 2'; const expectedTitle = 'Architecture of Angular';
const expectedH2 = ['Hero List', 'Sales Tax Calculator']; const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
beforeAll(() => browser.get('')); beforeAll(() => browser.get(''));

View File

@ -13,7 +13,7 @@ const HEROES = [
export class BackendService { export class BackendService {
constructor(private logger: Logger) {} constructor(private logger: Logger) {}
getAll(type: Type): PromiseLike<any[]> { getAll(type: Type<any>): PromiseLike<any[]> {
if (type === Hero) { if (type === Hero) {
// TODO get from the database // TODO get from the database
return Promise.resolve<Hero[]>(HEROES); return Promise.resolve<Hero[]>(HEROES);

View File

@ -13,7 +13,7 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'my-app', selector: 'my-app',
template: 'Welcome to Angular 2' template: 'Welcome to Angular'
}) })
export class AppComponent { export class AppComponent {
constructor(logger: Logger) { constructor(logger: Logger) {

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Architecture of Angular 2</title> <title>Architecture of Angular</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Architecture of Angular 2</title> <title>Architecture of Angular</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">

View File

@ -1,5 +1,5 @@
{ {
"description": "Intro to Angular2", "description": "Intro to Angular",
"files":[ "files":[
"!**/*.d.ts", "!**/*.d.ts",
"!**/*.js", "!**/*.js",

View File

@ -5,7 +5,7 @@ version: 0.0.1
environment: environment:
sdk: '>=1.13.0 <2.0.0' sdk: '>=1.13.0 <2.0.0'
dependencies: dependencies:
angular2: 2.0.0-beta.18 angular2: 2.0.0-beta.21
browser: ^0.10.0 browser: ^0.10.0
dart_to_js_script_rewriter: ^1.0.1 dart_to_js_script_rewriter: ^1.0.1
transformers: transformers:

View File

@ -1,10 +1,10 @@
/* tslint:disable:no-unused-variable */ /* tslint:disable:no-unused-variable */
// #docregion // #docregion
import { Directive, ElementRef, Input } from '@angular/core'; import { Directive, ElementRef, Input, Renderer } from '@angular/core';
@Directive({ selector: '[myHighlight]' }) @Directive({ selector: '[myHighlight]' })
export class HighlightDirective { export class HighlightDirective {
constructor(el: ElementRef) { constructor(el: ElementRef, renderer: Renderer) {
el.nativeElement.style.backgroundColor = 'yellow'; renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
} }
} }

View File

@ -1,6 +1,6 @@
/* tslint:disable:no-unused-variable */ /* tslint:disable:no-unused-variable */
// #docregion // #docregion
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; import { Directive, ElementRef, HostListener, Input, Renderer } from '@angular/core';
@Directive({ @Directive({
selector: '[myHighlight]' selector: '[myHighlight]'
@ -8,9 +8,7 @@ import { Directive, ElementRef, HostListener, Input } from '@angular/core';
export class HighlightDirective { export class HighlightDirective {
// #docregion ctor // #docregion ctor
private el: HTMLElement; constructor(private el: ElementRef, private renderer: Renderer) { }
constructor(el: ElementRef) { this.el = el.nativeElement; }
// #enddocregion ctor // #enddocregion ctor
// #docregion mouse-methods, host // #docregion mouse-methods, host
@ -28,7 +26,7 @@ export class HighlightDirective {
// #enddocregion host // #enddocregion host
private highlight(color: string) { private highlight(color: string) {
this.el.style.backgroundColor = color; this.renderer.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
} }
// #enddocregion mouse-methods // #enddocregion mouse-methods

View File

@ -1,6 +1,6 @@
// #docplaster // #docplaster
// #docregion full // #docregion full
import { Directive, ElementRef, HostListener, Input } from '@angular/core'; import { Directive, ElementRef, HostListener, Input, Renderer } from '@angular/core';
@Directive({ @Directive({
selector: '[myHighlight]' selector: '[myHighlight]'
@ -8,9 +8,8 @@ import { Directive, ElementRef, HostListener, Input } from '@angular/core';
// #docregion class // #docregion class
export class HighlightDirective { export class HighlightDirective {
private _defaultColor = 'red'; private _defaultColor = 'red';
private el: HTMLElement;
constructor(el: ElementRef) { this.el = el.nativeElement; } constructor(private el: ElementRef, private renderer: Renderer) { }
// #enddocregion class // #enddocregion class
// #docregion defaultColor // #docregion defaultColor
@ -34,7 +33,7 @@ export class HighlightDirective {
} }
private highlight(color: string) { private highlight(color: string) {
this.el.style.backgroundColor = color; this.renderer.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
} }
} }
// #enddocregion class // #enddocregion class

View File

@ -2,17 +2,16 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { MovieListComponent } from './movie-list.component'; import { MovieListComponent } from './movie-list.component';
import { routes } from './app.routes'; import { routing } from './app.routing';
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule, BrowserModule,
FormsModule, FormsModule,
RouterModule.forRoot(routes, {}) routing
], ],
declarations: [ declarations: [
AppComponent, AppComponent,

View File

@ -1,9 +0,0 @@
// #docregion
import { RouterConfig } from '@angular/router';
import { MovieListComponent } from './movie-list.component';
export const routes: RouterConfig = [
{ path: '', redirectTo: '/movies', pathMatch: 'full' },
{ path: 'movies', component: MovieListComponent }
];

View File

@ -0,0 +1,12 @@
// #docregion
import { ModuleWithProviders } 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 }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,25 @@
/// <reference path='../_protractor/e2e.d.ts' />
'use strict';
/* tslint:disable:quotemark */
describe('AOT Compilation', function () {
beforeAll(function () {
browser.get('');
});
it('should load page and click button', function (done) {
let headingSelector = element.all(by.css('h1')).get(0);
expect(headingSelector.getText()).toEqual('My First Angular App');
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();
});
});
});

View File

@ -0,0 +1,5 @@
**/*.ngfactory.ts
**/*.metadata.json
dist
!app/tsconfig.json
!rollup.js

View File

@ -0,0 +1,7 @@
<!-- #docregion -->
<button (click)="toggleHeading()">Toggle Heading</button>
<h1 *ngIf="showHeading">My First Angular App</h1>
<h3>List of Heroes</h3>
<div *ngFor="let hero of heroes">{{hero}}</div>

View File

@ -0,0 +1,17 @@
// #docregion
// #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;
}
}

View File

@ -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 { }

View File

@ -0,0 +1,6 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,6 @@
// #docregion
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

View File

@ -0,0 +1,4 @@
{
"build": "build:aot",
"run": "http-server:e2e"
}

View File

@ -0,0 +1,23 @@
<!-- #docregion -->
<!DOCTYPE html>
<html>
<head>
<title>Ahead of time compilation</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
</head>
<!-- #docregion bundle -->
<body>
<my-app>Loading...</my-app>
</body>
<script src="dist/build.js"></script>
<!-- #enddocregion bundle -->
</html>

View File

@ -0,0 +1,25 @@
// #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: 'app/main.js',
dest: 'dist/build.js', // output a single application bundle
sourceMap: false,
format: 'iife',
plugins: [
nodeResolve({jsnext: true, module: true}),
// #docregion commonjs
commonjs({
include: 'node_modules/rxjs/**',
}),
// #enddocregion commonjs
// #docregion uglify
uglify()
// #enddocregion uglify
]
}
// #enddocregion config

View File

@ -1,7 +1,7 @@
{ {
"compilerOptions": { "compilerOptions": {
"target": "es5", "target": "es5",
"module": "system", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "node",
"sourceMap": true, "sourceMap": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
@ -9,5 +9,16 @@
"removeComments": false, "removeComments": false,
"noImplicitAny": true, "noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true "suppressImplicitAnyIndexErrors": true
},
"files": [
"app/app.module.ts",
"app/main.ts",
"./typings/index.d.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
} }
} }

View File

@ -1,4 +1,4 @@
import { NgModule } from '@angular/core'; import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -30,12 +30,17 @@ let directives: any[] = [
VoteTakerComponent VoteTakerComponent
]; ];
let schemas: any[] = [];
// Include Countdown examples // Include Countdown examples
// unless in e2e tests which they break. // unless in e2e tests which they break.
if (!/e2e/.test(location.search)) { if (!/e2e/.test(location.search)) {
console.log('adding countdown timer examples'); console.log('adding countdown timer examples');
directives.push(CountdownLocalVarParentComponent); directives.push(CountdownLocalVarParentComponent);
directives.push(CountdownViewChildParentComponent); directives.push(CountdownViewChildParentComponent);
} else {
// In e2e test use CUSTOM_ELEMENTS_SCHEMA to supress unknown element errors
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
} }
@NgModule({ @NgModule({
@ -43,6 +48,7 @@ if (!/e2e/.test(location.search)) {
BrowserModule BrowserModule
], ],
declarations: directives, declarations: directives,
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ],
schemas: schemas
}) })
export class AppModule { } export class AppModule { }

View File

@ -1,5 +1,5 @@
import { browserDynamicPlatform } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
browserDynamicPlatform().bootstrapModule(AppModule); platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -1,15 +1,12 @@
// #docregion // #docregion
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { SomeAbsoluteComponent, SomeRelativeComponent } from './some.component';
@Component({ @Component({
selector: 'my-app', selector: 'my-app',
template: template:
`<h1>Absolute & <i>Component-Relative</i> Paths</h1> `<h1>Absolute & <i>Component-Relative</i> Paths</h1>
<absolute-path></absolute-path> <absolute-path></absolute-path>
<relative-path></relative-path> <relative-path></relative-path>
`, `
directives: [SomeAbsoluteComponent, SomeRelativeComponent]
}) })
export class AppComponent {} export class AppComponent {}

View File

@ -2,13 +2,16 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { SomeAbsoluteComponent, SomeRelativeComponent } from './some.component';
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule BrowserModule
], ],
declarations: [ declarations: [
AppComponent AppComponent,
SomeAbsoluteComponent,
SomeRelativeComponent
], ],
bootstrap: [ AppComponent ] bootstrap: [ AppComponent ]
}) })

View File

@ -1,15 +1,16 @@
// #docregion // #docregion
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { XHRBackend } from '@angular/http'; import { HttpModule } from '@angular/http';
// import { appRouterProviders } from './app.routes';
/* import { routing } from './app.routing';*/
import { LocationStrategy, import { LocationStrategy,
HashLocationStrategy } from '@angular/common'; HashLocationStrategy } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { HeroData } from './hero-data'; import { HeroData } from './hero-data';
import { InMemoryBackendService, import { InMemoryWebApiModule } from 'angular2-in-memory-web-api';
SEED_DATA } from 'angular2-in-memory-web-api';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { HeroBioComponent } from './hero-bio.component'; import { HeroBioComponent } from './hero-bio.component';
@ -31,44 +32,43 @@ import { ParentFinderComponent,
BethComponent, BethComponent,
BobComponent } from './parent-finder.component'; BobComponent } from './parent-finder.component';
const DIRECTIVES = [ const declarations = [
AppComponent,
HeroBiosComponent, HeroBiosAndContactsComponent, HeroBioComponent, HeroBiosComponent, HeroBiosAndContactsComponent, HeroBioComponent,
HeroesBaseComponent, SortedHeroesComponent, HeroesBaseComponent, SortedHeroesComponent,
HeroOfTheMonthComponent, HeroContactComponent, HeroOfTheMonthComponent, HeroContactComponent,
HighlightDirective, HighlightDirective,
ParentFinderComponent, ParentFinderComponent,
AppComponent
]; ];
const B_DIRECTIVES = [ BarryComponent, BethComponent, BobComponent ]; const a_components = [AliceComponent, AlexComponent ];
// #docregion C_DIRECTIVES const b_components = [ BarryComponent, BethComponent, BobComponent ];
const C_DIRECTIVES = [
const c_components = [
CarolComponent, ChrisComponent, CraigComponent, CarolComponent, ChrisComponent, CraigComponent,
CathyComponent CathyComponent
]; ];
// #enddocregion C_DIRECTIVES
// #docregion bootstrap
@NgModule({ @NgModule({
imports: [ BrowserModule, FormsModule ], imports: [
declarations: [ ...DIRECTIVES, BrowserModule,
...B_DIRECTIVES, FormsModule,
...C_DIRECTIVES, HttpModule,
AliceComponent, InMemoryWebApiModule.forRoot(HeroData)
AlexComponent ], // routing TODO: add routes
],
declarations: [
declarations,
a_components,
b_components,
c_components,
],
bootstrap: [ AppComponent ], bootstrap: [ AppComponent ],
// #docregion providers
providers: [ providers: [
// appRouterProviders, TODO: add routes { provide: LocationStrategy, useClass: HashLocationStrategy }
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: HeroData } // in-mem server data
] ]
// #enddocregion providers
}) })
export class AppModule { export class AppModule { }
constructor() {
}
}
// #enddocregion bootstraps

View File

@ -1,7 +0,0 @@
import { provideRouter, RouterConfig } from '@angular/router';
const routes: RouterConfig = [];
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -0,0 +1,10 @@
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
export const appRoutingProviders: any[] = [
];

View File

@ -2,7 +2,7 @@
/* tslint:disable:*/ /* tslint:disable:*/
// #docplaster // #docplaster
// #docregion // #docregion
import { Component, forwardRef, Optional, provide, SkipSelf } from '@angular/core'; import { Component, forwardRef, Optional, SkipSelf } from '@angular/core';
// A component base class (see AlexComponent) // A component base class (see AlexComponent)
export abstract class Base { name = 'Count Basie'; } export abstract class Base { name = 'Count Basie'; }

View File

@ -0,0 +1,180 @@
/// <reference path="../_protractor/e2e.d.ts" />
'use strict'; // necessary for node!
// THESE TESTS ARE INCOMPLETE
describeIf(browser.appIsTs || browser.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: protractor.ElementFinder,
form: protractor.ElementFinder,
title: protractor.ElementFinder,
nameInput: protractor.ElementFinder,
alterEgoInput: protractor.ElementFinder,
powerSelect: protractor.ElementFinder,
errorMessages: protractor.ElementArrayFinder,
heroFormButtons: protractor.ElementArrayFinder,
heroSubmitted: protractor.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');
}

View File

@ -0,0 +1,12 @@
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<hero-form-template1></hero-form-template1>
<hr>
<hero-form-template2></hero-form-template2>
<hr>
<hero-form-reactive3></hero-form-reactive3>`
})
export class AppComponent { }

View File

@ -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 { }

View File

@ -0,0 +1,6 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,47 @@
<!-- #docregion -->
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form 3 (Reactive)</h1>
<!-- #docregion form-tag-->
<form [formGroup]="heroForm" *ngIf="active" (ngSubmit)="onSubmit()">
<!-- #enddocregion form-tag-->
<div class="form-group">
<!-- #docregion name-with-error-msg -->
<label for="name">Name</label>
<input type="text" id="name" class="form-control"
formControlName="name" required >
<div *ngIf="formErrors.name" class="alert alert-danger">
{{ formErrors.name }}
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" id="alterEgo" class="form-control"
formControlName="alterEgo" >
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
formControlName="power" required >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="formErrors.power" class="alert alert-danger">
{{ formErrors.power }}
</div>
</div>
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.valid">Submit</button>
<button type="button" class="btn btn-default"
(click)="addHero()">New Hero</button>
</form>
</div>
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
</div>

View File

@ -0,0 +1,117 @@
/* 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({
moduleId: module.id,
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
// #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

View File

@ -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 { }

View File

@ -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);
}
}
// #docregion directive

View File

@ -1,11 +1,9 @@
// #docregion // #docregion
export class Hero { export class Hero {
constructor( constructor(
public id: number, public id: number,
public name: string, public name: string,
public power: string, public power: string,
public alterEgo?: string public alterEgo?: string
) { } ) { }
} }

View File

@ -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 { }

View File

@ -0,0 +1,32 @@
// #docregion
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'hero-submitted',
template: `
<div *ngIf="submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">Name</div>
<div class="col-xs-9 pull-left">{{ hero.name }}</div>
</div>
<div class="row">
<div class="col-xs-3">Alter Ego</div>
<div class="col-xs-9 pull-left">{{ hero.alterEgo }}</div>
</div>
<div class="row">
<div class="col-xs-3">Power</div>
<div class="col-xs-9 pull-left">{{ hero.power }}</div>
</div>
<br>
<button class="btn btn-default" (click)="onClick()">Edit</button>
</div>`
})
export class SubmittedComponent {
@Input() hero: Hero;
@Input() submitted = false;
@Output() submittedChange = new EventEmitter<boolean>();
onClick() { this.submittedChange.emit(false); }
}

View File

@ -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 { }

View File

@ -0,0 +1,61 @@
<!-- #docregion -->
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form 1 (Template)</h1>
<!-- #docregion form-tag-->
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
<!-- #enddocregion form-tag-->
<div class="form-group">
<!-- #docregion name-with-error-msg -->
<label for="name">Name</label>
<input type="text" id="name" class="form-control"
required minlength="4" maxlength="24"
name="name" [(ngModel)]="hero.name"
#name="ngModel" >
<div *ngIf="name.errors && (name.dirty || name.touched)"
class="alert alert-danger">
<div [hidden]="!name.errors.required">
Name is required
</div>
<div [hidden]="!name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div [hidden]="!name.errors.maxlength">
Name cannot be more than 24 characters long.
</div>
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" id="alterEgo" class="form-control"
name="alterEgo"
[(ngModel)]="hero.alterEgo" >
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
name="power"
[(ngModel)]="hero.power" required
#power="ngModel" >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
<div [hidden]="!power.errors.required">Power is required</div>
</div>
</div>
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.form.valid">Submit</button>
<button type="button" class="btn btn-default"
(click)="addHero()">New Hero</button>
</form>
</div>
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
</div>

View File

@ -0,0 +1,48 @@
/* tslint:disable: member-ordering */
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { Hero } from '../shared/hero';
@Component({
moduleId: module.id,
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

View File

@ -0,0 +1,52 @@
<!-- #docregion -->
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form 2 (Template & Messages)</h1>
<!-- #docregion form-tag-->
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
<!-- #enddocregion form-tag-->
<div class="form-group">
<!-- #docregion name-with-error-msg -->
<label for="name">Name</label>
<!-- #docregion name-input -->
<input type="text" id="name" class="form-control"
required minlength="4" maxlength="24" forbiddenName="bob"
name="name" [(ngModel)]="hero.name" >
<!-- #enddocregion name-input -->
<div *ngIf="formErrors.name" class="alert alert-danger">
{{ formErrors.name }}
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" id="alterEgo" class="form-control"
name="alterEgo"
[(ngModel)]="hero.alterEgo" >
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
name="power"
[(ngModel)]="hero.power" required >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="formErrors.power" class="alert alert-danger">
{{ formErrors.power }}
</div>
</div>
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.form.valid">Submit</button>
<button type="button" class="btn btn-default"
(click)="addHero()">New Hero</button>
</form>
</div>
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
</div>

View File

@ -0,0 +1,100 @@
/* 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({
moduleId: module.id,
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

View File

@ -1,9 +1,7 @@
/* #docregion */ .ng-valid[required], .ng-valid.required {
.ng-valid[required] {
border-left: 5px solid #42A948; /* green */ border-left: 5px solid #42A948; /* green */
} }
.ng-invalid { .ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */ border-left: 5px solid #a94442; /* red */
} }
/* #enddocregion */

View File

@ -1,18 +1,13 @@
<!DOCTYPE html>
<!-- #docregion -->
<html> <html>
<head> <head>
<title>Hero Form</title> <title>Hero Form with Validation</title>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- #docregion bootstrap -->
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
<!-- #enddocregion bootstrap -->
<!-- #docregion styles -->
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="forms.css"> <link rel="stylesheet" href="forms.css">
<!-- #enddocregion styles -->
<!-- Polyfill(s) for older browsers --> <!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/core-js/client/shim.min.js"></script>
@ -30,5 +25,5 @@
<body> <body>
<my-app>Loading...</my-app> <my-app>Loading...</my-app>
</body> </body>
</html> </html>

View File

@ -1,5 +1,5 @@
{ {
"description": "Forms-Deprecated", "description": "Validation",
"files":[ "files":[
"!**/*.d.ts", "!**/*.d.ts",
"!**/*.js" "!**/*.js"

View File

@ -1,6 +1,6 @@
// #docregion // #docregion
import { browserDynamicPlatform } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
browserDynamicPlatform().bootstrapModule(AppModule); platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -1,5 +1,5 @@
{ {
"description": "Set The Document Title In Angular 2", "description": "Set The Document Title In Angular",
"files": [ "files": [
"!**/*.d.ts", "!**/*.d.ts",
"!**/*.js", "!**/*.js",

View File

@ -25,7 +25,7 @@ describe('TypeScript to Javascript tests', function () {
it('should support optional, attribute, and query injections', function () { it('should support optional, attribute, and query injections', function () {
let app = element(by.css('hero-di-inject-additional')); let app = element(by.css('hero-di-inject-additional'));
let h1 = app.element(by.css('h1')); let h1 = app.element(by.css('h1'));
let okMsg = app.element(by.css('.ok-msg')); let okMsg = app.element(by.css('p'));
expect(h1.getText()).toBe('Tour of Heroes'); expect(h1.getText()).toBe('Tour of Heroes');
app.element(by.buttonText('OK')).click(); app.element(by.buttonText('OK')).click();

View File

@ -6,7 +6,7 @@
template: template:
'<h1>{{titlePrefix}} {{title}}</h1>' + '<h1>{{titlePrefix}} {{title}}</h1>' +
'<button (click)="ok()">OK</button>' + '<button (click)="ok()">OK</button>' +
'<ng-content></ng-content>' '<p>{{ msg }}</p>'
}).Class({ }).Class({
constructor: [ constructor: [
[ [
@ -14,20 +14,14 @@
new ng.core.Inject('titlePrefix') new ng.core.Inject('titlePrefix')
], ],
new ng.core.Attribute('title'), new ng.core.Attribute('title'),
[ function(titlePrefix, title) {
new ng.core.Query('okMsg'),
ng.core.ElementRef
],
function(titlePrefix, title, msg) {
this.titlePrefix = titlePrefix; this.titlePrefix = titlePrefix;
this.title = title; this.title = title;
this.msg = msg; this.msg = '';
} }
], ],
ok: function() { ok: function() {
var msgEl = this.msg = 'OK!';
this.msg.first.nativeElement;
msgEl.textContent = 'OK!';
} }
}); });
// #enddocregion // #enddocregion
@ -35,7 +29,6 @@
var AppComponent = ng.core.Component({ var AppComponent = ng.core.Component({
selector: 'hero-di-inject-additional', selector: 'hero-di-inject-additional',
template: '<hero-title title="Tour of Heroes">' + template: '<hero-title title="Tour of Heroes">' +
'<span #okMsg class="ok-msg"></span>' +
'</hero-title>' '</hero-title>'
}).Class({ }).Class({
constructor: function() { } constructor: function() { }

View File

@ -4,8 +4,8 @@
// #enddocregion appimport // #enddocregion appimport
// #docregion ng2import // #docregion ng2import
var bootstrap = var platformBrowserDynamic =
ng.platformBrowserDynamic.bootstrap; ng.platformBrowserDynamic.platformBrowserDynamic;
var LocationStrategy = var LocationStrategy =
ng.common.LocationStrategy; ng.common.LocationStrategy;
var HashLocationStrategy = var HashLocationStrategy =
@ -17,20 +17,17 @@
// #enddocregion appimport // #enddocregion appimport
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic(); platformBrowserDynamic().bootstrapModule(app.HeroesModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDslModule);
platformBrowserDynamic.bootstrapModule(app.HeroesModule); platformBrowserDynamic().bootstrapModule(app.HeroesLifecycleModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDslModule); platformBrowserDynamic().bootstrapModule(app.HeroesDIModule);
platformBrowserDynamic.bootstrapModule(app.HeroesLifecycleModule); platformBrowserDynamic().bootstrapModule(app.HeroDIInlineModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDIModule); platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule);
platformBrowserDynamic.bootstrapModule(app.HeroDIInlineModule); platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule2);
platformBrowserDynamic.bootstrapModule(app.HeroesDIInjectModule); platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectAdditionalModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDIInjectModule2); platformBrowserDynamic().bootstrapModule(app.HeroesIOModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDIInjectAdditionalModule); platformBrowserDynamic().bootstrapModule(app.HeroesHostBindingsModule);
platformBrowserDynamic.bootstrapModule(app.HeroesIOModule); platformBrowserDynamic().bootstrapModule(app.HeroesQueriesModule);
platformBrowserDynamic.bootstrapModule(app.HeroesHostBindingsModule);
platformBrowserDynamic.bootstrapModule(app.HeroesQueriesModule);
}); });
// #docregion appimport // #docregion appimport

View File

@ -10,7 +10,7 @@
<script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script> <script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/rxjs/bundles/Rx.umd.js"></script> <script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/@angular/core/bundles/core.umd.js"></script> <script src="node_modules/@angular/core/bundles/core.umd.js"></script>
<script src="node_modules/@angular/common/bundles/common.umd.js"></script> <script src="node_modules/@angular/common/bundles/common.umd.js"></script>
<script src="node_modules/@angular/compiler/bundles/compiler.umd.js"></script> <script src="node_modules/@angular/compiler/bundles/compiler.umd.js"></script>

View File

@ -1,11 +1,8 @@
import { import {
Attribute, Attribute,
Component, Component,
ElementRef,
Inject, Inject,
Optional, Optional,
Query,
QueryList,
NgModule NgModule
} from '@angular/core'; } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
@ -16,24 +13,21 @@ import { BrowserModule } from '@angular/platform-browser';
template: ` template: `
<h1>{{titlePrefix}} {{title}}</h1> <h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button> <button (click)="ok()">OK</button>
<ng-content></ng-content> <p>{{ msg }}</p>
` `
}) })
class TitleComponent { class TitleComponent {
private msg: string = '';
constructor( constructor(
@Inject('titlePrefix') @Inject('titlePrefix')
@Optional() @Optional()
private titlePrefix: string, private titlePrefix: string,
@Attribute('title') @Attribute('title')
private title: string, private title: string) {
@Query('okMsg')
private msg: QueryList<ElementRef>) {
} }
ok() { ok() {
let msgEl = this.msg = 'OK!';
this.msg.first.nativeElement;
msgEl.textContent = 'OK!';
} }
} }
// #enddocregion // #enddocregion
@ -41,7 +35,6 @@ class TitleComponent {
@Component({ @Component({
selector: 'hero-di-inject-additional', selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes"> template: `<hero-title title="Tour of Heroes">
<span #okMsg class="ok-msg"></span>
</hero-title>` </hero-title>`
}) })
class AppComponent { } class AppComponent { }

View File

@ -1,7 +1,6 @@
/* tslint:disable no-unused-variable */ /* tslint:disable no-unused-variable */
// #docregion ng2import // #docregion ng2import
import { bootstrap } import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
from '@angular/platform-browser-dynamic';
import { import {
LocationStrategy, LocationStrategy,
HashLocationStrategy HashLocationStrategy
@ -12,8 +11,6 @@ import {
import { HeroComponent } from './hero.component'; import { HeroComponent } from './hero.component';
// #enddocregion appimport // #enddocregion appimport
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { HeroesModule } from './hero.component'; import { HeroesModule } from './hero.component';
import { HeroesLifecycleModule } from './hero-lifecycle.component'; import { HeroesLifecycleModule } from './hero-lifecycle.component';
import { HeroesDIModule } from './hero-di.component'; import { HeroesDIModule } from './hero-di.component';

View File

@ -7,6 +7,6 @@ describe('cli-quickstart App', () => {
it('should display message saying app works', () => { it('should display message saying app works', () => {
let pageTitle = element(by.css('cli-quickstart-app h1')).getText(); let pageTitle = element(by.css('cli-quickstart-app h1')).getText();
expect(pageTitle).toEqual('My First Angular 2 App'); expect(pageTitle).toEqual('My First Angular App');
}); });
}); });

Some files were not shown because too many files have changed in this diff Show More