docs(aio): update migrated content from anguar.io


@ -0,0 +1,14 @@
|
||||
// #docregion
|
||||
export abstract class RouteParams {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export function routeParamsFactory(i: any) {
|
||||
return i.get('$routeParams');
|
||||
}
|
||||
|
||||
export const routeParamsProvider = {
|
||||
provide: RouteParams,
|
||||
useFactory: routeParamsFactory,
|
||||
deps: ['$injector']
|
||||
};
|
@ -0,0 +1,30 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule, UrlHandlingStrategy, UrlTree } from '@angular/router';
|
||||
import { APP_BASE_HREF, HashLocationStrategy, LocationStrategy } from '@angular/common';
|
||||
|
||||
import { PhoneListComponent } from './phone-list/phone-list.component';
|
||||
|
||||
export class Ng1Ng2UrlHandlingStrategy implements UrlHandlingStrategy {
|
||||
shouldProcessUrl(url: UrlTree) {
|
||||
return url.toString() === '/' || url.toString() === '/phones';
|
||||
}
|
||||
extract(url: UrlTree) { return url; }
|
||||
merge(url: UrlTree, whole: UrlTree) { return url; }
|
||||
}
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'phones', pathMatch: 'full' },
|
||||
{ path: 'phones', component: PhoneListComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [ RouterModule.forRoot(routes) ],
|
||||
exports: [ RouterModule ],
|
||||
providers: [
|
||||
{ provide: APP_BASE_HREF, useValue: '!' },
|
||||
{ provide: LocationStrategy, useClass: HashLocationStrategy },
|
||||
{ provide: UrlHandlingStrategy, useClass: Ng1Ng2UrlHandlingStrategy }
|
||||
]
|
||||
})
|
||||
export class AppRoutingModule { }
|
@ -0,0 +1,67 @@
|
||||
/* Animate `ngRepeat` in `phoneList` component */
|
||||
.phone-list-item.ng-enter,
|
||||
.phone-list-item.ng-leave,
|
||||
.phone-list-item.ng-move {
|
||||
overflow: hidden;
|
||||
transition: 0.5s linear all;
|
||||
}
|
||||
|
||||
.phone-list-item.ng-enter,
|
||||
.phone-list-item.ng-leave.ng-leave-active,
|
||||
.phone-list-item.ng-move {
|
||||
height: 0;
|
||||
margin-bottom: 0;
|
||||
opacity: 0;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.phone-list-item.ng-enter.ng-enter-active,
|
||||
.phone-list-item.ng-leave,
|
||||
.phone-list-item.ng-move.ng-move-active {
|
||||
height: 120px;
|
||||
margin-bottom: 20px;
|
||||
opacity: 1;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
/* Animate view transitions with `ngView` */
|
||||
.view-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.view-frame {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.view-frame.ng-enter,
|
||||
.view-frame.ng-leave {
|
||||
background: white;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.view-frame.ng-enter {
|
||||
animation: 1s fade-in;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.view-frame.ng-leave {
|
||||
animation: 1s fade-out;
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
|
||||
/* Older browsers might need vendor-prefixes for keyframes and animation! */
|
@ -0,0 +1,43 @@
|
||||
'use strict';
|
||||
|
||||
angular.
|
||||
module('phonecatApp').
|
||||
animation('.phone', function phoneAnimationFactory() {
|
||||
return {
|
||||
addClass: animateIn,
|
||||
removeClass: animateOut
|
||||
};
|
||||
|
||||
function animateIn(element: JQuery, className: string, done: () => void) {
|
||||
if (className !== 'selected') { return; }
|
||||
|
||||
element.css({
|
||||
display: 'block',
|
||||
position: 'absolute',
|
||||
top: 500,
|
||||
left: 0
|
||||
}).animate({
|
||||
top: 0
|
||||
}, done);
|
||||
|
||||
return function animateInEnd(wasCanceled: boolean) {
|
||||
if (wasCanceled) { element.stop(); }
|
||||
};
|
||||
}
|
||||
|
||||
function animateOut(element: JQuery, className: string, done: () => void) {
|
||||
if (className !== 'selected') { return; }
|
||||
|
||||
element.css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0
|
||||
}).animate({
|
||||
top: -500
|
||||
}, done);
|
||||
|
||||
return function animateOutEnd(wasCanceled: boolean) {
|
||||
if (wasCanceled) { element.stop(); }
|
||||
};
|
||||
}
|
||||
});
|
@ -0,0 +1,13 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'phonecat-app',
|
||||
template: `
|
||||
<router-outlet></router-outlet>
|
||||
<div class="view-container">
|
||||
<div ng-view class="view-frame"></div>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class AppComponent { }
|
@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
angular.
|
||||
module('phonecatApp').
|
||||
config(['$locationProvider', '$routeProvider',
|
||||
function config($locationProvider: angular.ILocationProvider,
|
||||
$routeProvider: angular.route.IRouteProvider) {
|
||||
$locationProvider.hashPrefix('!');
|
||||
// #docregion ajs-routes
|
||||
$routeProvider
|
||||
.when('/phones/:phoneId', {
|
||||
template: '<phone-detail></phone-detail>'
|
||||
});
|
||||
// #enddocregion ajs-routes
|
||||
}
|
||||
]);
|
93
aio/content/examples/upgrade-phonecat-3-router/app/app.css
Normal file
@ -0,0 +1,93 @@
|
||||
body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-bottom: 1px solid gray;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* View: Phone list */
|
||||
.phones {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.phones li {
|
||||
clear: both;
|
||||
height: 115px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.thumb {
|
||||
float: left;
|
||||
height: 100px;
|
||||
margin: -0.5em 1em 1.5em 0;
|
||||
padding-bottom: 1em;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
/* View: Phone detail */
|
||||
.phone {
|
||||
background-color: white;
|
||||
display: none;
|
||||
float: left;
|
||||
height: 400px;
|
||||
margin-bottom: 2em;
|
||||
margin-right: 3em;
|
||||
padding: 2em;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.phone:first-child {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.phone-images {
|
||||
background-color: white;
|
||||
float: left;
|
||||
height: 450px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
.phone-thumbs {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.phone-thumbs img {
|
||||
height: 100px;
|
||||
padding: 1em;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.phone-thumbs li {
|
||||
background-color: white;
|
||||
border: 1px solid black;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.specs {
|
||||
clear: both;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.specs dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.specs > li {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.specs > li > span {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// #docregion
|
||||
'use strict';
|
||||
|
||||
// Define the `phonecatApp` Angular 1 module
|
||||
angular.module('phonecatApp', [
|
||||
'ngAnimate',
|
||||
'ngRoute',
|
||||
'core',
|
||||
'phoneDetail',
|
||||
'phoneList',
|
||||
]);
|
@ -0,0 +1,42 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { UpgradeModule } from '@angular/upgrade/static';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { Phone } from './core/phone/phone.service';
|
||||
import { CheckmarkPipe } from './core/checkmark/checkmark.pipe';
|
||||
import { PhoneListComponent } from './phone-list/phone-list.component';
|
||||
import { PhoneDetailComponent } from './phone-detail/phone-detail.component';
|
||||
import { routeParamsProvider } from './ajs-upgraded-providers';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
UpgradeModule,
|
||||
HttpModule,
|
||||
FormsModule,
|
||||
AppRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
PhoneListComponent,
|
||||
PhoneDetailComponent,
|
||||
CheckmarkPipe
|
||||
],
|
||||
entryComponents: [
|
||||
PhoneListComponent,
|
||||
PhoneDetailComponent
|
||||
],
|
||||
providers: [
|
||||
Phone,
|
||||
routeParamsProvider
|
||||
],
|
||||
// #docregion bootstrap
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
// #enddocregion bootstrap
|
@ -0,0 +1,11 @@
|
||||
// #docregion
|
||||
import { CheckmarkPipe } from './checkmark.pipe';
|
||||
|
||||
describe('CheckmarkPipe', function() {
|
||||
|
||||
it('should convert boolean values to unicode checkmark or cross', function () {
|
||||
const checkmarkPipe = new CheckmarkPipe();
|
||||
expect(checkmarkPipe.transform(true)).toBe('\u2713');
|
||||
expect(checkmarkPipe.transform(false)).toBe('\u2718');
|
||||
});
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
// #docregion
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({name: 'checkmark'})
|
||||
export class CheckmarkPipe implements PipeTransform {
|
||||
transform(input: boolean) {
|
||||
return input ? '\u2713' : '\u2718';
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
// Define the `core` module
|
||||
angular.module('core', ['core.phone']);
|
@ -0,0 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
// Define the `core.phone` module
|
||||
angular.module('core.phone', ['ngResource']);
|
@ -0,0 +1,51 @@
|
||||
// #docregion
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
import {
|
||||
Http,
|
||||
BaseRequestOptions,
|
||||
ResponseOptions,
|
||||
Response
|
||||
} from '@angular/http';
|
||||
import { MockBackend, MockConnection } from '@angular/http/testing';
|
||||
import { Phone, PhoneData } from './phone.service';
|
||||
|
||||
describe('Phone', function() {
|
||||
let phone: Phone;
|
||||
let phonesData: PhoneData[] = [
|
||||
{name: 'Phone X', snippet: '', images: []},
|
||||
{name: 'Phone Y', snippet: '', images: []},
|
||||
{name: 'Phone Z', snippet: '', images: []}
|
||||
];
|
||||
let mockBackend: MockBackend;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
Phone,
|
||||
MockBackend,
|
||||
BaseRequestOptions,
|
||||
{ provide: Http,
|
||||
useFactory: (backend: MockBackend, options: BaseRequestOptions) => new Http(backend, options),
|
||||
deps: [MockBackend, BaseRequestOptions]
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(inject([MockBackend, Phone], (_mockBackend_: MockBackend, _phone_: Phone) => {
|
||||
mockBackend = _mockBackend_;
|
||||
phone = _phone_;
|
||||
}));
|
||||
|
||||
it('should fetch the phones data from `/phones/phones.json`', (done: () => void) => {
|
||||
mockBackend.connections.subscribe((conn: MockConnection) => {
|
||||
conn.mockRespond(new Response(new ResponseOptions({body: JSON.stringify(phonesData)})));
|
||||
});
|
||||
phone.query().subscribe(result => {
|
||||
expect(result).toEqual(phonesData);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -0,0 +1,32 @@
|
||||
// #docregion
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Http, Response } from '@angular/http';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
declare var angular: angular.IAngularStatic;
|
||||
import { downgradeInjectable } from '@angular/upgrade/static';
|
||||
|
||||
import 'rxjs/add/operator/map';
|
||||
|
||||
export interface PhoneData {
|
||||
name: string;
|
||||
snippet: string;
|
||||
images: string[];
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class Phone {
|
||||
constructor(private http: Http) { }
|
||||
query(): Observable<PhoneData[]> {
|
||||
return this.http.get(`phones/phones.json`)
|
||||
.map((res: Response) => res.json());
|
||||
}
|
||||
get(id: string): Observable<PhoneData> {
|
||||
return this.http.get(`phones/${id}.json`)
|
||||
.map((res: Response) => res.json());
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('core.phone')
|
||||
.factory('phone', downgradeInjectable(Phone));
|
||||
|
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 28 KiB |
@ -0,0 +1,10 @@
|
||||
// #docregion
|
||||
import { platformBrowser } from '@angular/platform-browser';
|
||||
import { UpgradeModule } from '@angular/upgrade/static';
|
||||
|
||||
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
|
||||
|
||||
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory).then(platformRef => {
|
||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
||||
upgrade.bootstrap(document.documentElement, ['phonecatApp']);
|
||||
});
|
10
aio/content/examples/upgrade-phonecat-3-router/app/main.ts
Normal file
@ -0,0 +1,10 @@
|
||||
// #docregion
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { UpgradeModule } from '@angular/upgrade/static';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
|
||||
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
|
||||
upgrade.bootstrap(document.documentElement, ['phonecatApp']);
|
||||
});
|
@ -0,0 +1,59 @@
|
||||
// #docregion
|
||||
// #docregion activatedroute
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
// #enddocregion activatedroute
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PhoneDetailComponent } from './phone-detail.component';
|
||||
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||
import { CheckmarkPipe } from '../core/checkmark/checkmark.pipe';
|
||||
|
||||
function xyzPhoneData(): PhoneData {
|
||||
return {
|
||||
name: 'phone xyz',
|
||||
snippet: '',
|
||||
images: ['image/url1.png', 'image/url2.png']
|
||||
};
|
||||
}
|
||||
|
||||
class MockPhone {
|
||||
get(id: string): Observable<PhoneData> {
|
||||
return Observable.of(xyzPhoneData());
|
||||
}
|
||||
}
|
||||
|
||||
// #docregion activatedroute
|
||||
|
||||
class ActivatedRouteMock {
|
||||
constructor(public snapshot: any) {}
|
||||
}
|
||||
|
||||
// #enddocregion activatedroute
|
||||
|
||||
describe('PhoneDetailComponent', () => {
|
||||
|
||||
// #docregion activatedroute
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CheckmarkPipe, PhoneDetailComponent ],
|
||||
providers: [
|
||||
{ provide: Phone, useClass: MockPhone },
|
||||
{ provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) }
|
||||
]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
// #enddocregion activatedroute
|
||||
|
||||
it('should fetch phone detail', () => {
|
||||
const fixture = TestBed.createComponent(PhoneDetailComponent);
|
||||
fixture.detectChanges();
|
||||
let compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('h1').textContent).toContain(xyzPhoneData().name);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,33 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
declare var angular: angular.IAngularStatic;
|
||||
import { downgradeComponent } from '@angular/upgrade/static';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||
import { RouteParams } from '../ajs-upgraded-providers';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'phone-detail.template.html',
|
||||
})
|
||||
export class PhoneDetailComponent {
|
||||
phone: PhoneData;
|
||||
mainImageUrl: string;
|
||||
|
||||
constructor(routeParams: RouteParams, phone: Phone) {
|
||||
phone.get(routeParams['phoneId']).subscribe(phone => {
|
||||
this.phone = phone;
|
||||
this.setImage(phone.images[0]);
|
||||
});
|
||||
}
|
||||
|
||||
setImage(imageUrl: string) {
|
||||
this.mainImageUrl = imageUrl;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('phoneDetail')
|
||||
.directive(
|
||||
'phoneDetail',
|
||||
downgradeComponent({component: PhoneDetailComponent}) as angular.IDirectiveFactory
|
||||
);
|
@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
// Define the `phoneDetail` module
|
||||
angular.module('phoneDetail', [
|
||||
'ngRoute',
|
||||
'core.phone'
|
||||
]);
|
@ -0,0 +1,120 @@
|
||||
<!-- #docregion -->
|
||||
<div *ngIf="phone">
|
||||
<div class="phone-images">
|
||||
<img [src]="img" class="phone"
|
||||
[ngClass]="{selected: img === mainImageUrl}"
|
||||
*ngFor="let img of phone.images" />
|
||||
</div>
|
||||
|
||||
<h1>{{phone.name}}</h1>
|
||||
|
||||
<p>{{phone.description}}</p>
|
||||
|
||||
<ul class="phone-thumbs">
|
||||
<li *ngFor="let img of phone.images">
|
||||
<img [src]="img" (click)="setImage(img)" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="specs">
|
||||
<li>
|
||||
<span>Availability and Networks</span>
|
||||
<dl>
|
||||
<dt>Availability</dt>
|
||||
<dd *ngFor="let availability of phone.availability">{{availability}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Battery</span>
|
||||
<dl>
|
||||
<dt>Type</dt>
|
||||
<dd>{{phone.battery?.type}}</dd>
|
||||
<dt>Talk Time</dt>
|
||||
<dd>{{phone.battery?.talkTime}}</dd>
|
||||
<dt>Standby time (max)</dt>
|
||||
<dd>{{phone.battery?.standbyTime}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Storage and Memory</span>
|
||||
<dl>
|
||||
<dt>RAM</dt>
|
||||
<dd>{{phone.storage?.ram}}</dd>
|
||||
<dt>Internal Storage</dt>
|
||||
<dd>{{phone.storage?.flash}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Connectivity</span>
|
||||
<dl>
|
||||
<dt>Network Support</dt>
|
||||
<dd>{{phone.connectivity?.cell}}</dd>
|
||||
<dt>WiFi</dt>
|
||||
<dd>{{phone.connectivity?.wifi}}</dd>
|
||||
<dt>Bluetooth</dt>
|
||||
<dd>{{phone.connectivity?.bluetooth}}</dd>
|
||||
<dt>Infrared</dt>
|
||||
<dd>{{phone.connectivity?.infrared | checkmark}}</dd>
|
||||
<dt>GPS</dt>
|
||||
<dd>{{phone.connectivity?.gps | checkmark}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Android</span>
|
||||
<dl>
|
||||
<dt>OS Version</dt>
|
||||
<dd>{{phone.android?.os}}</dd>
|
||||
<dt>UI</dt>
|
||||
<dd>{{phone.android?.ui}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Size and Weight</span>
|
||||
<dl>
|
||||
<dt>Dimensions</dt>
|
||||
<dd *ngFor="let dim of phone.sizeAndWeight?.dimensions">{{dim}}</dd>
|
||||
<dt>Weight</dt>
|
||||
<dd>{{phone.sizeAndWeight?.weight}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Display</span>
|
||||
<dl>
|
||||
<dt>Screen size</dt>
|
||||
<dd>{{phone.display?.screenSize}}</dd>
|
||||
<dt>Screen resolution</dt>
|
||||
<dd>{{phone.display?.screenResolution}}</dd>
|
||||
<dt>Touch screen</dt>
|
||||
<dd>{{phone.display?.touchScreen | checkmark}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Hardware</span>
|
||||
<dl>
|
||||
<dt>CPU</dt>
|
||||
<dd>{{phone.hardware?.cpu}}</dd>
|
||||
<dt>USB</dt>
|
||||
<dd>{{phone.hardware?.usb}}</dd>
|
||||
<dt>Audio / headphone jack</dt>
|
||||
<dd>{{phone.hardware?.audioJack}}</dd>
|
||||
<dt>FM Radio</dt>
|
||||
<dd>{{phone.hardware?.fmRadio | checkmark}}</dd>
|
||||
<dt>Accelerometer</dt>
|
||||
<dd>{{phone.hardware?.accelerometer | checkmark}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Camera</span>
|
||||
<dl>
|
||||
<dt>Primary</dt>
|
||||
<dd>{{phone.camera?.primary}}</dd>
|
||||
<dt>Features</dt>
|
||||
<dd>{{phone.camera?.features?.join(', ')}}</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li>
|
||||
<span>Additional Features</span>
|
||||
<dd>{{phone.additionalFeatures}}</dd>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
@ -0,0 +1,66 @@
|
||||
/* tslint:disable */
|
||||
// #docregion
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { SpyLocation } from '@angular/common/testing';
|
||||
|
||||
import { PhoneListComponent } from './phone-list.component';
|
||||
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||
|
||||
class ActivatedRouteMock {
|
||||
constructor(public snapshot: any) {}
|
||||
}
|
||||
|
||||
class MockPhone {
|
||||
query(): Observable<PhoneData[]> {
|
||||
return Observable.of([
|
||||
{name: 'Nexus S', snippet: '', images: []},
|
||||
{name: 'Motorola DROID', snippet: '', images: []}
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
let fixture: ComponentFixture<PhoneListComponent>;
|
||||
|
||||
describe('PhoneList', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ PhoneListComponent ],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: new ActivatedRouteMock({ params: { 'phoneId': 1 } }) },
|
||||
{ provide: Location, useClass: SpyLocation },
|
||||
{ provide: Phone, useClass: MockPhone },
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PhoneListComponent);
|
||||
});
|
||||
|
||||
it('should create "phones" model with 2 phones fetched from xhr', () => {
|
||||
fixture.detectChanges();
|
||||
let compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelectorAll('.phone-list-item').length).toBe(2);
|
||||
expect(
|
||||
compiled.querySelector('.phone-list-item:nth-child(1)').textContent
|
||||
).toContain('Motorola DROID');
|
||||
expect(
|
||||
compiled.querySelector('.phone-list-item:nth-child(2)').textContent
|
||||
).toContain('Nexus S');
|
||||
});
|
||||
|
||||
xit('should set the default value of orderProp model', () => {
|
||||
fixture.detectChanges();
|
||||
let compiled = fixture.debugElement.nativeElement;
|
||||
expect(
|
||||
compiled.querySelector('select option:last-child').selected
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,60 @@
|
||||
// #docregion
|
||||
declare var angular: angular.IAngularStatic;
|
||||
import { downgradeComponent } from '@angular/upgrade/static';
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Phone, PhoneData } from '../core/phone/phone.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'phone-list.template.html'
|
||||
})
|
||||
export class PhoneListComponent {
|
||||
phones: PhoneData[];
|
||||
query: string;
|
||||
orderProp: string;
|
||||
|
||||
constructor(phone: Phone) {
|
||||
phone.query().subscribe(phones => {
|
||||
this.phones = phones;
|
||||
});
|
||||
this.orderProp = 'age';
|
||||
}
|
||||
|
||||
getPhones(): PhoneData[] {
|
||||
return this.sortPhones(this.filterPhones(this.phones));
|
||||
}
|
||||
|
||||
private filterPhones(phones: PhoneData[]) {
|
||||
if (phones && this.query) {
|
||||
return phones.filter(phone => {
|
||||
let name = phone.name.toLowerCase();
|
||||
let snippet = phone.snippet.toLowerCase();
|
||||
return name.indexOf(this.query) >= 0 || snippet.indexOf(this.query) >= 0;
|
||||
});
|
||||
}
|
||||
return phones;
|
||||
}
|
||||
|
||||
private sortPhones(phones: PhoneData[]) {
|
||||
if (phones && this.orderProp) {
|
||||
return phones
|
||||
.slice(0) // Make a copy
|
||||
.sort((a, b) => {
|
||||
if (a[this.orderProp] < b[this.orderProp]) {
|
||||
return -1;
|
||||
} else if ([b[this.orderProp] < a[this.orderProp]]) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('phoneList')
|
||||
.directive(
|
||||
'phoneList',
|
||||
downgradeComponent({component: PhoneListComponent}) as angular.IDirectiveFactory
|
||||
);
|
@ -0,0 +1,4 @@
|
||||
'use strict';
|
||||
|
||||
// Define the `phoneList` module
|
||||
angular.module('phoneList', ['core.phone']);
|
@ -0,0 +1,38 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<!--Sidebar content-->
|
||||
|
||||
<p>
|
||||
Search:
|
||||
<input [(ngModel)]="query" />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Sort by:
|
||||
<select [(ngModel)]="orderProp">
|
||||
<option value="name">Alphabetical</option>
|
||||
<option value="age">Newest</option>
|
||||
</select>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<!--Body content-->
|
||||
|
||||
<!-- #docregion list -->
|
||||
<ul class="phones">
|
||||
<li *ngFor="let phone of getPhones()"
|
||||
class="thumbnail phone-list-item">
|
||||
<a [routerLink]="['/phones', phone.id]" class="thumb">
|
||||
<img [src]="phone.imageUrl" [alt]="phone.name" />
|
||||
</a>
|
||||
<a [routerLink]="['/phones', phone.id]" class="name">{{phone.name}}</a>
|
||||
<p>{{phone.snippet}}</p>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- #enddocregion list -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,64 @@
|
||||
{
|
||||
"additionalFeatures": "Front Facing 1.3MP Camera",
|
||||
"android": {
|
||||
"os": "Android 2.2",
|
||||
"ui": "Dell Stage"
|
||||
},
|
||||
"availability": [
|
||||
"T-Mobile"
|
||||
],
|
||||
"battery": {
|
||||
"standbyTime": "",
|
||||
"talkTime": "",
|
||||
"type": "Lithium Ion (Li-Ion) (2780 mAH)"
|
||||
},
|
||||
"camera": {
|
||||
"features": [
|
||||
"Flash",
|
||||
"Video"
|
||||
],
|
||||
"primary": "5.0 megapixels"
|
||||
},
|
||||
"connectivity": {
|
||||
"bluetooth": "Bluetooth 2.1",
|
||||
"cell": "T-mobile HSPA+ @ 2100/1900/AWS/850 MHz",
|
||||
"gps": true,
|
||||
"infrared": false,
|
||||
"wifi": "802.11 b/g"
|
||||
},
|
||||
"description": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around. Android\u2122 2.2-based tablet with over-the-air upgrade capability for future OS releases. A vibrant 7-inch, multitouch display with full Adobe\u00ae Flash 10.1 pre-installed. Includes a 1.3 MP front-facing camera for face-to-face chats on popular services such as Qik or Skype. 16 GB of internal storage, plus Wi-Fi, Bluetooth and built-in GPS keeps you in touch with the world around you. Connect on your terms. Save with 2-year contract or flexibility with prepaid pay-as-you-go plans",
|
||||
"display": {
|
||||
"screenResolution": "WVGA (800 x 480)",
|
||||
"screenSize": "7.0 inches",
|
||||
"touchScreen": true
|
||||
},
|
||||
"hardware": {
|
||||
"accelerometer": true,
|
||||
"audioJack": "3.5mm",
|
||||
"cpu": "nVidia Tegra T20",
|
||||
"fmRadio": false,
|
||||
"physicalKeyboard": false,
|
||||
"usb": "USB 2.0"
|
||||
},
|
||||
"id": "dell-streak-7",
|
||||
"images": [
|
||||
"img/phones/dell-streak-7.0.jpg",
|
||||
"img/phones/dell-streak-7.1.jpg",
|
||||
"img/phones/dell-streak-7.2.jpg",
|
||||
"img/phones/dell-streak-7.3.jpg",
|
||||
"img/phones/dell-streak-7.4.jpg"
|
||||
],
|
||||
"name": "Dell Streak 7",
|
||||
"sizeAndWeight": {
|
||||
"dimensions": [
|
||||
"199.9 mm (w)",
|
||||
"119.8 mm (h)",
|
||||
"12.4 mm (d)"
|
||||
],
|
||||
"weight": "450.0 grams"
|
||||
},
|
||||
"storage": {
|
||||
"flash": "16000MB",
|
||||
"ram": "512MB"
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
{
|
||||
"additionalFeatures": "",
|
||||
"android": {
|
||||
"os": "Android 2.2",
|
||||
"ui": "MOTOBLUR"
|
||||
},
|
||||
"availability": [
|
||||
"AT&T"
|
||||
],
|
||||
"battery": {
|
||||
"standbyTime": "400 hours",
|
||||
"talkTime": "5 hours",
|
||||
"type": "Lithium Ion (Li-Ion) (1930 mAH)"
|
||||
},
|
||||
"camera": {
|
||||
"features": [
|
||||
""
|
||||
],
|
||||
"primary": ""
|
||||
},
|
||||
"connectivity": {
|
||||
"bluetooth": "Bluetooth 2.1",
|
||||
"cell": "WCDMA 850/1900/2100, GSM 850/900/1800/1900, HSDPA 14Mbps (Category 10) Edge Class 12, GPRS Class 12, eCompass, AGPS",
|
||||
"gps": true,
|
||||
"infrared": false,
|
||||
"wifi": "802.11 a/b/g/n"
|
||||
},
|
||||
"description": "MOTOROLA ATRIX 4G gives you dual-core processing power and the revolutionary webtop application. With webtop and a compatible Motorola docking station, sold separately, you can surf the Internet with a full Firefox browser, create and edit docs, or access multimedia on a large screen almost anywhere.",
|
||||
"display": {
|
||||
"screenResolution": "QHD (960 x 540)",
|
||||
"screenSize": "4.0 inches",
|
||||
"touchScreen": true
|
||||
},
|
||||
"hardware": {
|
||||
"accelerometer": true,
|
||||
"audioJack": "3.5mm",
|
||||
"cpu": "1 GHz Dual Core",
|
||||
"fmRadio": false,
|
||||
"physicalKeyboard": false,
|
||||
"usb": "USB 2.0"
|
||||
},
|
||||
"id": "motorola-atrix-4g",
|
||||
"images": [
|
||||
"img/phones/motorola-atrix-4g.0.jpg",
|
||||
"img/phones/motorola-atrix-4g.1.jpg",
|
||||
"img/phones/motorola-atrix-4g.2.jpg",
|
||||
"img/phones/motorola-atrix-4g.3.jpg"
|
||||
],
|
||||
"name": "MOTOROLA ATRIX\u2122 4G",
|
||||
"sizeAndWeight": {
|
||||
"dimensions": [
|
||||
"63.5 mm (w)",
|
||||
"117.75 mm (h)",
|
||||
"10.95 mm (d)"
|
||||
],
|
||||
"weight": "135.0 grams"
|
||||
},
|
||||
"storage": {
|
||||
"flash": "",
|
||||
"ram": ""
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
{
|
||||
"additionalFeatures": "Sensors: proximity, ambient light, barometer, gyroscope",
|
||||
"android": {
|
||||
"os": "Android 3.0",
|
||||
"ui": "Honeycomb"
|
||||
},
|
||||
"availability": [
|
||||
""
|
||||
],
|
||||
"battery": {
|
||||
"standbyTime": "336 hours",
|
||||
"talkTime": "24 hours",
|
||||
"type": "Other ( mAH)"
|
||||
},
|
||||
"camera": {
|
||||
"features": [
|
||||
"Flash",
|
||||
"Video"
|
||||
],
|
||||
"primary": "5.0 megapixels"
|
||||
},
|
||||
"connectivity": {
|
||||
"bluetooth": "Bluetooth 2.1",
|
||||
"cell": "",
|
||||
"gps": true,
|
||||
"infrared": false,
|
||||
"wifi": "802.11 b/g/n"
|
||||
},
|
||||
"description": "Motorola XOOM with Wi-Fi has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.",
|
||||
"display": {
|
||||
"screenResolution": "WXGA (1200 x 800)",
|
||||
"screenSize": "10.1 inches",
|
||||
"touchScreen": true
|
||||
},
|
||||
"hardware": {
|
||||
"accelerometer": true,
|
||||
"audioJack": "3.5mm",
|
||||
"cpu": "1 GHz Dual Core Tegra 2",
|
||||
"fmRadio": false,
|
||||
"physicalKeyboard": false,
|
||||
"usb": "USB 2.0"
|
||||
},
|
||||
"id": "motorola-xoom-with-wi-fi",
|
||||
"images": [
|
||||
"img/phones/motorola-xoom-with-wi-fi.0.jpg",
|
||||
"img/phones/motorola-xoom-with-wi-fi.1.jpg",
|
||||
"img/phones/motorola-xoom-with-wi-fi.2.jpg",
|
||||
"img/phones/motorola-xoom-with-wi-fi.3.jpg",
|
||||
"img/phones/motorola-xoom-with-wi-fi.4.jpg",
|
||||
"img/phones/motorola-xoom-with-wi-fi.5.jpg"
|
||||
],
|
||||
"name": "Motorola XOOM\u2122 with Wi-Fi",
|
||||
"sizeAndWeight": {
|
||||
"dimensions": [
|
||||
"249.1 mm (w)",
|
||||
"167.8 mm (h)",
|
||||
"12.9 mm (d)"
|
||||
],
|
||||
"weight": "708.0 grams"
|
||||
},
|
||||
"storage": {
|
||||
"flash": "32000MB",
|
||||
"ram": "1000MB"
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
{
|
||||
"additionalFeatures": "Front-facing camera. Sensors: proximity, ambient light, barometer, gyroscope.",
|
||||
"android": {
|
||||
"os": "Android 3.0",
|
||||
"ui": "Android"
|
||||
},
|
||||
"availability": [
|
||||
"Verizon"
|
||||
],
|
||||
"battery": {
|
||||
"standbyTime": "336 hours",
|
||||
"talkTime": "24 hours",
|
||||
"type": "Other (3250 mAH)"
|
||||
},
|
||||
"camera": {
|
||||
"features": [
|
||||
"Flash",
|
||||
"Video"
|
||||
],
|
||||
"primary": "5.0 megapixels"
|
||||
},
|
||||
"connectivity": {
|
||||
"bluetooth": "Bluetooth 2.1",
|
||||
"cell": "CDMA 800 /1900 LTE 700, Rx diversity in all bands",
|
||||
"gps": true,
|
||||
"infrared": false,
|
||||
"wifi": "802.11 a/b/g/n"
|
||||
},
|
||||
"description": "MOTOROLA XOOM has a super-powerful dual-core processor and Android\u2122 3.0 (Honeycomb) \u2014 the Android platform designed specifically for tablets. With its 10.1-inch HD widescreen display, you\u2019ll enjoy HD video in a thin, light, powerful and upgradeable tablet.",
|
||||
"display": {
|
||||
"screenResolution": "WXGA (1200 x 800)",
|
||||
"screenSize": "10.1 inches",
|
||||
"touchScreen": true
|
||||
},
|
||||
"hardware": {
|
||||
"accelerometer": true,
|
||||
"audioJack": "3.5mm",
|
||||
"cpu": "1 GHz Dual Core Tegra 2",
|
||||
"fmRadio": false,
|
||||
"physicalKeyboard": false,
|
||||
"usb": "USB 2.0"
|
||||
},
|
||||
"id": "motorola-xoom",
|
||||
"images": [
|
||||
"img/phones/motorola-xoom.0.jpg",
|
||||
"img/phones/motorola-xoom.1.jpg",
|
||||
"img/phones/motorola-xoom.2.jpg"
|
||||
],
|
||||
"name": "MOTOROLA XOOM\u2122",
|
||||
"sizeAndWeight": {
|
||||
"dimensions": [
|
||||
"249.0 mm (w)",
|
||||
"168.0 mm (h)",
|
||||
"12.7 mm (d)"
|
||||
],
|
||||
"weight": "726.0 grams"
|
||||
},
|
||||
"storage": {
|
||||
"flash": "32000MB",
|
||||
"ram": "1000MB"
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
{
|
||||
"additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope, Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)",
|
||||
"android": {
|
||||
"os": "Android 2.3",
|
||||
"ui": "Android"
|
||||
},
|
||||
"availability": [
|
||||
"M1,",
|
||||
"O2,",
|
||||
"Orange,",
|
||||
"Singtel,",
|
||||
"StarHub,",
|
||||
"T-Mobile,",
|
||||
"Vodafone"
|
||||
],
|
||||
"battery": {
|
||||
"standbyTime": "428 hours",
|
||||
"talkTime": "6 hours",
|
||||
"type": "Lithium Ion (Li-Ion) (1500 mAH)"
|
||||
},
|
||||
"camera": {
|
||||
"features": [
|
||||
"Flash",
|
||||
"Video"
|
||||
],
|
||||
"primary": "5.0 megapixels"
|
||||
},
|
||||
"connectivity": {
|
||||
"bluetooth": "Bluetooth 2.1",
|
||||
"cell": "Quad-band GSM: 850, 900, 1800, 1900\r\nTri-band HSPA: 900, 2100, 1700\r\nHSPA type: HSDPA (7.2Mbps) HSUPA (5.76Mbps)",
|
||||
"gps": true,
|
||||
"infrared": false,
|
||||
"wifi": "802.11 b/g/n"
|
||||
},
|
||||
"description": "Nexus S is the next generation of Nexus devices, co-developed by Google and Samsung. The latest Android platform (Gingerbread), paired with a 1 GHz Hummingbird processor and 16GB of memory, makes Nexus S one of the fastest phones on the market. It comes pre-installed with the best of Google apps and enabled with new and popular features like true multi-tasking, Wi-Fi hotspot, Internet Calling, NFC support, and full web browsing. With this device, users will also be the first to receive software upgrades and new Google mobile apps as soon as they become available. For more details, visit http://www.google.com/nexus.",
|
||||
"display": {
|
||||
"screenResolution": "WVGA (800 x 480)",
|
||||
"screenSize": "4.0 inches",
|
||||
"touchScreen": true
|
||||
},
|
||||
"hardware": {
|
||||
"accelerometer": true,
|
||||
"audioJack": "3.5mm",
|
||||
"cpu": "1GHz Cortex A8 (Hummingbird) processor",
|
||||
"fmRadio": false,
|
||||
"physicalKeyboard": false,
|
||||
"usb": "USB 2.0"
|
||||
},
|
||||
"id": "nexus-s",
|
||||
"images": [
|
||||
"img/phones/nexus-s.0.jpg",
|
||||
"img/phones/nexus-s.1.jpg",
|
||||
"img/phones/nexus-s.2.jpg",
|
||||
"img/phones/nexus-s.3.jpg"
|
||||
],
|
||||
"name": "Nexus S",
|
||||
"sizeAndWeight": {
|
||||
"dimensions": [
|
||||
"63.0 mm (w)",
|
||||
"123.9 mm (h)",
|
||||
"10.88 mm (d)"
|
||||
],
|
||||
"weight": "129.0 grams"
|
||||
},
|
||||
"storage": {
|
||||
"flash": "16384MB",
|
||||
"ram": "512MB"
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
[
|
||||
{
|
||||
"age": 0,
|
||||
"id": "motorola-xoom-with-wi-fi",
|
||||
"imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg",
|
||||
"name": "Motorola XOOM\u2122 with Wi-Fi",
|
||||
"snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)."
|
||||
},
|
||||
{
|
||||
"age": 1,
|
||||
"id": "motorola-xoom",
|
||||
"imageUrl": "img/phones/motorola-xoom.0.jpg",
|
||||
"name": "MOTOROLA XOOM\u2122",
|
||||
"snippet": "The Next, Next Generation\n\nExperience the future with MOTOROLA XOOM, the world's first tablet powered by Android 3.0 (Honeycomb)."
|
||||
},
|
||||
{
|
||||
"age": 2,
|
||||
"carrier": "AT&T",
|
||||
"id": "motorola-atrix-4g",
|
||||
"imageUrl": "img/phones/motorola-atrix-4g.0.jpg",
|
||||
"name": "MOTOROLA ATRIX\u2122 4G",
|
||||
"snippet": "MOTOROLA ATRIX 4G the world's most powerful smartphone."
|
||||
},
|
||||
{
|
||||
"age": 3,
|
||||
"id": "dell-streak-7",
|
||||
"imageUrl": "img/phones/dell-streak-7.0.jpg",
|
||||
"name": "Dell Streak 7",
|
||||
"snippet": "Introducing Dell\u2122 Streak 7. Share photos, videos and movies together. It\u2019s small enough to carry around, big enough to gather around."
|
||||
},
|
||||
{
|
||||
"age": 4,
|
||||
"carrier": "Cellular South",
|
||||
"id": "samsung-gem",
|
||||
"imageUrl": "img/phones/samsung-gem.0.jpg",
|
||||
"name": "Samsung Gem\u2122",
|
||||
"snippet": "The Samsung Gem\u2122 brings you everything that you would expect and more from a touch display smart phone \u2013 more apps, more features and a more affordable price."
|
||||
},
|
||||
{
|
||||
"age": 5,
|
||||
"carrier": "Dell",
|
||||
"id": "dell-venue",
|
||||
"imageUrl": "img/phones/dell-venue.0.jpg",
|
||||
"name": "Dell Venue",
|
||||
"snippet": "The Dell Venue; Your Personal Express Lane to Everything"
|
||||
},
|
||||
{
|
||||
"age": 6,
|
||||
"carrier": "Best Buy",
|
||||
"id": "nexus-s",
|
||||
"imageUrl": "img/phones/nexus-s.0.jpg",
|
||||
"name": "Nexus S",
|
||||
"snippet": "Fast just got faster with Nexus S. A pure Google experience, Nexus S is the first phone to run Gingerbread (Android 2.3), the fastest version of Android yet."
|
||||
},
|
||||
{
|
||||
"age": 7,
|
||||
"carrier": "Cellular South",
|
||||
"id": "lg-axis",
|
||||
"imageUrl": "img/phones/lg-axis.0.jpg",
|
||||
"name": "LG Axis",
|
||||
"snippet": "Android Powered, Google Maps Navigation, 5 Customizable Home Screens"
|
||||
},
|
||||
{
|
||||
"age": 8,
|
||||
"id": "samsung-galaxy-tab",
|
||||
"imageUrl": "img/phones/samsung-galaxy-tab.0.jpg",
|
||||
"name": "Samsung Galaxy Tab\u2122",
|
||||
"snippet": "Feel Free to Tab\u2122. The Samsung Galaxy Tab\u2122 brings you an ultra-mobile entertainment experience through its 7\u201d display, high-power processor and Adobe\u00ae Flash\u00ae Player compatibility."
|
||||
},
|
||||
{
|
||||
"age": 9,
|
||||
"carrier": "Cellular South",
|
||||
"id": "samsung-showcase-a-galaxy-s-phone",
|
||||
"imageUrl": "img/phones/samsung-showcase-a-galaxy-s-phone.0.jpg",
|
||||
"name": "Samsung Showcase\u2122 a Galaxy S\u2122 phone",
|
||||
"snippet": "The Samsung Showcase\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance, even outdoors"
|
||||
},
|
||||
{
|
||||
"age": 10,
|
||||
"carrier": "Verizon",
|
||||
"id": "droid-2-global-by-motorola",
|
||||
"imageUrl": "img/phones/droid-2-global-by-motorola.0.jpg",
|
||||
"name": "DROID\u2122 2 Global by Motorola",
|
||||
"snippet": "The first smartphone with a 1.2 GHz processor and global capabilities."
|
||||
},
|
||||
{
|
||||
"age": 11,
|
||||
"carrier": "Verizon",
|
||||
"id": "droid-pro-by-motorola",
|
||||
"imageUrl": "img/phones/droid-pro-by-motorola.0.jpg",
|
||||
"name": "DROID\u2122 Pro by Motorola",
|
||||
"snippet": "The next generation of DOES."
|
||||
},
|
||||
{
|
||||
"age": 12,
|
||||
"carrier": "AT&T",
|
||||
"id": "motorola-bravo-with-motoblur",
|
||||
"imageUrl": "img/phones/motorola-bravo-with-motoblur.0.jpg",
|
||||
"name": "MOTOROLA BRAVO\u2122 with MOTOBLUR\u2122",
|
||||
"snippet": "An experience to cheer about."
|
||||
},
|
||||
{
|
||||
"age": 13,
|
||||
"carrier": "T-Mobile",
|
||||
"id": "motorola-defy-with-motoblur",
|
||||
"imageUrl": "img/phones/motorola-defy-with-motoblur.0.jpg",
|
||||
"name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
|
||||
"snippet": "Are you ready for everything life throws your way?"
|
||||
},
|
||||
{
|
||||
"age": 14,
|
||||
"carrier": "T-Mobile",
|
||||
"id": "t-mobile-mytouch-4g",
|
||||
"imageUrl": "img/phones/t-mobile-mytouch-4g.0.jpg",
|
||||
"name": "T-Mobile myTouch 4G",
|
||||
"snippet": "The T-Mobile myTouch 4G is a premium smartphone designed to deliver blazing fast 4G speeds so that you can video chat from practically anywhere, with or without Wi-Fi."
|
||||
},
|
||||
{
|
||||
"age": 15,
|
||||
"carrier": "US Cellular",
|
||||
"id": "samsung-mesmerize-a-galaxy-s-phone",
|
||||
"imageUrl": "img/phones/samsung-mesmerize-a-galaxy-s-phone.0.jpg",
|
||||
"name": "Samsung Mesmerize\u2122 a Galaxy S\u2122 phone",
|
||||
"snippet": "The Samsung Mesmerize\u2122 delivers a cinema quality experience like you\u2019ve never seen before. Its innovative 4\u201d touch display technology provides rich picture brilliance,even outdoors"
|
||||
},
|
||||
{
|
||||
"age": 16,
|
||||
"carrier": "Sprint",
|
||||
"id": "sanyo-zio",
|
||||
"imageUrl": "img/phones/sanyo-zio.0.jpg",
|
||||
"name": "SANYO ZIO",
|
||||
"snippet": "The Sanyo Zio by Kyocera is an Android smartphone with a combination of ultra-sleek styling, strong performance and unprecedented value."
|
||||
},
|
||||
{
|
||||
"age": 17,
|
||||
"id": "samsung-transform",
|
||||
"imageUrl": "img/phones/samsung-transform.0.jpg",
|
||||
"name": "Samsung Transform\u2122",
|
||||
"snippet": "The Samsung Transform\u2122 brings you a fun way to customize your Android powered touch screen phone to just the way you like it through your favorite themed \u201cSprint ID Service Pack\u201d."
|
||||
},
|
||||
{
|
||||
"age": 18,
|
||||
"id": "t-mobile-g2",
|
||||
"imageUrl": "img/phones/t-mobile-g2.0.jpg",
|
||||
"name": "T-Mobile G2",
|
||||
"snippet": "The T-Mobile G2 with Google is the first smartphone built for 4G speeds on T-Mobile's new network. Get the information you need, faster than you ever thought possible."
|
||||
},
|
||||
{
|
||||
"age": 19,
|
||||
"id": "motorola-charm-with-motoblur",
|
||||
"imageUrl": "img/phones/motorola-charm-with-motoblur.0.jpg",
|
||||
"name": "Motorola CHARM\u2122 with MOTOBLUR\u2122",
|
||||
"snippet": "Motorola CHARM fits easily in your pocket or palm. Includes MOTOBLUR service."
|
||||
}
|
||||
]
|