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 `