Compare commits

..

27 Commits
4.2.0 ... 4.2.1

Author SHA1 Message Date
15090a8ad4 docs: add changelog for 4.2.1 2017-06-09 16:11:29 -07:00
8575e3f71c release: cut the 4.2.1 release 2017-06-09 16:04:09 -07:00
90b0713e32 refactor(compiler): don’t write summaries for jit by default
The default is false externally but true internally at Google.
2017-06-09 15:58:53 -07:00
d56b7ed96d docs(aio): reorganise the sidenav menu (#16934)
Reorganizes the items in the sidenav menu and consolidates the quickstart
and cli-quickstart guides into one.
2017-06-09 14:48:53 -07:00
db5e5067a0 build(aio): update typescript to 2.3.2 (#17382) 2017-06-09 14:36:36 -07:00
0020dad595 docs(aio): update examples to 4.2 (#17367) 2017-06-09 14:35:35 -07:00
c2d31fb01e fix(http): move destructuring inside {Request,Response}Options ctor
Previously the RequestOptions/ResponseOptions classes had constructors
with a destructured argument hash (represented by the
{Request,Response}OptionsArgs type). This type consists entirely of
optional members.

This produces a .d.ts file which includes the constructor declaration:

constructor({param, otherParam}?: OptionsArgs);

However, this declaration doesn't type-check properly. TypeScript
determines the actual type of the hash parameter to be OptionsArgs | undefined,
which it then concludes does not have a `param` or `otherParam` member.

This is a bug in TypeScript ( https://github.com/microsoft/typescript/issues/10078 ).
As a workaround, destructuring is moved inside the method, where it does not produce
broken artifacts in the .d.ts.

Fixes #16663.
2017-06-09 14:34:39 -07:00
65d49d5c94 fix(aio): temporarily remove link to source from the API pages (#17371)
We need to come up with a better design (possibly involving an icon button) to
link to the source code (for viewing and/or editing).

Fixes #17254
2017-06-09 14:14:39 -07:00
3a99af2696 docs(packaging): update homepage in @angular/tsc-wrapped (#17352)
Motivation: `yarn outdated`, for exmaple, shows the homepage URL on the command line. If copy-pasting or clicking on the URL, it's nice to see the repo's page instead of a 404.
2017-06-09 13:35:23 -07:00
503fd1fbaf docs(aio): fix image width on the homepage 2017-06-09 13:32:52 -07:00
4c74dba2f3 docs(aio): update events page 2017-06-09 13:32:52 -07:00
33df13ad65 build(aio): update to 4.2 (#17369) 2017-06-09 13:31:12 -07:00
ce18c68eca fix(aio): temporarily remove the focus style of top-bar nav items
Temporarily addresses #17216 until we upgrade to an `@angular/material` version
that includes angular/material2@3bc82f6dc.
2017-06-09 20:37:12 +01:00
2d5623911a fix(aio): sidebar folder state after select item
Closes #17245 and #17253

When the user selects a doc item in the side nav:
1) expand folder(s) leading to the selected doc item
2) on a wide display, keep other already expanded folders open
3) on narrow (mobile) display, collapse other expanded folders

Used to do (3) when wide. Issue #17245 asks for (2).

That logic was bypassed for selected node when we allowed headers to have content
because that unintentionally expanded the header’s folder when selected.
Because the selected node is no longer a header with content, removing this exclusion
also means that folders are expanded/collapsed with above logic even for API pages.
2017-06-09 16:53:54 +01:00
a0b30e5dfb docs(aio): remove example specific .gitignore files
All the files that should be ignored are defined in the
`aio/content/examples/.gitigore` folder.
2017-06-09 14:33:21 +01:00
76a920651c docs(aio): remove cli-quickstart styles.css from git 2017-06-09 14:33:21 +01:00
ef6609a723 docs(aio): remove example specific styles from the shared boilerplate styles.css 2017-06-09 14:33:21 +01:00
c0dcb342f3 docs(aio): create styles.css snippet file for toh-pt5 example 2017-06-09 14:33:21 +01:00
8a9a5ecdd7 docs(aio): move example specific styles into router example app.css file 2017-06-09 14:33:21 +01:00
12c5ead39c docs(aio): do not ignore i18n example js file 2017-06-09 14:33:21 +01:00
3db6b6ca7a build(aio): ignore example files that are gitignored
Rather than hard coding excludes into the dgeni config,
use the fact that we are already ignoring the boilerplate
and generated files via the .gitignore file.
2017-06-09 14:33:21 +01:00
e894f5c399 fix(aio): expand the main content width when there is no ToC
Previously, the main content would always leave a 18% margin on the right to be
occupied by the ToC (even if there was no ToC).
This commit lets the main content expand to the right to occupy all the
available space when there is no ToC.

Fixes #17205
Fixes #17270
2017-06-09 13:33:51 +01:00
8524187869 fix(aio): restrain scrolling inside ToC (when cursor over ToC)
Previously, when scrolling the ToC and reaching the top/bottom, further
mousewheel events would result in scrolling the window (and thus the main
content). This is standard browser behavior. In the case of the ToC though, the
`ScrollSpy` would detect scrolling in the main content and scroll the active ToC
to entry into view, thus resetting the scroll position of the ToC.

Reproduction:
1. Open  `~/guide/template-syntax`.
2. Start scrolling through the long ToC.
3. Try to go to the bottom of the ToC.
4. Once you reach the bottom, the main content starts scrolling down.
5. The first section ("HTML in templates") becomes "active", so the ToC is
   scrolled back up to make its corresponding entry visible.
6. Go back to step 2.

This commit improves the UX, by not allowing the main content to scroll when the
cursor is ovr the ToC and the user has scrolled all the way to the top/bottom of
it.
2017-06-09 10:38:06 +01:00
f7422a9607 fix(aio): animate hamburger in/out
Fixes #17215
2017-06-09 08:17:48 +01:00
cf0a9e0730 docs: add changelog for 4.2.0 2017-06-08 15:38:20 -07:00
8e5beb024f release: cut the 4.2.0 release 2017-06-08 15:38:20 -07:00
576d6d8f86 feat(aio): update the home page and docs landing page content (#17325)
Closes #17268
Closes #17230
2017-06-08 15:26:15 -07:00
73 changed files with 2499 additions and 2179 deletions

View File

@ -1,3 +1,15 @@
<a name="4.2.1"></a>
## [4.2.1](https://github.com/angular/angular/compare/4.2.0-rc.2...4.2.1) (2017-06-09)
### Bug Fixes
* **compiler:** dont write summaries for jit by default ([d3a5f1a](https://github.com/angular/angular/commit/d3a5f1a))
* **http:** move destructuring inside {Request,Response}Options ctor ([c2d31fb](https://github.com/angular/angular/commit/c2d31fb)), closes [#16663](https://github.com/angular/angular/issues/16663)
<a name="4.2.0"></a> <a name="4.2.0"></a>
# [4.2.0](https://github.com/angular/angular/compare/4.2.0-rc.2...4.2.0) salubrious-stratagem (2017-06-08) # [4.2.0](https://github.com/angular/angular/compare/4.2.0-rc.2...4.2.0) salubrious-stratagem (2017-06-08)

View File

@ -52,6 +52,9 @@ dist/
!aot/index.html !aot/index.html
!rollup-config.js !rollup-config.js
# i18n
!i18n/src/systemjs-text-plugin.js
# testing # testing
!testing/src/browser-test-shim.js !testing/src/browser-test-shim.js
!testing/karma*.js !testing/karma*.js

View File

@ -1 +0,0 @@
**/*.js

View File

@ -44,7 +44,7 @@ import { Heroes } from './hero.service';
animate('0.2s ease-in') animate('0.2s ease-in')
]), ]),
transition('* => void', [ transition('* => void', [
animate('0.2s 10 ease-out', style({ animate('0.2s 10s ease-out', style({
opacity: 0, opacity: 0,
transform: 'translateX(100%)' transform: 'translateX(100%)'
})) }))

View File

@ -1,7 +0,0 @@
**/*.ngfactory.ts
**/*.ngsummary.json
**/*.shim.ngstyle.ts
**/*.metadata.json
dist
!app/tsconfig.json
!rollup-config.js

View File

@ -1,45 +0,0 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage/*
/libpeerconnection.log
npm-debug.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
#System Files
.DS_Store
Thumbs.db
!src/styles.css
!karma.conf.js
!protractor.conf.js

View File

@ -1,116 +0,0 @@
/* #docregion , quickstart, toh */
/* Master Styles */
h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
h2, h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
}
body {
margin: 2em;
}
/* #enddocregion quickstart */
body, input[text], button {
color: #888;
font-family: Cambria, Georgia;
}
/* #enddocregion toh */
a {
cursor: pointer;
cursor: hand;
}
button {
font-family: Arial;
background-color: #eee;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
cursor: hand;
}
button:hover {
background-color: #cfd8dc;
}
button:disabled {
background-color: #eee;
color: #aaa;
cursor: auto;
}
/* Navigation link styles */
nav a {
padding: 5px 10px;
text-decoration: none;
margin-right: 10px;
margin-top: 10px;
display: inline-block;
background-color: #eee;
border-radius: 4px;
}
nav a:visited, a:link {
color: #607D8B;
}
nav a:hover {
color: #039be5;
background-color: #CFD8DC;
}
nav a.active {
color: #039be5;
}
/* items class */
.items {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 24em;
}
.items li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.items li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.items li.selected {
background-color: #CFD8DC;
color: white;
}
.items li.selected:hover {
background-color: #BBD8DC;
}
.items .text {
position: relative;
top: -3px;
}
.items .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
/* #docregion toh */
/* everywhere else */
* {
font-family: Arial, Helvetica, sans-serif;
}

View File

@ -1 +0,0 @@
**/*.js

View File

@ -1 +0,0 @@
!systemjs.config.server.js

View File

@ -1,6 +0,0 @@
**/*.ngfactory.ts
**/*.metadata.json
dist
!app/tsconfig.json
!rollup.js
!src/systemjs-text-plugin.js

View File

@ -0,0 +1,47 @@
/* items class */
.items {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 24em;
}
.items li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.items li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.items li.selected {
background-color: #CFD8DC;
color: white;
}
.items li.selected:hover {
background-color: #BBD8DC;
}
.items .text {
position: relative;
top: -3px;
}
.items .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}

View File

@ -10,6 +10,7 @@
<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">
<link rel="stylesheet" href="app.css">
<!-- Polyfills --> <!-- Polyfills -->
<script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/core-js/client/shim.min.js"></script>

View File

@ -1,2 +0,0 @@
*.js
!systemjs.custom.js

View File

@ -1 +0,0 @@
!src/browser-test-shim.js

View File

@ -0,0 +1,22 @@
/* Master Styles */
h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
h2, h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
}
body {
margin: 2em;
}
body, input[text], button {
color: #888;
font-family: Cambria, Georgia;
}
/* everywhere else */
* {
font-family: Arial, Helvetica, sans-serif;
}

View File

@ -1,8 +0,0 @@
aot/**/*.ts
**/*.ngfactory.ts
**/*.ngsummary.json
**/*.metadata.json
**/*.js
dist
!app/tsconfig.json
!/*.js

View File

@ -1 +0,0 @@
!karma.conf.ajs.js

View File

@ -1,8 +0,0 @@
aot/**/*
!aot/index.html
dist
!app/tsconfig.json
!rollup-config.js
!karma.conf.ajs.js
!copy-dist-files.js
!systemjs.config.1.js

View File

@ -1 +0,0 @@
!tsconfig.json

View File

@ -1,5 +0,0 @@
dist
!karma.webpack.conf.js
!webpack.config.js
!config/*
!public/css/styles.css

View File

@ -9,14 +9,14 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@angular/common": "~4.0.0", "@angular/common": "~4.2.0",
"@angular/compiler": "~4.0.0", "@angular/compiler": "~4.2.0",
"@angular/core": "~4.0.0", "@angular/core": "~4.2.0",
"@angular/forms": "~4.0.0", "@angular/forms": "~4.2.0",
"@angular/http": "~4.0.0", "@angular/http": "~4.2.0",
"@angular/platform-browser": "~4.0.0", "@angular/platform-browser": "~4.2.0",
"@angular/platform-browser-dynamic": "~4.0.0", "@angular/platform-browser-dynamic": "~4.2.0",
"@angular/router": "~4.0.0", "@angular/router": "~4.2.0",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"rxjs": "5.0.1", "rxjs": "5.0.1",
"zone.js": "^0.8.4" "zone.js": "^0.8.4"

View File

@ -38,7 +38,7 @@ This page introduces modules; the [Angular modules](guide/ngmodule) page covers
<br class="clear"> <br class="clear">
Every Angular app has at least one Angular module class, [the _root module_](guide/appmodule "AppModule: the root module"), Every Angular app has at least one Angular module class, [the _root module_](guide/bootstrapping "AppModule: the root module"),
conventionally named `AppModule`. conventionally named `AppModule`.
While the _root module_ may be the only module in a small application, most apps have many more While the _root module_ may be the only module in a small application, most apps have many more

View File

@ -1,8 +1,8 @@
# AppModule: the root module # Bootstrapping
An Angular module class describes how the application parts fit together. An Angular module class describes how the application parts fit together.
Every application has at least one Angular module, the _root_ module Every application has at least one Angular module, the _root_ module
that you [bootstrap](guide/appmodule#main) to launch the application. that you [bootstrap](guide/bootstrapping#main) to launch the application.
You can call it anything you want. The conventional name is `AppModule`. You can call it anything you want. The conventional name is `AppModule`.
The [setup](guide/setup) instructions produce a new project with the following minimal `AppModule`. The [setup](guide/setup) instructions produce a new project with the following minimal `AppModule`.
@ -10,7 +10,6 @@ You'll evolve this module as your application grows.
<code-example path="setup/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false"> <code-example path="setup/src/app/app.module.ts" title="src/app/app.module.ts" linenums="false">
</code-example> </code-example>
@ -26,7 +25,7 @@ The `@NgModule` decorator identifies `AppModule` as an Angular module class (als
* **_bootstrap_** &mdash; the _root_ component that Angular creates and inserts into the `index.html` host web page. * **_bootstrap_** &mdash; the _root_ component that Angular creates and inserts into the `index.html` host web page.
The [Angular Modules (NgModule)](guide/ngmodule) guide dives deeply into the details of Angular modules. The [Angular Modules (NgModule)](guide/ngmodule) guide dives deeply into the details of Angular modules.
All you need to know at the moment is a few basics about these three properties. All you need to know at the moment is a few basics about these three properties.
{@a imports} {@a imports}
@ -35,7 +34,7 @@ All you need to know at the moment is a few basics about these three properties.
### The _imports_ array ### The _imports_ array
Angular modules are a way to consolidate features that belong together into discrete units. Angular modules are a way to consolidate features that belong together into discrete units.
Many features of Angular itself are organized as Angular modules. Many features of Angular itself are organized as Angular modules.
HTTP services are in the `HttpModule`. The router is in the `RouterModule`. HTTP services are in the `HttpModule`. The router is in the `RouterModule`.
Eventually you may create a feature module. Eventually you may create a feature module.
@ -67,7 +66,7 @@ are unrelated and have completely different jobs.
The _JavaScript_ `import` statements give you access to symbols _exported_ by other files The _JavaScript_ `import` statements give you access to symbols _exported_ by other files
so you can reference them within _this_ file. so you can reference them within _this_ file.
You add `import` statements to almost every application file. You add `import` statements to almost every application file.
They have nothing to do with Angular and Angular knows nothing about them. They have nothing to do with Angular and Angular knows nothing about them.
The _module's_ `imports` array appears _exclusively_ in the `@NgModule` metadata object. The _module's_ `imports` array appears _exclusively_ in the `@NgModule` metadata object.
@ -86,10 +85,10 @@ that the application needs to function properly.
You tell Angular which components belong to the `AppModule` by listing it in the module's `declarations` array. You tell Angular which components belong to the `AppModule` by listing it in the module's `declarations` array.
As you create more components, you'll add them to `declarations`. As you create more components, you'll add them to `declarations`.
You must declare _every_ component in an `NgModule` class. You must declare _every_ component in an `NgModule` class.
If you use a component without declaring it, you'll see a clear error message in the browser console. If you use a component without declaring it, you'll see a clear error message in the browser console.
You'll learn to create two other kinds of classes &mdash; You'll learn to create two other kinds of classes &mdash;
[directives](guide/attribute-directives) and [pipes](guide/pipes) &mdash; [directives](guide/attribute-directives) and [pipes](guide/pipes) &mdash;
that you must also add to the `declarations` array. that you must also add to the `declarations` array.
@ -98,7 +97,7 @@ that you must also add to the `declarations` array.
**Only _declarables_** &mdash; _components_, _directives_ and _pipes_ &mdash; belong in the `declarations` array. **Only _declarables_** &mdash; _components_, _directives_ and _pipes_ &mdash; belong in the `declarations` array.
Do not put any other kind of class in `declarations`; _not_ `NgModule` classes, _not_ service classes, _not_ model classes. Do not put any other kind of class in `declarations`; _not_ `NgModule` classes, _not_ service classes, _not_ model classes.
@ -111,14 +110,14 @@ Do not put any other kind of class in `declarations`; _not_ `NgModule` classes,
### The _bootstrap_ array ### The _bootstrap_ array
You launch the application by [_bootstrapping_](guide/appmodule#main) the root `AppModule`. You launch the application by [_bootstrapping_](guide/bootstrapping#main) the root `AppModule`.
Among other things, the _bootstrapping_ process creates the component(s) listed in the `bootstrap` array Among other things, the _bootstrapping_ process creates the component(s) listed in the `bootstrap` array
and inserts each one into the browser DOM. and inserts each one into the browser DOM.
Each bootstrapped component is the base of its own tree of components. Each bootstrapped component is the base of its own tree of components.
Inserting a bootstrapped component usually triggers a cascade of component creations that fill out that tree. Inserting a bootstrapped component usually triggers a cascade of component creations that fill out that tree.
While you can put more than one component tree on a host web page, that's not typical. While you can put more than one component tree on a host web page, that's not typical.
Most applications have only one component tree and they bootstrap a single _root_ component. Most applications have only one component tree and they bootstrap a single _root_ component.
You can call the one _root_ component anything you want but most developers call it `AppComponent`. You can call the one _root_ component anything you want but most developers call it `AppComponent`.
@ -143,7 +142,7 @@ The variations depend upon how you want to compile the application and where you
In the beginning, you will compile the application dynamically with the _Just-in-Time (JIT)_ compiler In the beginning, you will compile the application dynamically with the _Just-in-Time (JIT)_ compiler
and you'll run it in a browser. You can learn about other options later. and you'll run it in a browser. You can learn about other options later.
The recommended place to bootstrap a JIT-compiled browser application is in a separate file The recommended place to bootstrap a JIT-compiled browser application is in a separate file
in the `src` folder named `src/main.ts` in the `src` folder named `src/main.ts`
<code-example path="setup/src/main.ts" title="src/main.ts" linenums="false"> <code-example path="setup/src/main.ts" title="src/main.ts" linenums="false">
@ -156,10 +155,10 @@ This code creates a browser platform for dynamic (JIT) compilation and
bootstraps the `AppModule` described above. bootstraps the `AppModule` described above.
The _bootstrapping_ process sets up the execution environment, The _bootstrapping_ process sets up the execution environment,
digs the _root_ `AppComponent` out of the module's `bootstrap` array, digs the _root_ `AppComponent` out of the module's `bootstrap` array,
creates an instance of the component and inserts it within the element tag identified by the component's `selector`. creates an instance of the component and inserts it within the element tag identified by the component's `selector`.
The `AppComponent` selector &mdash; here and in most documentation samples &mdash; is `my-app` The `AppComponent` selector &mdash; here and in most documentation samples &mdash; is `my-app`
so Angular looks for a `<my-app>` tag in the `index.html` like this one ... so Angular looks for a `<my-app>` tag in the `index.html` like this one ...
<code-example path="setup/src/index.html" region="my-app" title="setup/src/index.html" linenums="false"> <code-example path="setup/src/index.html" region="my-app" title="setup/src/index.html" linenums="false">

View File

@ -1,617 +0,0 @@
# CLI QuickStart
Good tools make application development quicker and easier to maintain than
if you did everything by hand.
The [**Angular CLI**](https://cli.angular.io/) is a **_command line interface_** tool
that can create a project, add files, and perform a variety of ongoing development tasks such
as testing, bundling, and deployment.
The goal in this guide is to build and run a simple Angular
application in TypeScript, using the Angular CLI
while adhering to the [Style Guide](guide/styleguide) recommendations that
benefit _every_ Angular project.
By the end of the chapter, you'll have a basic understanding of development with the CLI
and a foundation for both these documentation samples and for real world applications.
<!--
You'll pursue these ends in the following high-level steps:
1. [Set up](guide/cli-quickstart#devenv) the development environment.
2. [Create](guide/cli-quickstart#create-proj) a new project and skeleton application.
3. [Serve](guide/cli-quickstart#serve) the application.
4. [Edit](guide/cli-quickstart#first-component) the application.
-->
And you can also <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">download the example.</a>
<h2 id='devenv'>
Step 1. Set up the Development Environment
</h2>
You need to set up your development environment before you can do anything.
Install **[Node.js® and npm](https://nodejs.org/en/download/)**
if they are not already on your machine.
<div class="l-sub-section">
**Verify that you are running at least node `6.9.x` and npm `3.x.x`**
by running `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors, but newer versions are fine.
</div>
Then **install the [Angular CLI](https://github.com/angular/angular-cli)** globally.
<code-example language="sh" class="code-shell">
npm install -g @angular/cli
</code-example>
<h2 id='create-proj'>
Step 2. Create a new project
</h2>
Open a terminal window.
Generate a new project and skeleton application by running the following commands:
<code-example language="sh" class="code-shell">
ng new my-app
</code-example>
<div class="l-sub-section">
Patience please.
It takes time to set up a new project, most of it spent installing npm packages.
</div>
<h2 id='serve'>
Step 3: Serve the application
</h2>
Go to the project directory and launch the server.
<code-example language="sh" class="code-shell">
cd my-app
ng serve --open
</code-example>
The `ng serve` command launches the server, watches your files,
and rebuilds the app as you make changes to those files.
Using the `--open` (or just `-o`) option will automatically open your browser
on `http://localhost:4200/`.
Your app greets you with a message:
<figure>
<img src='generated/images/guide/cli-quickstart/app-works.png' alt="The app works!">
</figure>
<h2 id='first-component'>
Step 4: Edit your first Angular component
</h2>
The CLI created the first Angular component for you.
This is the _root component_ and it is named `app-root`.
You can find it in `./src/app/app.component.ts`.
Open the component file and change the `title` property from _app works!_ to _My First Angular App_:
<code-example path="cli-quickstart/src/app/app.component.ts" region="title" title="src/app/app.component.ts" linenums="false"></code-example>
The browser reloads automatically with the revised title. That's nice, but it could look better.
Open `src/app/app.component.css` and give the component some style.
<code-example path="cli-quickstart/src/app/app.component.css" title="src/app/app.component.css" linenums="false"></code-example>
<figure>
<img src='generated/images/guide/cli-quickstart/my-first-app.png' alt="Output of QuickStart app">
</figure>
Looking good!
## What's next?
That's about all you'd expect to do in a "Hello, World" app.
You're ready to take the [Tour of Heroes Tutorial](tutorial) and build
a small application that demonstrates the great things you can build with Angular.
Or you can stick around a bit longer to learn about the files in your brand new project.
## Project file review
An Angular CLI project is the foundation for both quick experiments and enterprise solutions.
The first file you should check out is `README.md`.
It has some basic information on how to use CLI commands.
Whenever you want to know more about how Angular CLI works make sure to visit
[the Angular CLI repository](https://github.com/angular/angular-cli) and
[Wiki](https://github.com/angular/angular-cli/wiki).
Some of the generated files might be unfamiliar to you.
### The `src` folder
Your app lives in the `src` folder.
All Angular components, templates, styles, images, and anything else your app needs go here.
Any files outside of this folder are meant to support building your app.
<div class='filetree'>
<div class='file'>src</div>
<div class='children'>
<div class='file'>app</div>
<div class='children'>
<div class='file'>app.component.css</div>
<div class='file'>app.component.html</div>
<div class="file">app.component.spec.ts</div>
<div class="file">app.component.ts</div>
<div class="file">app.module.ts</div>
</div>
<div class="file">assets</div>
<div class='children'>
<div class="file">.gitkeep</div>
</div>
<div class="file">environments</div>
<div class='children'>
<div class="file">environment.prod.ts</div>
<div class="file">environment.ts</div>
</div>
<div class="file">favicon.ico</div>
<div class="file">index.html</div>
<div class="file">main.ts</div>
<div class="file">polyfills.ts</div>
<div class="file">styles.css</div>
<div class="file">test.ts</div>
<div class="file">tsconfig.app.json</div>
<div class="file">tsconfig.spec.json</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
`app/app.component.{ts,html,css,spec.ts}`
</td>
<td>
Defines the `AppComponent` along with an HTML template, CSS stylesheet, and a unit test.
It is the **root** component of what will become a tree of nested components
as the application evolves.
</td>
</tr>
<tr>
<td>
`app/app.module.ts`
</td>
<td>
Defines `AppModule`, the [root module](guide/appmodule "AppModule: the root module") that tells Angular how to assemble the application.
Right now it declares only the `AppComponent`.
Soon there will be more components to declare.
</td>
</tr>
<tr>
<td>
`assets/*`
</td>
<td>
A folder where you can put images and anything else to be copied wholesale
when you build your application.
</td>
</tr>
<tr>
<td>
`environments/*`
</td>
<td>
This folder contains one file for each of your destination environments,
each exporting simple configuration variables to use in your application.
The files are replaced on-the-fly when you build your app.
You might use a different API endpoint for development than you do for production
or maybe different analytics tokens.
You might even use some mock services.
Either way, the CLI has you covered.
</td>
</tr>
<tr>
<td>
`favicon.ico`
</td>
<td>
Every site wants to look good on the bookmark bar.
Get started with your very own Angular icon.
</td>
</tr>
<tr>
<td>
`index.html`
</td>
<td>
The main HTML page that is served when someone visits your site.
Most of the time you'll never need to edit it.
The CLI automatically adds all `js` and `css` files when building your app so you
never need to add any `&lt;script&gt;` or `&lt;link&gt;` tags here manually.
</td>
</tr>
<tr>
<td>
`main.ts`
</td>
<td>
The main entry point for your app.
Compiles the application with the [JIT compiler](guide/glossary#jit)
and bootstraps the application's root module (`AppModule`) to run in the browser.
You can also use the [AOT compiler](guide/glossary#ahead-of-time-aot-compilation)
without changing any code by passing in `--aot` to `ng build` or `ng serve`.
</td>
</tr>
<tr>
<td>
`polyfills.ts`
</td>
<td>
Different browsers have different levels of support of the web standards.
Polyfills help normalize those differences.
You should be pretty safe with `core-js` and `zone.js`, but be sure to check out
the [Browser Support guide](guide/browser-support) for more information.
</td>
</tr>
<tr>
<td>
`styles.css`
</td>
<td>
Your global styles go here.
Most of the time you'll want to have local styles in your components for easier maintenance,
but styles that affect all of your app need to be in a central place.
</td>
</tr>
<tr>
<td>
`test.ts`
</td>
<td>
This is the main entry point for your unit tests.
It has some custom configuration that might be unfamiliar, but it's not something you'll
need to edit.
</td>
</tr>
<tr>
<td>
`tsconfig.{app|spec}.json`
</td>
<td>
TypeScript compiler configuration for the Angular app (`tsconfig.app.json`)
and for the unit tests (`tsconfig.spec.json`).
</td>
</tr>
</table>
### The root folder
The `src/` folder is just one of the items inside the project's root folder.
Other files help you build, test, maintain, document, and deploy the app.
These files go in the root folder next to `src/`.
<div class='filetree'>
<div class="file">my-app</div>
<div class='children'>
<div class="file">e2e</div>
<div class='children'>
<div class="file">app.e2e-spec.ts</div>
<div class="file">app.po.ts</div>
<div class="file">tsconfig.e2e.json</div>
</div>
<div class="file">node_modules/...</div>
<div class="file">src/...</div>
<div class="file">.angular-cli.json</div>
<div class="file">.editorconfig</div>
<div class="file">.gitignore</div>
<div class="file">karma.conf.js</div>
<div class="file">package.json</div>
<div class="file">protractor.conf.js</div>
<div class="file">README.md</div>
<div class="file">tsconfig.json</div>
<div class="file">tslint.json</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
`e2e/`
</td>
<td>
Inside `e2e/` live the End-to-End tests.
They shouldn't be inside `src/` because e2e tests are really a separate app that
just so happens to test your main app.
That's also why they have their own `tsconfig.e2e.json`.
</td>
</tr>
<tr>
<td>
`node_modules/`
</td>
<td>
`Node.js` creates this folder and puts all third party modules listed in
`package.json` inside of it.
</td>
</tr>
<tr>
<td>
`.angular-cli.json`
</td>
<td>
Configuration for Angular CLI.
In this file you can set several defaults and also configure what files are included
when your project is build.
Check out the official documentation if you want to know more.
</td>
</tr>
<tr>
<td>
`.editorconfig`
</td>
<td>
Simple configuration for your editor to make sure everyone that uses your project
has the same basic configuration.
Most editors support an `.editorconfig` file.
See http://editorconfig.org for more information.
</td>
</tr>
<tr>
<td>
`.gitignore`
</td>
<td>
Git configuration to make sure autogenerated files are not commited to source control.
</td>
</tr>
<tr>
<td>
`karma.conf.js`
</td>
<td>
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
used when running `ng test`.
</td>
</tr>
<tr>
<td>
`package.json`
</td>
<td>
`npm` configuration listing the third party packages your project uses.
You can also add your own [custom scripts](https://docs.npmjs.com/misc/scripts) here.
</td>
</tr>
<tr>
<td>
`protractor.conf.js`
</td>
<td>
End-to-end test configuration for [Protractor](http://www.protractortest.org/),
used when running `ng e2e`.
</td>
</tr>
<tr>
<td>
`README.md`
</td>
<td>
Basic documentation for your project, pre-filled with CLI command information.
Make sure to enhance it with project documentation so that anyone
checking out the repo can build your app!
</td>
</tr>
<tr>
<td>
`tsconfig.json`
</td>
<td>
TypeScript compiler configuration for your IDE to pick up and give you helpful tooling.
</td>
</tr>
<tr>
<td>
`tslint.json`
</td>
<td>
Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with
[Codelyzer](http://codelyzer.com/), used when running `ng lint`.
Linting helps keep your code style consistent.
</td>
</tr>
</table>
<div class="l-sub-section">
### Next Step
If you're new to Angular, continue with the
[tutorial](tutorial "Tour of Heroes tutorial").
You can skip the "Setup" step since you're already using the Angular CLI setup.
</div>

View File

@ -12,7 +12,7 @@ making some of them public so external components can use them.
And there are many more options covered here. And there are many more options covered here.
Before reading this page, read the Before reading this page, read the
[The Root Module](guide/appmodule) page, which introduces NgModules and the essentials [The Root Module](guide/bootstrapping) page, which introduces NgModules and the essentials
of creating and maintaining a single root `AppModule` for the entire application. of creating and maintaining a single root `AppModule` for the entire application.
This page covers NgModules in greater depth. This page covers NgModules in greater depth.

View File

@ -1,79 +1,617 @@
<h1 class="no-toc">QuickStart</h1> # QuickStart
Angular applications are made up of _components_. Good tools make application development quicker and easier to maintain than
A _component_ is the combination of an HTML template and a component class that controls a portion of the screen. Here is an example of a component that displays a simple string: if you did everything by hand.
The [**Angular CLI**](https://cli.angular.io/) is a **_command line interface_** tool
that can create a project, add files, and perform a variety of ongoing development tasks such
as testing, bundling, and deployment.
The goal in this guide is to build and run a simple Angular
application in TypeScript, using the Angular CLI
while adhering to the [Style Guide](guide/styleguide) recommendations that
benefit _every_ Angular project.
By the end of the chapter, you'll have a basic understanding of development with the CLI
and a foundation for both these documentation samples and for real world applications.
<!--
You'll pursue these ends in the following high-level steps:
1. [Set up](guide/cli-quickstart#devenv) the development environment.
2. [Create](guide/cli-quickstart#create-proj) a new project and skeleton application.
3. [Serve](guide/cli-quickstart#serve) the application.
4. [Edit](guide/cli-quickstart#first-component) the application.
-->
And you can also <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blank">download the example.</a>
<code-example path="quickstart/src/app/app.component.ts" title="src/app/app.component.ts" linenums="false">
<h2 id='devenv'>
Step 1. Set up the Development Environment
</h2>
You need to set up your development environment before you can do anything.
Install **[Node.js® and npm](https://nodejs.org/en/download/)**
if they are not already on your machine.
<div class="l-sub-section">
**Verify that you are running at least node `6.9.x` and npm `3.x.x`**
by running `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors, but newer versions are fine.
</div>
Then **install the [Angular CLI](https://github.com/angular/angular-cli)** globally.
<code-example language="sh" class="code-shell">
npm install -g @angular/cli
</code-example> </code-example>
<h2 id='create-proj'>
Step 2. Create a new project
</h2>
Open a terminal window.
Generate a new project and skeleton application by running the following commands:
<code-example language="sh" class="code-shell">
ng new my-app
</code-example>
<div class="l-sub-section"> <div class="l-sub-section">
Try this **<live-example noDownload>QuickStart example on Plunker</live-example>** without installing anything. Patience please.
Try it locally with the [***QuickStart seed***](guide/setup "Setup for local development with the QuickStart seed") It takes time to set up a new project, most of it spent installing npm packages.
and prepare for development of a real Angular application.
</div> </div>
Every component begins with an `@Component` [decorator](guide/glossary#decorator '"decorator" explained')
function that takes a _metadata_ object. The metadata object describes how the HTML template and component class work together.
The `selector` property tells Angular to display the component inside a custom `<my-app>` tag in the `index.html`. <h2 id='serve'>
Step 3: Serve the application
</h2>
<code-example path="quickstart/src/index.html" region="my-app" title="index.html (inside &lt;body&gt;)" linenums="false">
Go to the project directory and launch the server.
<code-example language="sh" class="code-shell">
cd my-app
ng serve --open
</code-example> </code-example>
The `template` property defines a message inside an `<h1>` header. The `ng serve` command launches the server, watches your files,
The message starts with "Hello" and ends with `{{name}}`, and rebuilds the app as you make changes to those files.
which is an Angular [interpolation binding](guide/displaying-data) expression.
At runtime, Angular replaces `{{name}}` with the value of the component's `name` property. Using the `--open` (or just `-o`) option will automatically open your browser
Interpolation binding is one of many Angular features you'll discover in this documentation. on `http://localhost:4200/`.
Your app greets you with a message:
In the example, change the component class's `name` property from `'Angular'` to `'World'` and see what happens. <figure>
<img src='generated/images/guide/cli-quickstart/app-works.png' alt="The app works!">
</figure>
<div class="callout is-helpful">
<header>
A word about TypeScript <h2 id='first-component'>
</header> Step 4: Edit your first Angular component
</h2>
<p> The CLI created the first Angular component for you.
This example is written in <a href="http://www.typescriptlang.org/" title="TypeScript">TypeScript</a>, a superset of JavaScript. Angular This is the _root component_ and it is named `app-root`.
uses TypeScript because its types make it easy to support developer productivity with tooling. You can also write Angular code in JavaScript; [this guide](guide/ts-to-js] explains how. You can find it in `./src/app/app.component.ts`.
</p>
Open the component file and change the `title` property from _app works!_ to _My First Angular App_:
<code-example path="cli-quickstart/src/app/app.component.ts" region="title" title="src/app/app.component.ts" linenums="false"></code-example>
The browser reloads automatically with the revised title. That's nice, but it could look better.
Open `src/app/app.component.css` and give the component some style.
<code-example path="cli-quickstart/src/app/app.component.css" title="src/app/app.component.css" linenums="false"></code-example>
<figure>
<img src='generated/images/guide/cli-quickstart/my-first-app.png' alt="Output of QuickStart app">
</figure>
Looking good!
## What's next?
That's about all you'd expect to do in a "Hello, World" app.
You're ready to take the [Tour of Heroes Tutorial](tutorial) and build
a small application that demonstrates the great things you can build with Angular.
Or you can stick around a bit longer to learn about the files in your brand new project.
## Project file review
An Angular CLI project is the foundation for both quick experiments and enterprise solutions.
The first file you should check out is `README.md`.
It has some basic information on how to use CLI commands.
Whenever you want to know more about how Angular CLI works make sure to visit
[the Angular CLI repository](https://github.com/angular/angular-cli) and
[Wiki](https://github.com/angular/angular-cli/wiki).
Some of the generated files might be unfamiliar to you.
### The `src` folder
Your app lives in the `src` folder.
All Angular components, templates, styles, images, and anything else your app needs go here.
Any files outside of this folder are meant to support building your app.
<div class='filetree'>
<div class='file'>src</div>
<div class='children'>
<div class='file'>app</div>
<div class='children'>
<div class='file'>app.component.css</div>
<div class='file'>app.component.html</div>
<div class="file">app.component.spec.ts</div>
<div class="file">app.component.ts</div>
<div class="file">app.module.ts</div>
</div>
<div class="file">assets</div>
<div class='children'>
<div class="file">.gitkeep</div>
</div>
<div class="file">environments</div>
<div class='children'>
<div class="file">environment.prod.ts</div>
<div class="file">environment.ts</div>
</div>
<div class="file">favicon.ico</div>
<div class="file">index.html</div>
<div class="file">main.ts</div>
<div class="file">polyfills.ts</div>
<div class="file">styles.css</div>
<div class="file">test.ts</div>
<div class="file">tsconfig.app.json</div>
<div class="file">tsconfig.spec.json</div>
</div>
</div> </div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
`app/app.component.{ts,html,css,spec.ts}`
</td>
<td>
Defines the `AppComponent` along with an HTML template, CSS stylesheet, and a unit test.
It is the **root** component of what will become a tree of nested components
as the application evolves.
</td>
</tr>
<tr>
<td>
`app/app.module.ts`
</td>
<td>
Defines `AppModule`, the [root module](guide/bootstrapping "AppModule: the root module") that tells Angular how to assemble the application.
Right now it declares only the `AppComponent`.
Soon there will be more components to declare.
</td>
</tr>
<tr>
<td>
`assets/*`
</td>
<td>
A folder where you can put images and anything else to be copied wholesale
when you build your application.
</td>
</tr>
<tr>
<td>
`environments/*`
</td>
<td>
This folder contains one file for each of your destination environments,
each exporting simple configuration variables to use in your application.
The files are replaced on-the-fly when you build your app.
You might use a different API endpoint for development than you do for production
or maybe different analytics tokens.
You might even use some mock services.
Either way, the CLI has you covered.
</td>
</tr>
<tr>
<td>
`favicon.ico`
</td>
<td>
Every site wants to look good on the bookmark bar.
Get started with your very own Angular icon.
</td>
</tr>
<tr>
<td>
`index.html`
</td>
<td>
The main HTML page that is served when someone visits your site.
Most of the time you'll never need to edit it.
The CLI automatically adds all `js` and `css` files when building your app so you
never need to add any `&lt;script&gt;` or `&lt;link&gt;` tags here manually.
</td>
</tr>
<tr>
<td>
`main.ts`
</td>
<td>
The main entry point for your app.
Compiles the application with the [JIT compiler](guide/glossary#jit)
and bootstraps the application's root module (`AppModule`) to run in the browser.
You can also use the [AOT compiler](guide/glossary#ahead-of-time-aot-compilation)
without changing any code by passing in `--aot` to `ng build` or `ng serve`.
</td>
</tr>
<tr>
<td>
`polyfills.ts`
</td>
<td>
Different browsers have different levels of support of the web standards.
Polyfills help normalize those differences.
You should be pretty safe with `core-js` and `zone.js`, but be sure to check out
the [Browser Support guide](guide/browser-support) for more information.
</td>
</tr>
<tr>
<td>
`styles.css`
</td>
<td>
Your global styles go here.
Most of the time you'll want to have local styles in your components for easier maintenance,
but styles that affect all of your app need to be in a central place.
</td>
</tr>
<tr>
<td>
`test.ts`
</td>
<td>
This is the main entry point for your unit tests.
It has some custom configuration that might be unfamiliar, but it's not something you'll
need to edit.
</td>
</tr>
<tr>
<td>
`tsconfig.{app|spec}.json`
</td>
<td>
TypeScript compiler configuration for the Angular app (`tsconfig.app.json`)
and for the unit tests (`tsconfig.spec.json`).
</td>
</tr>
</table>
### The root folder
The `src/` folder is just one of the items inside the project's root folder.
Other files help you build, test, maintain, document, and deploy the app.
These files go in the root folder next to `src/`.
<div class='filetree'>
<div class="file">my-app</div>
<div class='children'>
<div class="file">e2e</div>
<div class='children'>
<div class="file">app.e2e-spec.ts</div>
<div class="file">app.po.ts</div>
<div class="file">tsconfig.e2e.json</div>
</div>
<div class="file">node_modules/...</div>
<div class="file">src/...</div>
<div class="file">.angular-cli.json</div>
<div class="file">.editorconfig</div>
<div class="file">.gitignore</div>
<div class="file">karma.conf.js</div>
<div class="file">package.json</div>
<div class="file">protractor.conf.js</div>
<div class="file">README.md</div>
<div class="file">tsconfig.json</div>
<div class="file">tslint.json</div>
</div>
</div>
<style>
td, th {vertical-align: top}
</style>
<table width="100%">
<col width="20%">
</col>
<col width="80%">
</col>
<tr>
<th>
File
</th>
<th>
Purpose
</th>
</tr>
<tr>
<td>
`e2e/`
</td>
<td>
Inside `e2e/` live the End-to-End tests.
They shouldn't be inside `src/` because e2e tests are really a separate app that
just so happens to test your main app.
That's also why they have their own `tsconfig.e2e.json`.
</td>
</tr>
<tr>
<td>
`node_modules/`
</td>
<td>
`Node.js` creates this folder and puts all third party modules listed in
`package.json` inside of it.
</td>
</tr>
<tr>
<td>
`.angular-cli.json`
</td>
<td>
Configuration for Angular CLI.
In this file you can set several defaults and also configure what files are included
when your project is build.
Check out the official documentation if you want to know more.
</td>
</tr>
<tr>
<td>
`.editorconfig`
</td>
<td>
Simple configuration for your editor to make sure everyone that uses your project
has the same basic configuration.
Most editors support an `.editorconfig` file.
See http://editorconfig.org for more information.
</td>
</tr>
<tr>
<td>
`.gitignore`
</td>
<td>
Git configuration to make sure autogenerated files are not commited to source control.
</td>
</tr>
<tr>
<td>
`karma.conf.js`
</td>
<td>
Unit test configuration for the [Karma test runner](https://karma-runner.github.io),
used when running `ng test`.
</td>
</tr>
<tr>
<td>
`package.json`
</td>
<td>
`npm` configuration listing the third party packages your project uses.
You can also add your own [custom scripts](https://docs.npmjs.com/misc/scripts) here.
</td>
</tr>
<tr>
<td>
`protractor.conf.js`
</td>
<td>
End-to-end test configuration for [Protractor](http://www.protractortest.org/),
used when running `ng e2e`.
</td>
</tr>
<tr>
<td>
`README.md`
</td>
<td>
Basic documentation for your project, pre-filled with CLI command information.
Make sure to enhance it with project documentation so that anyone
checking out the repo can build your app!
</td>
</tr>
<tr>
<td>
`tsconfig.json`
</td>
<td>
TypeScript compiler configuration for your IDE to pick up and give you helpful tooling.
</td>
</tr>
<tr>
<td>
`tslint.json`
</td>
<td>
Linting configuration for [TSLint](https://palantir.github.io/tslint/) together with
[Codelyzer](http://codelyzer.com/), used when running `ng lint`.
Linting helps keep your code style consistent.
</td>
</tr>
</table>
<div class="l-sub-section"> <div class="l-sub-section">
### Next Step
If you're new to Angular, continue with the
### Next step [tutorial](tutorial "Tour of Heroes tutorial").
You can skip the "Setup" step since you're already using the Angular CLI setup.
Start the [**tutorial**](tutorial "Tour of Heroes tutorial").
</div> </div>

View File

@ -3,11 +3,11 @@
{@a develop-locally} {@a develop-locally}
The <live-example name=quickstart>QuickStart live-coding</live-example> example is an Angular _playground_. The <live-example name=quickstart>QuickStart live-coding</live-example> example is an Angular _playground_.
It's not where you'd develop a real application. It's not where you'd develop a real application.
You [should develop locally](guide/setup#why-locally "Why develop locally") on your own machine ... and that's also how we think you should learn Angular. You [should develop locally](guide/setup#why-locally "Why develop locally") on your own machine ... and that's also how we think you should learn Angular.
Setting up a new project on your machine is quick and easy with the **QuickStart seed**, Setting up a new project on your machine is quick and easy with the **QuickStart seed**,
maintained [on github](https://github.com/angular/quickstart "Install the github QuickStart repo"). maintained [on github](https://github.com/angular/quickstart "Install the github QuickStart repo").
Make sure you have [node and npm installed](guide/setup#install-prerequisites "What if you don't have node and npm?"). Make sure you have [node and npm installed](guide/setup#install-prerequisites "What if you don't have node and npm?").
@ -124,7 +124,7 @@ Open a terminal window in the project folder and enter the following commands fo
The **QuickStart seed** contains the same application as the QuickStart playground. The **QuickStart seed** contains the same application as the QuickStart playground.
But its true purpose is to provide a solid foundation for _local_ development. But its true purpose is to provide a solid foundation for _local_ development.
Consequently, there are _many more files_ in the project folder on your machine, Consequently, there are _many more files_ in the project folder on your machine,
most of which you can [learn about later](guide/setup-systemjs-anatomy "Setup Anatomy"). most of which you can [learn about later](guide/setup-systemjs-anatomy "Setup Anatomy").
@ -187,7 +187,7 @@ Focus on the following three TypeScript (`.ts`) files in the **`/src`** folder.
All guides and cookbooks have _at least these core files_. All guides and cookbooks have _at least these core files_.
Each file has a distinct purpose and evolves independently as the application grows. Each file has a distinct purpose and evolves independently as the application grows.
Files outside `src/` concern building, deploying, and testing your app. Files outside `src/` concern building, deploying, and testing your app.
@ -239,7 +239,7 @@ The following are all in `src/`
Defines the same `AppComponent` as the one in the QuickStart playground. Defines the same `AppComponent` as the one in the QuickStart playground.
It is the **root** component of what will become a tree of nested components It is the **root** component of what will become a tree of nested components
as the application evolves. as the application evolves.
</td> </td>
</tr> </tr>
@ -253,7 +253,7 @@ The following are all in `src/`
<td> <td>
Defines `AppModule`, the [root module](guide/appmodule "AppModule: the root module") that tells Angular how to assemble the application. Defines `AppModule`, the [root module](guide/bootstrapping "AppModule: the root module") that tells Angular how to assemble the application.
Right now it declares only the `AppComponent`. Right now it declares only the `AppComponent`.
Soon there will be more components to declare. Soon there will be more components to declare.
</td> </td>
@ -270,7 +270,7 @@ The following are all in `src/`
Compiles the application with the [JIT compiler](guide/glossary#jit) and Compiles the application with the [JIT compiler](guide/glossary#jit) and
[bootstraps](guide/appmodule#main "bootstrap the application") [bootstraps](guide/bootstrapping#main "bootstrap the application")
the application's main module (`AppModule`) to run in the browser. the application's main module (`AppModule`) to run in the browser.
The JIT compiler is a reasonable choice during the development of most projects and The JIT compiler is a reasonable choice during the development of most projects and
it's the only viable choice for a sample running in a _live-coding_ environment like Plunker. it's the only viable choice for a sample running in a _live-coding_ environment like Plunker.
@ -315,8 +315,8 @@ Get them now</a> if they're not already installed on your machine.
by running the commands `node -v` and `npm -v` in a terminal/console window. by running the commands `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors. Older versions produce errors.
We recommend [nvm](https://github.com/creationix/nvm) for managing multiple versions of node and npm. We recommend [nvm](https://github.com/creationix/nvm) for managing multiple versions of node and npm.
You may need [nvm](https://github.com/creationix/nvm) if you already have projects running on your machine that You may need [nvm](https://github.com/creationix/nvm) if you already have projects running on your machine that
use other versions of node and npm. use other versions of node and npm.
@ -334,7 +334,7 @@ You can play with the sample code, share your changes with friends, and download
The [QuickStart](guide/quickstart "Angular QuickStart Playground") shows just the `AppComponent` file. The [QuickStart](guide/quickstart "Angular QuickStart Playground") shows just the `AppComponent` file.
It creates the equivalent of `app.module.ts` and `main.ts` internally _for the playground only_. It creates the equivalent of `app.module.ts` and `main.ts` internally _for the playground only_.
so the reader can discover Angular without distraction. so the reader can discover Angular without distraction.
The other samples are based on the QuickStart seed. The other samples are based on the QuickStart seed.
As much fun as this is ... As much fun as this is ...
@ -343,7 +343,7 @@ As much fun as this is ...
* transpiling TypeScript in the browser is slow * transpiling TypeScript in the browser is slow
* the type support, refactoring, and code completion only work in your local IDE * the type support, refactoring, and code completion only work in your local IDE
Use the <live-example title="QuickStart Seed in Plunker">live coding</live-example> environment as a _playground_, Use the <live-example title="QuickStart Seed in Plunker">live coding</live-example> environment as a _playground_,
a place to try the documentation samples and experiment on your own. a place to try the documentation samples and experiment on your own.
It's the perfect place to reproduce a bug when you want to It's the perfect place to reproduce a bug when you want to
<a href="https://github.com/angular/angular/issues/new" title="File a documentation issue">file a documentation issue</a> or <a href="https://github.com/angular/angular/issues/new" title="File a documentation issue">file a documentation issue</a> or

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -5,8 +5,8 @@ Angular is a platform that makes it easy to build applications with the web. Ang
<div class="card-container"> <div class="card-container">
<a href="generated/live-examples/quickstart/eplnkr.html" target="_blank" class="docs-card" <a href="generated/live-examples/quickstart/eplnkr.html" target="_blank" class="docs-card"
title="Experience Angular in a live coding environment"> title="Experience Angular in a live coding environment">
<section>Experience Angular</section> <section>Get a Glimpse of Angular</section>
<p>A quick look at an Angular application.</p> <p>A quick look at an Angular "hello world" application.</p>
<p class="card-footer">Angular in Action</p> <p class="card-footer">Angular in Action</p>
</a> </a>
@ -16,8 +16,6 @@ Angular is a platform that makes it easy to build applications with the web. Ang
<p class="card-footer" > <p class="card-footer" >
<a href="guide/quickstart" title="Angular Quickstart">Quickstart</a> <a href="guide/quickstart" title="Angular Quickstart">Quickstart</a>
</p> </p>
<!--<p class="card-footer"><a href="guide/quickstart">Quickstart</a></p>
<p class="card-footer"><a href="guide/tutorial">Tutorial</a></p>-->
</div> </div>
<a href="guide/architecture" class="docs-card" title="Angular Architecture"> <a href="guide/architecture" class="docs-card" title="Angular Architecture">

View File

@ -19,6 +19,12 @@
<td>Tokyo, Japan</td> <td>Tokyo, Japan</td>
<td>June 17, 2017</td> <td>June 17, 2017</td>
</tr> </tr>
<!-- AngularMix -->
<tr>
<th><a href="https://angularmix.com/" title="AngularMix">AngularMix</a></th>
<td>Universal Studios, Orlando, Florida</td>
<td>October 8, 2017</td>
</tr>
<!-- ReactiveConf --> <!-- ReactiveConf -->
<tr> <tr>
<th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th> <th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th>
@ -29,7 +35,7 @@
<tr> <tr>
<th><a href="http://angularconnect.com" title="AngularConnect">AngularConnect</a></th> <th><a href="http://angularconnect.com" title="AngularConnect">AngularConnect</a></th>
<td>London, United Kingdom</td> <td>London, United Kingdom</td>
<td>Nov. 07, 2017</td> <td>November 07, 2017</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -32,10 +32,10 @@
<!--Announcement Bar--> <!--Announcement Bar-->
<div class="homepage-container"> <div class="homepage-container">
<div class="announcement-bar"> <div class="announcement-bar">
<img src="assets/images/logos/angular/angular-banner-logo-grey.png" width="64"/> <img src="generated/images/marketing/angular-mix.png" height="40" width="151">
<p>Angular v4.0 is out! Smaller, faster, no biggie...</p> <p>Join us at our newest event, October 2017</p>
<button class="button"> <button class="button">
<a href="http://angularjs.blogspot.com/2017/03/angular-400-now-available.html" target="_blank">Learn More</a> <a href="https://angularmix.com/">Learn More</a>
</button> </button>
</div> </div>
</div> </div>
@ -44,7 +44,7 @@
<div layout="row" layout-xs="column" class="home-row homepage-container"> <div layout="row" layout-xs="column" class="home-row homepage-container">
<div class="promo-img-container promo-1"> <div class="promo-img-container promo-1">
<div> <div>
<img height="222" src="assets/images/home/responsive-framework.svg" alt="responsive framework"> <img height="222" width="340" src="assets/images/home/responsive-framework.svg" alt="responsive framework">
</div> </div>
</div> </div>
@ -69,7 +69,7 @@
<div class="promo-img-container promo-2"> <div class="promo-img-container promo-2">
<div> <div>
<img height="222" src="assets/images/home/speed-performance.svg" alt="speed and performance"> <img height="222" width="323" src="assets/images/home/speed-performance.svg" alt="speed and performance">
</div> </div>
</div> </div>
</div> </div>
@ -112,12 +112,12 @@
<!-- CTA CARDS --> <!-- CTA CARDS -->
<div layout="row" layout-xs="column" class="home-row"> <div layout="row" layout-xs="column" class="home-row">
<a href="tutorial"> <a href="guide/quickstart">
<div class="card"> <div class="card">
<img src="../assets/images/icons/code-icon.svg" height="70px"> <img src="../assets/images/icons/code-icon.svg" height="70px">
<div class="card-text-container"> <div class="card-text-container">
<div class="text-headline">Start Tutorial</div> <div class="text-headline">Get Started</div>
<p>Start building your Angular application in TypeScript.</p> <p>Start building your Angular application.</p>
</div> </div>
</div> </div>
</a> </a>

View File

@ -15,6 +15,10 @@
{ {
"url": "events", "url": "events",
"title": "Events" "title": "Events"
},
{
"url": "https://blog.angularjs.org/",
"title": "Blog"
} }
], ],
@ -33,6 +37,10 @@
{ {
"url": "events", "url": "events",
"title": "Events" "title": "Events"
},
{
"url": "https://blog.angularjs.org/",
"title": "Blog"
} }
] ]
} }
@ -47,21 +55,10 @@
}, },
{ {
"url": "guide/quickstart",
"title": "Getting Started", "title": "Getting Started",
"tooltip": "A gentle introduction to Angular.", "tooltip": "A gentle introduction to Angular."
"children": [ },
{
"url": "guide/quickstart",
"title": "Basic Quickstart",
"tooltip": "A quick look at an Angular app without tooling."
},
{
"url": "guide/cli-quickstart",
"title": "CLI Quickstart",
"tooltip": "A quick look at an Angular app built with the Angular CLI."
}
]},
{ {
"title": "Tutorial", "title": "Tutorial",
@ -109,43 +106,14 @@
"title": "Fundamentals", "title": "Fundamentals",
"tooltip": "The fundamentals of Angular", "tooltip": "The fundamentals of Angular",
"children": [ "children": [
{
"url": "guide/animations",
"title": "Animations",
"tooltip": "A guide to Angular's animation system."
},
{
"title": "Angular Modules",
"tooltip": "Learn how directives modify the layout and behavior of elements.",
"children": [
{
"url": "guide/appmodule",
"title": "The Root AppModule",
"tooltip": "Tell Angular how to construct and bootstrap the app in the root \"AppModule\"."
},
{
"url": "guide/ngmodule",
"title": "NgModule",
"tooltip": "Define application modules with @NgModule."
},
{
"url": "guide/ngmodule-faq",
"title": "Angular Module FAQs",
"tooltip": "Answers to frequently asked questions about @NgModule."
}
]},
{ {
"url": "guide/architecture", "url": "guide/architecture",
"title": "Architecture", "title": "Architecture",
"tooltip": "The basic building blocks of Angular applications." "tooltip": "The basic building blocks of Angular applications."
}, },
{ {
"title": "Components", "title": "Template & Data Binding",
"tooltip": "Components present information to users and collect their input.", "tooltip": "Template & Data Binding",
"children": [ "children": [
{ {
"url": "guide/displaying-data", "url": "guide/displaying-data",
@ -167,23 +135,86 @@
"title": "Component Interaction", "title": "Component Interaction",
"tooltip": "Share information between different directives and components." "tooltip": "Share information between different directives and components."
}, },
{
"url": "guide/component-styles",
"title": "Component Styles",
"tooltip": "Learn how to apply CSS styles to components."
},
{ {
"url": "guide/dynamic-component-loader", "url": "guide/dynamic-component-loader",
"title": "Dynamic Components", "title": "Dynamic Components",
"tooltip": "Load components dynamically." "tooltip": "Load components dynamically."
}, },
{
"url": "guide/attribute-directives",
"title": "Attribute Directives",
"tooltip": "Attribute directives attach behavior to elements."
},
{
"url": "guide/structural-directives",
"title": "Structural Directives",
"tooltip": "Structural directives manipulate the layout of the page."
},
{ {
"url": "guide/pipes", "url": "guide/pipes",
"title": "Pipes", "title": "Pipes",
"tooltip": "Pipes transform displayed values within a template." "tooltip": "Pipes transform displayed values within a template."
},
{
"url": "guide/animations",
"title": "Animations",
"tooltip": "A guide to Angular's animation system."
} }
] ]
}, },
{
"title": "Forms",
"tooltip": "Angular Forms",
"children": [
{
"url": "guide/user-input",
"title": "User Input",
"tooltip": "User input triggers DOM events. We listen to those events with event bindings that funnel updated values back into our components and models."
},
{
"url": "guide/forms",
"title": "Template-driven Forms",
"tooltip": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors."
},
{
"url": "guide/form-validation",
"title": "Form Validation",
"tooltip": "Validate user's form entries."
},
{
"url": "guide/reactive-forms",
"title": "Reactive Forms",
"tooltip": "Create a reactive form using FormBuilder, groups, and arrays."
},
{
"url": "guide/dynamic-form",
"title": "Dynamic forms",
"tooltip": "Render dynamic forms with FormGroup."
}
]
},
{
"url": "guide/bootstrapping",
"title": "Bootstrapping",
"tooltip": "Tell Angular how to construct and bootstrap the app in the root \"AppModule\"."
},
{
"title": "NgModules",
"tooltip": "Learn how to use NgModules to make your apps efficient.",
"children": [
{
"url": "guide/ngmodule",
"title": "NgModules",
"tooltip": "Define application modules with @NgModule."
},
{
"url": "guide/ngmodule-faq",
"title": "NgModule FAQs",
"tooltip": "Answers to frequently asked questions about @NgModule."
}
]},
{ {
"title": "Dependency Injection", "title": "Dependency Injection",
@ -207,73 +238,26 @@
] ]
}, },
{
"title": "Directives",
"tooltip": "Learn how directives modify the layout and behavior of elements.",
"children": [
{
"url": "guide/attribute-directives",
"title": "Attribute Directives",
"tooltip": "Attribute directives attach behavior to elements."
},
{
"url": "guide/structural-directives",
"title": "Structural Directives",
"tooltip": "Structural directives manipulate the layout of the page."
}
]
},
{ {
"url": "guide/http", "url": "guide/http",
"title": "HTTP", "title": "Server Communication",
"tooltip": "Use HTTP to talk to a remote server." "tooltip": "Use HTTP to talk to a remote server."
}, },
{
"url": "guide/i18n",
"title": "Internationalization (i18n)",
"tooltip": "Translate the app's template text into multiple languages."
},
{ {
"url": "guide/router", "url": "guide/router",
"title": "Routing & Navigation", "title": "Routing & Navigation",
"tooltip": "Discover the basics of screen navigation with the Angular Router." "tooltip": "Discover the basics of screen navigation with the Angular Router."
}, },
{ {
"title": "User Input", "url": "guide/testing",
"tooltip": "User Input", "title": "Testing",
"children": [ "tooltip": "Techniques and practices for testing an Angular app."
{ },
"url": "guide/user-input", {
"title": "User Input", "url": "guide/cheatsheet",
"tooltip": "User input triggers DOM events. We listen to those events with event bindings that funnel updated values back into our components and models." "title": "Cheat Sheet",
}, "tooltip": "A quick guide to common Angular coding techniques."
}
{
"url": "guide/forms",
"title": "Template-driven Forms",
"tooltip": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors."
},
{
"url": "guide/reactive-forms",
"title": "Reactive Forms",
"tooltip": "Create a reactive form using FormBuilder, groups, and arrays."
},
{
"url": "guide/form-validation",
"title": "Form Validation",
"tooltip": "Validate user's form entries."
},
{
"url": "guide/dynamic-form",
"title": "Dynamic forms",
"tooltip": "Render dynamic forms with FormGroup."
}
]}
]}, ]},
{ {
@ -281,18 +265,21 @@
"tooltip": "Techniques for putting Angular to work in your environment", "tooltip": "Techniques for putting Angular to work in your environment",
"children": [ "children": [
{
"url": "guide/i18n",
"title": "Internationalization (i18n)",
"tooltip": "Translate the app's template text into multiple languages."
},
{ {
"url": "guide/security", "url": "guide/security",
"title": "Security", "title": "Security",
"tooltip": "Developing for content security in Angular applications." "tooltip": "Developing for content security in Angular applications."
}, },
{ {
"url": "guide/set-document-title", "url": "guide/ts-to-js",
"title": "Set the document tab title", "title": "TypeScript to JavaScript",
"tooltip": "Set the browser tab title dynamically with the Angular Title service" "tooltip": "Convert Angular TypeScript examples into ES6 and ES5 JavaScript."
}, },
{ {
"title": "Setup & Deployment", "title": "Setup & Deployment",
"tooltip": "Setup and Deployment", "tooltip": "Setup and Deployment",
@ -336,31 +323,19 @@
] ]
}, },
{
"url": "guide/testing",
"title": "Testing",
"tooltip": "Techniques and practices for testing an Angular app."
},
{
"url": "guide/ts-to-js",
"title": "TypeScript to JavaScript",
"tooltip": "Convert Angular TypeScript examples into ES6 and ES5 JavaScript."
},
{ {
"title": "Upgrading", "title": "Upgrading",
"tooltip": "Incrementally upgrade an AngularJS application to Angular.", "tooltip": "Incrementally upgrade an AngularJS application to Angular.",
"children": [ "children": [
{
"url": "guide/ajs-quick-reference",
"title": "AngularJS to Angular",
"tooltip": "Learn how AngularJS concepts and techniques map to Angular."
},
{ {
"url": "guide/upgrade", "url": "guide/upgrade",
"title": "Upgrading from AngularJS", "title": "Upgrading from AngularJS",
"tooltip": "Incrementally upgrade an AngularJS application to Angular." "tooltip": "Incrementally upgrade an AngularJS application to Angular."
},
{
"url": "guide/ajs-quick-reference",
"title": "AngularJS to Angular",
"tooltip": "Learn how AngularJS concepts and techniques map to Angular."
} }
] ]
}, },
@ -370,11 +345,15 @@
"title": "Visual Studio 2015 QuickStart", "title": "Visual Studio 2015 QuickStart",
"tooltip": "Use Visual Studio 2015 with the QuickStart files." "tooltip": "Use Visual Studio 2015 with the QuickStart files."
}, },
{ {
"url": "guide/webpack", "url": "guide/styleguide",
"title": "Webpack: An Introduction", "title": "Style Guide",
"tooltip": "Create Angular applications with Webpack based tooling." "tooltip": "Write Angular with style."
},
{
"url": "guide/glossary",
"title": "Glossary",
"tooltip": "Brief definitions of the most important words in the Angular vocabulary."
} }
] ]
}, },
@ -383,36 +362,6 @@
"title": "API", "title": "API",
"tooltip": "Details of the Angular classes and values.", "tooltip": "Details of the Angular classes and values.",
"url": "api" "url": "api"
},
{
"title": "References",
"tooltip": "References on Angular usage and style.",
"children": [
{
"url": "guide/change-log",
"title": "Change Log",
"tooltip": "An annotated history of recent documentation improvements."
},
{
"url": "guide/cheatsheet",
"title": "Cheat Sheet",
"tooltip": "A quick guide to common Angular coding techniques."
},
{
"url": "guide/glossary",
"title": "Glossary",
"tooltip": "Brief definitions of the most important words in the Angular vocabulary."
},
{
"url": "guide/styleguide",
"title": "Style Guide",
"tooltip": "Write Angular with style."
}
]
} }
], ],
@ -434,6 +383,11 @@
"url": "presskit", "url": "presskit",
"title": "Press Kit", "title": "Press Kit",
"tooltip": "Press contacts, logos, and branding." "tooltip": "Press contacts, logos, and branding."
},
{
"url": "https://blog.angularjs.org/",
"title": "Blog",
"tooltip": "Angular Blog"
} }
] ]
}, },

View File

@ -1,12 +1,5 @@
@title
Tutorial: Tour of Heroes
@intro
The Tour of Heroes tutorial takes you through the steps of creating an Angular application in TypeScript.
@description
# Tutorial: Tour of Heroes
The grand plan for this tutorial is to build an app that helps a staffing agency manage its stable of heroes. The grand plan for this tutorial is to build an app that helps a staffing agency manage its stable of heroes.
@ -34,7 +27,7 @@ When you're done with this tutorial, the app will look like this <live-example n
## The end game ## What you'll build
Here's a visual idea of where this tutorial leads, beginning with the "Dashboard" Here's a visual idea of where this tutorial leads, beginning with the "Dashboard"
view and the most heroic heroes: view and the most heroic heroes:

View File

@ -1200,7 +1200,7 @@ These correspond to the full set of master styles that you installed earlier dur
Here's an excerpt: Here's an excerpt:
<code-example path="toh-pt5/src/styles.css" region="toh" title="src/styles.css (excerpt)"> <code-example path="toh-pt5/src/styles.1.css" title="src/styles.css (excerpt)">
</code-example> </code-example>

View File

@ -27,9 +27,7 @@ describe('site App', function() {
// Show the menu // Show the menu
page.docsMenuLink.click(); page.docsMenuLink.click();
// Open the tutorial header // Tutorial folder should still be expanded because this test runs in wide mode
page.getNavItem(/tutorial/i).click();
// Navigate to the tutorial introduction via a link in the sidenav // Navigate to the tutorial introduction via a link in the sidenav
page.getNavItem(/introduction/i).click(); page.getNavItem(/introduction/i).click();
expect(page.getDocViewerText()).toMatch(/Tutorial: Tour of Heroes/i); expect(page.getDocViewerText()).toMatch(/Tutorial: Tour of Heroes/i);
@ -61,14 +59,6 @@ describe('site App', function() {
}); });
}); });
describe('api-docs', () => {
it('should show a link to github', () => {
page.navigateTo('api/common/NgClass');
expect(page.ghLink.getAttribute('href'))
.toMatch(/https:\/\/github.com\/angular\/angular\/tree\/.+\/packages\/common\/src\/directives\/ng_class\.ts/);
});
});
describe('tutorial docs', () => { describe('tutorial docs', () => {
it('should not render a paragraph element inside the h1 element', () => { it('should not render a paragraph element inside the h1 element', () => {
page.navigateTo('tutorial/toh-pt1'); page.navigateTo('tutorial/toh-pt1');

View File

@ -39,17 +39,17 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular/animations": "next", "@angular/animations": "4.2.0",
"@angular/common": "next", "@angular/common": "4.2.0",
"@angular/compiler": "next", "@angular/compiler": "4.2.0",
"@angular/core": "next", "@angular/core": "4.2.0",
"@angular/forms": "next", "@angular/forms": "4.2.0",
"@angular/http": "next", "@angular/http": "4.2.0",
"@angular/material": "^2.0.0-beta.3", "@angular/material": "^2.0.0-beta.3",
"@angular/platform-browser": "next", "@angular/platform-browser": "4.2.0",
"@angular/platform-browser-dynamic": "next", "@angular/platform-browser-dynamic": "4.2.0",
"@angular/platform-server": "next", "@angular/platform-server": "4.2.0",
"@angular/router": "next", "@angular/router": "4.2.0",
"@angular/service-worker": "^1.0.0-beta.12", "@angular/service-worker": "^1.0.0-beta.12",
"classlist.js": "^1.1.20150312", "classlist.js": "^1.1.20150312",
"core-js": "^2.4.1", "core-js": "^2.4.1",
@ -63,7 +63,7 @@
}, },
"devDependencies": { "devDependencies": {
"@angular/cli": "^1.1.0-rc.0", "@angular/cli": "^1.1.0-rc.0",
"@angular/compiler-cli": "next", "@angular/compiler-cli": "4.2.0",
"@types/jasmine": "^2.5.47", "@types/jasmine": "^2.5.47",
"@types/node": "~6.0.60", "@types/node": "~6.0.60",
"archiver": "^1.3.0", "archiver": "^1.3.0",
@ -83,6 +83,7 @@
"hast-util-to-string": "^1.0.0", "hast-util-to-string": "^1.0.0",
"html": "^1.0.0", "html": "^1.0.0",
"http-server": "^0.9.0", "http-server": "^0.9.0",
"ignore": "^3.3.3",
"image-size": "^0.5.1", "image-size": "^0.5.1",
"jasmine-core": "~2.5.2", "jasmine-core": "~2.5.2",
"jasmine-spec-reporter": "~3.2.0", "jasmine-spec-reporter": "~3.2.0",
@ -106,7 +107,7 @@
"tree-kill": "^1.1.0", "tree-kill": "^1.1.0",
"ts-node": "~2.0.0", "ts-node": "~2.0.0",
"tslint": "~4.5.0", "tslint": "~4.5.0",
"typescript": "2.2.0", "typescript": "2.3.2",
"unist-util-filter": "^0.2.1", "unist-util-filter": "^0.2.1",
"unist-util-source": "^1.0.1", "unist-util-source": "^1.0.1",
"unist-util-visit": "^1.1.1", "unist-util-visit": "^1.1.1",

View File

@ -5,7 +5,7 @@
</div> </div>
<md-toolbar color="primary" class="app-toolbar"> <md-toolbar color="primary" class="app-toolbar">
<button class="hamburger" md-button <button class="hamburger" [class.starting]="isStarting" md-button
(click)="sidenav.toggle()" title="Docs menu"> (click)="sidenav.toggle()" title="Docs menu">
<md-icon [ngClass]="{'sidenav-open': !isSideBySide }" svgIcon="menu"></md-icon> <md-icon [ngClass]="{'sidenav-open': !isSideBySide }" svgIcon="menu"></md-icon>
</button> </button>
@ -15,11 +15,11 @@
</md-toolbar> </md-toolbar>
<aio-search-results #searchResults *ngIf="showSearchResults" (resultSelected)="hideSearchResults()"></aio-search-results> <aio-search-results #searchResults *ngIf="showSearchResults" (resultSelected)="hideSearchResults()"></aio-search-results>
<md-sidenav-container class="sidenav-container" [class.starting]="isStarting" role="main"> <md-sidenav-container class="sidenav-container" [class.starting]="isStarting" [class.has-floating-toc]="hasFloatingToc" role="main">
<md-sidenav [ngClass]="{'collapsed': !isSideBySide }" #sidenav class="sidenav" [opened]="isOpened" [mode]="mode" (open)="updateHostClasses()" (close)="updateHostClasses()"> <md-sidenav [ngClass]="{'collapsed': !isSideBySide }" #sidenav class="sidenav" [opened]="isOpened" [mode]="mode" (open)="updateHostClasses()" (close)="updateHostClasses()">
<aio-nav-menu *ngIf="!isSideBySide" [nodes]="topMenuNarrowNodes" [currentNode]="currentNodes?.TopBarNarrow"></aio-nav-menu> <aio-nav-menu *ngIf="!isSideBySide" [nodes]="topMenuNarrowNodes" [currentNode]="currentNodes?.TopBarNarrow" [isWide]="false"></aio-nav-menu>
<aio-nav-menu [nodes]="sideNavNodes" [currentNode]="currentNodes?.SideNav" ></aio-nav-menu> <aio-nav-menu [nodes]="sideNavNodes" [currentNode]="currentNodes?.SideNav" [isWide]="isSideBySide"></aio-nav-menu>
<div class="doc-version" title="Angular docs version {{currentDocVersion?.title}}"> <div class="doc-version" title="Angular docs version {{currentDocVersion?.title}}">
<aio-select (change)="onDocVersionChange($event.index)" [options]="docVersions" [selected]="docVersions && docVersions[0]"></aio-select> <aio-select (change)="onDocVersionChange($event.index)" [options]="docVersions" [selected]="docVersions && docVersions[0]"></aio-select>
@ -33,7 +33,7 @@
</md-sidenav-container> </md-sidenav-container>
<div *ngIf="showFloatingToc" class="toc-container" [style.max-height.px]="tocMaxHeight"> <div *ngIf="hasFloatingToc" class="toc-container" [style.max-height.px]="tocMaxHeight" (mousewheel)="restrainScrolling($event)">
<aio-toc></aio-toc> <aio-toc></aio-toc>
</div> </div>

View File

@ -3,7 +3,7 @@ import { async, inject, ComponentFixture, TestBed, fakeAsync, tick } from '@angu
import { Title } from '@angular/platform-browser'; import { Title } from '@angular/platform-browser';
import { APP_BASE_HREF } from '@angular/common'; import { APP_BASE_HREF } from '@angular/common';
import { Http } from '@angular/http'; import { Http } from '@angular/http';
import { MdProgressBar } from '@angular/material'; import { MdProgressBar, MdSidenav } from '@angular/material';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@ -27,7 +27,7 @@ import { SearchService } from 'app/search/search.service';
import { SelectComponent, Option } from 'app/shared/select/select.component'; import { SelectComponent, Option } from 'app/shared/select/select.component';
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service'; import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service';
import { TocComponent } from 'app/embedded/toc/toc.component'; import { TocComponent } from 'app/embedded/toc/toc.component';
import { MdSidenav } from '@angular/material'; import { TocItem, TocService } from 'app/shared/toc.service';
const sideBySideBreakPoint = 992; const sideBySideBreakPoint = 992;
const hideToCBreakPoint = 800; const hideToCBreakPoint = 800;
@ -40,6 +40,7 @@ describe('AppComponent', () => {
let hamburger: HTMLButtonElement; let hamburger: HTMLButtonElement;
let locationService: MockLocationService; let locationService: MockLocationService;
let sidenav: HTMLElement; let sidenav: HTMLElement;
let tocService: TocService;
const initializeTest = () => { const initializeTest = () => {
fixture = TestBed.createComponent(AppComponent); fixture = TestBed.createComponent(AppComponent);
@ -48,10 +49,12 @@ describe('AppComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
component.onResize(sideBySideBreakPoint + 1); // wide by default component.onResize(sideBySideBreakPoint + 1); // wide by default
docViewer = fixture.debugElement.query(By.css('aio-doc-viewer')).nativeElement; const de = fixture.debugElement;
hamburger = fixture.debugElement.query(By.css('.hamburger')).nativeElement; docViewer = de.query(By.css('aio-doc-viewer')).nativeElement;
locationService = fixture.debugElement.injector.get(LocationService) as any; hamburger = de.query(By.css('.hamburger')).nativeElement;
sidenav = fixture.debugElement.query(By.css('md-sidenav')).nativeElement; locationService = de.injector.get(LocationService) as any as MockLocationService;
sidenav = de.query(By.css('md-sidenav')).nativeElement;
tocService = de.injector.get(TocService);
}; };
describe('with proper DocViewer', () => { describe('with proper DocViewer', () => {
@ -72,19 +75,74 @@ describe('AppComponent', () => {
}); });
}); });
describe('onResize', () => { describe('hasFloatingToc', () => {
it('should update `isSideBySide` accordingly', () => { it('should initially be true', () => {
component.onResize(sideBySideBreakPoint + 1); const fixture2 = TestBed.createComponent(AppComponent);
expect(component.isSideBySide).toBe(true); const component2 = fixture2.componentInstance;
component.onResize(sideBySideBreakPoint - 1);
expect(component.isSideBySide).toBe(false); expect(component2.hasFloatingToc).toBe(true);
}); });
it('should update `showFloatingToc` accordingly', () => { it('should be false on narrow screens', () => {
component.onResize(hideToCBreakPoint + 1);
expect(component.showFloatingToc).toBe(true);
component.onResize(hideToCBreakPoint - 1); component.onResize(hideToCBreakPoint - 1);
expect(component.showFloatingToc).toBe(false);
tocService.tocList.next([{}, {}, {}] as TocItem[]);
expect(component.hasFloatingToc).toBe(false);
tocService.tocList.next([]);
expect(component.hasFloatingToc).toBe(false);
tocService.tocList.next([{}, {}, {}] as TocItem[]);
expect(component.hasFloatingToc).toBe(false);
});
it('should be true on wide screens unless the toc is empty', () => {
component.onResize(hideToCBreakPoint + 1);
tocService.tocList.next([{}, {}, {}] as TocItem[]);
expect(component.hasFloatingToc).toBe(true);
tocService.tocList.next([]);
expect(component.hasFloatingToc).toBe(false);
tocService.tocList.next([{}, {}, {}] as TocItem[]);
expect(component.hasFloatingToc).toBe(true);
});
it('should be false when toc is empty', () => {
tocService.tocList.next([]);
component.onResize(hideToCBreakPoint + 1);
expect(component.hasFloatingToc).toBe(false);
component.onResize(hideToCBreakPoint - 1);
expect(component.hasFloatingToc).toBe(false);
component.onResize(hideToCBreakPoint + 1);
expect(component.hasFloatingToc).toBe(false);
});
it('should be true when toc is not empty unless the screen is narrow', () => {
tocService.tocList.next([{}, {}, {}] as TocItem[]);
component.onResize(hideToCBreakPoint + 1);
expect(component.hasFloatingToc).toBe(true);
component.onResize(hideToCBreakPoint - 1);
expect(component.hasFloatingToc).toBe(false);
component.onResize(hideToCBreakPoint + 1);
expect(component.hasFloatingToc).toBe(true);
});
});
describe('isSideBySide', () => {
it('should be updated on resize', () => {
component.onResize(sideBySideBreakPoint - 1);
expect(component.isSideBySide).toBe(false);
component.onResize(sideBySideBreakPoint + 1);
expect(component.isSideBySide).toBe(true);
}); });
}); });
@ -472,18 +530,82 @@ describe('AppComponent', () => {
})); }));
}); });
describe('restrainScrolling()', () => {
const preventedScrolling = (currentTarget: object, deltaY: number) => {
const evt = {
deltaY,
currentTarget,
defaultPrevented: false,
preventDefault() { this.defaultPrevented = true; }
} as any as WheelEvent;
component.restrainScrolling(evt);
return evt.defaultPrevented;
};
it('should prevent scrolling up if already at the top', () => {
const elem = {scrollTop: 0};
expect(preventedScrolling(elem, -100)).toBe(true);
expect(preventedScrolling(elem, +100)).toBe(false);
expect(preventedScrolling(elem, -10)).toBe(true);
});
it('should prevent scrolling down if already at the bottom', () => {
const elem = {scrollTop: 100, scrollHeight: 150, clientHeight: 50};
expect(preventedScrolling(elem, +10)).toBe(true);
expect(preventedScrolling(elem, -10)).toBe(false);
expect(preventedScrolling(elem, +5)).toBe(true);
elem.clientHeight -= 10;
expect(preventedScrolling(elem, +5)).toBe(false);
elem.scrollHeight -= 20;
expect(preventedScrolling(elem, +5)).toBe(true);
elem.scrollTop -= 30;
expect(preventedScrolling(elem, +5)).toBe(false);
});
it('should not prevent scrolling if neither at the top nor at the bottom', () => {
const elem = {scrollTop: 50, scrollHeight: 150, clientHeight: 50};
expect(preventedScrolling(elem, +100)).toBe(false);
expect(preventedScrolling(elem, -100)).toBe(false);
});
});
describe('aio-toc', () => { describe('aio-toc', () => {
let tocDebugElement: DebugElement; let tocDebugElement: DebugElement;
let tocContainer: DebugElement; let tocContainer: DebugElement;
beforeEach(() => { const setHasFloatingToc = hasFloatingToc => {
component.hasFloatingToc = hasFloatingToc;
fixture.detectChanges();
tocDebugElement = fixture.debugElement.query(By.directive(TocComponent)); tocDebugElement = fixture.debugElement.query(By.directive(TocComponent));
tocContainer = tocDebugElement.parent; tocContainer = tocDebugElement && tocDebugElement.parent;
};
beforeEach(() => setHasFloatingToc(true));
it('should show/hide `<aio-toc>` based on `hasFloatingToc`', () => {
expect(tocDebugElement).toBeTruthy();
expect(tocContainer).toBeTruthy();
setHasFloatingToc(false);
expect(tocDebugElement).toBeFalsy();
expect(tocContainer).toBeFalsy();
setHasFloatingToc(true);
expect(tocDebugElement).toBeTruthy();
expect(tocContainer).toBeTruthy();
}); });
it('should have a non-embedded `<aio-toc>` element', () => { it('should have a non-embedded `<aio-toc>` element', () => {
expect(tocDebugElement).toBeDefined();
expect(tocDebugElement.classes['embedded']).toBeFalsy(); expect(tocDebugElement.classes['embedded']).toBeFalsy();
}); });
@ -495,6 +617,16 @@ describe('AppComponent', () => {
expect(tocContainer.styles['max-height']).toBe('100px'); expect(tocContainer.styles['max-height']).toBe('100px');
}); });
it('should restrain scrolling inside the ToC container', () => {
const restrainScrolling = spyOn(component, 'restrainScrolling');
const evt = {};
expect(restrainScrolling).not.toHaveBeenCalled();
tocContainer.triggerEventHandler('mousewheel', evt);
expect(restrainScrolling).toHaveBeenCalledWith(evt);
});
}); });
describe('footer', () => { describe('footer', () => {

View File

@ -12,7 +12,9 @@ import { SearchResultsComponent } from 'app/search/search-results/search-results
import { SearchBoxComponent } from 'app/search/search-box/search-box.component'; import { SearchBoxComponent } from 'app/search/search-box/search-box.component';
import { SearchService } from 'app/search/search.service'; import { SearchService } from 'app/search/search.service';
import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service'; import { SwUpdateNotificationsService } from 'app/sw-updates/sw-update-notifications.service';
import { TocService } from 'app/shared/toc.service';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { combineLatest } from 'rxjs/observable/combineLatest'; import { combineLatest } from 'rxjs/observable/combineLatest';
const sideNavView = 'SideNav'; const sideNavView = 'SideNav';
@ -65,8 +67,9 @@ export class AppComponent implements OnInit {
topMenuNodes: NavigationNode[]; topMenuNodes: NavigationNode[];
topMenuNarrowNodes: NavigationNode[]; topMenuNarrowNodes: NavigationNode[];
showFloatingToc = false; hasFloatingToc = true;
showFloatingTocWidth = 800; private showFloatingToc = new BehaviorSubject(false);
private showFloatingTocWidth = 800;
tocMaxHeight: string; tocMaxHeight: string;
private tocMaxHeightOffset = 0; private tocMaxHeightOffset = 0;
@ -103,8 +106,9 @@ export class AppComponent implements OnInit {
private navigationService: NavigationService, private navigationService: NavigationService,
private scrollService: ScrollService, private scrollService: ScrollService,
private searchService: SearchService, private searchService: SearchService,
private swUpdateNotifications: SwUpdateNotificationsService private swUpdateNotifications: SwUpdateNotificationsService,
) { } private tocService: TocService
) { }
ngOnInit() { ngOnInit() {
// Do not initialize the search on browsers that lack web worker support // Do not initialize the search on browsers that lack web worker support
@ -174,6 +178,10 @@ export class AppComponent implements OnInit {
this.navigationService.versionInfo.subscribe( vi => this.versionInfo = vi ); this.navigationService.versionInfo.subscribe( vi => this.versionInfo = vi );
this.swUpdateNotifications.enable(); this.swUpdateNotifications.enable();
const hasNonEmptyToc = this.tocService.tocList.map(tocList => tocList.length > 0);
combineLatest(hasNonEmptyToc, this.showFloatingToc)
.subscribe(([hasToc, showFloatingToc]) => this.hasFloatingToc = hasToc && showFloatingToc);
} }
// Scroll to the anchor in the hash fragment or top of doc. // Scroll to the anchor in the hash fragment or top of doc.
@ -207,7 +215,7 @@ export class AppComponent implements OnInit {
@HostListener('window:resize', ['$event.target.innerWidth']) @HostListener('window:resize', ['$event.target.innerWidth'])
onResize(width) { onResize(width) {
this.isSideBySide = width > this.sideBySideWidth; this.isSideBySide = width > this.sideBySideWidth;
this.showFloatingToc = width > this.showFloatingTocWidth; this.showFloatingToc.next(width > this.showFloatingTocWidth);
} }
@HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey', '$event.altKey']) @HostListener('click', ['$event.target', '$event.button', '$event.ctrlKey', '$event.metaKey', '$event.altKey'])
@ -275,6 +283,25 @@ export class AppComponent implements OnInit {
this.tocMaxHeight = (document.body.scrollHeight - window.pageYOffset - this.tocMaxHeightOffset).toFixed(2); this.tocMaxHeight = (document.body.scrollHeight - window.pageYOffset - this.tocMaxHeightOffset).toFixed(2);
} }
// Restrain scrolling inside an element, when the cursor is over it
restrainScrolling(evt: WheelEvent) {
const elem = evt.currentTarget as Element;
const scrollTop = elem.scrollTop;
if (evt.deltaY < 0) {
// Trying to scroll up: Prevent scrolling if already at the top.
if (scrollTop < 1) {
evt.preventDefault();
}
} else {
// Trying to scroll down: Prevent scrolling if already at the bottom.
const maxScrollTop = elem.scrollHeight - elem.clientHeight;
if (maxScrollTop - scrollTop < 1) {
evt.preventDefault();
}
}
}
// Search related methods and handlers // Search related methods and handlers

View File

@ -20,7 +20,7 @@
</button> </button>
<div class="heading-children" [ngClass]="classes"> <div class="heading-children" [ngClass]="classes">
<aio-nav-item *ngFor="let node of node.children" [level]="level + 1" <aio-nav-item *ngFor="let node of node.children" [level]="level + 1" [isWide]="isWide"
[node]="node" [selectedNodes]="selectedNodes"></aio-nav-item> [node]="node" [selectedNodes]="selectedNodes"></aio-nav-item>
</div> </div>
</div> </div>

View File

@ -1,159 +1,196 @@
import { TestBed } from '@angular/core/testing';
import { SimpleChange, SimpleChanges } from '@angular/core'; import { By } from '@angular/platform-browser';
import { SimpleChange, SimpleChanges, NO_ERRORS_SCHEMA } from '@angular/core';
import { NavItemComponent } from './nav-item.component'; import { NavItemComponent } from './nav-item.component';
import { NavigationNode } from 'app/navigation/navigation.model'; import { NavigationNode } from 'app/navigation/navigation.model';
// Testing the component class behaviors, independent of its template describe('NavItemComponent', () => {
// No dependencies. Just new it and test :)
// Let e2e tests verify how it displays.
describe('NavItemComponent (class-only)', () => {
let component: NavItemComponent; // Testing the component class behaviors, independent of its template
// No dependencies. Just new it and test :)
// Let e2e tests verify how it displays.
describe('(class-only)', () => {
let selectedNodes: NavigationNode[]; let component: NavItemComponent;
let setClassesSpy: jasmine.Spy;
function initialize(nd: NavigationNode) { let selectedNodes: NavigationNode[];
component.node = nd; let setClassesSpy: jasmine.Spy;
onChanges(); // Angular calls when initializing the component
}
// Enough to triggers component's ngOnChange method function initialize(nd: NavigationNode) {
function onChanges() { component.node = nd;
component.ngOnChanges({node: <SimpleChange><any> 'anything' }); onChanges(); // Angular calls when initializing the component
} }
beforeEach(() => { // Enough to triggers component's ngOnChange method
function onChanges() {
component.ngOnChanges({node: <SimpleChange><any> 'anything' });
}
component = new NavItemComponent(); beforeEach(() => {
setClassesSpy = spyOn(component, 'setClasses').and.callThrough();
// Selected nodes is the selected node and its header ancestors component = new NavItemComponent();
selectedNodes = [ setClassesSpy = spyOn(component, 'setClasses').and.callThrough();
{ title: 'a' }, // selected node: an item or a header
{ title: 'parent' }, // selected node's header parent
{ title: 'grandparent' }, // selected node's header grandparent
];
component.selectedNodes = selectedNodes;
});
describe('should have expected classes when initialized', () => { // Selected nodes is the selected node and its header ancestors
it('with selected node', () => { selectedNodes = [
initialize(selectedNodes[0]); { title: 'a' }, // selected node: an item or a header
expect(component.classes).toEqual( { title: 'parent' }, // selected node's header parent
// selecting the current node has no effect on expanded state, { title: 'grandparent' }, // selected node's header grandparent
// even if current node is a header. ];
{ 'level-1': true, collapsed: true, expanded: false, selected: true} component.selectedNodes = selectedNodes;
);
}); });
it('with selected node ancestor', () => { describe('should have expected classes when initialized', () => {
initialize(selectedNodes[1]); it('with selected node', () => {
expect(component.classes).toEqual( initialize(selectedNodes[0]);
// ancestor is a header and should be expanded expect(component.classes).toEqual(
{ 'level-1': true, collapsed: false, expanded: true, selected: true} // selected node should be expanded even if is a header.
); { 'level-1': true, collapsed: false, expanded: true, selected: true }
);
});
it('with selected node ancestor', () => {
initialize(selectedNodes[1]);
expect(component.classes).toEqual(
// ancestor is a header and should be expanded
{ 'level-1': true, collapsed: false, expanded: true, selected: true }
);
});
it('with other than a selected node or ancestor', () => {
initialize({ title: 'x' });
expect(component.classes).toEqual(
{ 'level-1': true, collapsed: true, expanded: false, selected: false }
);
});
}); });
it('with other than a selected node or ancestor', () => { describe('when becomes a non-selected node', () => {
initialize({ title: 'x' });
expect(component.classes).toEqual( // this node won't be the selected node when ngOnChanges() called
{ 'level-1': true, collapsed: true, expanded: false, selected: false} beforeEach(() => component.node = { title: 'x' });
);
it('should de-select if previously selected', () => {
component.isSelected = true;
onChanges();
expect(component.isSelected).toBe(false, 'becomes de-selected');
});
it('should collapse if previously expanded in narrow mode', () => {
component.isWide = false;
component.isExpanded = true;
onChanges();
expect(component.isExpanded).toBe(false, 'becomes collapsed');
});
it('should remain expanded in wide mode', () => {
component.isWide = true;
component.isExpanded = true;
onChanges();
expect(component.isExpanded).toBe(true, 'remains expanded');
});
});
describe('when becomes a selected node', () => {
// this node will be the selected node when ngOnChanges() called
beforeEach(() => component.node = selectedNodes[0]);
it('should select when previously not selected', () => {
component.isSelected = false;
onChanges();
expect(component.isSelected).toBe(true, 'becomes selected');
});
it('should expand the current node or keep it expanded', () => {
component.isExpanded = false;
onChanges();
expect(component.isExpanded).toBe(true, 'becomes true');
component.isExpanded = true;
onChanges();
expect(component.isExpanded).toBe(true, 'remains true');
});
});
describe('when becomes a selected ancestor node', () => {
// this node will be a selected node ancestor header when ngOnChanges() called
beforeEach(() => component.node = selectedNodes[2]);
it('should select when previously not selected', () => {
component.isSelected = false;
onChanges();
expect(component.isSelected).toBe(true, 'becomes selected');
});
it('should always expand this header', () => {
component.isExpanded = false;
onChanges();
expect(component.isExpanded).toBe(true, 'becomes expanded');
component.isExpanded = false;
onChanges();
expect(component.isExpanded).toBe(true, 'stays expanded');
});
});
describe('when headerClicked()', () => {
// current node doesn't matter in these tests.
it('should expand when headerClicked() and previously collapsed', () => {
component.isExpanded = false;
component.headerClicked();
expect(component.isExpanded).toBe(true, 'should be expanded');
});
it('should collapse when headerClicked() and previously expanded', () => {
component.isExpanded = true;
component.headerClicked();
expect(component.isExpanded).toBe(false, 'should be collapsed');
});
it('should not change isSelected when headerClicked()', () => {
component.isSelected = true;
component.headerClicked();
expect(component.isSelected).toBe(true, 'remains selected');
component.isSelected = false;
component.headerClicked();
expect(component.isSelected).toBe(false, 'remains not selected');
});
it('should set classes', () => {
component.headerClicked();
expect(setClassesSpy).toHaveBeenCalled();
});
}); });
}); });
describe('when becomes a non-selected node', () => { describe('(via TestBed)', () => {
it('should pass the `isWide` property to all child nav-items', () => {
TestBed.configureTestingModule({
declarations: [NavItemComponent],
schemas: [NO_ERRORS_SCHEMA]
});
const fixture = TestBed.createComponent(NavItemComponent);
fixture.componentInstance.node = {
title: 'x',
children: [{ title: 'a' }, { title: 'b' }]
};
// this node won't be the selected node when ngOnChanges() called fixture.componentInstance.isWide = true;
beforeEach(() => component.node = { title: 'x' }); fixture.detectChanges();
let children = fixture.debugElement.queryAll(By.directive(NavItemComponent));
expect(children.length).toEqual(2);
children.forEach(child => expect(child.componentInstance.isWide).toBe(true));
it('should collapse if previously expanded', () => { fixture.componentInstance.isWide = false;
component.isExpanded = true; fixture.detectChanges();
onChanges(); children = fixture.debugElement.queryAll(By.directive(NavItemComponent));
expect(component.isExpanded).toBe(false, 'becomes collapsed'); expect(children.length).toEqual(2);
}); children.forEach(child => expect(child.componentInstance.isWide).toBe(false));
it('should de-select if previously selected', () => {
component.isSelected = true;
onChanges();
expect(component.isSelected).toBe(false, 'becomes de-selected');
});
});
describe('when becomes a selected node', () => {
// this node will be the selected node when ngOnChanges() called
beforeEach(() => component.node = selectedNodes[0]);
it('should select when previously not selected', () => {
component.isSelected = false;
onChanges();
expect(component.isSelected).toBe(true, 'becomes selected');
});
it('should leave the expanded/collapsed state untouched', () => {
component.isExpanded = false;
onChanges();
expect(component.isExpanded).toBe(false, 'remains false');
component.isExpanded = true;
onChanges();
expect(component.isExpanded).toBe(true, 'remains true');
});
});
describe('when becomes a selected ancestor node', () => {
// this node will be a selected node ancestor header when ngOnChanges() called
beforeEach(() => component.node = selectedNodes[2]);
it('should select when previously not selected', () => {
component.isSelected = false;
onChanges();
expect(component.isSelected).toBe(true, 'becomes selected');
});
it('should always expand this header', () => {
component.isExpanded = false;
onChanges();
expect(component.isExpanded).toBe(true, 'becomes expanded');
component.isExpanded = false;
onChanges();
expect(component.isExpanded).toBe(true, 'stays expanded');
});
});
describe('when headerClicked()', () => {
// current node doesn't matter in these tests.
it('should expand when headerClicked() and previously collapsed', () => {
component.isExpanded = false;
component.headerClicked();
expect(component.isExpanded).toBe(true, 'should be expanded');
});
it('should collapse when headerClicked() and previously expanded', () => {
component.isExpanded = true;
component.headerClicked();
expect(component.isExpanded).toBe(false, 'should be collapsed');
});
it('should not change isSelected when headerClicked()', () => {
component.isSelected = true;
component.headerClicked();
expect(component.isSelected).toBe(true, 'remains selected');
component.isSelected = false;
component.headerClicked();
expect(component.isSelected).toBe(false, 'remains not selected');
});
it('should set classes', () => {
component.headerClicked();
expect(setClassesSpy).toHaveBeenCalled();
}); });
}); });
}); });

View File

@ -6,20 +6,23 @@ import { NavigationNode } from 'app/navigation/navigation.model';
templateUrl: 'nav-item.component.html', templateUrl: 'nav-item.component.html',
}) })
export class NavItemComponent implements OnChanges { export class NavItemComponent implements OnChanges {
@Input() selectedNodes: NavigationNode[]; @Input() isWide = false;
@Input() node: NavigationNode;
@Input() level = 1; @Input() level = 1;
@Input() node: NavigationNode;
@Input() selectedNodes: NavigationNode[];
isExpanded = false; isExpanded = false;
isSelected = false; isSelected = false;
classes: {[index: string]: boolean }; classes: {[index: string]: boolean };
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
if (changes['selectedNodes'] || changes['node']) { if (changes['selectedNodes'] || changes['node'] || changes['isWide']) {
if (this.selectedNodes) { if (this.selectedNodes) {
const ix = this.selectedNodes.indexOf(this.node); const ix = this.selectedNodes.indexOf(this.node);
this.isSelected = ix !== -1; this.isSelected = ix !== -1; // this node is the selected node or its ancestor
if (ix !== 0) { this.isExpanded = this.isSelected; } this.isExpanded = this.isSelected || // expand if selected or ...
// preserve expanded state when display is wide; collapse in mobile.
(this.isWide && this.isExpanded);
} else { } else {
this.isSelected = false; this.isSelected = false;
} }

View File

@ -4,11 +4,12 @@ import { CurrentNode, NavigationNode } from 'app/navigation/navigation.service';
@Component({ @Component({
selector: 'aio-nav-menu', selector: 'aio-nav-menu',
template: ` template: `
<aio-nav-item *ngFor="let node of filteredNodes" [node]="node" [selectedNodes]="currentNode?.nodes"> <aio-nav-item *ngFor="let node of filteredNodes" [node]="node" [selectedNodes]="currentNode?.nodes" [isWide]="isWide">
</aio-nav-item>` </aio-nav-item>`
}) })
export class NavMenuComponent { export class NavMenuComponent {
@Input() currentNode: CurrentNode; @Input() currentNode: CurrentNode;
@Input() nodes: NavigationNode[] ; @Input() isWide = false;
@Input() nodes: NavigationNode[];
get filteredNodes() { return this.nodes ? this.nodes.filter(n => !n.hidden) : []; } get filteredNodes() { return this.nodes ? this.nodes.filter(n => !n.hidden) : []; }
} }

View File

@ -42,12 +42,12 @@ md-sidenav.mat-sidenav.sidenav {
md-sidenav-container.sidenav-container { md-sidenav-container.sidenav-container {
min-height: 100%; min-height: 100%;
height: auto !important; height: auto !important;
max-width: 82%; max-width: 100%;
margin: 0; margin: 0;
transform: none; transform: none;
@media (max-width: 800px) { &.has-floating-toc {
max-width: 100%; max-width: 82%;
} }
} }
@ -135,6 +135,7 @@ button.vertical-menu-item {
font-weight: 400; font-weight: 400;
padding-left: 20px; padding-left: 20px;
transition: background-color 0.2s; transition: background-color 0.2s;
text-transform: uppercase;
} }
.level-2 { .level-2 {

View File

@ -43,9 +43,11 @@ aio-top-menu {
&:focus { &:focus {
outline: none; outline: none;
background: rgba($white, 0.15); // Temporarily remove the focus styling until we update to an @angular/material version that
border-radius: 4px; // includes https://github.com/angular/material2/commit/3bc82f6dc.
padding: 8px 16px; // background: rgba($white, 0.15);
// border-radius: 4px;
// padding: 8px 16px;
} }
} }
} }
@ -86,10 +88,8 @@ aio-shell.page-resources md-toolbar.mat-toolbar {
} }
@media (min-width: 992px) { @media (min-width: 992px) {
padding-left: 24px;
button.hamburger { button.hamburger {
display: none; margin: 0 24px 0 -88px;
} }
} }
} }

View File

@ -1,13 +1,13 @@
.api-info-bar { .api-info-bar {
max-width: 800px; max-width: 800px;
text-align: center; text-align: left;
span { span {
margin: 0 16px; margin: 0 16px 0 0;
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
display: block; display: block;
} }
} }
} }

View File

@ -8,14 +8,19 @@
} }
.hamburger.mat-button { .hamburger.mat-button {
transition: color 0.2s; height: 100%;
height: 100%; margin: 0;
margin: 0; padding: 0;
padding: 0;
&:not(.starting) {
transition-duration: .4s;
transition-property: color, margin;
transition-timing-function: cubic-bezier(.25, .8, .25, 1);
}
} }
.hamburger.mat-button:hover { .hamburger.mat-button:hover {
color: $offwhite; color: $offwhite;
} }
.hamburger .mat-icon { .hamburger .mat-icon {

View File

@ -1,4 +1,3 @@
/* #docregion , quickstart, toh */
/* Master Styles */ /* Master Styles */
h1 { h1 {
color: #369; color: #369;
@ -13,12 +12,10 @@ h2, h3 {
body { body {
margin: 2em; margin: 2em;
} }
/* #enddocregion quickstart */
body, input[text], button { body, input[text], button {
color: #888; color: #888;
font-family: Cambria, Georgia; font-family: Cambria, Georgia;
} }
/* #enddocregion toh */
a { a {
cursor: pointer; cursor: pointer;
cursor: hand; cursor: hand;
@ -62,54 +59,6 @@ nav a.active {
color: #039be5; color: #039be5;
} }
/* items class */
.items {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 24em;
}
.items li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.items li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.items li.selected {
background-color: #CFD8DC;
color: white;
}
.items li.selected:hover {
background-color: #BBD8DC;
}
.items .text {
position: relative;
top: -3px;
}
.items .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
/* #docregion toh */
/* everywhere else */ /* everywhere else */
* { * {
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;

View File

@ -67,7 +67,7 @@
'rxjs': 'npm:rxjs@5.0.1', 'rxjs': 'npm:rxjs@5.0.1',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js', 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js', 'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js',
'typescript': 'npm:typescript@2.2.1/lib/typescript.js', 'typescript': 'npm:typescript@2.3.2/lib/typescript.js',
}, },
// packages tells the System loader how to load when no filename and/or no extension // packages tells the System loader how to load when no filename and/or no extension

View File

@ -54,7 +54,7 @@
'rxjs': 'npm:rxjs@5.0.1', 'rxjs': 'npm:rxjs@5.0.1',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js', 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js', 'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js',
'typescript': 'npm:typescript@2.2.1/lib/typescript.js', 'typescript': 'npm:typescript@2.3.2/lib/typescript.js',
}, },
// packages tells the System loader how to load when no filename and/or no extension // packages tells the System loader how to load when no filename and/or no extension

View File

@ -12,19 +12,19 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@angular/animations": "~4.0.0", "@angular/animations": "~4.2.0",
"@angular/common": "~4.0.0", "@angular/common": "~4.2.0",
"@angular/compiler": "~4.0.0", "@angular/compiler": "~4.2.0",
"@angular/compiler-cli": "~4.0.0", "@angular/compiler-cli": "~4.2.0",
"@angular/core": "~4.0.0", "@angular/core": "~4.2.0",
"@angular/forms": "~4.0.0", "@angular/forms": "~4.2.0",
"@angular/http": "~4.0.0", "@angular/http": "~4.2.0",
"@angular/platform-browser": "~4.0.0", "@angular/platform-browser": "~4.2.0",
"@angular/platform-browser-dynamic": "~4.0.0", "@angular/platform-browser-dynamic": "~4.2.0",
"@angular/platform-server": "~4.0.0", "@angular/platform-server": "~4.2.0",
"@angular/router": "~4.0.0", "@angular/router": "~4.2.0",
"@angular/tsc-wrapped": "~4.0.0", "@angular/tsc-wrapped": "~4.2.0",
"@angular/upgrade": "~4.0.0", "@angular/upgrade": "~4.2.0",
"angular-in-memory-web-api": "~0.3.2", "angular-in-memory-web-api": "~0.3.2",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"rxjs": "5.0.1", "rxjs": "5.0.1",
@ -80,7 +80,7 @@
"style-loader": "^0.13.1", "style-loader": "^0.13.1",
"ts-node": "^1.3.0", "ts-node": "^1.3.0",
"tslint": "^3.15.1", "tslint": "^3.15.1",
"typescript": "~2.2.0", "typescript": "~2.3.2",
"webpack": "2.2.1", "webpack": "2.2.1",
"webpack-dev-server": "2.4.1", "webpack-dev-server": "2.4.1",
"webpack-merge": "^3.0.0" "webpack-merge": "^3.0.0"

File diff suppressed because it is too large Load Diff

View File

@ -6,17 +6,29 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
const Package = require('dgeni').Package; const Package = require('dgeni').Package;
const globby = require('globby');
const ignore = require('ignore');
const fs = require('fs');
const path = require('canonical-path');
const basePackage = require('../angular-base-package'); const basePackage = require('../angular-base-package');
const contentPackage = require('../content-package'); const contentPackage = require('../content-package');
const { CONTENTS_PATH } = require('../config'); const { CONTENTS_PATH, GUIDE_EXAMPLES_PATH } = require('../config');
module.exports = new Package('angular-content', [basePackage, contentPackage]) module.exports = new Package('angular-content', [basePackage, contentPackage])
// Where do we get the source files? // Where do we get the source files?
.config(function(readFilesProcessor, collectExamples) { .config(function(readFilesProcessor, collectExamples) {
const gitignoreFile = fs.readFileSync(path.resolve(GUIDE_EXAMPLES_PATH, '.gitignore'), 'utf8');
const gitignore = ignore().add(gitignoreFile);
const examplePaths = globby.sync('**/*', { cwd: GUIDE_EXAMPLES_PATH, mark: true, dot: true })
.filter(filePath => filePath !== '.gitignore') // we are not interested in the .gitignore file itself
.filter(filePath => !/\/$/.test(filePath)); // this filter removes the folders, leaving only files
const filteredExamplePaths = gitignore.filter(examplePaths) // filter out files that match the .gitignore rules
.map(filePath => path.resolve(GUIDE_EXAMPLES_PATH, filePath)); // we need the full paths for the filereader
readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([ readFilesProcessor.sourceFiles = readFilesProcessor.sourceFiles.concat([
{ {
basePath: CONTENTS_PATH, basePath: CONTENTS_PATH,
@ -36,26 +48,7 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
}, },
{ {
basePath: CONTENTS_PATH, basePath: CONTENTS_PATH,
include: CONTENTS_PATH + '/examples/**/*', include: filteredExamplePaths,
exclude: [
'**/*plnkr.no-link.html',
'**/node_modules/**',
// boilerplate files
'**/*/src/systemjs-angular-loader.js',
'**/*/src/systemjs.config.js',
'**/*/src/tsconfig.json',
'**/*/bs-config.e2e.json',
'**/*/bs-config.json',
'**/*/package.json',
'**/*/tslint.json',
// example files
'**/_test-output',
'**/protractor-helpers.js',
'**/e2e-spec.js',
'**/ts/**/*.js',
'**/js-es6*/**/*.js',
'**/ts-snippets/**/*.js',
],
fileReader: 'exampleFileReader' fileReader: 'exampleFileReader'
}, },
{ {

View File

@ -6,6 +6,7 @@ const AIO_PATH = resolve(PROJECT_ROOT, 'aio');
const TEMPLATES_PATH = resolve(AIO_PATH, 'tools/transforms/templates'); const TEMPLATES_PATH = resolve(AIO_PATH, 'tools/transforms/templates');
const API_TEMPLATES_PATH = resolve(TEMPLATES_PATH, 'api'); const API_TEMPLATES_PATH = resolve(TEMPLATES_PATH, 'api');
const CONTENTS_PATH = resolve(AIO_PATH, 'content'); const CONTENTS_PATH = resolve(AIO_PATH, 'content');
const GUIDE_EXAMPLES_PATH = resolve(CONTENTS_PATH, 'examples');
const SRC_PATH = resolve(AIO_PATH, 'src'); const SRC_PATH = resolve(AIO_PATH, 'src');
const OUTPUT_PATH = resolve(SRC_PATH, 'generated'); const OUTPUT_PATH = resolve(SRC_PATH, 'generated');
const DOCS_OUTPUT_PATH = resolve(OUTPUT_PATH, 'docs'); const DOCS_OUTPUT_PATH = resolve(OUTPUT_PATH, 'docs');
@ -18,5 +19,5 @@ function requireFolder(dirname, folderPath) {
.map(p => require(resolve(absolutePath, p))); .map(p => require(resolve(absolutePath, p)));
} }
module.exports = { PROJECT_ROOT, AIO_PATH, TEMPLATES_PATH, API_TEMPLATES_PATH, CONTENTS_PATH, SRC_PATH, OUTPUT_PATH, DOCS_OUTPUT_PATH, API_SOURCE_PATH, requireFolder }; module.exports = { PROJECT_ROOT, AIO_PATH, TEMPLATES_PATH, API_TEMPLATES_PATH, CONTENTS_PATH, GUIDE_EXAMPLES_PATH, SRC_PATH, OUTPUT_PATH, DOCS_OUTPUT_PATH, API_SOURCE_PATH, requireFolder };

View File

@ -11,8 +11,4 @@
NgModule: {@link {$ doc.ngModule $}} NgModule: {@link {$ doc.ngModule $}}
</span> </span>
{% endif %} {% endif %}
</div>
<span class="info-bar-item">
{$ github.githubViewLink(doc, versionInfo) $}
</span>
</div>

View File

@ -2,9 +2,11 @@
# yarn lockfile v1 # yarn lockfile v1
"@angular/animations@next": "@angular/animations@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.2.0-beta.1.tgz#0e84c3f306d407da1546db3e8b5490effbe5ad7c" resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-4.2.0.tgz#e964fc56c9621f28679f24d5e69026e2d1571425"
dependencies:
tslib "^1.7.1"
"@angular/cli@^1.1.0-rc.0": "@angular/cli@^1.1.0-rc.0":
version "1.1.0-rc.0" version "1.1.0-rc.0"
@ -69,56 +71,73 @@
optionalDependencies: optionalDependencies:
node-sass "^4.3.0" node-sass "^4.3.0"
"@angular/common@next": "@angular/common@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.2.0-beta.1.tgz#d9d9cfc0188b9e391de9084e1e3f6fac448b5580" resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.2.0.tgz#5df34718bcefc49918bfcb2683f6c19720b66a61"
"@angular/compiler-cli@next":
version "4.2.0-beta.1"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.2.0-beta.1.tgz#24d8dad585ba9ecdb7b6ba8f342d7c1d05cc890b"
dependencies: dependencies:
"@angular/tsc-wrapped" "4.2.0-beta.1" tslib "^1.7.1"
"@angular/compiler-cli@4.2.0":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-4.2.0.tgz#bd6f6b71f003df48a8f86184a8c16533afdf23ec"
dependencies:
"@angular/tsc-wrapped" "4.2.0"
minimist "^1.2.0" minimist "^1.2.0"
reflect-metadata "^0.1.2" reflect-metadata "^0.1.2"
"@angular/compiler@next": "@angular/compiler@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.2.0-beta.1.tgz#0817630876e7d721b1bf6f34c4d1a4434e21164d" resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-4.2.0.tgz#a21df81995b210f822ffd70b57247d474876fbed"
dependencies:
tslib "^1.7.1"
"@angular/core@next": "@angular/core@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.2.0-beta.1.tgz#533c0da98310333ac44bb9249d200db38f514b65" resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.2.0.tgz#8bf57d01379c2a9e29476ad569dec9e20d5b17dc"
dependencies:
tslib "^1.7.1"
"@angular/forms@next": "@angular/forms@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.2.0-beta.1.tgz#fa3be8ab19dd8689bbdeae8c5b8119f2983d24d1" resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-4.2.0.tgz#cb3ae69172e254452fa77578605ebc1bb72138c9"
dependencies:
tslib "^1.7.1"
"@angular/http@next": "@angular/http@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.2.0-beta.1.tgz#0549ea48c82f9b5a568ba2feea5210781b6d3cd3" resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.2.0.tgz#484af53639e04a68834c5167a1955d2d0cde8e1c"
dependencies:
tslib "^1.7.1"
"@angular/material@^2.0.0-beta.3": "@angular/material@^2.0.0-beta.3":
version "2.0.0-beta.4" version "2.0.0-beta.4"
resolved "https://registry.yarnpkg.com/@angular/material/-/material-2.0.0-beta.4.tgz#137ef759867213308613172c54dfe69061a10829" resolved "https://registry.yarnpkg.com/@angular/material/-/material-2.0.0-beta.4.tgz#137ef759867213308613172c54dfe69061a10829"
"@angular/platform-browser-dynamic@next": "@angular/platform-browser-dynamic@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.2.0-beta.1.tgz#a5a19129fcdca0951d62491f8ec6439c26ea93be" resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-4.2.0.tgz#b84c05616bd824e15b52b2b85c47b58b25d0158a"
dependencies:
tslib "^1.7.1"
"@angular/platform-browser@next": "@angular/platform-browser@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.2.0-beta.1.tgz#f26536b11067c3956b2eaa892fd8fe943e8decd4" resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.2.0.tgz#dfd782e7ebacba1bbe2ae0556d5d7fb012f2a6cd"
dependencies:
tslib "^1.7.1"
"@angular/platform-server@next": "@angular/platform-server@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-4.2.0-beta.1.tgz#a530356a2f32bd08a05731b144a0162a5221dcb7" resolved "https://registry.yarnpkg.com/@angular/platform-server/-/platform-server-4.2.0.tgz#90add7fcd9c4f568a31058c9d93a9aca09eb4c58"
dependencies: dependencies:
parse5 "^3.0.1" parse5 "^3.0.1"
tslib "^1.7.1"
xhr2 "^0.1.4" xhr2 "^0.1.4"
"@angular/router@next": "@angular/router@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.2.0-beta.1.tgz#b7a4649120373f667451f62a9d60aafdde793a1b" resolved "https://registry.yarnpkg.com/@angular/router/-/router-4.2.0.tgz#7cda9a23621ee41b466eced8bb4cbb62237ba6b9"
dependencies:
tslib "^1.7.1"
"@angular/service-worker@^1.0.0-beta.12": "@angular/service-worker@^1.0.0-beta.12":
version "1.0.0-beta.13" version "1.0.0-beta.13"
@ -127,9 +146,9 @@
base64-js "^1.1.2" base64-js "^1.1.2"
jshashes "^1.0.5" jshashes "^1.0.5"
"@angular/tsc-wrapped@4.2.0-beta.1": "@angular/tsc-wrapped@4.2.0":
version "4.2.0-beta.1" version "4.2.0"
resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.2.0-beta.1.tgz#78b28b853e4cccf3bda4caee89039de63a7a7fd8" resolved "https://registry.yarnpkg.com/@angular/tsc-wrapped/-/tsc-wrapped-4.2.0.tgz#e62ce9953c27ba96e4c6daf117f10e31169ccea2"
dependencies: dependencies:
tsickle "^0.21.0" tsickle "^0.21.0"
@ -3362,9 +3381,9 @@ ieee754@^1.1.4:
version "1.1.8" version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
ignore@^3.2.0: ignore@^3.2.0, ignore@^3.3.3:
version "3.3.0" version "3.3.3"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.0.tgz#3812d22cbe9125f2c2b4915755a1b8abd745a001" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
ignorefs@^1.0.0, ignorefs@^1.1.1: ignorefs@^1.0.0, ignorefs@^1.1.1:
version "1.2.0" version "1.2.0"
@ -7150,14 +7169,14 @@ typescript@2.1:
version "2.1.6" version "2.1.6"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.6.tgz#40c7e6e9e5da7961b7718b55505f9cac9487a607" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.6.tgz#40c7e6e9e5da7961b7718b55505f9cac9487a607"
typescript@2.2.0, "typescript@>=2.0.0 <2.4.0": typescript@2.3.2, typescript@^2.2.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.0.tgz#626f2fc70087d2480f21ebb12c1888288c8614e3"
typescript@^2.2.1:
version "2.3.2" version "2.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.2.tgz#f0f045e196f69a72f06b25fd3bd39d01c3ce9984" resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.2.tgz#f0f045e196f69a72f06b25fd3bd39d01c3ce9984"
"typescript@>=2.0.0 <2.4.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.0.tgz#626f2fc70087d2480f21ebb12c1888288c8614e3"
uglify-js@^2.6, uglify-js@^2.8.5, uglify-js@~2.8.22: uglify-js@^2.6, uglify-js@^2.8.5, uglify-js@~2.8.22:
version "2.8.23" version "2.8.23"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.23.tgz#8230dd9783371232d62a7821e2cf9a817270a8a0" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.23.tgz#8230dd9783371232d62a7821e2cf9a817270a8a0"

View File

@ -1,6 +1,6 @@
{ {
"name": "angular-srcs", "name": "angular-srcs",
"version": "4.2.0", "version": "4.2.1",
"private": true, "private": true,
"branchPattern": "2.0.*", "branchPattern": "2.0.*",
"description": "Angular - a web framework for modern web apps", "description": "Angular - a web framework for modern web apps",

View File

@ -3,7 +3,8 @@
// For TypeScript 1.8, we have to lay out generated files // For TypeScript 1.8, we have to lay out generated files
// in the same source directory with your code. // in the same source directory with your code.
"genDir": ".", "genDir": ".",
"debug": true "debug": true,
"enableSummariesForJit": true
}, },
"compilerOptions": { "compilerOptions": {

View File

@ -9,7 +9,7 @@
"ng-xi18n": "./src/extract_i18n.js" "ng-xi18n": "./src/extract_i18n.js"
}, },
"dependencies": { "dependencies": {
"@angular/tsc-wrapped": "4.2.0", "@angular/tsc-wrapped": "4.2.1",
"reflect-metadata": "^0.1.2", "reflect-metadata": "^0.1.2",
"minimist": "^1.2.0" "minimist": "^1.2.0"
}, },

View File

@ -100,6 +100,7 @@ export class CodeGenerator {
i18nFormat: cliOptions.i18nFormat, i18nFormat: cliOptions.i18nFormat,
locale: cliOptions.locale, missingTranslation, locale: cliOptions.locale, missingTranslation,
enableLegacyTemplate: options.enableLegacyTemplate !== false, enableLegacyTemplate: options.enableLegacyTemplate !== false,
enableSummariesForJit: options.enableSummariesForJit !== false,
}); });
return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost); return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost);
} }

View File

@ -20,6 +20,10 @@ import {CodeGenerator} from './codegen';
function codegen( function codegen(
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program, ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program,
host: ts.CompilerHost) { host: ts.CompilerHost) {
if (ngOptions.enableSummariesForJit === undefined) {
// default to false
ngOptions.enableSummariesForJit = false;
}
return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen(); return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen();
} }

View File

@ -99,10 +99,15 @@ export class NgTools_InternalApi_NG_2 {
missingTranslation: options.missingTranslation !, missingTranslation: options.missingTranslation !,
basePath: options.basePath basePath: options.basePath
}; };
const ngOptions = options.angularCompilerOptions;
if (ngOptions.enableSummariesForJit === undefined) {
// default to false
ngOptions.enableSummariesForJit = false;
}
// Create the Code Generator. // Create the Code Generator.
const codeGenerator = CodeGenerator.create( const codeGenerator =
options.angularCompilerOptions, cliOptions, options.program, options.host, hostContext); CodeGenerator.create(ngOptions, cliOptions, options.program, options.host, hostContext);
return codeGenerator.codegen(); return codeGenerator.codegen();
} }

View File

@ -25,7 +25,7 @@ function compile(
return ngChecker.getDiagnostics(); return ngChecker.getDiagnostics();
} }
fdescribe('ng type checker', () => { describe('ng type checker', () => {
let angularFiles = setup(); let angularFiles = setup();
function accept(...files: MockDirectory[]) { function accept(...files: MockDirectory[]) {

View File

@ -261,5 +261,52 @@ describe('compiler-cli', () => {
}) })
.catch(e => done.fail(e)); .catch(e => done.fail(e));
}); });
it('should not produce ngsummary files by default', (done) => {
writeConfig(`{
"extends": "./tsconfig-base.json",
"files": ["mymodule.ts"]
}`);
write('mymodule.ts', `
import {NgModule} from '@angular/core';
@NgModule()
export class MyModule {}
`);
main({p: basePath})
.then((exitCode) => {
expect(exitCode).toEqual(0);
expect(fs.existsSync(path.resolve(outDir, 'mymodule.ngsummary.js'))).toBe(false);
done();
})
.catch(e => done.fail(e));
});
it('should produce ngsummary files if configured', (done) => {
writeConfig(`{
"extends": "./tsconfig-base.json",
"files": ["mymodule.ts"],
"angularCompilerOptions": {
"enableSummariesForJit": true
}
}`);
write('mymodule.ts', `
import {NgModule} from '@angular/core';
@NgModule()
export class MyModule {}
`);
main({p: basePath})
.then((exitCode) => {
expect(exitCode).toEqual(0);
expect(fs.existsSync(path.resolve(outDir, 'mymodule.ngsummary.js'))).toBe(true);
done();
})
.catch(e => done.fail(e));
});
}); });
}); });

View File

@ -35,7 +35,8 @@ export class AotCompiler {
private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler, private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler,
private _outputEmitter: OutputEmitter, private _outputEmitter: OutputEmitter,
private _summaryResolver: SummaryResolver<StaticSymbol>, private _localeId: string|null, private _summaryResolver: SummaryResolver<StaticSymbol>, private _localeId: string|null,
private _translationFormat: string|null, private _symbolResolver: StaticSymbolResolver) {} private _translationFormat: string|null, private _enableSummariesForJit: boolean|null,
private _symbolResolver: StaticSymbolResolver) {}
clearCache() { this._metadataResolver.clearCache(); } clearCache() { this._metadataResolver.clearCache(); }
@ -204,10 +205,12 @@ export class AotCompiler {
o.StmtModifier.Exported o.StmtModifier.Exported
])); ]));
}); });
return [ const summaryJson = new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json);
new GeneratedFile(srcFileUrl, summaryFileName(srcFileUrl), json), if (this._enableSummariesForJit) {
this._codegenSourceModule(srcFileUrl, forJitOutputCtx) return [summaryJson, this._codegenSourceModule(srcFileUrl, forJitOutputCtx)];
]; };
return [summaryJson];
} }
private _compileModule(outputCtx: OutputContext, ngModuleType: StaticSymbol): void { private _compileModule(outputCtx: OutputContext, ngModuleType: StaticSymbol): void {

View File

@ -70,6 +70,7 @@ export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCom
const compiler = new AotCompiler( const compiler = new AotCompiler(
config, compilerHost, staticReflector, resolver, tmplParser, new StyleCompiler(urlResolver), config, compilerHost, staticReflector, resolver, tmplParser, new StyleCompiler(urlResolver),
viewCompiler, new NgModuleCompiler(staticReflector), new TypeScriptEmitter(), summaryResolver, viewCompiler, new NgModuleCompiler(staticReflector), new TypeScriptEmitter(), summaryResolver,
options.locale || null, options.i18nFormat || null, symbolResolver); options.locale || null, options.i18nFormat || null, options.enableSummariesForJit || null,
symbolResolver);
return {compiler, reflector: staticReflector}; return {compiler, reflector: staticReflector};
} }

View File

@ -14,4 +14,5 @@ export interface AotCompilerOptions {
translations?: string; translations?: string;
missingTranslation?: MissingTranslationStrategy; missingTranslation?: MissingTranslationStrategy;
enableLegacyTemplate?: boolean; enableLegacyTemplate?: boolean;
enableSummariesForJit?: boolean
} }

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {AotCompiler, AotCompilerHost, AotCompilerOptions, CompileSummaryKind, GeneratedFile, createAotCompiler, toTypeScript} from '@angular/compiler'; import {AotCompiler, AotCompilerHost, AotCompilerOptions, CompileSummaryKind, GeneratedFile, toTypeScript} from '@angular/compiler';
import {MockDirectory, compile, setup} from './test_util'; import {MockDirectory, compile, setup} from './test_util';
@ -15,7 +15,7 @@ describe('aot summaries for jit', () => {
function compileApp(rootDir: MockDirectory, options: {useSummaries?: boolean} = {}): function compileApp(rootDir: MockDirectory, options: {useSummaries?: boolean} = {}):
{genFiles: GeneratedFile[], outDir: MockDirectory} { {genFiles: GeneratedFile[], outDir: MockDirectory} {
return compile([rootDir, angularFiles], options); return compile([rootDir, angularFiles], {...options, enableSummariesForJit: true});
} }
it('should create @Injectable summaries', () => { it('should create @Injectable summaries', () => {

View File

@ -79,9 +79,8 @@ export class RequestOptions {
responseType: ResponseContentType|null; responseType: ResponseContentType|null;
// TODO(Dzmitry): remove search when this.search is removed // TODO(Dzmitry): remove search when this.search is removed
constructor( constructor(opts: RequestOptionsArgs = {}) {
{method, headers, body, url, search, params, withCredentials, const {method, headers, body, url, search, params, withCredentials, responseType} = opts;
responseType}: RequestOptionsArgs = {}) {
this.method = method != null ? normalizeMethodName(method) : null; this.method = method != null ? normalizeMethodName(method) : null;
this.headers = headers != null ? headers : null; this.headers = headers != null ? headers : null;
this.body = body != null ? body : null; this.body = body != null ? body : null;

View File

@ -65,7 +65,8 @@ export class ResponseOptions {
*/ */
type: ResponseType|null; type: ResponseType|null;
url: string|null; url: string|null;
constructor({body, status, headers, statusText, type, url}: ResponseOptionsArgs = {}) { constructor(opts: ResponseOptionsArgs = {}) {
const {body, status, headers, statusText, type, url} = opts;
this.body = body != null ? body : null; this.body = body != null ? body : null;
this.status = status != null ? status : null; this.status = status != null ? status : null;
this.headers = headers != null ? headers : null; this.headers = headers != null ? headers : null;

View File

@ -1,8 +1,8 @@
{ {
"name": "@angular/tsc-wrapped", "name": "@angular/tsc-wrapped",
"version": "4.2.0", "version": "4.2.1",
"description": "Wraps the tsc CLI, allowing extensions.", "description": "Wraps the tsc CLI, allowing extensions.",
"homepage": "https://github.com/angular/angular/tree/master/tools/tsc-wrapped", "homepage": "https://github.com/angular/angular/blob/master/tools/@angular/tsc-wrapped",
"bugs": "https://github.com/angular/angular/issues", "bugs": "https://github.com/angular/angular/issues",
"contributors": [ "contributors": [
"Alex Eagle <alexeagle@google.com>", "Alex Eagle <alexeagle@google.com>",

View File

@ -81,6 +81,10 @@ interface Options extends ts.CompilerOptions {
// Whether to enable support for <template> and the template attribute (true by default) // Whether to enable support for <template> and the template attribute (true by default)
enableLegacyTemplate?: boolean; enableLegacyTemplate?: boolean;
// Whether to generate .ngsummary.ts files that allow to use AOTed artifacts
// in JIT mode.
enableSummariesForJit?: boolean;
} }
export default Options; export default Options;

View File

@ -144,7 +144,7 @@ export declare class RequestOptions {
/** @deprecated */ search: URLSearchParams; /** @deprecated */ search: URLSearchParams;
url: string | null; url: string | null;
withCredentials: boolean | null; withCredentials: boolean | null;
constructor({method, headers, body, url, search, params, withCredentials, responseType}?: RequestOptionsArgs); constructor(opts?: RequestOptionsArgs);
merge(options?: RequestOptionsArgs): RequestOptions; merge(options?: RequestOptionsArgs): RequestOptions;
} }
@ -192,7 +192,7 @@ export declare class ResponseOptions {
headers: Headers | null; headers: Headers | null;
status: number | null; status: number | null;
url: string | null; url: string | null;
constructor({body, status, headers, statusText, type, url}?: ResponseOptionsArgs); constructor(opts?: ResponseOptionsArgs);
merge(options?: ResponseOptionsArgs): ResponseOptions; merge(options?: ResponseOptionsArgs): ResponseOptions;
} }