diff --git a/public/docs/_examples/upgrade/README.md b/public/docs/_examples/upgrade/README.md
new file mode 100644
index 0000000000..507c99f2b7
--- /dev/null
+++ b/public/docs/_examples/upgrade/README.md
@@ -0,0 +1,6 @@
+Each subdirectory here is a version of the PhoneCat app.
+
+Each version is fully functional, but omits the JSON data and image
+files in the interest of keeping things clean. To run each app
+in its full form, copy the `img` and `phones` directories from
+https://github.com/angular/angular-phonecat/tree/master/app under `app`.
diff --git a/public/docs/_examples/upgrade/ts/classes/.bowerrc b/public/docs/_examples/upgrade/ts/classes/.bowerrc
new file mode 100644
index 0000000000..5773025bf9
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "app/bower_components"
+}
diff --git a/public/docs/_examples/upgrade/ts/classes/.gitignore b/public/docs/_examples/upgrade/ts/classes/.gitignore
new file mode 100644
index 0000000000..8cfe0da551
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/.gitignore
@@ -0,0 +1,6 @@
+app/**/*.js
+app/**/*.js.map
+test/unit/**/*.js
+test/unit/**/*.js.map
+test/e2e/**/*.js
+test/e2e/**/*.js.map
diff --git a/public/docs/_examples/upgrade/ts/classes/app/css/.gitkeep b/public/docs/_examples/upgrade/ts/classes/app/css/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/classes/app/css/animations.css b/public/docs/_examples/upgrade/ts/classes/app/css/animations.css
new file mode 100644
index 0000000000..46f3da6ecb
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/css/animations.css
@@ -0,0 +1,97 @@
+/*
+ * animations css stylesheet
+ */
+
+/* animate ngRepeat in phone listing */
+
+.phone-listing.ng-enter,
+.phone-listing.ng-leave,
+.phone-listing.ng-move {
+ -webkit-transition: 0.5s linear all;
+ -moz-transition: 0.5s linear all;
+ -o-transition: 0.5s linear all;
+ transition: 0.5s linear all;
+}
+
+.phone-listing.ng-enter,
+.phone-listing.ng-move {
+ opacity: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.phone-listing.ng-move.ng-move-active,
+.phone-listing.ng-enter.ng-enter-active {
+ opacity: 1;
+ height: 120px;
+}
+
+.phone-listing.ng-leave {
+ opacity: 1;
+ overflow: hidden;
+}
+
+.phone-listing.ng-leave.ng-leave-active {
+ opacity: 0;
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+/* cross fading between routes with ngView */
+
+.view-container {
+ position: relative;
+}
+
+.view-frame.ng-enter,
+.view-frame.ng-leave {
+ background: white;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+.view-frame.ng-enter {
+ -webkit-animation: 0.5s fade-in;
+ -moz-animation: 0.5s fade-in;
+ -o-animation: 0.5s fade-in;
+ animation: 0.5s fade-in;
+ z-index: 100;
+}
+
+.view-frame.ng-leave {
+ -webkit-animation: 0.5s fade-out;
+ -moz-animation: 0.5s fade-out;
+ -o-animation: 0.5s fade-out;
+ animation: 0.5s fade-out;
+ z-index: 99;
+}
+
+@keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-moz-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-webkit-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-moz-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-webkit-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+
diff --git a/public/docs/_examples/upgrade/ts/classes/app/css/app.css b/public/docs/_examples/upgrade/ts/classes/app/css/app.css
new file mode 100644
index 0000000000..951ea087cc
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/css/app.css
@@ -0,0 +1,99 @@
+/* app css stylesheet */
+
+body {
+ padding-top: 20px;
+}
+
+
+.phone-images {
+ background-color: white;
+ width: 450px;
+ height: 450px;
+ overflow: hidden;
+ position: relative;
+ float: left;
+}
+
+.phones {
+ list-style: none;
+}
+
+.thumb {
+ float: left;
+ margin: -0.5em 1em 1.5em 0;
+ padding-bottom: 1em;
+ height: 100px;
+ width: 100px;
+}
+
+.phones li {
+ clear: both;
+ height: 115px;
+ padding-top: 15px;
+}
+
+/** Detail View **/
+img.phone {
+ float: left;
+ margin-right: 3em;
+ margin-bottom: 2em;
+ background-color: white;
+ padding: 2em;
+ height: 400px;
+ width: 400px;
+ display: none;
+}
+
+img.phone:first-child {
+ display: block;
+}
+
+
+ul.phone-thumbs {
+ margin: 0;
+ list-style: none;
+}
+
+ul.phone-thumbs li {
+ border: 1px solid black;
+ display: inline-block;
+ margin: 1em;
+ background-color: white;
+}
+
+ul.phone-thumbs img {
+ height: 100px;
+ width: 100px;
+ padding: 1em;
+}
+
+ul.phone-thumbs img:hover {
+ cursor: pointer;
+}
+
+
+ul.specs {
+ clear: both;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul.specs > li{
+ display: inline-block;
+ width: 200px;
+ vertical-align: top;
+}
+
+ul.specs > li > span{
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+ul.specs dt {
+ font-weight: bold;
+}
+
+h1 {
+ border-bottom: 1px solid gray;
+}
diff --git a/public/docs/_examples/upgrade/ts/classes/app/img/.gitkeep b/public/docs/_examples/upgrade/ts/classes/app/img/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings-white.png
new file mode 100644
index 0000000000..3bf6484a29
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings-white.png differ
diff --git a/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings.png
new file mode 100644
index 0000000000..5b67ffda5f
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/classes/app/img/glyphicons-halflings.png differ
diff --git a/public/docs/_examples/upgrade/ts/classes/app/index.html b/public/docs/_examples/upgrade/ts/classes/app/index.html
new file mode 100644
index 0000000000..74c39250b6
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+ Google Phone Gallery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/app.module.ts
new file mode 100644
index 0000000000..60b30ec24d
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/app.module.ts
@@ -0,0 +1,40 @@
+// #docregion pre-bootstrap
+// #docregion typings
+///
+///
+///
+// #enddocregion
+
+import core from './core/core.module';
+import phoneList from './phone_list/phone_list.module';
+import phoneDetail from './phone_detail/phone_detail.module';
+
+angular.module('phonecatApp', [
+ 'ngRoute',
+ core.name,
+ phoneList.name,
+ phoneDetail.name
+]).config(configure);
+
+configure.$inject = ['$routeProvider'];
+
+function configure($routeProvider) {
+ $routeProvider.
+ when('/phones', {
+ templateUrl: 'js/phone_list/phone_list.html',
+ controller: 'PhoneListCtrl',
+ controllerAs: 'vm'
+ }).
+ when('/phones/:phoneId', {
+ templateUrl: 'js/phone_detail/phone_detail.html',
+ controller: 'PhoneDetailCtrl',
+ controllerAs: 'vm'
+ }).
+ otherwise({
+ redirectTo: '/phones'
+ });
+}
+// #enddocregion pre-bootstrap
+// #docregion bootstrap
+angular.bootstrap(document.documentElement, ['phonecatApp']);
+// #enddocregion bootstrap
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/core/checkmark.filter.ts b/public/docs/_examples/upgrade/ts/classes/app/js/core/checkmark.filter.ts
new file mode 100644
index 0000000000..cd0215064f
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/core/checkmark.filter.ts
@@ -0,0 +1,6 @@
+// #docregion
+export default function checkmarkFilter() {
+ return function(input:boolean):string {
+ return input ? '\u2713' : '\u2718';
+ };
+}
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/core/core.module.ts
new file mode 100644
index 0000000000..c20ce33683
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/core/core.module.ts
@@ -0,0 +1,9 @@
+// #docregion
+import Phone from './phone.factory';
+import checkmarkFilter from './checkmark.filter';
+
+export default angular.module('phonecat.core', [
+ 'ngResource'
+ ])
+ .factory('Phone', Phone)
+ .filter('checkmark', checkmarkFilter);
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/core/phone.factory.ts b/public/docs/_examples/upgrade/ts/classes/app/js/core/phone.factory.ts
new file mode 100644
index 0000000000..a8492b29fc
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/core/phone.factory.ts
@@ -0,0 +1,10 @@
+// #docregion
+Phone.$inject = ['$resource'];
+
+function Phone($resource) {
+ return $resource('phones/:phoneId.json', {}, {
+ query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
+ });
+}
+
+export default Phone;
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.controller.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.controller.ts
new file mode 100644
index 0000000000..c5b96b6f08
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.controller.ts
@@ -0,0 +1,22 @@
+// #docregion
+interface PhoneRouteParams {
+ phoneId: string
+}
+
+class PhoneDetailCtrl {
+ phone:any;
+ mainImageUrl:string;
+ constructor($routeParams:PhoneRouteParams, Phone) {
+ this.phone = Phone.get({phoneId: $routeParams.phoneId}, (phone) =>
+ this.mainImageUrl = phone.images[0]
+ );
+ }
+
+ setImage(url:string) {
+ this.mainImageUrl = url;
+ }
+}
+
+PhoneDetailCtrl.$inject = ['$routeParams', 'Phone'];
+
+export default PhoneDetailCtrl;
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.html
new file mode 100644
index 0000000000..954c65c2cd
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.html
@@ -0,0 +1,118 @@
+
+
![]()
+
+
+{{vm.phone.name}}
+
+{{vm.phone.description}}
+
+
+ -
+
+
+
+
+
+ -
+ Availability and Networks
+
+ - Availability
+ - {{availability}}
+
+
+ -
+ Battery
+
+ - Type
+ - {{vm.phone.battery.type}}
+ - Talk Time
+ - {{vm.phone.battery.talkTime}}
+ - Standby time (max)
+ - {{vm.phone.battery.standbyTime}}
+
+
+ -
+ Storage and Memory
+
+ - RAM
+ - {{vm.phone.storage.ram}}
+ - Internal Storage
+ - {{vm.phone.storage.flash}}
+
+
+ -
+ Connectivity
+
+ - Network Support
+ - {{vm.phone.connectivity.cell}}
+ - WiFi
+ - {{vm.phone.connectivity.wifi}}
+ - Bluetooth
+ - {{vm.phone.connectivity.bluetooth}}
+ - Infrared
+ - {{vm.phone.connectivity.infrared | checkmark}}
+ - GPS
+ - {{vm.phone.connectivity.gps | checkmark}}
+
+
+ -
+ Android
+
+ - OS Version
+ - {{vm.phone.android.os}}
+ - UI
+ - {{vm.phone.android.ui}}
+
+
+ -
+ Size and Weight
+
+ - Dimensions
+ - {{dim}}
+ - Weight
+ - {{vm.phone.sizeAndWeight.weight}}
+
+
+ -
+ Display
+
+ - Screen size
+ - {{vm.phone.display.screenSize}}
+ - Screen resolution
+ - {{vm.phone.display.screenResolution}}
+ - Touch screen
+ - {{vm.phone.display.touchScreen | checkmark}}
+
+
+ -
+ Hardware
+
+ - CPU
+ - {{vm.phone.hardware.cpu}}
+ - USB
+ - {{vm.phone.hardware.usb}}
+ - Audio / headphone jack
+ - {{vm.phone.hardware.audioJack}}
+ - FM Radio
+ - {{vm.phone.hardware.fmRadio | checkmark}}
+ - Accelerometer
+ - {{vm.phone.hardware.accelerometer | checkmark}}
+
+
+ -
+ Camera
+
+ - Primary
+ - {{vm.phone.camera.primary}}
+ - Features
+ - {{vm.phone.camera.features.join(', ')}}
+
+
+ -
+ Additional Features
+
- {{vm.phone.additionalFeatures}}
+
+
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.module.ts
new file mode 100644
index 0000000000..16e7ac0baf
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/phone_detail/phone_detail.module.ts
@@ -0,0 +1,8 @@
+// #docregion
+import PhoneDetailCtrl from './phone_detail.controller';
+
+export default angular.module('phonecat.detail', [
+ 'ngRoute',
+ 'phonecat.core'
+ ])
+ .controller('PhoneDetailCtrl', PhoneDetailCtrl);
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.controller.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.controller.ts
new file mode 100644
index 0000000000..f1a5beb808
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.controller.ts
@@ -0,0 +1,14 @@
+// #docregion
+class PhoneListCtrl {
+ phones:any[];
+ orderProp:string;
+ query:string;
+ constructor(Phone) {
+ this.phones = Phone.query();
+ this.orderProp = 'age';
+ }
+}
+
+PhoneListCtrl.$inject = ['Phone'];
+
+export default PhoneListCtrl;
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.html
new file mode 100644
index 0000000000..471f474e89
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.module.ts
new file mode 100644
index 0000000000..758b937927
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/app/js/phone_list/phone_list.module.ts
@@ -0,0 +1,5 @@
+// #docregion
+import PhoneListCtrl from './phone_list.controller';
+
+export default angular.module('phonecat.list', ['phonecat.core'])
+ .controller('PhoneListCtrl', PhoneListCtrl);
diff --git a/public/docs/_examples/upgrade/ts/classes/bower.json b/public/docs/_examples/upgrade/ts/classes/bower.json
new file mode 100644
index 0000000000..03c0d72ea4
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/bower.json
@@ -0,0 +1,20 @@
+{
+ "name": "angular-phonecat",
+ "description": "A starter project for AngularJS",
+ "version": "0.0.0",
+ "homepage": "https://github.com/angular/angular-phonecat",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "angular": "1.5.0-beta.2",
+ "angular-mocks": "1.5.0-beta.2",
+ "jquery": "~2.1.1",
+ "bootstrap": "~3.1.1",
+ "angular-route": "1.5.0-beta.2",
+ "angular-resource": "1.5.0-beta.2",
+ "angular-animate": "1.5.0-beta.2"
+ },
+ "resolutions": {
+ "angular": "1.5.0-beta.2"
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/classes/test/e2e/scenarios.ts b/public/docs/_examples/upgrade/ts/classes/test/e2e/scenarios.ts
new file mode 100644
index 0000000000..4cdbefc047
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/e2e/scenarios.ts
@@ -0,0 +1,103 @@
+'use strict';
+
+/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */
+// #docregion declares
+declare var browser:any, element:any, by:any;
+// #enddocregion declares
+
+describe('PhoneCat App', function() {
+
+ it('should redirect index.html to index.html#/phones', function() {
+ browser.get('app/index.html');
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones');
+ });
+ });
+
+
+ describe('Phone list view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones');
+ });
+
+
+ it('should filter the phone list as a user types into the search box', function() {
+ var phoneList = element.all(by.repeater('phone in vm.phones'));
+ var query = element(by.model('vm.query'));
+
+ expect(phoneList.count()).toBe(20);
+
+ query.sendKeys('nexus');
+ expect(phoneList.count()).toBe(1);
+
+ query.clear();
+ query.sendKeys('motorola');
+ expect(phoneList.count()).toBe(8);
+ });
+
+
+ it('should be possible to control phone order via the drop down select box', function() {
+
+ var phoneNameColumn = element.all(by.repeater('phone in vm.phones').column('phone.name'));
+ var query = element(by.model('vm.query'));
+
+ function getNames() {
+ return phoneNameColumn.map(function(elm) {
+ return elm.getText();
+ });
+ }
+
+ query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter
+
+ expect(getNames()).toEqual([
+ "Motorola XOOM\u2122 with Wi-Fi",
+ "MOTOROLA XOOM\u2122"
+ ]);
+
+ element(by.model('vm.orderProp')).element(by.css('option[value="name"]')).click();
+
+ expect(getNames()).toEqual([
+ "MOTOROLA XOOM\u2122",
+ "Motorola XOOM\u2122 with Wi-Fi"
+ ]);
+ });
+
+
+ it('should render phone specific links', function() {
+ var query = element(by.model('vm.query'));
+ query.sendKeys('nexus');
+ element.all(by.css('.phones li a')).first().click();
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones/nexus-s');
+ });
+ });
+ });
+
+
+ describe('Phone detail view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones/nexus-s');
+ });
+
+
+ it('should display nexus-s page', function() {
+ expect(element(by.binding('vm.phone.name')).getText()).toBe('Nexus S');
+ });
+
+
+ it('should display the first phone image as the main phone image', function() {
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+
+
+ it('should swap main image if a thumbnail image is clicked on', function() {
+ element(by.css('.phone-thumbs li:nth-child(3) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/);
+
+ element(by.css('.phone-thumbs li:nth-child(1) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/classes/test/jasmine_matchers.d.ts b/public/docs/_examples/upgrade/ts/classes/test/jasmine_matchers.d.ts
new file mode 100644
index 0000000000..6d24879775
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/jasmine_matchers.d.ts
@@ -0,0 +1,6 @@
+// #docregion
+declare module jasmine {
+ interface Matchers {
+ toEqualData(expected: any):boolean;
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/classes/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/classes/test/karma_test_shim.js
new file mode 100644
index 0000000000..15cbee5d7d
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/karma_test_shim.js
@@ -0,0 +1,44 @@
+// #docregion
+// Cancel Karma's synchronous start,
+// we will call `__karma__.start()` later, once all the specs are loaded.
+__karma__.loaded = function() {};
+
+System.config({
+ packages: {
+ 'base/app/js': {
+ defaultExtension: false,
+ format: 'register',
+ map: Object.keys(window.__karma__.files).
+ filter(onlyAppFiles).
+ reduce(function createPathRecords(pathsMapping, appPath) {
+ // creates local module name mapping to global path with karma's fingerprint in path, e.g.:
+ // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
+ var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, '');
+ pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]
+ return pathsMapping;
+ }, {})
+
+ }
+ }
+});
+
+Promise.all(
+ Object.keys(window.__karma__.files) // All files served by Karma.
+ .filter(onlySpecFiles)
+ .map(function(moduleName) {
+ // loads all spec files via their global module names
+ return System.import(moduleName);
+}))
+.then(function() {
+ __karma__.start();
+}, function(error) {
+ __karma__.error(error.stack || error);
+});
+
+function onlyAppFiles(filePath) {
+ return /^\/base\/app\/js\/.*\.js$/.test(filePath)
+}
+
+function onlySpecFiles(path) {
+ return /\.spec\.js$/.test(path);
+}
diff --git a/public/docs/_examples/upgrade/ts/classes/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/classes/test/protractor-conf.js
new file mode 100644
index 0000000000..118c7b9ec2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/protractor-conf.js
@@ -0,0 +1,21 @@
+exports.config = {
+ allScriptsTimeout: 11000,
+
+ specs: [
+ 'e2e/*.js'
+ ],
+
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+
+ chromeOnly: true,
+
+ baseUrl: 'http://localhost:8000/',
+
+ framework: 'jasmine',
+
+ jasmineNodeOpts: {
+ defaultTimeoutInterval: 30000
+ }
+};
diff --git a/public/docs/_examples/upgrade/ts/classes/test/test_helper.ts b/public/docs/_examples/upgrade/ts/classes/test/test_helper.ts
new file mode 100644
index 0000000000..75f83fab7a
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/test_helper.ts
@@ -0,0 +1,3 @@
+// #docregion
+///
+///
diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/checkmark.filter.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/checkmark.filter.spec.ts
new file mode 100644
index 0000000000..bae35e6875
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/unit/checkmark.filter.spec.ts
@@ -0,0 +1,15 @@
+// #docregion top
+import '../../app/js/core/core.module';
+// #enddocregion top
+
+describe('checkmarkFilter', function() {
+
+ beforeEach(angular.mock.module('phonecat.core'));
+
+ it('should convert boolean values to unicode checkmark or cross',
+ inject(function(checkmarkFilter) {
+ expect(checkmarkFilter(true)).toBe('\u2713');
+ expect(checkmarkFilter(false)).toBe('\u2718');
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/phone.factory.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/phone.factory.spec.ts
new file mode 100644
index 0000000000..d7c95d347e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/unit/phone.factory.spec.ts
@@ -0,0 +1,15 @@
+// #docregion top
+import '../../app/js/core/core.module';
+// #enddocregion top
+
+describe('phoneFactory', function() {
+
+ // load modules
+ beforeEach(angular.mock.module('phonecat.core'));
+
+ // Test service availability
+ it('check the existence of Phone factory', inject(function(Phone) {
+ expect(Phone).toBeDefined();
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/phone_detail.controller.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/phone_detail.controller.spec.ts
new file mode 100644
index 0000000000..02a3e20240
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/unit/phone_detail.controller.spec.ts
@@ -0,0 +1,44 @@
+// #docregion top
+import '../../app/js/phone_detail/phone_detail.module';
+// #enddocregion top
+
+describe('PhoneDetailCtrl', function(){
+ var scope, $httpBackend, ctrl,
+ xyzPhoneData = function() {
+ return {
+ name: 'phone xyz',
+ images: ['image/url1.png', 'image/url2.png']
+ }
+ };
+
+ beforeEach(angular.mock.module('phonecat.detail'));
+
+ beforeEach(function(){
+ jasmine.addMatchers({
+ toEqualData: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ return {pass: angular.equals(actual, expected)};
+ }
+ };
+ }
+ });
+ });
+
+ beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
+ $httpBackend = _$httpBackend_;
+ $httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData());
+
+ $routeParams.phoneId = 'xyz';
+ scope = $rootScope.$new();
+ ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
+ }));
+
+
+ it('should fetch phone detail', function() {
+ expect(ctrl.phone).toEqualData({});
+ $httpBackend.flush();
+
+ expect(ctrl.phone).toEqualData(xyzPhoneData());
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/classes/test/unit/phone_list.controller.spec.ts b/public/docs/_examples/upgrade/ts/classes/test/unit/phone_list.controller.spec.ts
new file mode 100644
index 0000000000..efec5d5f08
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/classes/test/unit/phone_list.controller.spec.ts
@@ -0,0 +1,44 @@
+// #docregion top
+import '../../app/js/phone_list/phone_list.module';
+// #enddocregion top
+
+describe('PhoneListCtrl', function(){
+ var scope, ctrl, $httpBackend;
+
+ beforeEach(angular.mock.module('phonecat.list'));
+
+ beforeEach(function(){
+ jasmine.addMatchers({
+ toEqualData: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ return {pass: angular.equals(actual, expected)};
+ }
+ };
+ }
+ });
+ });
+
+ beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
+ $httpBackend = _$httpBackend_;
+ $httpBackend.expectGET('phones/phones.json').
+ respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
+
+ scope = $rootScope.$new();
+ ctrl = $controller('PhoneListCtrl', {$scope: scope});
+ }));
+
+
+ it('should create "phones" model with 2 phones fetched from xhr', function() {
+ expect(ctrl.phones).toEqualData([]);
+ $httpBackend.flush();
+
+ expect(ctrl.phones).toEqualData(
+ [{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
+ });
+
+
+ it('should set the default value of orderProp model', function() {
+ expect(ctrl.orderProp).toBe('age');
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/.bowerrc b/public/docs/_examples/upgrade/ts/ng2_components/.bowerrc
new file mode 100644
index 0000000000..5773025bf9
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "app/bower_components"
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/.gitignore b/public/docs/_examples/upgrade/ts/ng2_components/.gitignore
new file mode 100644
index 0000000000..8cfe0da551
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/.gitignore
@@ -0,0 +1,6 @@
+app/**/*.js
+app/**/*.js.map
+test/unit/**/*.js
+test/unit/**/*.js.map
+test/e2e/**/*.js
+test/e2e/**/*.js.map
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/css/.gitkeep b/public/docs/_examples/upgrade/ts/ng2_components/app/css/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/css/animations.css b/public/docs/_examples/upgrade/ts/ng2_components/app/css/animations.css
new file mode 100644
index 0000000000..46f3da6ecb
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/css/animations.css
@@ -0,0 +1,97 @@
+/*
+ * animations css stylesheet
+ */
+
+/* animate ngRepeat in phone listing */
+
+.phone-listing.ng-enter,
+.phone-listing.ng-leave,
+.phone-listing.ng-move {
+ -webkit-transition: 0.5s linear all;
+ -moz-transition: 0.5s linear all;
+ -o-transition: 0.5s linear all;
+ transition: 0.5s linear all;
+}
+
+.phone-listing.ng-enter,
+.phone-listing.ng-move {
+ opacity: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.phone-listing.ng-move.ng-move-active,
+.phone-listing.ng-enter.ng-enter-active {
+ opacity: 1;
+ height: 120px;
+}
+
+.phone-listing.ng-leave {
+ opacity: 1;
+ overflow: hidden;
+}
+
+.phone-listing.ng-leave.ng-leave-active {
+ opacity: 0;
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+/* cross fading between routes with ngView */
+
+.view-container {
+ position: relative;
+}
+
+.view-frame.ng-enter,
+.view-frame.ng-leave {
+ background: white;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+.view-frame.ng-enter {
+ -webkit-animation: 0.5s fade-in;
+ -moz-animation: 0.5s fade-in;
+ -o-animation: 0.5s fade-in;
+ animation: 0.5s fade-in;
+ z-index: 100;
+}
+
+.view-frame.ng-leave {
+ -webkit-animation: 0.5s fade-out;
+ -moz-animation: 0.5s fade-out;
+ -o-animation: 0.5s fade-out;
+ animation: 0.5s fade-out;
+ z-index: 99;
+}
+
+@keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-moz-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-webkit-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-moz-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-webkit-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/css/app.css b/public/docs/_examples/upgrade/ts/ng2_components/app/css/app.css
new file mode 100644
index 0000000000..f41c420776
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/css/app.css
@@ -0,0 +1,99 @@
+/* app css stylesheet */
+
+body {
+ padding-top: 20px;
+}
+
+
+.phone-images {
+ background-color: white;
+ width: 450px;
+ height: 450px;
+ overflow: hidden;
+ position: relative;
+ float: left;
+}
+
+.phones {
+ list-style: none;
+}
+
+.thumb {
+ float: left;
+ margin: -0.5em 1em 1.5em 0;
+ padding-bottom: 1em;
+ height: 100px;
+ width: 100px;
+}
+
+.phones li {
+ clear: both;
+ height: 115px;
+ padding-top: 15px;
+}
+
+/** Detail View **/
+img.phone {
+ float: left;
+ margin-right: 3em;
+ margin-bottom: 2em;
+ background-color: white;
+ padding: 2em;
+ height: 400px;
+ width: 400px;
+ display: none;
+}
+
+img.phone:first-of-type {
+ display: block;
+}
+
+
+ul.phone-thumbs {
+ margin: 0;
+ list-style: none;
+}
+
+ul.phone-thumbs li {
+ border: 1px solid black;
+ display: inline-block;
+ margin: 1em;
+ background-color: white;
+}
+
+ul.phone-thumbs img {
+ height: 100px;
+ width: 100px;
+ padding: 1em;
+}
+
+ul.phone-thumbs img:hover {
+ cursor: pointer;
+}
+
+
+ul.specs {
+ clear: both;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul.specs > li{
+ display: inline-block;
+ width: 200px;
+ vertical-align: top;
+}
+
+ul.specs > li > span{
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+ul.specs dt {
+ font-weight: bold;
+}
+
+h1 {
+ border-bottom: 1px solid gray;
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/img/.gitkeep b/public/docs/_examples/upgrade/ts/ng2_components/app/img/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings-white.png
new file mode 100644
index 0000000000..3bf6484a29
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings-white.png differ
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings.png
new file mode 100644
index 0000000000..5b67ffda5f
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/ng2_components/app/img/glyphicons-halflings.png differ
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/index.html b/public/docs/_examples/upgrade/ts/ng2_components/app/index.html
new file mode 100644
index 0000000000..be97a6cfe2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/index.html
@@ -0,0 +1,41 @@
+
+
+
+
+ Google Phone Gallery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/app.module.ts
new file mode 100644
index 0000000000..c421e8123e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/app.module.ts
@@ -0,0 +1,50 @@
+///
+///
+///
+
+// #docregion adapter-import
+import {UpgradeAdapter} from 'angular2/upgrade';
+// #enddocregion adapter-import
+// #docregion adapter-state-import
+import upgradeAdapter from './core/upgrade_adapter';
+// #enddocregion adapter-state-import
+// #docregion http-import
+import {HTTP_PROVIDERS} from 'angular2/http';
+// #enddocregion http-import
+import core from './core/core.module';
+import phoneList from './phone_list/phone_list.module';
+import phoneDetail from './phone_detail/phone_detail.module';
+
+upgradeAdapter.addProvider(HTTP_PROVIDERS);
+// #docregion upgrade-route-params
+upgradeAdapter.upgradeNg1Provider('$routeParams');
+// #enddocregion
+angular.module('phonecatApp', [
+ 'ngRoute',
+ core.name,
+ phoneList.name,
+ phoneDetail.name
+]).config(configure);
+
+configure.$inject = ['$routeProvider'];
+
+function configure($routeProvider) {
+ // #docregion list-route
+ $routeProvider.
+ when('/phones', {
+ template: ''
+ }).
+ // #enddocregion list-route
+ // #docregion detail-route
+ when('/phones/:phoneId', {
+ template: ''
+ }).
+ // #enddocregion detail-route
+ otherwise({
+ redirectTo: '/phones'
+ });
+}
+
+// #docregion app-bootstrap
+upgradeAdapter.bootstrap(document.documentElement, ['phonecatApp']);
+// #enddocregion app-bootstrap
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/CheckmarkPipe.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/CheckmarkPipe.ts
new file mode 100644
index 0000000000..5156f14b50
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/CheckmarkPipe.ts
@@ -0,0 +1,9 @@
+// #docregion
+import {Pipe} from 'angular2/core';
+
+@Pipe({name: 'checkmark'})
+export class CheckmarkPipe {
+ transform(input:string): string {
+ return input ? '\u2713' : '\u2718';
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/Phones.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/Phones.ts
new file mode 100644
index 0000000000..8186c4810c
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/Phones.ts
@@ -0,0 +1,37 @@
+// #docregion full
+import {Injectable} from 'angular2/core';
+import {Http, Response} from 'angular2/http';
+import {Observable} from 'rxjs';
+import 'rxjs/add/operator/map';
+
+// #docregion phone-interface
+export interface Phone {
+ name: string;
+ snippet: string;
+ images: string[];
+}
+// #enddocregion phone-interface
+
+// #docregion fullclass
+// #docregion class
+@Injectable()
+export class Phones {
+// #enddocregion class
+
+ constructor(private http: Http) { }
+
+ query():Observable {
+ return this.http.get(`phones/phones.json`)
+ .map((res:Response) => res.json());
+ }
+
+ get(id: string):Observable {
+ return this.http.get(`phones/${id}.json`)
+ .map((res:Response) => res.json());
+ }
+
+// #docregion class
+}
+// #enddocregion class
+// #enddocregion fullclass
+// #docregion full
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/core.module.ts
new file mode 100644
index 0000000000..8faf35f705
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/core.module.ts
@@ -0,0 +1,8 @@
+// #docregion
+import {Phones} from './Phones';
+import upgradeAdapter from './upgrade_adapter';
+
+upgradeAdapter.addProvider(Phones);
+
+export default angular.module('phonecat.core', [])
+ .factory('phones', upgradeAdapter.downgradeNg2Provider(Phones));
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/upgrade_adapter.ts
new file mode 100644
index 0000000000..e21be0e4d8
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/core/upgrade_adapter.ts
@@ -0,0 +1,9 @@
+// #docregion full
+import {UpgradeAdapter} from 'angular2/upgrade';
+
+// #docregion adapter-init
+const upgradeAdapter = new UpgradeAdapter();
+// #enddocregion adapter-init
+
+export default upgradeAdapter;
+// #enddocregion full
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/PhoneDetail.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/PhoneDetail.ts
new file mode 100644
index 0000000000..ea2876ba10
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/PhoneDetail.ts
@@ -0,0 +1,33 @@
+// #docregion
+// #docregion top
+import {Component, Inject} from 'angular2/core';
+import {Phones, Phone} from '../core/Phones';
+import {CheckmarkPipe} from '../core/CheckmarkPipe';
+
+interface PhoneRouteParams {
+ phoneId: string
+}
+
+@Component({
+ selector: 'pc-phone-detail',
+ templateUrl: 'js/phone_detail/phone_detail.html',
+ pipes: [CheckmarkPipe]
+})
+class PhoneDetail {
+// #enddocregion top
+ phone:Phone = undefined;
+ mainImageUrl:string;
+ constructor(@Inject('$routeParams') $routeParams:PhoneRouteParams,
+ phones:Phones) {
+ phones.get($routeParams.phoneId)
+ .subscribe(phone => {
+ this.phone = phone;
+ this.mainImageUrl = phone.images[0];
+ });
+ }
+
+ setImage(url:string) {
+ this.mainImageUrl = url;
+ }
+}
+export default PhoneDetail;
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/PhoneDetail_without_pipes.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/PhoneDetail_without_pipes.ts
new file mode 100644
index 0000000000..ca7bc1c0d2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/PhoneDetail_without_pipes.ts
@@ -0,0 +1,29 @@
+// #docregion
+import {Component, Inject} from 'angular2/core';
+import {Phones, Phone} from '../core/Phones';
+
+interface PhoneRouteParams {
+ phoneId: string
+}
+
+@Component({
+ selector: 'pc-phone-detail',
+ templateUrl: 'js/phone_detail/phone_detail.html'
+})
+class PhoneDetail {
+ phone:Phone = undefined;
+ mainImageUrl:string;
+ constructor(@Inject('$routeParams') $routeParams:PhoneRouteParams,
+ phones:Phones) {
+ phones.get($routeParams.phoneId)
+ .subscribe(phone => {
+ this.phone = phone;
+ this.mainImageUrl = phone.images[0];
+ });
+ }
+
+ setImage(url:string) {
+ this.mainImageUrl = url;
+ }
+}
+export default PhoneDetail;
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.html
new file mode 100644
index 0000000000..51cc10aad5
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.html
@@ -0,0 +1,115 @@
+
+
+
![]()
+
+{{phone?.name}}
+{{phone?.description}}
+
+ -
+
+
+
+
+ -
+ Availability and Networks
+
+ - Availability
+ - {{availability}}
+
+
+ -
+ Battery
+
+ - Type
+ - {{phone?.battery?.type}}
+ - Talk Time
+ - {{phone?.battery?.talkTime}}
+ - Standby time (max)
+ - {{phone?.battery?.standbyTime}}
+
+
+ -
+ Storage and Memory
+
+ - RAM
+ - {{phone?.storage?.ram}}
+ - Internal Storage
+ - {{phone?.storage?.flash}}
+
+
+ -
+ Connectivity
+
+ - Network Support
+ - {{phone?.connectivity?.cell}}
+ - WiFi
+ - {{phone?.connectivity?.wifi}}
+ - Bluetooth
+ - {{phone?.connectivity?.bluetooth}}
+ - Infrared
+ - {{phone?.connectivity?.infrared | checkmark}}
+ - GPS
+ - {{phone?.connectivity?.gps | checkmark}}
+
+
+ -
+ Android
+
+ - OS Version
+ - {{phone?.android?.os}}
+ - UI
+ - {{phone?.android?.ui}}
+
+
+ -
+ Size and Weight
+
+ - Dimensions
+ - {{dim}}
+ - Weight
+ - {{phone?.sizeAndWeight?.weight}}
+
+
+ -
+ Display
+
+ - Screen size
+ - {{phone?.display?.screenSize}}
+ - Screen resolution
+ - {{phone?.display?.screenResolution}}
+ - Touch screen
+ - {{phone?.display?.touchScreen | checkmark}}
+
+
+ -
+ Hardware
+
+ - CPU
+ - {{phone?.hardware?.cpu}}
+ - USB
+ - {{phone?.hardware?.usb}}
+ - Audio / headphone jack
+ - {{phone?.hardware?.audioJack}}
+ - FM Radio
+ - {{phone?.hardware?.fmRadio | checkmark}}
+ - Accelerometer
+ - {{phone?.hardware?.accelerometer | checkmark}}
+
+
+ -
+ Camera
+
+ - Primary
+ - {{phone?.camera?.primary}}
+ - Features
+ - {{phone?.camera?.features?.join(', ')}}
+
+
+ -
+ Additional Features
+
- {{phone?.additionalFeatures}}
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.module.ts
new file mode 100644
index 0000000000..3ae85d8d51
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_detail/phone_detail.module.ts
@@ -0,0 +1,10 @@
+// #docregion
+import PhoneDetail from './PhoneDetail';
+import upgradeAdapter from '../core/upgrade_adapter';
+
+export default angular.module('phonecat.detail', [
+ 'ngRoute',
+ 'phonecat.core'
+ ])
+ .directive('pcPhoneDetail',
+ upgradeAdapter.downgradeNg2Component(PhoneDetail))
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/OrderByPipe.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/OrderByPipe.ts
new file mode 100644
index 0000000000..3b82f03c9b
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/OrderByPipe.ts
@@ -0,0 +1,24 @@
+// #docregion
+import {Pipe} from 'angular2/core';
+
+@Pipe({name: 'orderBy'})
+export default class OrderByPipe {
+
+ transform(input:T[], args:string[]): T[] {
+ if (input) {
+ let property = args[0];
+ return input.slice().sort((a, b) => {
+ if (a[property] < b[property]) {
+ return -1;
+ } else if (b[property] < a[property]) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ } else {
+ return input;
+ }
+ }
+
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneFilterPipe.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneFilterPipe.ts
new file mode 100644
index 0000000000..cca575ece2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneFilterPipe.ts
@@ -0,0 +1,22 @@
+// #docregion
+import {Pipe} from 'angular2/core';
+import {Phone} from '../core/Phones';
+
+@Pipe({name: 'phoneFilter'})
+export default class PhoneFilterPipe {
+
+ transform(input:Phone[], args:string[]): Phone[] {
+ let query = args[0];
+ if (query) {
+ query = query.toLowerCase();
+ return input.filter((phone) => {
+ const name = phone.name.toLowerCase();
+ const snippet = phone.snippet.toLowerCase();
+ return name.indexOf(query) >= 0 || snippet.indexOf(query) >= 0;
+ });
+ } else {
+ return input;
+ }
+ }
+
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneList.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneList.ts
new file mode 100644
index 0000000000..cc83468d4d
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneList.ts
@@ -0,0 +1,26 @@
+// #docregion full
+// #docregion top
+import {Component} from 'angular2/core';
+import {Observable} from 'rxjs';
+import {Phones, Phone} from '../core/Phones';
+import PhoneFilterPipe from './PhoneFilterPipe';
+import OrderByPipe from './OrderByPipe';
+
+@Component({
+ selector: 'pc-phone-list',
+ templateUrl: 'js/phone_list/phone_list.html',
+ pipes: [PhoneFilterPipe, OrderByPipe],
+})
+class PhoneList {
+// #enddocregion top
+
+ phones:Observable;
+ orderProp:string;
+ query:string;
+ constructor(phones:Phones) {
+ this.phones = phones.query();
+ this.orderProp = 'age';
+ }
+}
+
+export default PhoneList;
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneList_without_pipes.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneList_without_pipes.ts
new file mode 100644
index 0000000000..ec9dc0d9db
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/PhoneList_without_pipes.ts
@@ -0,0 +1,22 @@
+// #docregion top
+import {Component} from 'angular2/core';
+import {Observable} from 'rxjs';
+import {Phones, Phone} from '../core/Phones';
+
+@Component({
+ selector: 'pc-phone-list',
+ templateUrl: 'js/phone_list/phone_list.html'
+})
+class PhoneList {
+// #enddocregion top
+
+ phones:Observable;
+ orderProp:string;
+ query:string;
+ constructor(phones:Phones) {
+ this.phones = phones.query();
+ this.orderProp = 'age';
+ }
+}
+
+export default PhoneList;
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.html
new file mode 100644
index 0000000000..71b84a9e88
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.module.ts
new file mode 100644
index 0000000000..f3a0de081d
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list.module.ts
@@ -0,0 +1,9 @@
+// #docregion
+import PhoneList from './PhoneList';
+import upgradeAdapter from '../core/upgrade_adapter';
+
+export default angular.module('phonecat.list', [
+ 'phonecat.core'
+ ])
+ .directive('pcPhoneList',
+ upgradeAdapter.downgradeNg2Component(PhoneList));
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_async.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_async.html
new file mode 100644
index 0000000000..ac9f18d67d
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_async.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.html b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.html
new file mode 100644
index 0000000000..a19d9a5455
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/app/js/phone_list/phone_list_without_pipes.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/bower.json b/public/docs/_examples/upgrade/ts/ng2_components/bower.json
new file mode 100644
index 0000000000..03c0d72ea4
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/bower.json
@@ -0,0 +1,20 @@
+{
+ "name": "angular-phonecat",
+ "description": "A starter project for AngularJS",
+ "version": "0.0.0",
+ "homepage": "https://github.com/angular/angular-phonecat",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "angular": "1.5.0-beta.2",
+ "angular-mocks": "1.5.0-beta.2",
+ "jquery": "~2.1.1",
+ "bootstrap": "~3.1.1",
+ "angular-route": "1.5.0-beta.2",
+ "angular-resource": "1.5.0-beta.2",
+ "angular-animate": "1.5.0-beta.2"
+ },
+ "resolutions": {
+ "angular": "1.5.0-beta.2"
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/e2e/scenarios.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/e2e/scenarios.ts
new file mode 100644
index 0000000000..7f443cfd84
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/e2e/scenarios.ts
@@ -0,0 +1,112 @@
+'use strict';
+
+/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */
+
+describe('PhoneCat App', function() {
+
+ it('should redirect index.html to index.html#/phones', function() {
+ browser.get('app/index.html');
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones');
+ });
+ });
+
+
+ describe('Phone list view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones');
+ });
+
+ it('should filter the phone list as a user types into the search box', function() {
+ var phoneList = element.all(by.css('.phones li'));
+ var query = element(by.css('input'));
+
+ expect(phoneList.count()).toBe(20);
+
+ query.sendKeys('nexus');
+ expect(phoneList.count()).toBe(1);
+
+ query.clear();
+ // https://github.com/angular/protractor/issues/2019
+ let str = 'motorola';
+ for (let i:number = 0; i < str.length; i++) {
+ query.sendKeys(str.charAt(i));
+ }
+
+ expect(phoneList.count()).toBe(8);
+ });
+
+
+ it('should be possible to control phone order via the drop down select box', function() {
+ var phoneNameColumn = element.all(by.css('.phones .name'));
+ var query = element(by.css('input'));
+
+ function getNames() {
+ return phoneNameColumn.map(function(elm) {
+ return elm.getText();
+ });
+ }
+
+ //let's narrow the dataset to make the test assertions shorter
+ // https://github.com/angular/protractor/issues/2019
+ let str = 'tablet';
+ for (let i:number = 0; i < str.length; i++) {
+ query.sendKeys(str.charAt(i));
+ }
+
+ expect(getNames()).toEqual([
+ "Motorola XOOM\u2122 with Wi-Fi",
+ "MOTOROLA XOOM\u2122"
+ ]);
+
+ element(by.css('select')).element(by.css('option[value="name"]')).click();
+
+ expect(getNames()).toEqual([
+ "MOTOROLA XOOM\u2122",
+ "Motorola XOOM\u2122 with Wi-Fi"
+ ]);
+ });
+
+
+ it('should render phone specific links', function() {
+ var query = element(by.css('input'));
+ // https://github.com/angular/protractor/issues/2019
+ let str = 'nexus';
+ for (let i:number = 0; i < str.length; i++) {
+ query.sendKeys(str.charAt(i));
+ }
+ element.all(by.css('.phones li a')).first().click();
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones/nexus-s');
+ });
+ });
+ });
+
+
+ describe('Phone detail view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones/nexus-s');
+ });
+
+
+ it('should display nexus-s page', function() {
+ expect(element(by.css('h1')).getText()).toBe('Nexus S');
+ });
+
+
+ it('should display the first phone image as the main phone image', function() {
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+
+
+ it('should swap main image if a thumbnail image is clicked on', function() {
+ element(by.css('.phone-thumbs li:nth-of-type(3) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/);
+
+ element(by.css('.phone-thumbs li:nth-of-type(1) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/ng2_components/test/karma_test_shim.js
new file mode 100644
index 0000000000..43c3d123ee
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/karma_test_shim.js
@@ -0,0 +1,54 @@
+// #docregion
+// Cancel Karma's synchronous start,
+// we will call `__karma__.start()` later, once all the specs are loaded.
+__karma__.loaded = function() {};
+
+System.config({
+ packages: {
+ 'base/app/js': {
+ defaultExtension: false,
+ format: 'register',
+ map: Object.keys(window.__karma__.files).
+ filter(onlyAppFiles).
+ reduce(function createPathRecords(pathsMapping, appPath) {
+ // creates local module name mapping to global path with karma's fingerprint in path, e.g.:
+ // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
+ var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, '');
+ pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]
+ return pathsMapping;
+ }, {})
+ },
+ 'rxjs': {
+ defaultExtension: 'js'
+ }
+ },
+ map: {
+ 'rxjs' : '/base/node_modules/rxjs'
+ }
+});
+
+// #docregion ng2
+System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) {
+ browser_adapter.BrowserDomAdapter.makeCurrent();
+}).then(function() {
+ return Promise.all(
+ Object.keys(window.__karma__.files) // All files served by Karma.
+ .filter(onlySpecFiles)
+ .map(function(moduleName) {
+ // loads all spec files via their global module names
+ return System.import(moduleName);
+ }));
+}).then(function() {
+ __karma__.start();
+}, function(error) {
+ __karma__.error(error.stack || error);
+});
+// #enddocregion ng2
+
+function onlyAppFiles(filePath) {
+ return /^\/base\/app\/js\/.*\.js$/.test(filePath)
+}
+
+function onlySpecFiles(path) {
+ return /\.spec\.js$/.test(path);
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/ng2_components/test/protractor-conf.js
new file mode 100644
index 0000000000..490e9bd078
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/protractor-conf.js
@@ -0,0 +1,21 @@
+exports.config = {
+ allScriptsTimeout: 11000,
+
+ specs: [
+ 'e2e/*.js'
+ ],
+
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+
+ directConnect: true,
+
+ baseUrl: 'http://localhost:8000/',
+
+ framework: 'jasmine',
+
+ jasmineNodeOpts: {
+ defaultTimeoutInterval: 30000
+ }
+};
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/test_helper.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/test_helper.ts
new file mode 100644
index 0000000000..dca9476b5e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/test_helper.ts
@@ -0,0 +1,2 @@
+// #docregion
+///
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/CheckmarkPipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/CheckmarkPipe.spec.ts
new file mode 100644
index 0000000000..9d5b92f6e0
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/CheckmarkPipe.spec.ts
@@ -0,0 +1,15 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject, expect} from 'angular2/testing';
+import {CheckmarkPipe} from '../../app/js/core/CheckmarkPipe';
+
+describe('CheckmarkPipe', function() {
+
+ beforeEachProviders(() => [CheckmarkPipe]);
+
+ it('should convert boolean values to unicode checkmark or cross',
+ inject([CheckmarkPipe], (checkmarkPipe) => {
+ expect(checkmarkPipe.transform(true)).toBe('\u2713');
+ expect(checkmarkPipe.transform(false)).toBe('\u2718');
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/OrderByPipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/OrderByPipe.spec.ts
new file mode 100644
index 0000000000..737ad10b82
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/OrderByPipe.spec.ts
@@ -0,0 +1,19 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+
+import OrderByPipe from '../../app/js/phone_list/OrderByPipe';
+
+describe('OrderByPipe', function() {
+
+ let input:any[] = [
+ {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []},
+ {name: 'Motorola DROID', snippet: 'An Android-for-business smartphone', images: []}
+ ];
+
+ beforeEachProviders(() => [OrderByPipe]);
+
+ it('should order by the given property', inject([OrderByPipe], (orderByPipe) => {
+ expect(orderByPipe.transform(input, ['name'])).toEqual([input[1], input[0]]);
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneDetail.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneDetail.spec.ts
new file mode 100644
index 0000000000..4775c5fdd5
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneDetail.spec.ts
@@ -0,0 +1,49 @@
+// #docregion
+import {provide} from 'angular2/core';
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Observable} from 'rxjs';
+import {FromObservable} from 'rxjs/observable/from';
+
+import {
+ describe,
+ beforeEachProviders,
+ injectAsync,
+ it,
+ expect,
+ TestComponentBuilder
+} from 'angular2/testing';
+import PhoneDetail from '../../app/js/phone_detail/PhoneDetail';
+import {Phones, Phone} from '../../app/js/core/Phones';
+
+function xyzPhoneData():Phone {
+ return {
+ name: 'phone xyz',
+ snippet: '',
+ images: ['image/url1.png', 'image/url2.png']
+ }
+}
+
+class MockPhones extends Phones {
+ get(id):Observable {
+ return FromObservable.create([xyzPhoneData()]);
+ }
+}
+
+describe('PhoneDetail', function(){
+
+ beforeEachProviders(() => [
+ provide(Phones, {useClass: MockPhones}),
+ provide('$routeParams', {useValue: {phoneId: 'xyz'}}),
+ HTTP_PROVIDERS
+ ]);
+
+ it('should fetch phone detail', injectAsync([TestComponentBuilder], (tcb) => {
+ return tcb.createAsync(PhoneDetail).then((fixture) => {
+ fixture.detectChanges();
+ let compiled = fixture.debugElement.nativeElement;
+
+ expect(compiled.querySelector('.h1')).toHaveText(xyzPhoneData().name);
+ });
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneFilterPipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneFilterPipe.spec.ts
new file mode 100644
index 0000000000..73e1772201
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneFilterPipe.spec.ts
@@ -0,0 +1,28 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+
+import PhoneFilterPipe from '../../app/js/phone_list/PhoneFilterPipe';
+import {Phone} from '../../app/js/core/Phones';
+
+describe('PhoneFilterPipe', function() {
+
+ let phones:Phone[] = [
+ {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []},
+ {name: 'Motorola DROID', snippet: 'an Android-for-business smartphone', images: []}
+ ];
+
+ beforeEachProviders(() => [PhoneFilterPipe]);
+
+ it('should return input when no query', inject([PhoneFilterPipe], (phoneFilterPipe) => {
+ expect(phoneFilterPipe.transform(phones, [])).toEqual(phones);
+ }));
+
+ it('should match based on name', inject([PhoneFilterPipe], (phoneFilterPipe) => {
+ expect(phoneFilterPipe.transform(phones, ['nexus'])).toEqual([phones[0]]);
+ }));
+
+ it('should match based on snippet', inject([PhoneFilterPipe], (phoneFilterPipe) => {
+ expect(phoneFilterPipe.transform(phones, ['android'])).toEqual([phones[1]]);
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneList.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneList.spec.ts
new file mode 100644
index 0000000000..e058f25e34
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/PhoneList.spec.ts
@@ -0,0 +1,58 @@
+// #docregion
+import {provide} from 'angular2/core';
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Observable} from 'rxjs';
+import {FromObservable} from 'rxjs/observable/from';
+
+import {
+ describe,
+ beforeEachProviders,
+ injectAsync,
+ it,
+ expect,
+ TestComponentBuilder
+} from 'angular2/testing';
+import PhoneList from '../../app/js/phone_list/PhoneList';
+import {Phones, Phone} from '../../app/js/core/Phones';
+
+class MockPhones extends Phones {
+ query():Observable {
+ return FromObservable.create([
+ [{name: 'Nexus S'}, {name: 'Motorola DROID'}]
+ ])
+ }
+}
+
+describe('PhoneList', function(){
+
+ beforeEachProviders(() => [
+ provide(Phones, {useClass: MockPhones}),
+ HTTP_PROVIDERS
+ ]);
+
+
+ it('should create "phones" model with 2 phones fetched from xhr',
+ injectAsync([TestComponentBuilder], (tcb) => {
+ return tcb.createAsync(PhoneList).then((fixture) => {
+ fixture.detectChanges();
+ fixture.detectChanges();
+
+ let compiled = fixture.debugElement.nativeElement;
+
+ expect(compiled.querySelectorAll('.phone-listing').length).toBe(2);
+ expect(compiled.querySelector('.phone-listing:nth-child(1)')).toHaveText('Nexus S');
+ expect(compiled.querySelector('.phone-listing:nth-child(2)')).toHaveText('Motorola DROID');
+ });
+ }));
+
+
+ it('should set the default value of orderProp model',
+ injectAsync([TestComponentBuilder], (tcb) => {
+ return tcb.createAsync(PhoneList).then((fixture) => {
+ fixture.detectChanges();
+ let compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector('select option:last-child').selected).toBe(true);
+ });
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_components/test/unit/Phones.spec.ts b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/Phones.spec.ts
new file mode 100644
index 0000000000..61f3fc1117
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_components/test/unit/Phones.spec.ts
@@ -0,0 +1,16 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Phones} from '../../app/js/core/Phones';
+
+describe('Phones', function() {
+
+ // load providers
+ beforeEachProviders(() => [Phones, HTTP_PROVIDERS]);
+
+ // Test service availability
+ it('check the existence of Phones', inject([Phones], (phones) => {
+ expect(phones).toBeDefined();
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/.bowerrc b/public/docs/_examples/upgrade/ts/ng2_final/.bowerrc
new file mode 100644
index 0000000000..5773025bf9
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "app/bower_components"
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/.gitignore b/public/docs/_examples/upgrade/ts/ng2_final/.gitignore
new file mode 100644
index 0000000000..8cfe0da551
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/.gitignore
@@ -0,0 +1,6 @@
+app/**/*.js
+app/**/*.js.map
+test/unit/**/*.js
+test/unit/**/*.js.map
+test/e2e/**/*.js
+test/e2e/**/*.js.map
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/css/.gitkeep b/public/docs/_examples/upgrade/ts/ng2_final/app/css/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/css/animations.css b/public/docs/_examples/upgrade/ts/ng2_final/app/css/animations.css
new file mode 100644
index 0000000000..46f3da6ecb
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/css/animations.css
@@ -0,0 +1,97 @@
+/*
+ * animations css stylesheet
+ */
+
+/* animate ngRepeat in phone listing */
+
+.phone-listing.ng-enter,
+.phone-listing.ng-leave,
+.phone-listing.ng-move {
+ -webkit-transition: 0.5s linear all;
+ -moz-transition: 0.5s linear all;
+ -o-transition: 0.5s linear all;
+ transition: 0.5s linear all;
+}
+
+.phone-listing.ng-enter,
+.phone-listing.ng-move {
+ opacity: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.phone-listing.ng-move.ng-move-active,
+.phone-listing.ng-enter.ng-enter-active {
+ opacity: 1;
+ height: 120px;
+}
+
+.phone-listing.ng-leave {
+ opacity: 1;
+ overflow: hidden;
+}
+
+.phone-listing.ng-leave.ng-leave-active {
+ opacity: 0;
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+/* cross fading between routes with ngView */
+
+.view-container {
+ position: relative;
+}
+
+.view-frame.ng-enter,
+.view-frame.ng-leave {
+ background: white;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+.view-frame.ng-enter {
+ -webkit-animation: 0.5s fade-in;
+ -moz-animation: 0.5s fade-in;
+ -o-animation: 0.5s fade-in;
+ animation: 0.5s fade-in;
+ z-index: 100;
+}
+
+.view-frame.ng-leave {
+ -webkit-animation: 0.5s fade-out;
+ -moz-animation: 0.5s fade-out;
+ -o-animation: 0.5s fade-out;
+ animation: 0.5s fade-out;
+ z-index: 99;
+}
+
+@keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-moz-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-webkit-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-moz-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-webkit-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/css/app.css b/public/docs/_examples/upgrade/ts/ng2_final/app/css/app.css
new file mode 100644
index 0000000000..f41c420776
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/css/app.css
@@ -0,0 +1,99 @@
+/* app css stylesheet */
+
+body {
+ padding-top: 20px;
+}
+
+
+.phone-images {
+ background-color: white;
+ width: 450px;
+ height: 450px;
+ overflow: hidden;
+ position: relative;
+ float: left;
+}
+
+.phones {
+ list-style: none;
+}
+
+.thumb {
+ float: left;
+ margin: -0.5em 1em 1.5em 0;
+ padding-bottom: 1em;
+ height: 100px;
+ width: 100px;
+}
+
+.phones li {
+ clear: both;
+ height: 115px;
+ padding-top: 15px;
+}
+
+/** Detail View **/
+img.phone {
+ float: left;
+ margin-right: 3em;
+ margin-bottom: 2em;
+ background-color: white;
+ padding: 2em;
+ height: 400px;
+ width: 400px;
+ display: none;
+}
+
+img.phone:first-of-type {
+ display: block;
+}
+
+
+ul.phone-thumbs {
+ margin: 0;
+ list-style: none;
+}
+
+ul.phone-thumbs li {
+ border: 1px solid black;
+ display: inline-block;
+ margin: 1em;
+ background-color: white;
+}
+
+ul.phone-thumbs img {
+ height: 100px;
+ width: 100px;
+ padding: 1em;
+}
+
+ul.phone-thumbs img:hover {
+ cursor: pointer;
+}
+
+
+ul.specs {
+ clear: both;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul.specs > li{
+ display: inline-block;
+ width: 200px;
+ vertical-align: top;
+}
+
+ul.specs > li > span{
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+ul.specs dt {
+ font-weight: bold;
+}
+
+h1 {
+ border-bottom: 1px solid gray;
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/img/.gitkeep b/public/docs/_examples/upgrade/ts/ng2_final/app/img/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings-white.png
new file mode 100644
index 0000000000..3bf6484a29
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings-white.png differ
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings.png
new file mode 100644
index 0000000000..5b67ffda5f
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/ng2_final/app/img/glyphicons-halflings.png differ
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/index.html b/public/docs/_examples/upgrade/ts/ng2_final/app/index.html
new file mode 100644
index 0000000000..0dc9748e51
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ Google Phone Gallery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/app.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/app.ts
new file mode 100644
index 0000000000..43b5b0b01c
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/app.ts
@@ -0,0 +1,48 @@
+// #docregion
+// #docregion importbootstrap
+import {Component, provide} from 'angular2/core';
+import {bootstrap} from 'angular2/platform/browser';
+
+import {Phones} from './core/Phones';
+import PhoneList from './phone_list/PhoneList';
+import PhoneDetail from './phone_detail/PhoneDetail';
+// #enddocregion importbootstrap
+
+// #docregion http-import
+import {HTTP_PROVIDERS} from 'angular2/http';
+// #enddocregion http-import
+
+// #docregion router-import
+import {
+ RouteConfig,
+ LocationStrategy,
+ HashLocationStrategy,
+ ROUTER_DIRECTIVES,
+ ROUTER_PROVIDERS
+} from 'angular2/router';
+// #enddocregion router-import
+
+// #docregion appcomponent
+@RouteConfig([
+ {path:'/phones', as: 'Phones', component: PhoneList},
+ {path:'/phones/:phoneId', as: 'Phone', component: PhoneDetail},
+ {path:'/', redirectTo: ['/phones']}
+])
+@Component({
+ selector: 'pc-app',
+ template: '',
+ directives: [ROUTER_DIRECTIVES]
+})
+class AppComponent {
+}
+// #enddocregion appcomponent
+
+// #docregion bootstrap
+bootstrap(AppComponent, [
+ HTTP_PROVIDERS,
+ ROUTER_PROVIDERS,
+ ROUTER_DIRECTIVES,
+ provide(LocationStrategy, {useClass: HashLocationStrategy}),
+ Phones
+]);
+// #enddocregion bootstrap
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/CheckmarkPipe.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/CheckmarkPipe.ts
new file mode 100644
index 0000000000..5156f14b50
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/CheckmarkPipe.ts
@@ -0,0 +1,9 @@
+// #docregion
+import {Pipe} from 'angular2/core';
+
+@Pipe({name: 'checkmark'})
+export class CheckmarkPipe {
+ transform(input:string): string {
+ return input ? '\u2713' : '\u2718';
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/Phones.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/Phones.ts
new file mode 100644
index 0000000000..8186c4810c
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/Phones.ts
@@ -0,0 +1,37 @@
+// #docregion full
+import {Injectable} from 'angular2/core';
+import {Http, Response} from 'angular2/http';
+import {Observable} from 'rxjs';
+import 'rxjs/add/operator/map';
+
+// #docregion phone-interface
+export interface Phone {
+ name: string;
+ snippet: string;
+ images: string[];
+}
+// #enddocregion phone-interface
+
+// #docregion fullclass
+// #docregion class
+@Injectable()
+export class Phones {
+// #enddocregion class
+
+ constructor(private http: Http) { }
+
+ query():Observable {
+ return this.http.get(`phones/phones.json`)
+ .map((res:Response) => res.json());
+ }
+
+ get(id: string):Observable {
+ return this.http.get(`phones/${id}.json`)
+ .map((res:Response) => res.json());
+ }
+
+// #docregion class
+}
+// #enddocregion class
+// #enddocregion fullclass
+// #docregion full
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/upgrade_adapter.ts
new file mode 100644
index 0000000000..e21be0e4d8
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/core/upgrade_adapter.ts
@@ -0,0 +1,9 @@
+// #docregion full
+import {UpgradeAdapter} from 'angular2/upgrade';
+
+// #docregion adapter-init
+const upgradeAdapter = new UpgradeAdapter();
+// #enddocregion adapter-init
+
+export default upgradeAdapter;
+// #enddocregion full
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/PhoneDetail.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/PhoneDetail.ts
new file mode 100644
index 0000000000..3b3de30fee
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/PhoneDetail.ts
@@ -0,0 +1,30 @@
+// #docregion
+// #docregion top
+import {Component, Inject} from 'angular2/core';
+import {RouteParams} from 'angular2/router';
+import {Phones, Phone} from '../core/Phones';
+import {CheckmarkPipe} from '../core/CheckmarkPipe';
+
+@Component({
+ selector: 'pc-phone-detail',
+ templateUrl: 'js/phone_detail/phone_detail.html',
+ pipes: [CheckmarkPipe]
+})
+class PhoneDetail {
+// #enddocregion top
+ phone:Phone = undefined;
+ mainImageUrl:string;
+ constructor(params:RouteParams,
+ phones:Phones) {
+ phones.get(params.get('phoneId'))
+ .subscribe(phone => {
+ this.phone = phone;
+ this.mainImageUrl = phone.images[0];
+ });
+ }
+
+ setImage(url:string) {
+ this.mainImageUrl = url;
+ }
+}
+export default PhoneDetail;
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.html
new file mode 100644
index 0000000000..51cc10aad5
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_detail/phone_detail.html
@@ -0,0 +1,115 @@
+
+
+
![]()
+
+{{phone?.name}}
+{{phone?.description}}
+
+ -
+
+
+
+
+ -
+ Availability and Networks
+
+ - Availability
+ - {{availability}}
+
+
+ -
+ Battery
+
+ - Type
+ - {{phone?.battery?.type}}
+ - Talk Time
+ - {{phone?.battery?.talkTime}}
+ - Standby time (max)
+ - {{phone?.battery?.standbyTime}}
+
+
+ -
+ Storage and Memory
+
+ - RAM
+ - {{phone?.storage?.ram}}
+ - Internal Storage
+ - {{phone?.storage?.flash}}
+
+
+ -
+ Connectivity
+
+ - Network Support
+ - {{phone?.connectivity?.cell}}
+ - WiFi
+ - {{phone?.connectivity?.wifi}}
+ - Bluetooth
+ - {{phone?.connectivity?.bluetooth}}
+ - Infrared
+ - {{phone?.connectivity?.infrared | checkmark}}
+ - GPS
+ - {{phone?.connectivity?.gps | checkmark}}
+
+
+ -
+ Android
+
+ - OS Version
+ - {{phone?.android?.os}}
+ - UI
+ - {{phone?.android?.ui}}
+
+
+ -
+ Size and Weight
+
+ - Dimensions
+ - {{dim}}
+ - Weight
+ - {{phone?.sizeAndWeight?.weight}}
+
+
+ -
+ Display
+
+ - Screen size
+ - {{phone?.display?.screenSize}}
+ - Screen resolution
+ - {{phone?.display?.screenResolution}}
+ - Touch screen
+ - {{phone?.display?.touchScreen | checkmark}}
+
+
+ -
+ Hardware
+
+ - CPU
+ - {{phone?.hardware?.cpu}}
+ - USB
+ - {{phone?.hardware?.usb}}
+ - Audio / headphone jack
+ - {{phone?.hardware?.audioJack}}
+ - FM Radio
+ - {{phone?.hardware?.fmRadio | checkmark}}
+ - Accelerometer
+ - {{phone?.hardware?.accelerometer | checkmark}}
+
+
+ -
+ Camera
+
+ - Primary
+ - {{phone?.camera?.primary}}
+ - Features
+ - {{phone?.camera?.features?.join(', ')}}
+
+
+ -
+ Additional Features
+
- {{phone?.additionalFeatures}}
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/OrderByPipe.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/OrderByPipe.ts
new file mode 100644
index 0000000000..3b82f03c9b
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/OrderByPipe.ts
@@ -0,0 +1,24 @@
+// #docregion
+import {Pipe} from 'angular2/core';
+
+@Pipe({name: 'orderBy'})
+export default class OrderByPipe {
+
+ transform(input:T[], args:string[]): T[] {
+ if (input) {
+ let property = args[0];
+ return input.slice().sort((a, b) => {
+ if (a[property] < b[property]) {
+ return -1;
+ } else if (b[property] < a[property]) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ } else {
+ return input;
+ }
+ }
+
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/PhoneFilterPipe.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/PhoneFilterPipe.ts
new file mode 100644
index 0000000000..cca575ece2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/PhoneFilterPipe.ts
@@ -0,0 +1,22 @@
+// #docregion
+import {Pipe} from 'angular2/core';
+import {Phone} from '../core/Phones';
+
+@Pipe({name: 'phoneFilter'})
+export default class PhoneFilterPipe {
+
+ transform(input:Phone[], args:string[]): Phone[] {
+ let query = args[0];
+ if (query) {
+ query = query.toLowerCase();
+ return input.filter((phone) => {
+ const name = phone.name.toLowerCase();
+ const snippet = phone.snippet.toLowerCase();
+ return name.indexOf(query) >= 0 || snippet.indexOf(query) >= 0;
+ });
+ } else {
+ return input;
+ }
+ }
+
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/PhoneList.ts b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/PhoneList.ts
new file mode 100644
index 0000000000..e7aa1dead1
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/PhoneList.ts
@@ -0,0 +1,28 @@
+// #docregion full
+// #docregion top
+import {Component} from 'angular2/core';
+import {RouterLink} from 'angular2/router';
+import {Observable} from 'rxjs';
+import {Phones, Phone} from '../core/Phones';
+import PhoneFilterPipe from './PhoneFilterPipe';
+import OrderByPipe from './OrderByPipe';
+
+@Component({
+ selector: 'pc-phone-list',
+ templateUrl: 'js/phone_list/phone_list.html',
+ pipes: [PhoneFilterPipe, OrderByPipe],
+ directives: [RouterLink]
+})
+class PhoneList {
+// #enddocregion top
+
+ phones:Observable;
+ orderProp:string;
+ query:string;
+ constructor(phones:Phones) {
+ this.phones = phones.query();
+ this.orderProp = 'age';
+ }
+}
+
+export default PhoneList;
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.html
new file mode 100644
index 0000000000..d605ff1f85
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/app/js/phone_list/phone_list.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/bower.json b/public/docs/_examples/upgrade/ts/ng2_final/bower.json
new file mode 100644
index 0000000000..03c0d72ea4
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/bower.json
@@ -0,0 +1,20 @@
+{
+ "name": "angular-phonecat",
+ "description": "A starter project for AngularJS",
+ "version": "0.0.0",
+ "homepage": "https://github.com/angular/angular-phonecat",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "angular": "1.5.0-beta.2",
+ "angular-mocks": "1.5.0-beta.2",
+ "jquery": "~2.1.1",
+ "bootstrap": "~3.1.1",
+ "angular-route": "1.5.0-beta.2",
+ "angular-resource": "1.5.0-beta.2",
+ "angular-animate": "1.5.0-beta.2"
+ },
+ "resolutions": {
+ "angular": "1.5.0-beta.2"
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/e2e/scenarios.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/e2e/scenarios.ts
new file mode 100644
index 0000000000..a8280cfed7
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/e2e/scenarios.ts
@@ -0,0 +1,114 @@
+'use strict';
+
+/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */
+
+describe('PhoneCat App', function() {
+
+ // #docregion redirect
+ it('should redirect index.html to index.html#/phones', function() {
+ browser.get('app/index.html');
+ browser.waitForAngular();
+ browser.getCurrentUrl().then(function(url) {
+ expect(url.endsWith('/phones')).toBe(true);
+ });
+ });
+ // #enddocregion redirect
+
+ describe('Phone list view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones');
+ });
+
+ it('should filter the phone list as a user types into the search box', function() {
+ var phoneList = element.all(by.css('.phones li'));
+ var query = element(by.css('input'));
+
+ expect(phoneList.count()).toBe(20);
+
+ query.sendKeys('nexus');
+ expect(phoneList.count()).toBe(1);
+
+ query.clear();
+ // https://github.com/angular/protractor/issues/2019
+ let str = 'motorola';
+ for (let i:number = 0; i < str.length; i++) {
+ query.sendKeys(str.charAt(i));
+ }
+
+ expect(phoneList.count()).toBe(8);
+ });
+
+
+ it('should be possible to control phone order via the drop down select box', function() {
+ var phoneNameColumn = element.all(by.css('.phones .name'));
+ var query = element(by.css('input'));
+
+ function getNames() {
+ return phoneNameColumn.map(function(elm) {
+ return elm.getText();
+ });
+ }
+
+ //let's narrow the dataset to make the test assertions shorter
+ // https://github.com/angular/protractor/issues/2019
+ let str = 'tablet';
+ for (let i:number = 0; i < str.length; i++) {
+ query.sendKeys(str.charAt(i));
+ }
+
+ expect(getNames()).toEqual([
+ "Motorola XOOM\u2122 with Wi-Fi",
+ "MOTOROLA XOOM\u2122"
+ ]);
+
+ element(by.css('select')).element(by.css('option[value="name"]')).click();
+ expect(getNames()).toEqual([
+ "MOTOROLA XOOM\u2122",
+ "Motorola XOOM\u2122 with Wi-Fi"
+ ]);
+ });
+
+
+ // #docregion links
+ it('should render phone specific links', function() {
+ var query = element(by.css('input'));
+ // https://github.com/angular/protractor/issues/2019
+ let str = 'nexus';
+ for (let i:number = 0; i < str.length; i++) {
+ query.sendKeys(str.charAt(i));
+ }
+ element.all(by.css('.phones li a')).first().click();
+ browser.getCurrentUrl().then(function(url) {
+ expect(url.endsWith('/phones/nexus-s')).toBe(true);
+ });
+ });
+ });
+ // #enddocregion links
+
+ describe('Phone detail view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones/nexus-s');
+ });
+
+
+ it('should display nexus-s page', function() {
+ expect(element(by.css('h1')).getText()).toBe('Nexus S');
+ });
+
+
+ it('should display the first phone image as the main phone image', function() {
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+
+
+ it('should swap main image if a thumbnail image is clicked on', function() {
+ element(by.css('.phone-thumbs li:nth-of-type(3) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/);
+
+ element(by.css('.phone-thumbs li:nth-of-type(1) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/ng2_final/test/karma_test_shim.js
new file mode 100644
index 0000000000..43c3d123ee
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/karma_test_shim.js
@@ -0,0 +1,54 @@
+// #docregion
+// Cancel Karma's synchronous start,
+// we will call `__karma__.start()` later, once all the specs are loaded.
+__karma__.loaded = function() {};
+
+System.config({
+ packages: {
+ 'base/app/js': {
+ defaultExtension: false,
+ format: 'register',
+ map: Object.keys(window.__karma__.files).
+ filter(onlyAppFiles).
+ reduce(function createPathRecords(pathsMapping, appPath) {
+ // creates local module name mapping to global path with karma's fingerprint in path, e.g.:
+ // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
+ var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, '');
+ pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]
+ return pathsMapping;
+ }, {})
+ },
+ 'rxjs': {
+ defaultExtension: 'js'
+ }
+ },
+ map: {
+ 'rxjs' : '/base/node_modules/rxjs'
+ }
+});
+
+// #docregion ng2
+System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) {
+ browser_adapter.BrowserDomAdapter.makeCurrent();
+}).then(function() {
+ return Promise.all(
+ Object.keys(window.__karma__.files) // All files served by Karma.
+ .filter(onlySpecFiles)
+ .map(function(moduleName) {
+ // loads all spec files via their global module names
+ return System.import(moduleName);
+ }));
+}).then(function() {
+ __karma__.start();
+}, function(error) {
+ __karma__.error(error.stack || error);
+});
+// #enddocregion ng2
+
+function onlyAppFiles(filePath) {
+ return /^\/base\/app\/js\/.*\.js$/.test(filePath)
+}
+
+function onlySpecFiles(path) {
+ return /\.spec\.js$/.test(path);
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/ng2_final/test/protractor-conf.js
new file mode 100644
index 0000000000..a1ea324632
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/protractor-conf.js
@@ -0,0 +1,25 @@
+exports.config = {
+ allScriptsTimeout: 11000,
+
+ specs: [
+ 'e2e/*.js'
+ ],
+
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+
+ directConnect: true,
+
+ baseUrl: 'http://localhost:8000/',
+
+ framework: 'jasmine',
+
+ jasmineNodeOpts: {
+ defaultTimeoutInterval: 30000
+ },
+
+ // #docregion ng2
+ useAllAngular2AppRoots: true
+ // #enddocregion ng2
+};
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/CheckmarkPipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/CheckmarkPipe.spec.ts
new file mode 100644
index 0000000000..9d5b92f6e0
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/CheckmarkPipe.spec.ts
@@ -0,0 +1,15 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject, expect} from 'angular2/testing';
+import {CheckmarkPipe} from '../../app/js/core/CheckmarkPipe';
+
+describe('CheckmarkPipe', function() {
+
+ beforeEachProviders(() => [CheckmarkPipe]);
+
+ it('should convert boolean values to unicode checkmark or cross',
+ inject([CheckmarkPipe], (checkmarkPipe) => {
+ expect(checkmarkPipe.transform(true)).toBe('\u2713');
+ expect(checkmarkPipe.transform(false)).toBe('\u2718');
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/OrderByPipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/OrderByPipe.spec.ts
new file mode 100644
index 0000000000..737ad10b82
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/OrderByPipe.spec.ts
@@ -0,0 +1,19 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+
+import OrderByPipe from '../../app/js/phone_list/OrderByPipe';
+
+describe('OrderByPipe', function() {
+
+ let input:any[] = [
+ {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []},
+ {name: 'Motorola DROID', snippet: 'An Android-for-business smartphone', images: []}
+ ];
+
+ beforeEachProviders(() => [OrderByPipe]);
+
+ it('should order by the given property', inject([OrderByPipe], (orderByPipe) => {
+ expect(orderByPipe.transform(input, ['name'])).toEqual([input[1], input[0]]);
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneDetail.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneDetail.spec.ts
new file mode 100644
index 0000000000..5df57def16
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneDetail.spec.ts
@@ -0,0 +1,53 @@
+import {provide} from 'angular2/core';
+// #docregion routeparams
+import {RouteParams} from 'angular2/router';
+// #enddocregion routeparams
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Observable} from 'rxjs';
+import {FromObservable} from 'rxjs/observable/from';
+
+import {
+ describe,
+ beforeEachProviders,
+ injectAsync,
+ it,
+ expect,
+ TestComponentBuilder
+} from 'angular2/testing';
+import PhoneDetail from '../../app/js/phone_detail/PhoneDetail';
+import {Phones, Phone} from '../../app/js/core/Phones';
+
+function xyzPhoneData():Phone {
+ return {
+ name: 'phone xyz',
+ snippet: '',
+ images: ['image/url1.png', 'image/url2.png']
+ }
+}
+
+class MockPhones extends Phones {
+ get(id):Observable {
+ return FromObservable.create([xyzPhoneData()]);
+ }
+}
+
+// #docregion routeparams
+describe('PhoneDetail', function(){
+
+ beforeEachProviders(() => [
+ provide(Phones, {useClass: MockPhones}),
+ provide(RouteParams, {useValue: new RouteParams({phoneId: 'xyz'})}),
+ HTTP_PROVIDERS
+ ]);
+ // #enddocregion routeparams
+
+ it('should fetch phone detail', injectAsync([TestComponentBuilder], (tcb) => {
+ return tcb.createAsync(PhoneDetail).then((fixture) => {
+ fixture.detectChanges();
+ let compiled = fixture.debugElement.nativeElement;
+
+ expect(compiled.querySelector('.h1')).toHaveText(xyzPhoneData().name);
+ });
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneFilterPipe.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneFilterPipe.spec.ts
new file mode 100644
index 0000000000..73e1772201
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneFilterPipe.spec.ts
@@ -0,0 +1,28 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+
+import PhoneFilterPipe from '../../app/js/phone_list/PhoneFilterPipe';
+import {Phone} from '../../app/js/core/Phones';
+
+describe('PhoneFilterPipe', function() {
+
+ let phones:Phone[] = [
+ {name: 'Nexus S', snippet: 'The Nexus S Phone', images: []},
+ {name: 'Motorola DROID', snippet: 'an Android-for-business smartphone', images: []}
+ ];
+
+ beforeEachProviders(() => [PhoneFilterPipe]);
+
+ it('should return input when no query', inject([PhoneFilterPipe], (phoneFilterPipe) => {
+ expect(phoneFilterPipe.transform(phones, [])).toEqual(phones);
+ }));
+
+ it('should match based on name', inject([PhoneFilterPipe], (phoneFilterPipe) => {
+ expect(phoneFilterPipe.transform(phones, ['nexus'])).toEqual([phones[0]]);
+ }));
+
+ it('should match based on snippet', inject([PhoneFilterPipe], (phoneFilterPipe) => {
+ expect(phoneFilterPipe.transform(phones, ['android'])).toEqual([phones[1]]);
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneList.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneList.spec.ts
new file mode 100644
index 0000000000..c1a98f94bd
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/PhoneList.spec.ts
@@ -0,0 +1,57 @@
+// #docregion
+import {provide} from 'angular2/core';
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Observable} from 'rxjs';
+import {FromObservable} from 'rxjs/observable/from';
+import {
+ describe,
+ beforeEachProviders,
+ injectAsync,
+ it,
+ expect,
+ TestComponentBuilder
+} from 'angular2/testing';
+import PhoneList from '../../app/js/phone_list/PhoneList';
+import {Phones, Phone} from '../../app/js/core/Phones';
+
+class MockPhones extends Phones {
+ query():Observable {
+ return FromObservable.create([
+ [{name: 'Nexus S'}, {name: 'Motorola DROID'}]
+ ])
+ }
+}
+
+describe('PhoneList', function(){
+
+ beforeEachProviders(() => [
+ provide(Phones, {useClass: MockPhones}),
+ HTTP_PROVIDERS
+ ]);
+
+
+ it('should create "phones" model with 2 phones fetched from xhr',
+ injectAsync([TestComponentBuilder], (tcb) => {
+ return tcb.createAsync(PhoneList).then((fixture) => {
+ fixture.detectChanges();
+ fixture.detectChanges();
+
+ let compiled = fixture.debugElement.nativeElement;
+
+ expect(compiled.querySelectorAll('.phone-listing').length).toBe(2);
+ expect(compiled.querySelector('.phone-listing:nth-child(1)')).toHaveText('Nexus S');
+ expect(compiled.querySelector('.phone-listing:nth-child(2)')).toHaveText('Motorola DROID');
+ });
+ }));
+
+
+ it('should set the default value of orderProp model',
+ injectAsync([TestComponentBuilder], (tcb) => {
+ return tcb.createAsync(PhoneList).then((fixture) => {
+ fixture.detectChanges();
+ let compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector('select option:last-child').selected).toBe(true);
+ });
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_final/test/unit/Phones.spec.ts b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/Phones.spec.ts
new file mode 100644
index 0000000000..61f3fc1117
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_final/test/unit/Phones.spec.ts
@@ -0,0 +1,16 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Phones} from '../../app/js/core/Phones';
+
+describe('Phones', function() {
+
+ // load providers
+ beforeEachProviders(() => [Phones, HTTP_PROVIDERS]);
+
+ // Test service availability
+ it('check the existence of Phones', inject([Phones], (phones) => {
+ expect(phones).toBeDefined();
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/.bowerrc b/public/docs/_examples/upgrade/ts/ng2_initial/.bowerrc
new file mode 100644
index 0000000000..5773025bf9
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "app/bower_components"
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/.gitignore b/public/docs/_examples/upgrade/ts/ng2_initial/.gitignore
new file mode 100644
index 0000000000..8cfe0da551
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/.gitignore
@@ -0,0 +1,6 @@
+app/**/*.js
+app/**/*.js.map
+test/unit/**/*.js
+test/unit/**/*.js.map
+test/e2e/**/*.js
+test/e2e/**/*.js.map
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/.gitkeep b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/animations.css b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/animations.css
new file mode 100644
index 0000000000..46f3da6ecb
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/animations.css
@@ -0,0 +1,97 @@
+/*
+ * animations css stylesheet
+ */
+
+/* animate ngRepeat in phone listing */
+
+.phone-listing.ng-enter,
+.phone-listing.ng-leave,
+.phone-listing.ng-move {
+ -webkit-transition: 0.5s linear all;
+ -moz-transition: 0.5s linear all;
+ -o-transition: 0.5s linear all;
+ transition: 0.5s linear all;
+}
+
+.phone-listing.ng-enter,
+.phone-listing.ng-move {
+ opacity: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.phone-listing.ng-move.ng-move-active,
+.phone-listing.ng-enter.ng-enter-active {
+ opacity: 1;
+ height: 120px;
+}
+
+.phone-listing.ng-leave {
+ opacity: 1;
+ overflow: hidden;
+}
+
+.phone-listing.ng-leave.ng-leave-active {
+ opacity: 0;
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+/* cross fading between routes with ngView */
+
+.view-container {
+ position: relative;
+}
+
+.view-frame.ng-enter,
+.view-frame.ng-leave {
+ background: white;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+.view-frame.ng-enter {
+ -webkit-animation: 0.5s fade-in;
+ -moz-animation: 0.5s fade-in;
+ -o-animation: 0.5s fade-in;
+ animation: 0.5s fade-in;
+ z-index: 100;
+}
+
+.view-frame.ng-leave {
+ -webkit-animation: 0.5s fade-out;
+ -moz-animation: 0.5s fade-out;
+ -o-animation: 0.5s fade-out;
+ animation: 0.5s fade-out;
+ z-index: 99;
+}
+
+@keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-moz-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-webkit-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-moz-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-webkit-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/css/app.css b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/app.css
new file mode 100644
index 0000000000..951ea087cc
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/css/app.css
@@ -0,0 +1,99 @@
+/* app css stylesheet */
+
+body {
+ padding-top: 20px;
+}
+
+
+.phone-images {
+ background-color: white;
+ width: 450px;
+ height: 450px;
+ overflow: hidden;
+ position: relative;
+ float: left;
+}
+
+.phones {
+ list-style: none;
+}
+
+.thumb {
+ float: left;
+ margin: -0.5em 1em 1.5em 0;
+ padding-bottom: 1em;
+ height: 100px;
+ width: 100px;
+}
+
+.phones li {
+ clear: both;
+ height: 115px;
+ padding-top: 15px;
+}
+
+/** Detail View **/
+img.phone {
+ float: left;
+ margin-right: 3em;
+ margin-bottom: 2em;
+ background-color: white;
+ padding: 2em;
+ height: 400px;
+ width: 400px;
+ display: none;
+}
+
+img.phone:first-child {
+ display: block;
+}
+
+
+ul.phone-thumbs {
+ margin: 0;
+ list-style: none;
+}
+
+ul.phone-thumbs li {
+ border: 1px solid black;
+ display: inline-block;
+ margin: 1em;
+ background-color: white;
+}
+
+ul.phone-thumbs img {
+ height: 100px;
+ width: 100px;
+ padding: 1em;
+}
+
+ul.phone-thumbs img:hover {
+ cursor: pointer;
+}
+
+
+ul.specs {
+ clear: both;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul.specs > li{
+ display: inline-block;
+ width: 200px;
+ vertical-align: top;
+}
+
+ul.specs > li > span{
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+ul.specs dt {
+ font-weight: bold;
+}
+
+h1 {
+ border-bottom: 1px solid gray;
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/.gitkeep b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings-white.png
new file mode 100644
index 0000000000..3bf6484a29
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings-white.png differ
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings.png
new file mode 100644
index 0000000000..5b67ffda5f
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/ng2_initial/app/img/glyphicons-halflings.png differ
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/index.html b/public/docs/_examples/upgrade/ts/ng2_initial/app/index.html
new file mode 100644
index 0000000000..a0739be79e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/index.html
@@ -0,0 +1,52 @@
+
+
+
+
+ Google Phone Gallery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/app.module.ts
new file mode 100644
index 0000000000..b8ea6945ee
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/app.module.ts
@@ -0,0 +1,50 @@
+///
+///
+///
+
+// #docregion adapter-import
+import {UpgradeAdapter} from 'angular2/upgrade';
+// #enddocregion adapter-import
+// #docregion adapter-state-import
+import upgradeAdapter from './core/upgrade_adapter';
+// #enddocregion adapter-state-import
+// #docregion http-import
+import {HTTP_PROVIDERS} from 'angular2/http';
+// #enddocregion http-import
+import core from './core/core.module';
+import phoneList from './phone_list/phone_list.module';
+import phoneDetail from './phone_detail/phone_detail.module';
+
+// #docregion add-http-providers
+upgradeAdapter.addProvider(HTTP_PROVIDERS);
+// #enddocregion add-http-providers
+
+angular.module('phonecatApp', [
+ 'ngRoute',
+ core.name,
+ phoneList.name,
+ phoneDetail.name
+]).config(configure);
+
+configure.$inject = ['$routeProvider'];
+
+function configure($routeProvider) {
+ $routeProvider.
+ when('/phones', {
+ templateUrl: 'js/phone_list/phone_list.html',
+ controller: 'PhoneListCtrl',
+ controllerAs: 'vm'
+ }).
+ when('/phones/:phoneId', {
+ templateUrl: 'js/phone_detail/phone_detail.html',
+ controller: 'PhoneDetailCtrl',
+ controllerAs: 'vm'
+ }).
+ otherwise({
+ redirectTo: '/phones'
+ });
+}
+
+// #docregion bootstrap
+upgradeAdapter.bootstrap(document.documentElement, ['phonecatApp']);
+// #enddocregion bootstrap
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/Phones.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/Phones.ts
new file mode 100644
index 0000000000..14625c5c9e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/Phones.ts
@@ -0,0 +1,38 @@
+// #docregion full
+import {Injectable} from 'angular2/core';
+import {Http, Response} from 'angular2/http';
+import {Observable} from 'rxjs';
+
+import 'rxjs/add/operator/map';
+
+// #docregion phone-interface
+export interface Phone {
+ name: string;
+ snippet: string;
+ images: string[];
+}
+// #enddocregion phone-interface
+
+// #docregion fullclass
+// #docregion class
+@Injectable()
+export class Phones {
+// #enddocregion class
+
+ constructor(private http: Http) { }
+
+ query():Observable {
+ return this.http.get(`phones/phones.json`)
+ .map((res:Response) => res.json());
+ }
+
+ get(id: string):Observable {
+ return this.http.get(`phones/${id}.json`)
+ .map((res:Response) => res.json());
+ }
+
+// #docregion class
+}
+// #enddocregion class
+// #enddocregion fullclass
+// #docregion full
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/checkmark.filter.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/checkmark.filter.ts
new file mode 100644
index 0000000000..84544b80a1
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/checkmark.filter.ts
@@ -0,0 +1,6 @@
+// #docregion
+export default function checkmarkFilter() {
+ return function(input:string):string {
+ return input ? '\u2713' : '\u2718';
+ };
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/core.module.ts
new file mode 100644
index 0000000000..cfc2fcf20a
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/core.module.ts
@@ -0,0 +1,10 @@
+// #docregion
+import {Phones} from './Phones';
+import checkmarkFilter from './checkmark.filter';
+import upgradeAdapter from './upgrade_adapter';
+
+upgradeAdapter.addProvider(Phones);
+
+export default angular.module('phonecat.core', [])
+ .factory('phones', upgradeAdapter.downgradeNg2Provider(Phones))
+ .filter('checkmark', checkmarkFilter);
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/upgrade_adapter.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/upgrade_adapter.ts
new file mode 100644
index 0000000000..e21be0e4d8
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/core/upgrade_adapter.ts
@@ -0,0 +1,9 @@
+// #docregion full
+import {UpgradeAdapter} from 'angular2/upgrade';
+
+// #docregion adapter-init
+const upgradeAdapter = new UpgradeAdapter();
+// #enddocregion adapter-init
+
+export default upgradeAdapter;
+// #enddocregion full
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.controller.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.controller.ts
new file mode 100644
index 0000000000..554eef41a0
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.controller.ts
@@ -0,0 +1,25 @@
+// #docregion
+import {Phones, Phone} from '../core/Phones';
+
+interface PhoneRouteParams {
+ phoneId: string
+}
+
+class PhoneDetailCtrl {
+ phone:Phone;
+ mainImageUrl:string;
+ constructor($routeParams:PhoneRouteParams, phones:Phones) {
+ phones.get($routeParams.phoneId)
+ .subscribe(phone => {
+ this.phone = phone;
+ this.mainImageUrl = phone.images[0];
+ });
+ }
+ setImage(url:string) {
+ this.mainImageUrl = url;
+ }
+}
+
+PhoneDetailCtrl.$inject = ['$routeParams', 'phones'];
+
+export default PhoneDetailCtrl;
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.html
new file mode 100644
index 0000000000..954c65c2cd
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.html
@@ -0,0 +1,118 @@
+
+
![]()
+
+
+{{vm.phone.name}}
+
+{{vm.phone.description}}
+
+
+ -
+
+
+
+
+
+ -
+ Availability and Networks
+
+ - Availability
+ - {{availability}}
+
+
+ -
+ Battery
+
+ - Type
+ - {{vm.phone.battery.type}}
+ - Talk Time
+ - {{vm.phone.battery.talkTime}}
+ - Standby time (max)
+ - {{vm.phone.battery.standbyTime}}
+
+
+ -
+ Storage and Memory
+
+ - RAM
+ - {{vm.phone.storage.ram}}
+ - Internal Storage
+ - {{vm.phone.storage.flash}}
+
+
+ -
+ Connectivity
+
+ - Network Support
+ - {{vm.phone.connectivity.cell}}
+ - WiFi
+ - {{vm.phone.connectivity.wifi}}
+ - Bluetooth
+ - {{vm.phone.connectivity.bluetooth}}
+ - Infrared
+ - {{vm.phone.connectivity.infrared | checkmark}}
+ - GPS
+ - {{vm.phone.connectivity.gps | checkmark}}
+
+
+ -
+ Android
+
+ - OS Version
+ - {{vm.phone.android.os}}
+ - UI
+ - {{vm.phone.android.ui}}
+
+
+ -
+ Size and Weight
+
+ - Dimensions
+ - {{dim}}
+ - Weight
+ - {{vm.phone.sizeAndWeight.weight}}
+
+
+ -
+ Display
+
+ - Screen size
+ - {{vm.phone.display.screenSize}}
+ - Screen resolution
+ - {{vm.phone.display.screenResolution}}
+ - Touch screen
+ - {{vm.phone.display.touchScreen | checkmark}}
+
+
+ -
+ Hardware
+
+ - CPU
+ - {{vm.phone.hardware.cpu}}
+ - USB
+ - {{vm.phone.hardware.usb}}
+ - Audio / headphone jack
+ - {{vm.phone.hardware.audioJack}}
+ - FM Radio
+ - {{vm.phone.hardware.fmRadio | checkmark}}
+ - Accelerometer
+ - {{vm.phone.hardware.accelerometer | checkmark}}
+
+
+ -
+ Camera
+
+ - Primary
+ - {{vm.phone.camera.primary}}
+ - Features
+ - {{vm.phone.camera.features.join(', ')}}
+
+
+ -
+ Additional Features
+
- {{vm.phone.additionalFeatures}}
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.module.ts
new file mode 100644
index 0000000000..16e7ac0baf
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_detail/phone_detail.module.ts
@@ -0,0 +1,8 @@
+// #docregion
+import PhoneDetailCtrl from './phone_detail.controller';
+
+export default angular.module('phonecat.detail', [
+ 'ngRoute',
+ 'phonecat.core'
+ ])
+ .controller('PhoneDetailCtrl', PhoneDetailCtrl);
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.controller.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.controller.ts
new file mode 100644
index 0000000000..d8ddf9a507
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.controller.ts
@@ -0,0 +1,17 @@
+// #docregion
+import {Phones, Phone} from '../core/Phones';
+
+class PhoneListCtrl {
+ phones:Phone[];
+ orderProp:string;
+ query:string;
+ constructor(phones:Phones) {
+ phones.query()
+ .subscribe(phones => this.phones = phones);
+ this.orderProp = 'age';
+ }
+}
+
+PhoneListCtrl.$inject = ['phones'];
+
+export default PhoneListCtrl;
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.html
new file mode 100644
index 0000000000..471f474e89
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.module.ts
new file mode 100644
index 0000000000..d2e7200778
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/app/js/phone_list/phone_list.module.ts
@@ -0,0 +1,5 @@
+// #docregion
+import PhoneListCtrl from './phone_list.controller';
+
+export default angular.module('phonecat.list', [])
+ .controller('PhoneListCtrl', PhoneListCtrl);
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/bower.json b/public/docs/_examples/upgrade/ts/ng2_initial/bower.json
new file mode 100644
index 0000000000..9ee83a5022
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/bower.json
@@ -0,0 +1,20 @@
+{
+ "name": "angular-phonecat",
+ "description": "A starter project for AngularJS",
+ "version": "0.0.0",
+ "homepage": "https://github.com/angular/angular-phonecat",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "angular": "1.5.0-beta.0",
+ "angular-mocks": "1.5.0-beta.0",
+ "jquery": "~2.1.1",
+ "bootstrap": "~3.1.1",
+ "angular-route": "1.5.0-beta.0",
+ "angular-resource": "1.5.0-beta.0",
+ "angular-animate": "1.5.0-beta.0"
+ },
+ "resolutions": {
+ "angular": "1.5.0-beta.0"
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/e2e/scenarios.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/e2e/scenarios.ts
new file mode 100644
index 0000000000..f20d0a294c
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/e2e/scenarios.ts
@@ -0,0 +1,99 @@
+'use strict';
+
+/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */
+
+describe('PhoneCat App', function() {
+
+ it('should redirect index.html to index.html#/phones', function() {
+ browser.get('app/index.html');
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones');
+ });
+ });
+
+
+ describe('Phone list view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones');
+ });
+
+ it('should filter the phone list as a user types into the search box', function() {
+ var phoneList = element.all(by.repeater('phone in vm.phones'));
+ var query = element(by.model('vm.query'));
+
+ expect(phoneList.count()).toBe(20);
+
+ query.sendKeys('nexus');
+ expect(phoneList.count()).toBe(1);
+
+ query.clear();
+ query.sendKeys('motorola');
+ expect(phoneList.count()).toBe(8);
+ });
+
+
+ it('should be possible to control phone order via the drop down select box', function() {
+
+ var phoneNameColumn = element.all(by.repeater('phone in vm.phones').column(0));
+ var query = element(by.model('vm.query'));
+
+ function getNames() {
+ return phoneNameColumn.map(function(elm) {
+ return elm.getText();
+ });
+ }
+
+ query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter
+
+ expect(getNames()).toEqual([
+ "Motorola XOOM\u2122 with Wi-Fi",
+ "MOTOROLA XOOM\u2122"
+ ]);
+
+ element(by.model('vm.orderProp')).element(by.css('option[value="name"]')).click();
+
+ expect(getNames()).toEqual([
+ "MOTOROLA XOOM\u2122",
+ "Motorola XOOM\u2122 with Wi-Fi"
+ ]);
+ });
+
+
+ it('should render phone specific links', function() {
+ var query = element(by.model('vm.query'));
+ query.sendKeys('nexus');
+ element.all(by.css('.phones li a')).first().click();
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones/nexus-s');
+ });
+ });
+ });
+
+
+ describe('Phone detail view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones/nexus-s');
+ });
+
+
+ it('should display nexus-s page', function() {
+ expect(element(by.binding('vm.phone.name')).getText()).toBe('Nexus S');
+ });
+
+
+ it('should display the first phone image as the main phone image', function() {
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+
+
+ it('should swap main image if a thumbnail image is clicked on', function() {
+ element(by.css('.phone-thumbs li:nth-child(3) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/);
+
+ element(by.css('.phone-thumbs li:nth-child(1) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/ng2_initial/test/karma_test_shim.js
new file mode 100644
index 0000000000..43c3d123ee
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/karma_test_shim.js
@@ -0,0 +1,54 @@
+// #docregion
+// Cancel Karma's synchronous start,
+// we will call `__karma__.start()` later, once all the specs are loaded.
+__karma__.loaded = function() {};
+
+System.config({
+ packages: {
+ 'base/app/js': {
+ defaultExtension: false,
+ format: 'register',
+ map: Object.keys(window.__karma__.files).
+ filter(onlyAppFiles).
+ reduce(function createPathRecords(pathsMapping, appPath) {
+ // creates local module name mapping to global path with karma's fingerprint in path, e.g.:
+ // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
+ var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, '');
+ pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]
+ return pathsMapping;
+ }, {})
+ },
+ 'rxjs': {
+ defaultExtension: 'js'
+ }
+ },
+ map: {
+ 'rxjs' : '/base/node_modules/rxjs'
+ }
+});
+
+// #docregion ng2
+System.import('angular2/src/platform/browser/browser_adapter').then(function(browser_adapter) {
+ browser_adapter.BrowserDomAdapter.makeCurrent();
+}).then(function() {
+ return Promise.all(
+ Object.keys(window.__karma__.files) // All files served by Karma.
+ .filter(onlySpecFiles)
+ .map(function(moduleName) {
+ // loads all spec files via their global module names
+ return System.import(moduleName);
+ }));
+}).then(function() {
+ __karma__.start();
+}, function(error) {
+ __karma__.error(error.stack || error);
+});
+// #enddocregion ng2
+
+function onlyAppFiles(filePath) {
+ return /^\/base\/app\/js\/.*\.js$/.test(filePath)
+}
+
+function onlySpecFiles(path) {
+ return /\.spec\.js$/.test(path);
+}
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/ng2_initial/test/protractor-conf.js
new file mode 100644
index 0000000000..118c7b9ec2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/protractor-conf.js
@@ -0,0 +1,21 @@
+exports.config = {
+ allScriptsTimeout: 11000,
+
+ specs: [
+ 'e2e/*.js'
+ ],
+
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+
+ chromeOnly: true,
+
+ baseUrl: 'http://localhost:8000/',
+
+ framework: 'jasmine',
+
+ jasmineNodeOpts: {
+ defaultTimeoutInterval: 30000
+ }
+};
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/test_helper.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/test_helper.ts
new file mode 100644
index 0000000000..dca9476b5e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/test_helper.ts
@@ -0,0 +1,2 @@
+// #docregion
+///
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/Phones.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/Phones.spec.ts
new file mode 100644
index 0000000000..61f3fc1117
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/Phones.spec.ts
@@ -0,0 +1,16 @@
+// #docregion
+import {describe, beforeEachProviders, it, inject} from 'angular2/testing';
+import {HTTP_PROVIDERS} from 'angular2/http';
+import {Phones} from '../../app/js/core/Phones';
+
+describe('Phones', function() {
+
+ // load providers
+ beforeEachProviders(() => [Phones, HTTP_PROVIDERS]);
+
+ // Test service availability
+ it('check the existence of Phones', inject([Phones], (phones) => {
+ expect(phones).toBeDefined();
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/checkmark.filter.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/checkmark.filter.spec.ts
new file mode 100644
index 0000000000..bae35e6875
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/checkmark.filter.spec.ts
@@ -0,0 +1,15 @@
+// #docregion top
+import '../../app/js/core/core.module';
+// #enddocregion top
+
+describe('checkmarkFilter', function() {
+
+ beforeEach(angular.mock.module('phonecat.core'));
+
+ it('should convert boolean values to unicode checkmark or cross',
+ inject(function(checkmarkFilter) {
+ expect(checkmarkFilter(true)).toBe('\u2713');
+ expect(checkmarkFilter(false)).toBe('\u2718');
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_detail.controller.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_detail.controller.spec.ts
new file mode 100644
index 0000000000..12f8402b73
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_detail.controller.spec.ts
@@ -0,0 +1,44 @@
+// #docregion
+import {Observable} from 'rxjs';
+import {describe, beforeEach, it} from 'angular2/testing';
+import '../../app/js/phone_detail/phone_detail.module';
+import {Phones} from '../../app/js/core/Phones';
+
+import {FromObservable} from 'rxjs/observable/from';
+
+describe('PhoneDetailCtrl', function(){
+ var scope, phones, $controller,
+ xyzPhoneData = function() {
+ return {
+ name: 'phone xyz',
+ snippet: '',
+ images: ['image/url1.png', 'image/url2.png']
+ }
+ };
+
+ beforeEach(angular.mock.module('phonecat.detail'));
+
+ // Supply a hand-instantianted instance of the Phones service
+ beforeEach(angular.mock.module(function($provide) {
+ $provide.factory('phones', function() {
+ return new Phones(null);
+ });
+ }));
+
+ beforeEach(inject(function(_phones_, _$controller_, $rootScope, $routeParams) {
+ phones = _phones_;
+ $controller = _$controller_;
+ $routeParams.phoneId = 'xyz';
+ scope = $rootScope.$new();
+ }));
+
+
+ it('should fetch phone detail', function() {
+ spyOn(phones, 'get').and.returnValue(FromObservable.create([xyzPhoneData()]));
+
+ let ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
+
+ expect(phones.get).toHaveBeenCalledWith('xyz');
+ expect(ctrl.phone).toEqual(xyzPhoneData());
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_list.controller.spec.ts b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_list.controller.spec.ts
new file mode 100644
index 0000000000..1c216aeb30
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/ng2_initial/test/unit/phone_list.controller.spec.ts
@@ -0,0 +1,39 @@
+// #docregion
+import {Observable} from 'rxjs';
+import {describe, beforeEach, it} from 'angular2/testing';
+import '../../app/js/phone_list/phone_list.module';
+import {Phones} from '../../app/js/core/Phones';
+
+import {FromObservable} from 'rxjs/observable/from';
+
+describe('PhoneListCtrl', function(){
+ var scope, ctrl, $httpBackend;
+
+ beforeEach(angular.mock.module('phonecat.list'));
+
+ // Supply a hand-instantianted instance of the Phones service
+ beforeEach(angular.mock.module(function($provide) {
+ $provide.factory('phones', function() {
+ return new Phones(null);
+ });
+ }));
+
+ beforeEach(inject(function(phones, $rootScope, $controller) {
+ spyOn(phones, 'query').and.returnValue(FromObservable.create([
+ [{name: 'Nexus S'}, {name: 'Motorola DROID'}]
+ ]));
+ scope = $rootScope.$new();
+ ctrl = $controller('PhoneListCtrl', {$scope: scope});
+ }));
+
+
+ it('should create "phones" model with 2 phones fetched from xhr', function() {
+ expect(ctrl.phones).toEqual(
+ [{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
+ });
+
+
+ it('should set the default value of orderProp model', function() {
+ expect(ctrl.orderProp).toBe('age');
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/.bowerrc b/public/docs/_examples/upgrade/ts/typescript-conversion/.bowerrc
new file mode 100644
index 0000000000..5773025bf9
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/.bowerrc
@@ -0,0 +1,3 @@
+{
+ "directory": "app/bower_components"
+}
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/.gitignore b/public/docs/_examples/upgrade/ts/typescript-conversion/.gitignore
new file mode 100644
index 0000000000..8cfe0da551
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/.gitignore
@@ -0,0 +1,6 @@
+app/**/*.js
+app/**/*.js.map
+test/unit/**/*.js
+test/unit/**/*.js.map
+test/e2e/**/*.js
+test/e2e/**/*.js.map
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/.gitkeep b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/animations.css b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/animations.css
new file mode 100644
index 0000000000..46f3da6ecb
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/animations.css
@@ -0,0 +1,97 @@
+/*
+ * animations css stylesheet
+ */
+
+/* animate ngRepeat in phone listing */
+
+.phone-listing.ng-enter,
+.phone-listing.ng-leave,
+.phone-listing.ng-move {
+ -webkit-transition: 0.5s linear all;
+ -moz-transition: 0.5s linear all;
+ -o-transition: 0.5s linear all;
+ transition: 0.5s linear all;
+}
+
+.phone-listing.ng-enter,
+.phone-listing.ng-move {
+ opacity: 0;
+ height: 0;
+ overflow: hidden;
+}
+
+.phone-listing.ng-move.ng-move-active,
+.phone-listing.ng-enter.ng-enter-active {
+ opacity: 1;
+ height: 120px;
+}
+
+.phone-listing.ng-leave {
+ opacity: 1;
+ overflow: hidden;
+}
+
+.phone-listing.ng-leave.ng-leave-active {
+ opacity: 0;
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+/* cross fading between routes with ngView */
+
+.view-container {
+ position: relative;
+}
+
+.view-frame.ng-enter,
+.view-frame.ng-leave {
+ background: white;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+.view-frame.ng-enter {
+ -webkit-animation: 0.5s fade-in;
+ -moz-animation: 0.5s fade-in;
+ -o-animation: 0.5s fade-in;
+ animation: 0.5s fade-in;
+ z-index: 100;
+}
+
+.view-frame.ng-leave {
+ -webkit-animation: 0.5s fade-out;
+ -moz-animation: 0.5s fade-out;
+ -o-animation: 0.5s fade-out;
+ animation: 0.5s fade-out;
+ z-index: 99;
+}
+
+@keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-moz-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+@-webkit-keyframes fade-in {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+@keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-moz-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+@-webkit-keyframes fade-out {
+ from { opacity: 1; }
+ to { opacity: 0; }
+}
+
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/app.css b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/app.css
new file mode 100644
index 0000000000..f41c420776
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/css/app.css
@@ -0,0 +1,99 @@
+/* app css stylesheet */
+
+body {
+ padding-top: 20px;
+}
+
+
+.phone-images {
+ background-color: white;
+ width: 450px;
+ height: 450px;
+ overflow: hidden;
+ position: relative;
+ float: left;
+}
+
+.phones {
+ list-style: none;
+}
+
+.thumb {
+ float: left;
+ margin: -0.5em 1em 1.5em 0;
+ padding-bottom: 1em;
+ height: 100px;
+ width: 100px;
+}
+
+.phones li {
+ clear: both;
+ height: 115px;
+ padding-top: 15px;
+}
+
+/** Detail View **/
+img.phone {
+ float: left;
+ margin-right: 3em;
+ margin-bottom: 2em;
+ background-color: white;
+ padding: 2em;
+ height: 400px;
+ width: 400px;
+ display: none;
+}
+
+img.phone:first-of-type {
+ display: block;
+}
+
+
+ul.phone-thumbs {
+ margin: 0;
+ list-style: none;
+}
+
+ul.phone-thumbs li {
+ border: 1px solid black;
+ display: inline-block;
+ margin: 1em;
+ background-color: white;
+}
+
+ul.phone-thumbs img {
+ height: 100px;
+ width: 100px;
+ padding: 1em;
+}
+
+ul.phone-thumbs img:hover {
+ cursor: pointer;
+}
+
+
+ul.specs {
+ clear: both;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul.specs > li{
+ display: inline-block;
+ width: 200px;
+ vertical-align: top;
+}
+
+ul.specs > li > span{
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+ul.specs dt {
+ font-weight: bold;
+}
+
+h1 {
+ border-bottom: 1px solid gray;
+}
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/.gitkeep b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings-white.png b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings-white.png
new file mode 100644
index 0000000000..3bf6484a29
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings-white.png differ
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings.png b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings.png
new file mode 100644
index 0000000000..5b67ffda5f
Binary files /dev/null and b/public/docs/_examples/upgrade/ts/typescript-conversion/app/img/glyphicons-halflings.png differ
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/index.html b/public/docs/_examples/upgrade/ts/typescript-conversion/app/index.html
new file mode 100644
index 0000000000..326cd44a44
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+ Google Phone Gallery
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/app.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/app.module.ts
new file mode 100644
index 0000000000..1ad958caec
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/app.module.ts
@@ -0,0 +1,41 @@
+// #docregion pre-bootstrap
+// #docregion typings
+///
+///
+///
+// #enddocregion
+
+import core from './core/core.module';
+import phoneList from './phone_list/phone_list.module';
+import phoneDetail from './phone_detail/phone_detail.module';
+
+angular.module('phonecatApp', [
+ 'ngAnimate',
+ 'ngRoute',
+ core.name,
+ phoneList.name,
+ phoneDetail.name
+]).config(configure);
+
+configure.$inject = ['$routeProvider'];
+
+function configure($routeProvider) {
+ $routeProvider.
+ when('/phones', {
+ templateUrl: 'js/phone_list/phone_list.html',
+ controller: 'PhoneListCtrl',
+ controllerAs: 'vm'
+ }).
+ when('/phones/:phoneId', {
+ templateUrl: 'js/phone_detail/phone_detail.html',
+ controller: 'PhoneDetailCtrl',
+ controllerAs: 'vm'
+ }).
+ otherwise({
+ redirectTo: '/phones'
+ });
+}
+// #enddocregion pre-bootstrap
+// #docregion bootstrap
+angular.bootstrap(document.documentElement, ['phonecatApp']);
+// #enddocregion bootstrap
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/checkmark.filter.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/checkmark.filter.ts
new file mode 100644
index 0000000000..b2615f15e4
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/checkmark.filter.ts
@@ -0,0 +1,6 @@
+// #docregion
+export default function checkmarkFilter() {
+ return function(input) {
+ return input ? '\u2713' : '\u2718';
+ };
+}
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/core.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/core.module.ts
new file mode 100644
index 0000000000..c20ce33683
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/core.module.ts
@@ -0,0 +1,9 @@
+// #docregion
+import Phone from './phone.factory';
+import checkmarkFilter from './checkmark.filter';
+
+export default angular.module('phonecat.core', [
+ 'ngResource'
+ ])
+ .factory('Phone', Phone)
+ .filter('checkmark', checkmarkFilter);
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/phone.factory.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/phone.factory.ts
new file mode 100644
index 0000000000..a8492b29fc
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/core/phone.factory.ts
@@ -0,0 +1,10 @@
+// #docregion
+Phone.$inject = ['$resource'];
+
+function Phone($resource) {
+ return $resource('phones/:phoneId.json', {}, {
+ query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
+ });
+}
+
+export default Phone;
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.controller.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.controller.ts
new file mode 100644
index 0000000000..c8745c0cd2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.controller.ts
@@ -0,0 +1,14 @@
+// #docregion
+PhoneDetailCtrl.$inject = ['$routeParams', 'Phone'];
+
+function PhoneDetailCtrl($routeParams, Phone) {
+ var vm = this;
+ vm.phone = Phone.get({phoneId: $routeParams.phoneId}, function(phone) {
+ vm.mainImageUrl = phone.images[0];
+ });
+ vm.setImage = function(imageUrl) {
+ vm.mainImageUrl = imageUrl;
+ };
+}
+
+export default PhoneDetailCtrl;
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.html b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.html
new file mode 100644
index 0000000000..954c65c2cd
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.html
@@ -0,0 +1,118 @@
+
+
![]()
+
+
+{{vm.phone.name}}
+
+{{vm.phone.description}}
+
+
+ -
+
+
+
+
+
+ -
+ Availability and Networks
+
+ - Availability
+ - {{availability}}
+
+
+ -
+ Battery
+
+ - Type
+ - {{vm.phone.battery.type}}
+ - Talk Time
+ - {{vm.phone.battery.talkTime}}
+ - Standby time (max)
+ - {{vm.phone.battery.standbyTime}}
+
+
+ -
+ Storage and Memory
+
+ - RAM
+ - {{vm.phone.storage.ram}}
+ - Internal Storage
+ - {{vm.phone.storage.flash}}
+
+
+ -
+ Connectivity
+
+ - Network Support
+ - {{vm.phone.connectivity.cell}}
+ - WiFi
+ - {{vm.phone.connectivity.wifi}}
+ - Bluetooth
+ - {{vm.phone.connectivity.bluetooth}}
+ - Infrared
+ - {{vm.phone.connectivity.infrared | checkmark}}
+ - GPS
+ - {{vm.phone.connectivity.gps | checkmark}}
+
+
+ -
+ Android
+
+ - OS Version
+ - {{vm.phone.android.os}}
+ - UI
+ - {{vm.phone.android.ui}}
+
+
+ -
+ Size and Weight
+
+ - Dimensions
+ - {{dim}}
+ - Weight
+ - {{vm.phone.sizeAndWeight.weight}}
+
+
+ -
+ Display
+
+ - Screen size
+ - {{vm.phone.display.screenSize}}
+ - Screen resolution
+ - {{vm.phone.display.screenResolution}}
+ - Touch screen
+ - {{vm.phone.display.touchScreen | checkmark}}
+
+
+ -
+ Hardware
+
+ - CPU
+ - {{vm.phone.hardware.cpu}}
+ - USB
+ - {{vm.phone.hardware.usb}}
+ - Audio / headphone jack
+ - {{vm.phone.hardware.audioJack}}
+ - FM Radio
+ - {{vm.phone.hardware.fmRadio | checkmark}}
+ - Accelerometer
+ - {{vm.phone.hardware.accelerometer | checkmark}}
+
+
+ -
+ Camera
+
+ - Primary
+ - {{vm.phone.camera.primary}}
+ - Features
+ - {{vm.phone.camera.features.join(', ')}}
+
+
+ -
+ Additional Features
+
- {{vm.phone.additionalFeatures}}
+
+
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.module.ts
new file mode 100644
index 0000000000..5ea1739577
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_detail/phone_detail.module.ts
@@ -0,0 +1,8 @@
+// #docregion
+import PhoneDetailCtrl from './phone_detail.controller';
+
+export default angular.module('phonecat.detail', [
+ 'phonecat.core',
+ 'ngRoute'
+ ])
+ .controller('PhoneDetailCtrl', PhoneDetailCtrl);
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.controller.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.controller.ts
new file mode 100644
index 0000000000..63dc2a6548
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.controller.ts
@@ -0,0 +1,10 @@
+// #docregion
+PhoneListCtrl.$inject = ['Phone'];
+
+function PhoneListCtrl(Phone) {
+ var vm = this;
+ vm.phones = Phone.query();
+ vm.orderProp = 'age';
+}
+
+export default PhoneListCtrl;
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.html b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.html
new file mode 100644
index 0000000000..471f474e89
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ Search:
+ Sort by:
+
+
+
+
+
+
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.module.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.module.ts
new file mode 100644
index 0000000000..758b937927
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/app/js/phone_list/phone_list.module.ts
@@ -0,0 +1,5 @@
+// #docregion
+import PhoneListCtrl from './phone_list.controller';
+
+export default angular.module('phonecat.list', ['phonecat.core'])
+ .controller('PhoneListCtrl', PhoneListCtrl);
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/bower.json b/public/docs/_examples/upgrade/ts/typescript-conversion/bower.json
new file mode 100644
index 0000000000..03c0d72ea4
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/bower.json
@@ -0,0 +1,20 @@
+{
+ "name": "angular-phonecat",
+ "description": "A starter project for AngularJS",
+ "version": "0.0.0",
+ "homepage": "https://github.com/angular/angular-phonecat",
+ "license": "MIT",
+ "private": true,
+ "dependencies": {
+ "angular": "1.5.0-beta.2",
+ "angular-mocks": "1.5.0-beta.2",
+ "jquery": "~2.1.1",
+ "bootstrap": "~3.1.1",
+ "angular-route": "1.5.0-beta.2",
+ "angular-resource": "1.5.0-beta.2",
+ "angular-animate": "1.5.0-beta.2"
+ },
+ "resolutions": {
+ "angular": "1.5.0-beta.2"
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/e2e/scenarios.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/e2e/scenarios.ts
new file mode 100644
index 0000000000..4cdbefc047
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/e2e/scenarios.ts
@@ -0,0 +1,103 @@
+'use strict';
+
+/* http://docs.angularjs.org/guide/dev_guide.e2e-testing */
+// #docregion declares
+declare var browser:any, element:any, by:any;
+// #enddocregion declares
+
+describe('PhoneCat App', function() {
+
+ it('should redirect index.html to index.html#/phones', function() {
+ browser.get('app/index.html');
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones');
+ });
+ });
+
+
+ describe('Phone list view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones');
+ });
+
+
+ it('should filter the phone list as a user types into the search box', function() {
+ var phoneList = element.all(by.repeater('phone in vm.phones'));
+ var query = element(by.model('vm.query'));
+
+ expect(phoneList.count()).toBe(20);
+
+ query.sendKeys('nexus');
+ expect(phoneList.count()).toBe(1);
+
+ query.clear();
+ query.sendKeys('motorola');
+ expect(phoneList.count()).toBe(8);
+ });
+
+
+ it('should be possible to control phone order via the drop down select box', function() {
+
+ var phoneNameColumn = element.all(by.repeater('phone in vm.phones').column('phone.name'));
+ var query = element(by.model('vm.query'));
+
+ function getNames() {
+ return phoneNameColumn.map(function(elm) {
+ return elm.getText();
+ });
+ }
+
+ query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter
+
+ expect(getNames()).toEqual([
+ "Motorola XOOM\u2122 with Wi-Fi",
+ "MOTOROLA XOOM\u2122"
+ ]);
+
+ element(by.model('vm.orderProp')).element(by.css('option[value="name"]')).click();
+
+ expect(getNames()).toEqual([
+ "MOTOROLA XOOM\u2122",
+ "Motorola XOOM\u2122 with Wi-Fi"
+ ]);
+ });
+
+
+ it('should render phone specific links', function() {
+ var query = element(by.model('vm.query'));
+ query.sendKeys('nexus');
+ element.all(by.css('.phones li a')).first().click();
+ browser.getLocationAbsUrl().then(function(url) {
+ expect(url).toEqual('/phones/nexus-s');
+ });
+ });
+ });
+
+
+ describe('Phone detail view', function() {
+
+ beforeEach(function() {
+ browser.get('app/index.html#/phones/nexus-s');
+ });
+
+
+ it('should display nexus-s page', function() {
+ expect(element(by.binding('vm.phone.name')).getText()).toBe('Nexus S');
+ });
+
+
+ it('should display the first phone image as the main phone image', function() {
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+
+
+ it('should swap main image if a thumbnail image is clicked on', function() {
+ element(by.css('.phone-thumbs li:nth-child(3) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.2.jpg/);
+
+ element(by.css('.phone-thumbs li:nth-child(1) img')).click();
+ expect(element(by.css('img.phone.active')).getAttribute('src')).toMatch(/img\/phones\/nexus-s.0.jpg/);
+ });
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/jasmine_matchers.d.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/jasmine_matchers.d.ts
new file mode 100644
index 0000000000..6d24879775
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/jasmine_matchers.d.ts
@@ -0,0 +1,6 @@
+// #docregion
+declare module jasmine {
+ interface Matchers {
+ toEqualData(expected: any):boolean;
+ }
+}
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma_test_shim.js b/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma_test_shim.js
new file mode 100644
index 0000000000..15cbee5d7d
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/karma_test_shim.js
@@ -0,0 +1,44 @@
+// #docregion
+// Cancel Karma's synchronous start,
+// we will call `__karma__.start()` later, once all the specs are loaded.
+__karma__.loaded = function() {};
+
+System.config({
+ packages: {
+ 'base/app/js': {
+ defaultExtension: false,
+ format: 'register',
+ map: Object.keys(window.__karma__.files).
+ filter(onlyAppFiles).
+ reduce(function createPathRecords(pathsMapping, appPath) {
+ // creates local module name mapping to global path with karma's fingerprint in path, e.g.:
+ // './hero.service': '/base/src/app/hero.service.js?f4523daf879cfb7310ef6242682ccf10b2041b3e'
+ var moduleName = appPath.replace(/^\/base\/app\/js\//, './').replace(/\.js$/, '');
+ pathsMapping[moduleName] = appPath + '?' + window.__karma__.files[appPath]
+ return pathsMapping;
+ }, {})
+
+ }
+ }
+});
+
+Promise.all(
+ Object.keys(window.__karma__.files) // All files served by Karma.
+ .filter(onlySpecFiles)
+ .map(function(moduleName) {
+ // loads all spec files via their global module names
+ return System.import(moduleName);
+}))
+.then(function() {
+ __karma__.start();
+}, function(error) {
+ __karma__.error(error.stack || error);
+});
+
+function onlyAppFiles(filePath) {
+ return /^\/base\/app\/js\/.*\.js$/.test(filePath)
+}
+
+function onlySpecFiles(path) {
+ return /\.spec\.js$/.test(path);
+}
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/protractor-conf.js b/public/docs/_examples/upgrade/ts/typescript-conversion/test/protractor-conf.js
new file mode 100644
index 0000000000..118c7b9ec2
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/protractor-conf.js
@@ -0,0 +1,21 @@
+exports.config = {
+ allScriptsTimeout: 11000,
+
+ specs: [
+ 'e2e/*.js'
+ ],
+
+ capabilities: {
+ 'browserName': 'chrome'
+ },
+
+ chromeOnly: true,
+
+ baseUrl: 'http://localhost:8000/',
+
+ framework: 'jasmine',
+
+ jasmineNodeOpts: {
+ defaultTimeoutInterval: 30000
+ }
+};
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/test_helper.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/test_helper.ts
new file mode 100644
index 0000000000..75f83fab7a
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/test_helper.ts
@@ -0,0 +1,3 @@
+// #docregion
+///
+///
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/checkmark.filter.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/checkmark.filter.spec.ts
new file mode 100644
index 0000000000..bae35e6875
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/checkmark.filter.spec.ts
@@ -0,0 +1,15 @@
+// #docregion top
+import '../../app/js/core/core.module';
+// #enddocregion top
+
+describe('checkmarkFilter', function() {
+
+ beforeEach(angular.mock.module('phonecat.core'));
+
+ it('should convert boolean values to unicode checkmark or cross',
+ inject(function(checkmarkFilter) {
+ expect(checkmarkFilter(true)).toBe('\u2713');
+ expect(checkmarkFilter(false)).toBe('\u2718');
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone.factory.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone.factory.spec.ts
new file mode 100644
index 0000000000..d7c95d347e
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone.factory.spec.ts
@@ -0,0 +1,15 @@
+// #docregion top
+import '../../app/js/core/core.module';
+// #enddocregion top
+
+describe('phoneFactory', function() {
+
+ // load modules
+ beforeEach(angular.mock.module('phonecat.core'));
+
+ // Test service availability
+ it('check the existence of Phone factory', inject(function(Phone) {
+ expect(Phone).toBeDefined();
+ }));
+
+});
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_detail.controller.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_detail.controller.spec.ts
new file mode 100644
index 0000000000..02a3e20240
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_detail.controller.spec.ts
@@ -0,0 +1,44 @@
+// #docregion top
+import '../../app/js/phone_detail/phone_detail.module';
+// #enddocregion top
+
+describe('PhoneDetailCtrl', function(){
+ var scope, $httpBackend, ctrl,
+ xyzPhoneData = function() {
+ return {
+ name: 'phone xyz',
+ images: ['image/url1.png', 'image/url2.png']
+ }
+ };
+
+ beforeEach(angular.mock.module('phonecat.detail'));
+
+ beforeEach(function(){
+ jasmine.addMatchers({
+ toEqualData: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ return {pass: angular.equals(actual, expected)};
+ }
+ };
+ }
+ });
+ });
+
+ beforeEach(inject(function(_$httpBackend_, $rootScope, $routeParams, $controller) {
+ $httpBackend = _$httpBackend_;
+ $httpBackend.expectGET('phones/xyz.json').respond(xyzPhoneData());
+
+ $routeParams.phoneId = 'xyz';
+ scope = $rootScope.$new();
+ ctrl = $controller('PhoneDetailCtrl', {$scope: scope});
+ }));
+
+
+ it('should fetch phone detail', function() {
+ expect(ctrl.phone).toEqualData({});
+ $httpBackend.flush();
+
+ expect(ctrl.phone).toEqualData(xyzPhoneData());
+ });
+});
diff --git a/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_list.controller.spec.ts b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_list.controller.spec.ts
new file mode 100644
index 0000000000..efec5d5f08
--- /dev/null
+++ b/public/docs/_examples/upgrade/ts/typescript-conversion/test/unit/phone_list.controller.spec.ts
@@ -0,0 +1,44 @@
+// #docregion top
+import '../../app/js/phone_list/phone_list.module';
+// #enddocregion top
+
+describe('PhoneListCtrl', function(){
+ var scope, ctrl, $httpBackend;
+
+ beforeEach(angular.mock.module('phonecat.list'));
+
+ beforeEach(function(){
+ jasmine.addMatchers({
+ toEqualData: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ return {pass: angular.equals(actual, expected)};
+ }
+ };
+ }
+ });
+ });
+
+ beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
+ $httpBackend = _$httpBackend_;
+ $httpBackend.expectGET('phones/phones.json').
+ respond([{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
+
+ scope = $rootScope.$new();
+ ctrl = $controller('PhoneListCtrl', {$scope: scope});
+ }));
+
+
+ it('should create "phones" model with 2 phones fetched from xhr', function() {
+ expect(ctrl.phones).toEqualData([]);
+ $httpBackend.flush();
+
+ expect(ctrl.phones).toEqualData(
+ [{name: 'Nexus S'}, {name: 'Motorola DROID'}]);
+ });
+
+
+ it('should set the default value of orderProp model', function() {
+ expect(ctrl.orderProp).toBe('age');
+ });
+});
diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json
index 02453a3398..1a8f3c296e 100644
--- a/public/docs/ts/latest/guide/_data.json
+++ b/public/docs/ts/latest/guide/_data.json
@@ -8,11 +8,11 @@
"cheatsheet": {
"title": "Angular Cheat Sheet"
},
-
+
"architecture": {
"title": "Architecture Overview"
},
-
+
"displaying-data": {
"title": "Displaying Data",
"intro": "In Angular, we display data by binding component properties to elements in HTML templates using interpolation and other forms of Property Binding."
@@ -27,7 +27,7 @@
"title": "Forms",
"intro": "A form creates a cohesive, effective, and compelling data entry experience. An Angular form coordinates a set of data-bound user controls, tracks changes, validates input, and presents errors."
},
-
+
"dependency-injection": {
"title": "Dependency Injection",
"intro": "Angular's dependency injection system creates and delivers dependent services \"just-in-time\"."
@@ -47,17 +47,22 @@
"title": "Attribute Directives",
"intro": "Attribute directives attach behavior to elements."
},
-
+
"structural-directives": {
"title": "Structural Directives",
"intro": "Angular has a powerful template engine that lets us easily manipulate the DOM structure of our elements."
- },
+ },
"hierarchical-dependency-injection": {
"title": "Hierarchical Injectors",
"intro": "Angular's hierarchical dependency injection system supports nested injectors in parallel with the component tree."
},
+ "upgrade": {
+ "title": "Upgrading from 1.x",
+ "intro": "Angular 1 applications can be incrementally upgraded to Angular 2."
+ },
+
"glossary": {
"title": "Glossary",
"intro": "Brief definitions of the most important words in the Angular 2 vocabulary"
diff --git a/public/docs/ts/latest/guide/upgrade.jade b/public/docs/ts/latest/guide/upgrade.jade
new file mode 100644
index 0000000000..713d4ea441
--- /dev/null
+++ b/public/docs/ts/latest/guide/upgrade.jade
@@ -0,0 +1,1291 @@
+include ../../../../_includes/_util-fns
+
+:marked
+ Having an existing Angular 1 application doesn't mean that we can't
+ begin enjoying everything Angular 2 has to offer. That's beause
+ Angular 2 comes with built-in tools for migrating Angular 1 projects
+ over to the Angular 2 platform.
+
+ One of the keys to a successful upgrade is to do it incrementally,
+ by running the two frameworks side by side in the same application,
+ and porting Angular 1 components to Angular 2 one by one. This makes
+ it possible to upgrade even large and complex applications without
+ disrupting other work. The `upgrade` module in Angular 2 has
+ been designed to make incremental upgrading seamless.
+
+ In this chapter we will look at a complete example of preparing and
+ upgrading an application using the `upgrade` module. The app we're going
+ to work on is [Angular PhoneCat](https://github.com/angular/angular-phonecat)
+ from [the original Angular 1 tutorial](https://docs.angularjs.org/tutorial),
+ which is where many of us began our Angular adventures. Now we'll see how to
+ bring that application to the brave new world of Angular 2.
+
+ During the process we'll learn
+
+ - How to prepare and align an Angular 1 application with Angular 2
+
+ - How to use the SystemJS module loader and TypeScript with Angular 1
+
+ - How to develop and test a hybrid Angular 1+2 application
+
+ - How to migrate an application to Angular 2 one component at a time
+
+ To follow along with the tutorial, clone the
+ [angular-phonecat](https://github.com/angular/angular-phonecat) repository
+ and apply the steps as we go
+
+.alert.is-important
+ :marked
+ If you do clone this repository, note that it doesn't look like this guide
+ assumes yet. There's [a pull request](https://github.com/angular/angular-phonecat/pull/289)
+ that will change this. Meanwhile, you'll find a good starting point from
+ [this commit](https://github.com/teropa/angular-phonecat/commit/d6fb83e1c2db9d1812c7c478fdb8d92301ef0061).
+
+.l-main-section
+:marked
+ ## Preparing for the Upgrade
+
+ In terms of project structure, this is where our work begins
+
+ ```
+ angular-phonecat
+ ├── bower.json
+ ├── package.json
+ ├── app
+ │ ├── js
+ │ │ ├── core
+ │ │ │ ├── checkmark.filter.js
+ │ │ │ ├── core.module.js
+ │ │ │ └── phone.factory.js
+ │ │ ├── phone_detail
+ │ │ │ ├── phone_detail.html
+ │ │ │ ├── phone_detail.module.js
+ │ │ │ └── phone_detail.controller.js
+ │ │ ├── phone_list
+ │ │ │ ├── phone_list.html
+ │ │ │ ├── phone_list.module.js
+ │ │ │ └── phone_list.controller.js
+ │ │ └── app.module.js
+ │ ├── css
+ │ │ ├── animations.css
+ │ │ └── app.css
+ │ ├── img
+ │ │ └── ...
+ │ ├── phones
+ │ │ └── ...
+ │ └── index.html
+ └── test
+ ├── e2e
+ │ └── scenarios.js
+ ├── unit
+ │ ├── checkmark.filter.spec.js
+ │ ├── phone_detail.controller.spec.js
+ │ ├── phone.factory.spec.js
+ │ └── phone_list.controller.spec.js
+ ├── karma.conf.js
+ └── protractor-conf.js
+ ```
+
+ This is actually a pretty good starting point. In particular, this organization
+ follows the [Angular Style Guide](https://github.com/johnpapa/angular-styleguide),
+ which is an important [preparation step](preparation.html) before a successful upgrade.
+
+ * Each controller, factory, and filter is in its own source file, as per the
+ [Rule of 1](https://github.com/johnpapa/angular-styleguide#single-responsibility).
+ * The `core`, `phoneDetail`, and `phoneList` modules are each in their
+ own subdirectory. Those subdirectories contain the JavaScript code as well as
+ the HTML templates that go with each particular feature. This is in line with the
+ [Folders-by-Feature Structure](https://github.com/johnpapa/angular-styleguide#style-y152)
+ and [Modularity](https://github.com/johnpapa/angular-styleguide#modularity)
+ rules.
+
+:marked
+ ## TypeScript And Module Loading
+
+ Since we're going to be writing our Angular 2 code in TypeScript, it makes sense to
+ bring in the TypeScript compiler even before we begin upgrading.
+
+ In order to use TypeScript's ES2015 module system to `import` and `export` code, we're
+ going to need a JavaScript module loader. Our application doesn't currently
+ use one, and is just using plain old `