Merge branch 'pr/2' into fix-styleguide-trigger-positioning
This commit is contained in:
commit
0bae5fca69
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"live": "angular-io",
|
||||||
|
"ngdocsdev": "ngdocsdev"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
13
.travis.yml
13
.travis.yml
|
@ -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
|
||||||
|
|
14
README.md
14
README.md
|
@ -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:
|
||||||
|
|
205
gulpfile.js
205
gulpfile.js
|
@ -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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
44
harp.json
44
harp.json
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
package.json
11
package.json
|
@ -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": {
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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")
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"description": "Angular 2 Animations",
|
"description": "Angular Animations",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js"
|
"!**/*.js"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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(''));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"description": "Intro to Angular2",
|
"description": "Intro to Angular",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js",
|
"!**/*.js",
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 }
|
|
||||||
];
|
|
|
@ -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 |
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
**/*.ngfactory.ts
|
||||||
|
**/*.metadata.json
|
||||||
|
dist
|
||||||
|
!app/tsconfig.json
|
||||||
|
!rollup.js
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 { }
|
|
@ -0,0 +1,6 @@
|
||||||
|
// #docregion
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app.module';
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
@ -0,0 +1,6 @@
|
||||||
|
// #docregion
|
||||||
|
import { platformBrowser } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
||||||
|
|
||||||
|
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"build": "build:aot",
|
||||||
|
"run": "http-server:e2e"
|
||||||
|
}
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 { }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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 ]
|
||||||
})
|
})
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { provideRouter, RouterConfig } from '@angular/router';
|
|
||||||
|
|
||||||
const routes: RouterConfig = [];
|
|
||||||
|
|
||||||
export const appRouterProviders = [
|
|
||||||
provideRouter(routes)
|
|
||||||
];
|
|
|
@ -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[] = [
|
||||||
|
|
||||||
|
];
|
|
@ -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'; }
|
||||||
|
|
|
@ -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');
|
||||||
|
}
|
|
@ -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 { }
|
|
@ -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 { }
|
|
@ -0,0 +1,6 @@
|
||||||
|
// #docregion
|
||||||
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||||
|
|
||||||
|
import { AppModule } from './app.module';
|
||||||
|
|
||||||
|
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
@ -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>
|
|
@ -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
|
|
@ -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 { }
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
}
|
}
|
|
@ -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 { }
|
|
@ -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); }
|
||||||
|
}
|
|
@ -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 { }
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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
|
|
@ -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 */
|
|
|
@ -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>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"description": "Forms-Deprecated",
|
"description": "Validation",
|
||||||
"files":[
|
"files":[
|
||||||
"!**/*.d.ts",
|
"!**/*.d.ts",
|
||||||
"!**/*.js"
|
"!**/*.js"
|
|
@ -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);
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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() { }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 { }
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue