chore: rename modules/examples to modules/playground

The directory contains code authored in a style that makes it transpilable to dart. As such, these are not idiomatic examples of Angular 2 usage.

The main purpose of this directory is to enable experimentation with Angular within the angular/angular repository.

Closes #4342

Closes #4639
This commit is contained in:
kutyel
2015-10-10 00:25:17 +02:00
committed by Flavio Corpa Ríos
parent c3ab20cc87
commit e4e74ae65c
248 changed files with 190 additions and 190 deletions

View File

@ -0,0 +1,14 @@
import {Component, View, NgIf} from 'angular2/angular2';
@Component({selector: 'animate-app'})
@View({
directives: [NgIf],
template: `
<h1>The box is {{visible ? 'visible' : 'hidden'}}</h1>
<div class="ng-animate box" *ng-if="visible"></div>
<button (click)="visible = !visible">Animate</button>
`
})
export class AnimateApp {
visible: boolean = false;
}

View File

@ -0,0 +1,25 @@
body {
padding: 20px;
}
.box {
width: 100px;
height: 100px;
background-color: red;
transition: all 0.35s ease-in-out;
}
.box.blue {
background-color: blue;
}
.box.ng-enter {
opacity: 0;
height: 0;
}
.box.ng-enter-active {
opacity: 1;
height: 100px;
}
.box.ng-leave-active {
opacity: 0;
height: 0;
}

View File

@ -0,0 +1,10 @@
<!doctype html>
<html>
<title>Animation Example</title>
<link rel="stylesheet" type="text/css" href="./css/app.css" />
<base href="/playground/src/animate/">
<body>
<animate-app>Loading...</animate-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,6 @@
import {AnimateApp} from './animate-app';
import {bootstrap} from 'angular2/bootstrap';
export function main() {
bootstrap(AnimateApp);
}

View File

@ -0,0 +1,14 @@
<!doctype html>
<html>
<head>
<title>Async</title>
</head>
<body>
<async-app>
Loading...
</async-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,96 @@
import {bootstrap} from 'angular2/bootstrap';
import {NgIf, Component, View} from 'angular2/core';
import {TimerWrapper} from 'angular2/src/core/facade/async';
@Component({selector: 'async-app'})
@View({
template: `
<div id='increment'>
<span class='val'>{{val1}}</span>
<button class='action' (click)="increment()">Increment</button>
</div>
<div id='delayedIncrement'>
<span class='val'>{{val2}}</span>
<button class='action' (click)="delayedIncrement()">Delayed Increment</button>
<button class='cancel' *ng-if="timeoutId != null" (click)="cancelDelayedIncrement()">Cancel</button>
</div>
<div id='multiDelayedIncrements'>
<span class='val'>{{val3}}</span>
<button class='action' (click)="multiDelayedIncrements(10)">10 Delayed Increments</button>
<button class='cancel' *ng-if="multiTimeoutId != null" (click)="cancelMultiDelayedIncrements()">Cancel</button>
</div>
<div id='periodicIncrement'>
<span class='val'>{{val4}}</span>
<button class='action' (click)="periodicIncrement()">Periodic Increment</button>
<button class='cancel' *ng-if="intervalId != null" (click)="cancelPeriodicIncrement()">Cancel</button>
</div>
`,
directives: [NgIf]
})
class AsyncApplication {
val1: number = 0;
val2: number = 0;
val3: number = 0;
val4: number = 0;
timeoutId = null;
multiTimeoutId = null;
intervalId = null;
increment(): void { this.val1++; };
delayedIncrement(): void {
this.cancelDelayedIncrement();
this.timeoutId = TimerWrapper.setTimeout(() => {
this.val2++;
this.timeoutId = null;
}, 2000);
};
multiDelayedIncrements(i: number): void {
this.cancelMultiDelayedIncrements();
var self = this;
function helper(_i) {
if (_i <= 0) {
self.multiTimeoutId = null;
return;
}
self.multiTimeoutId = TimerWrapper.setTimeout(() => {
self.val3++;
helper(_i - 1);
}, 500);
}
helper(i);
};
periodicIncrement(): void {
this.cancelPeriodicIncrement();
this.intervalId = TimerWrapper.setInterval(() => { this.val4++; }, 2000)
};
cancelDelayedIncrement(): void {
if (this.timeoutId != null) {
TimerWrapper.clearTimeout(this.timeoutId);
this.timeoutId = null;
}
};
cancelMultiDelayedIncrements(): void {
if (this.multiTimeoutId != null) {
TimerWrapper.clearTimeout(this.multiTimeoutId);
this.multiTimeoutId = null;
}
};
cancelPeriodicIncrement(): void {
if (this.intervalId != null) {
TimerWrapper.clearInterval(this.intervalId);
this.intervalId = null;
}
};
}
export function main() {
bootstrap(AsyncApplication);
}

View File

@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<title>Benchpress test</title>
</head>
<body>
<button onclick="pleaseLog()">Click me</button>
<div id="log"></div>
<script type="text/javascript">
function pleaseLog() {
document.getElementById("log").innerHTML = "hi";
}
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
import {bootstrap} from 'angular2/bootstrap';
import {Component, View} from 'angular2/core';
@Component({selector: 'gestures-app'})
@View({templateUrl: 'template.html'})
class GesturesCmp {
swipeDirection: string = '-';
pinchScale: number = 1;
rotateAngle: number = 0;
onSwipe(event): void { this.swipeDirection = event.deltaX > 0 ? 'right' : 'left'; }
onPinch(event): void { this.pinchScale = event.scale; }
onRotate(event): void { this.rotateAngle = event.rotation; }
}
export function main() {
bootstrap(GesturesCmp);
}

View File

@ -0,0 +1,15 @@
<style type="text/css">
.row {
height: 33%;
text-align: center;
border-bottom: 1px solid black;
margin: 0;
padding: 0;
-webkit-user-select: none;
}
</style>
<div class="row" (swipe)="onSwipe($event)">Swipe (direction = {{swipeDirection}})</div>
<div class="row" (pinch)="onPinch($event)">pinch (scale = {{pinchScale}})</div>
<div class="row" (rotate)="onRotate($event)">Rotate (angle = {{rotateAngle}})</div>
<div class="row"></div>

View File

@ -0,0 +1,11 @@
<!doctype html>
<html>
<title>Hello Angular 2.0</title>
<body>
<hello-app>
Loading...
</hello-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,62 @@
import {bootstrap} from 'angular2/bootstrap';
import {ElementRef, Component, Directive, Injectable} from 'angular2/core';
import {Renderer} from 'angular2/render';
export function main() {
// Bootstrapping only requires specifying a root component.
// The boundary between the Angular application and the rest of the page is
// the shadowDom of this root component.
// The selector of the component passed in is used to find where to insert the
// application.
// You can use the light dom of the <hello-app> tag as temporary content (for
// example 'Loading...') before the application is ready.
bootstrap(HelloCmp);
}
// A service available to the Injector, used by the HelloCmp component.
@Injectable()
class GreetingService {
greeting: string = 'hello';
}
// Directives are light-weight. They don't allow new
// expression contexts (use @Component for those needs).
@Directive({selector: '[red]'})
class RedDec {
// ElementRef is always injectable and it wraps the element on which the
// directive was found by the compiler.
constructor(el: ElementRef, renderer: Renderer) { renderer.setElementStyle(el, 'color', 'red'); }
}
// Angular 2.0 supports 2 basic types of directives:
// - Component - the basic building blocks of Angular 2.0 apps. Backed by
// ShadowDom.(http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
// - Directive - add behavior to existing elements.
// @Component is AtScript syntax to annotate the HelloCmp class as an Angular
// 2.0 component.
@Component({
// The Selector prop tells Angular on which elements to instantiate this
// class. The syntax supported is a basic subset of CSS selectors, for example
// 'element', '[attr]', [attr=foo]', etc.
selector: 'hello-app',
// These are services that would be created if a class in the component's
// template tries to inject them.
viewProviders: [GreetingService],
// Expressions in the template (like {{greeting}}) are evaluated in the
// context of the HelloCmp class below.
template: `<div class="greeting">{{greeting}} <span red>world</span>!</div>
<button class="changeButton" (click)="changeGreeting()">change greeting</button>`,
// All directives used in the template need to be specified. This allows for
// modularity (RedDec can only be used in this template)
// and better tooling (the template can be invalidated if the attribute is
// misspelled).
directives: [RedDec]
})
export class HelloCmp {
greeting: string;
constructor(service: GreetingService) { this.greeting = service.greeting; }
changeGreeting(): void { this.greeting = 'howdy'; }
}

View File

@ -0,0 +1,21 @@
import {Component, View, NgFor} from 'angular2/angular2';
import {Http} from 'angular2/http';
@Component({selector: 'http-app'})
@View({
directives: [NgFor],
template: `
<h1>people</h1>
<ul class="people">
<li *ng-for="#person of people">
hello, {{person['name']}}
</li>
</ul>
`
})
export class HttpCmp {
people: Object;
constructor(http: Http) {
http.get('./people.json').map(res => res.json()).subscribe(res => this.people = res);
}
}

View File

@ -0,0 +1,11 @@
<!doctype html>
<html>
<title>Hello Http</title>
<body>
<http-app>
Loading...
</http-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,7 @@
import {bootstrap} from 'angular2/bootstrap';
import {HTTP_PROVIDERS} from 'angular2/http';
import {HttpCmp} from './http_comp';
export function main() {
bootstrap(HttpCmp, [HTTP_PROVIDERS]);
}

View File

@ -0,0 +1 @@
[{"name":"Jeff"}]

View File

@ -0,0 +1,11 @@
<!doctype html>
<html>
<title>Hello Jsonp</title>
<body>
<jsonp-app>
Loading...
</jsonp-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,7 @@
import {bootstrap} from 'angular2/bootstrap';
import {JSONP_PROVIDERS} from 'angular2/http';
import {JsonpCmp} from './jsonp_comp';
export function main() {
bootstrap(JsonpCmp, [JSONP_PROVIDERS]);
}

View File

@ -0,0 +1,22 @@
import {Component, View, NgFor} from 'angular2/angular2';
import {Jsonp, Response} from 'angular2/http';
import {ObservableWrapper} from 'angular2/src/core/facade/async';
@Component({selector: 'jsonp-app'})
@View({
directives: [NgFor],
template: `
<h1>people</h1>
<ul class="people">
<li *ng-for="#person of people">
hello, {{person['name']}}
</li>
</ul>
`
})
export class JsonpCmp {
people: Object;
constructor(jsonp: Jsonp) {
jsonp.get('./people.json?callback=JSONP_CALLBACK').subscribe(res => this.people = res.json());
}
}

View File

@ -0,0 +1,2 @@
// This can only be requested once due to constant method name :(
__ng_jsonp__.__req0.finished([{"name":"caitp"}])

View File

@ -0,0 +1,26 @@
<!doctype html>
<html>
<title>Key events</title>
<style>
.sample-area {
text-align: center;
margin: 5px;
height: 50px;
line-height: 50px;
border-radius: 5px;
border: 1px solid #d0d0d0;
}
.sample-area:focus {
border: 1px solid blue;
color: blue;
font-weight: bold;
}
</style>
<body>
<key-events-app>
Loading...
</key-events-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,36 @@
import {bootstrap} from 'angular2/bootstrap';
import {Component, View} from 'angular2/core';
import {KeyEventsPlugin} from 'angular2/src/core/render/dom/events/key_events';
@Component({selector: 'key-events-app'})
@View({
template: `Click in the following area and press a key to display its name:<br>
<div (keydown)="onKeyDown($event)" class="sample-area" tabindex="0">{{lastKey}}</div><br>
Click in the following area and press shift.enter:<br>
<div
(keydown.shift.enter)="onShiftEnter($event)"
(click)="resetShiftEnter()"
class="sample-area"
tabindex="0"
>{{shiftEnter ? 'You pressed shift.enter!' : ''}}</div>`
})
class KeyEventsApp {
lastKey: string = '(none)';
shiftEnter: boolean = false;
onKeyDown(event): void {
this.lastKey = KeyEventsPlugin.getEventFullKey(event);
event.preventDefault();
}
onShiftEnter(event): void {
this.shiftEnter = true;
event.preventDefault();
}
resetShiftEnter(): void { this.shiftEnter = false; }
}
export function main() {
bootstrap(KeyEventsApp);
}

View File

@ -0,0 +1,12 @@
Language: JavaScript
BasedOnStyle: Google
ColumnLimit: 100
TabWidth: 2
ContinuationIndentWidth: 4
MaxEmptyLinesToKeep : 2
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty

View File

@ -0,0 +1,88 @@
<style>
section {
background: #f7f7f7;
border-radius: 3px;
text-align: center;
margin: 1em;
position: relative !important;
padding-bottom: 10px;
}
.label {
position: absolute;
bottom: 5px;
left: 7px;
color: #ccc;
font-size: 14px;
}
.custom {
background-color: #ae0001;
color: #eeba30;
}
.custom:hover, .custom.md-button-focus {
background-color: #740001;
color: #d3a625;
}
</style>
<h1>Button demo</h1>
<p>
You just clicked: <span>{{previousClick}}</span>
</p>
<section>
<form (submit)="submit('form submit')">
<button md-button>SUBMIT</button>
<button>Native button</button>
</form>
<span class="label">form submit</span>
</section>
<section>
<span class="label">Regular button</span>
<button md-button (click)="click('button')">BUTTON</button>
<button md-button class="md-primary" (click)="click('primary')">PRIMARY</button>
<button md-button disabled="disabled" (click)="click('disabled')">DISABLED</button>
<button md-button class="md-accent" (click)="click('accent')">ACCENT</button>
<button md-button class="md-warn" (click)="click('warn')">WARN</button>
<button md-button class="custom" (click)="click('custom')">CUSTOM</button>
</section>
<section>
<span class="label">Raised button</span>
<button md-raised-button (click)="click('raised')">BUTTON</button>
<button md-raised-button class="md-primary" (click)="click('raised primary')">PRIMARY</button>
<button md-raised-button disabled="disabled" (click)="click('raised disabled')">DISABLED</button>
<button md-raised-button class="md-accent" (click)="click('raised accent')">ACCENT</button>
<button md-raised-button class="md-warn" (click)="click('raised warn')">WARN</button>
<button md-raised-button class="custom" (click)="click('custom raised')">CUSTOM</button>
</section>
<section>
<span class="label">Fab button</span>
<button md-fab (click)="click('fab')">BTN</button>
<button md-fab class="md-primary" (click)="click('fab primary')">PRMY</button>
<button md-fab disabled="disabled" (click)="click('fab disabled')">DIS</button>
<button md-fab class="md-accent" (click)="click('fab accent')">ACC</button>
<button md-fab class="md-warn" (click)="click('fab warn')">WRN</button>
<button md-fab class="custom" (click)="click('custom fab')">CSTM</button>
</section>
<section>
<span class="label">Anchor / hyperlink</span>
<a md-button href="http://google.com" target="_blank">HREF</a>
<a md-button href="http://google.com" disabled>DISABLED HREF</a>
<a md-raised-button target="_blank" href="http://google.com">RAISED HREF</a>
</section>
<section dir="rtl">
<span class="label" dir="ltr">Right-to-left</span>
<button md-button (click)="click('Hebrew button')">לחצן</button>
<button md-raised-button (click)="click('Hebrew raised button')">העלה</button>
<a md-button href="http://translate.google.com">עוגן</a>
</section>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material button demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto, 'Helvetica Neue', sans-serif; } </style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,44 @@
import {bootstrap} from 'angular2/bootstrap';
import {bind, provide, Component, NgFor, UrlResolver, View, ViewEncapsulation} from 'angular2/core';
import {MdButton, MdAnchor} from 'angular2_material/src/components/button/button';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({
selector: 'demo-app',
})
@View({
templateUrl: './demo_app.html',
directives: [MdButton, MdAnchor, NgFor],
encapsulation: ViewEncapsulation.None
})
class DemoApp {
previousClick: string;
action: string;
clickCount: number;
items: number[];
constructor() {
this.previousClick = 'Nothing';
this.action = "ACTIVATE";
this.clickCount = 0;
this.items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
}
click(msg: string) {
this.previousClick = msg;
}
submit(msg: string, event) {
event.preventDefault();
this.previousClick = msg;
}
increment() {
this.clickCount++;
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,9 @@
<div md-theme="default">
<h2>Checkbox demo</h2>
<md-checkbox (click)="increment()">Normal checkbox</md-checkbox>
<md-checkbox class="md-primary" (click)="increment()">Primary checkbox</md-checkbox>
<md-checkbox disabled (click)="increment()">Disabled checkbox</md-checkbox>
<p>Toggle count: {{toggleCount}}</p>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material checkbox demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; } </style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,38 @@
import {bootstrap} from 'angular2/bootstrap';
import {
bind,
provide,
Component,
Directive,
UrlResolver,
View,
ViewEncapsulation
} from 'angular2/core';
import {MdCheckbox} from 'angular2_material/src/components/checkbox/checkbox';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({
selector: 'demo-app',
})
@View({
templateUrl: './demo_app.html',
directives: [MdCheckbox],
encapsulation: ViewEncapsulation.None
})
class DemoApp {
toggleCount: number;
constructor() {
this.toggleCount = 0;
}
increment() {
this.toggleCount++;
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,23 @@
library angular2_examples.material.demo_common;
import 'package:angular2/src/core/dom/browser_adapter.dart';
import 'package:angular2/src/core/compiler/url_resolver.dart';
void commonDemoSetup() {
BrowserDomAdapter.makeCurrent();
}
class DemoUrlResolver extends UrlResolver {
@override
String resolve(String baseUrl, String url) {
const MATERIAL_PKG = 'package:angular2_material/';
// We run a proxy server in front of pub serve that prepends "example" to
// paths
if (url.startsWith(MATERIAL_PKG)) {
return '/examples/packages/angular2_material/' +
url.substring(MATERIAL_PKG.length);
}
return super.resolve(baseUrl, url);
}
}

View File

@ -0,0 +1,27 @@
import {print} from 'angular2/src/core/facade/lang';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {isPresent, isBlank, RegExpWrapper, StringWrapper} from 'angular2/src/core/facade/lang';
import {DOM} from 'angular2/src/core/dom/dom_adapter';
import {Injectable} from 'angular2/core';
import {BrowserDomAdapter} from 'angular2/src/core/dom/browser_adapter';
export function commonDemoSetup(): void {
BrowserDomAdapter.makeCurrent();
}
@Injectable()
export class DemoUrlResolver extends UrlResolver {
constructor() {
super();
}
resolve(baseUrl: string, url: string): string {
// The standard UrlResolver looks for "package:" templateUrls in
// node_modules, however in our repo we host material widgets at the root.
if (url.startsWith('package:angular2_material/')) {
return '/' + url.substring(8);
}
return super.resolve(baseUrl, url);
}
}

View File

@ -0,0 +1,32 @@
<div>
<h2>Dialog demo</h2>
<button id="open" type="button" (click)="open()" [disabled]="!!dialogRef">
Open a dialog
</button>
<button type="button" (click)="close()" [disabled]="!dialogRef">
Close the dialog
</button>
<p>
Last result: {{lastResult}}
</p>
<hr>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
<p> Here are some paragaphs to make the page scrollable</p>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material dialog demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; } </style>
</head>
<body class="dialog-demo">
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,106 @@
import {bootstrap} from 'angular2/bootstrap';
import {
bind,
provide,
ElementRef,
ComponentRef,
Component,
UrlResolver,
View,
ViewEncapsulation
} from 'angular2/core';
import {
MdDialog,
MdDialogRef,
MdDialogConfig
} from 'angular2_material/src/components/dialog/dialog';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
import {isPresent} from 'angular2/src/core/facade/lang';
@Component({
selector: 'demo-app',
viewProviders: [MdDialog],
})
@View({
templateUrl: './demo_app.html',
directives: [],
encapsulation: ViewEncapsulation.None,
})
class DemoApp {
dialog: MdDialog;
elementRef: ElementRef;
dialogRef: MdDialogRef;
dialogConfig: MdDialogConfig;
lastResult: string;
constructor(mdDialog: MdDialog, elementRef: ElementRef) {
this.dialog = mdDialog;
this.elementRef = elementRef;
this.dialogConfig = new MdDialogConfig();
this.dialogConfig.width = '60%';
this.dialogConfig.height = '60%';
this.lastResult = '';
}
open() {
if (isPresent(this.dialogRef)) {
return;
}
this.dialog.open(SimpleDialogComponent, this.elementRef, this.dialogConfig)
.then(ref => {
this.dialogRef = ref;
ref.instance.numCoconuts = 777;
ref.whenClosed.then(result => {
this.dialogRef = null;
this.lastResult = result;
});
});
}
close() {
this.dialogRef.close();
}
}
@Component({
selector: 'simple-dialog',
inputs: ['numCoconuts'],
})
@View({
encapsulation: ViewEncapsulation.None,
template: `
<h2>This is the dialog content</h2>
<p>There are {{numCoconuts}} coconuts.</p>
<p>Return: <input (input)="updateValue($event)"></p>
<button type="button" (click)="done()">Done</button>
`
})
class SimpleDialogComponent {
numCoconuts: number;
dialogRef: MdDialogRef;
toReturn: string;
constructor(dialogRef: MdDialogRef) {
this.numCoconuts = 0;
this.dialogRef = dialogRef;
this.toReturn = '';
}
updateValue(event) {
this.toReturn = event.target.value;
}
done() {
this.dialogRef.close(this.toReturn);
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,41 @@
<style>
md-grid-tile {
background-color: lightblue;
}
md-grid-list {
min-height: 400px;
}
</style>
<div>
<h2>grid-list demo</h2>
<md-grid-list cols="4" row-height="50px" gutter-size="2em" id="complex">
<md-grid-tile rowspan="1" colspan="2"> Tile #1 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #2 </md-grid-tile>
<md-grid-tile rowspan="3" colspan="1"> Tile #3 </md-grid-tile>
<md-grid-tile rowspan="2" colspan="2"> Tile #4 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="3"> Tile #5 </md-grid-tile>
</md-grid-list>
<hr>
<md-grid-list cols="4" row-height="50px" gutter-size="2em" id="simple">
<md-grid-tile rowspan="1" colspan="1"> Tile #1 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #2 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #3 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #4 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #5 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #6 </md-grid-tile>
<md-grid-tile rowspan="1" colspan="1"> Tile #7 </md-grid-tile>
</md-grid-list>
</div>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material grid-list demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; } </style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,28 @@
import {bootstrap} from 'angular2/bootstrap';
import {bind, provide, Component, UrlResolver, View, ViewEncapsulation} from 'angular2/core';
import {MdGridList, MdGridTile} from 'angular2_material/src/components/grid_list/grid_list';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({
selector: 'demo-app',
})
@View({
templateUrl: './demo_app.html',
directives: [MdGridList, MdGridTile],
encapsulation: ViewEncapsulation.None,
})
class DemoApp {
tile3RowSpan: number;
tile3ColSpan: number;
constructor() {
this.tile3RowSpan = 3;
this.tile3ColSpan = 3;
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,43 @@
<style>@import "package:angular2_material/src/components/input/input.css";</style>
<style>
body {
max-width: 500px;
}
</style>
<div>
<h2>input demo</h2>
<h3>Normal input</h3>
<md-input-container>
<label>Name</label>
<input md-input>
</md-input-container>
<h3>Pre-filled value</h3>
<md-input-container>
<label>Favorite Framework</label>
<input value="Angular">
</md-input-container>
<h3>Disabled input</h3>
<md-input-container>
<label>ID Number</label>
<input disabled>
</md-input-container>
<h3>Disabled, pre-filled input</h3>
<md-input-container>
<label>Best TV show</label>
<input disabled value="Firefly">
</md-input-container>
<!--<h3>textarea</h3>
<md-input-container>
<label>What I did on my summer vaccation</label>
<textarea></textarea>
</md-input-container>-->
</div>

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material input demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; }
</style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,19 @@
import {bootstrap} from 'angular2/bootstrap';
import {bind, provide, Component, UrlResolver, View, ViewEncapsulation} from 'angular2/core';
import {MdInputContainer, MdInput} from 'angular2_material/src/components/input/input';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({selector: 'demo-app'})
@View({
templateUrl: './demo_app.html',
directives: [MdInputContainer, MdInput],
encapsulation: ViewEncapsulation.None
})
class DemoApp {
constructor() {}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,40 @@
<div style="width: 500px;">
<h2>Progress-linear demo</h2>
<p>
Determinate: primary
<md-progress-linear mode="determinate" [value]="progress" class="md-accent">
</md-progress-linear>
</p>
<p>
Determinate: accent
<md-progress-linear mode="determinate" [value]="progress" class="md-primary">
</md-progress-linear>
</p>
<p>
Buffer
<md-progress-linear mode="buffer"
[value]="progress" [buffer-value]="progress + (200 / progress)" class="md-warn">
</md-progress-linear>
</p>
<p>
Indeterminate
<md-progress-linear mode="indeterminate" class="md-primary">
</md-progress-linear>
</p>
<p>
Query
<md-progress-linear mode="query" class="md-accent">
</md-progress-linear>
</p>
<!--<md-progress-linear></md-progress-linear>-->
<p>Progress: {{progress}}</p>
<button type="button" (click)="step(10)" id="increment">Increment</button>
<button type="button" (click)="step(-10)" id="decrement">Decrement</button>
</div>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material progress-linear demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; } </style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,30 @@
import {bootstrap} from 'angular2/bootstrap';
import {bind, provide, Component, View, ViewEncapsulation} from 'angular2/core';
import {MdProgressLinear} from 'angular2_material/src/components/progress-linear/progress_linear';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({
selector: 'demo-app',
})
@View({
templateUrl: './demo_app.html',
directives: [MdProgressLinear],
encapsulation: ViewEncapsulation.None,
})
class DemoApp {
progress: number;
constructor() {
this.progress = 40;
}
step(s: number) {
this.progress += s;
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,41 @@
<style>
md-radio-button {
max-width: 200px;
}
</style>
<div>
<h2>Radio buttons</h2>
<h3>Inside of a radiogroup</h3>
<md-radio-group #scifi (change)="onGroupChange()" id="scifi-group">
<md-radio-button value="star-wars">Star Wars</md-radio-button>
<md-radio-button value="star-trek" id="special-radio">Star Trek</md-radio-button>
<md-radio-button value="bsg" disabled>Battlestar Galactica</md-radio-button>
<md-radio-button [value]="thirdValue">Dr. Who</md-radio-button>
</md-radio-group>
<p>Your selection: {{scifi.value}}</p>
<p>radio group value change count: {{groupValueChangeCount}}</p>
<hr>
<h3>Standalone</h3>
<md-radio-button name="element" (click)="onIndividualClick()">Earth</md-radio-button>
<md-radio-button name="element" (click)="onIndividualClick()">Fire</md-radio-button>
<md-radio-button name="element" (click)="onIndividualClick()" disabled>Wind (disabled)</md-radio-button>
<md-radio-button name="element" (click)="onIndividualClick()">Heart</md-radio-button>
<p>individual radio value change count: {{individualValueChanges}}</p>
<hr>
<h3>Disabled radio group</h3>
<p>Chosen: {{pokemon}}</p>
<md-radio-group disabled [value]="pokemon">
<md-radio-button value="fire">Charmander</md-radio-button>
<md-radio-button value="leaf">Bulbasaur</md-radio-button>
<md-radio-button value="water">Squirtle</md-radio-button>
</md-radio-group>
<button type="button" (click)="chooseCharmander()">Choose Charmander</button>
</div>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material radio demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style> * { font-family: RobotoDraft, Roboto; } </style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,47 @@
import {bootstrap} from 'angular2/bootstrap';
import {bind, provide, Component, UrlResolver, View, ViewEncapsulation} from 'angular2/core';
import {MdRadioButton, MdRadioGroup} from 'angular2_material/src/components/radio/radio_button';
import {MdRadioDispatcher} from 'angular2_material/src/components/radio/radio_dispatcher';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({
selector: 'demo-app',
viewProviders: [MdRadioDispatcher],
})
@View({
templateUrl: './demo_app.html',
directives: [MdRadioGroup, MdRadioButton],
encapsulation: ViewEncapsulation.None,
})
class DemoApp {
thirdValue;
groupValueChangeCount;
individualValueChanges;
pokemon;
someTabindex;
constructor() {
this.thirdValue = 'dr-who';
this.groupValueChangeCount = 0;
this.individualValueChanges = 0;
this.pokemon = '';
this.someTabindex = 888;
}
chooseCharmander() {
this.pokemon = 'fire';
}
onGroupChange() {
this.groupValueChangeCount++;
}
onIndividualClick() {
this.individualValueChanges++;
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,9 @@
<div md-theme="default">
<h2>NgSwitch demo</h2>
<md-switch (click)="increment()">Normal switch</md-switch>
<md-switch class="md-primary" (click)="increment()">Primary switch</md-switch>
<md-switch disabled (click)="increment()">Disabled switch</md-switch>
<p>Toggle count: {{toggleCount}}</p>
</div>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>ng-material switch demo</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:400,500,700,400italic">
<style>
* {
font-family: RobotoDraft, Roboto;
}
</style>
</head>
<body>
<demo-app>Loading...</demo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,30 @@
import {bootstrap} from 'angular2/bootstrap';
import {bind, provide, Component, View, ViewEncapsulation} from 'angular2/core';
import {MdSwitch} from 'angular2_material/src/components/switcher/switch';
import {UrlResolver} from 'angular2/src/core/compiler/url_resolver';
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
@Component({
selector: 'demo-app',
})
@View({
templateUrl: './demo_app.html',
directives: [MdSwitch],
encapsulation: ViewEncapsulation.None,
})
class DemoApp {
toggleCount: number;
constructor() {
this.toggleCount = 0;
}
increment() {
this.toggleCount++;
}
}
export function main() {
commonDemoSetup();
bootstrap(DemoApp, [provide(UrlResolver, {useValue: new DemoUrlResolver()})]);
}

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Model Driven Forms</title>
<style>
.ng-touched.ng-invalid {
border-color: red;
}
</style>
</head>
<body>
<model-driven-forms>
Loading...
</model-driven-forms>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,161 @@
import {bootstrap} from 'angular2/bootstrap';
import {
FORM_DIRECTIVES,
NgControl,
Validators,
NgFormModel,
FormBuilder,
NgIf,
NgFor,
Component,
Directive,
View,
Host
} from 'angular2/core';
import {RegExpWrapper, print, isPresent} from 'angular2/src/core/facade/lang';
/**
* Custom validator.
*/
function creditCardValidator(c): {[key: string]: boolean} {
if (isPresent(c.value) && RegExpWrapper.test(/^\d{16}$/g, c.value)) {
return null;
} else {
return {"invalidCreditCard": true};
}
}
/**
* This is a component that displays an error message.
*
* For instance,
*
* <show-error control="creditCard" [errors]="['required', 'invalidCreditCard']"></show-error>
*
* Will display the "is required" error if the control is empty, and "invalid credit card" if the
* control is not empty
* but not valid.
*
* In a real application, this component would receive a service that would map an error code to an
* actual error message.
* To make it simple, we are using a simple map here.
*/
@Component({selector: 'show-error', inputs: ['controlPath: control', 'errorTypes: errors']})
@View({
template: `
<span *ng-if="errorMessage !== null">{{errorMessage}}</span>
`,
directives: [NgIf]
})
class ShowError {
formDir;
controlPath: string;
errorTypes: string[];
constructor(@Host() formDir: NgFormModel) { this.formDir = formDir; }
get errorMessage(): string {
var control = this.formDir.form.find(this.controlPath);
if (isPresent(control) && control.touched) {
for (var i = 0; i < this.errorTypes.length; ++i) {
if (control.hasError(this.errorTypes[i])) {
return this._errorMessage(this.errorTypes[i]);
}
}
}
return null;
}
_errorMessage(code: string): string {
var config = {'required': 'is required', 'invalidCreditCard': 'is invalid credit card number'};
return config[code];
}
}
@Component({selector: 'model-driven-forms', viewProviders: [FormBuilder]})
@View({
template: `
<h1>Checkout Form (Model Driven)</h1>
<form (ng-submit)="onSubmit()" [ng-form-model]="form" #f="form">
<p>
<label for="firstName">First Name</label>
<input type="text" id="firstName" ng-control="firstName">
<show-error control="firstName" [errors]="['required']"></show-error>
</p>
<p>
<label for="middleName">Middle Name</label>
<input type="text" id="middleName" ng-control="middleName">
</p>
<p>
<label for="lastName">Last Name</label>
<input type="text" id="lastName" ng-control="lastName">
<show-error control="lastName" [errors]="['required']"></show-error>
</p>
<p>
<label for="country">Country</label>
<select id="country" ng-control="country">
<option *ng-for="#c of countries" [value]="c">{{c}}</option>
</select>
</p>
<p>
<label for="creditCard">Credit Card</label>
<input type="text" id="creditCard" ng-control="creditCard">
<show-error control="creditCard" [errors]="['required', 'invalidCreditCard']"></show-error>
</p>
<p>
<label for="amount">Amount</label>
<input type="number" id="amount" ng-control="amount">
<show-error control="amount" [errors]="['required']"></show-error>
</p>
<p>
<label for="email">Email</label>
<input type="email" id="email" ng-control="email">
<show-error control="email" [errors]="['required']"></show-error>
</p>
<p>
<label for="comments">Comments</label>
<textarea id="comments" ng-control="comments">
</textarea>
</p>
<button type="submit" [disabled]="!f.form.valid">Submit</button>
</form>
`,
directives: [FORM_DIRECTIVES, NgFor, ShowError]
})
class ModelDrivenForms {
form;
countries = ['US', 'Canada'];
constructor(fb: FormBuilder) {
this.form = fb.group({
"firstName": ["", Validators.required],
"middleName": [""],
"lastName": ["", Validators.required],
"country": ["Canada", Validators.required],
"creditCard": ["", Validators.compose([Validators.required, creditCardValidator])],
"amount": [0, Validators.required],
"email": ["", Validators.required],
"comments": [""]
});
}
onSubmit(): void {
print("Submitting:");
print(this.form.value);
}
}
export function main() {
bootstrap(ModelDrivenForms);
}

View File

@ -0,0 +1,39 @@
library benchmarks.src.naive_infinite_scroll.app;
import "package:angular2/src/core/facade/collection.dart" show List, ListWrapper;
import "scroll_area.dart" show ScrollAreaComponent;
import "package:angular2/angular2.dart" show Component, Directive, View, IterableDiffers, SkipSelf, Binding;
import "package:angular2/core.dart" show ObservableListDiffFactory, NgIf, NgFor;
import 'package:observe/observe.dart' show ObservableList;
createDiffers(IterableDiffers parent) {
return IterableDiffers.create([const ObservableListDiffFactory()], parent);
}
const binding = const Binding(IterableDiffers,
toFactory: createDiffers, deps: const [ const[IterableDiffers, const SkipSelf()]]);
@Component(
selector: "scroll-app",
bindings: const [binding]
)
@View(directives: const [ScrollAreaComponent, NgIf, NgFor], template: '''
<div>
<div style="display: flex">
<scroll-area id="testArea"></scroll-area>
</div>
<div template="ng-if scrollAreas.length > 0">
<p>Following tables are only here to add weight to the UI:</p>
<scroll-area template="ng-for #scrollArea of scrollAreas"></scroll-area>
</div>
</div>''')
class App {
List<int> scrollAreas;
App() {
var scrollAreas = [];
for (var i = 0; i < 300; i++) {
scrollAreas.add(i);
}
this.scrollAreas = new ObservableList.from(scrollAreas);
}
}

View File

@ -0,0 +1,135 @@
library benchmarks.src.naive_infinite_scroll.cells;
import "package:angular2/src/core/facade/collection.dart"
show List, ListWrapper, Map;
import "common.dart"
show Company, Opportunity, Offering, Account, CustomDate, STATUS_LIST;
import "package:angular2/core.dart" show NgFor;
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
class HasStyle {
int cellWidth;
HasStyle() {}
set width(int w) {
this.cellWidth = w;
}
}
@Component(
selector: "company-name",
inputs: const ["width: cell-width", "company"],
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
template: '''<div [style.width.px]="cellWidth">{{company.name}}</div>'''
)
class CompanyNameComponent extends HasStyle {
Company company;
}
@Component(
selector: "opportunity-name",
inputs: const ["width: cell-width", "opportunity"],
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
template: '''<div [style.width.px]="cellWidth">{{opportunity.name}}</div>'''
)
class OpportunityNameComponent extends HasStyle {
Opportunity opportunity;
}
@Component(
selector: "offering-name",
inputs: const ["width: cell-width", "offering"],
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
template: '''<div [style.width.px]="cellWidth">{{offering.name}}</div>'''
)
class OfferingNameComponent extends HasStyle {
Offering offering;
}
class Stage {
String name;
bool isDisabled;
String backgroundColor;
Function apply;
}
@Component(
selector: "stage-buttons",
inputs: const ["width: cell-width", "offering"],
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(directives: const [NgFor], template: '''
<div [style.width.px]="cellWidth">
<button template="ng-for #stage of stages"
[disabled]="stage.isDisabled"
[style.background-color]="stage.backgroundColor"
on-click="setStage(stage)">
{{stage.name}}
</button>
</div>''')
class StageButtonsComponent extends HasStyle {
Offering _offering;
List<Stage> stages;
Offering get offering {
return this._offering;
}
set offering(Offering offering) {
this._offering = offering;
this._computeStageButtons();
}
setStage(Stage stage) {
this._offering.status = stage.name;
this._offering.name = this._offering.name + "!";
this._computeStageButtons();
}
_computeStageButtons() {
var disabled = true;
this.stages = ListWrapper.clone(STATUS_LIST.map((status) {
var isCurrent = this._offering.status == status;
var stage = new Stage();
stage.name = status;
stage.isDisabled = disabled;
stage.backgroundColor = disabled ? "#DDD" : isCurrent ? "#DDF" : "#FDD";
if (isCurrent) {
disabled = false;
}
return stage;
}).toList());
}
}
@Component(
selector: "account-cell",
inputs: const ["width: cell-width", "account"],
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(directives: const [], template: '''
<div [style.width.px]="cellWidth">
<a href="/account/{{account.accountId}}">
{{account.accountId}}
</a>
</div>''')
class AccountCellComponent extends HasStyle {
Account account;
}
@Component(
selector: "formatted-cell",
inputs: const ["width: cell-width", "value"],
changeDetection: ChangeDetectionStrategy.OnPushObserve
)
@View(
directives: const [],
template: '''<div [style.width.px]="cellWidth">{{formattedValue}}</div>''')
class FormattedCellComponent extends HasStyle {
String formattedValue;
set value(value) {
if (value is CustomDate) {
this.formattedValue =
'''${ value . month}/${ value . day}/${ value . year}''';
} else {
this.formattedValue = value.toString();
}
}
}

View File

@ -0,0 +1,241 @@
library benchmarks.src.naive_infinite_scroll.common;
import "package:angular2/src/core/facade/math.dart" show Math;
import "package:angular2/src/core/facade/collection.dart";
import 'package:observe/observe.dart';
import 'dart:collection';
import 'dart:async';
var ITEMS = 1000;
var ITEM_HEIGHT = 40;
var VISIBLE_ITEMS = 17;
var HEIGHT = ITEMS * ITEM_HEIGHT;
var VIEW_PORT_HEIGHT = ITEM_HEIGHT * VISIBLE_ITEMS;
var COMPANY_NAME_WIDTH = 100;
var OPPORTUNITY_NAME_WIDTH = 100;
var OFFERING_NAME_WIDTH = 100;
var ACCOUNT_CELL_WIDTH = 50;
var BASE_POINTS_WIDTH = 50;
var KICKER_POINTS_WIDTH = 50;
var STAGE_BUTTONS_WIDTH = 220;
var BUNDLES_WIDTH = 120;
var DUE_DATE_WIDTH = 100;
var END_DATE_WIDTH = 100;
var AAT_STATUS_WIDTH = 100;
var ROW_WIDTH = COMPANY_NAME_WIDTH +
OPPORTUNITY_NAME_WIDTH +
OFFERING_NAME_WIDTH +
ACCOUNT_CELL_WIDTH +
BASE_POINTS_WIDTH +
KICKER_POINTS_WIDTH +
STAGE_BUTTONS_WIDTH +
BUNDLES_WIDTH +
DUE_DATE_WIDTH +
END_DATE_WIDTH +
AAT_STATUS_WIDTH;
var STATUS_LIST = ["Planned", "Pitched", "Won", "Lost"];
var AAT_STATUS_LIST = ["Active", "Passive", "Abandoned"];
// Imitate Streamy entities.
// Just a non-trivial object. Nothing fancy or correct.
class CustomDate {
num year;
num month;
num day;
CustomDate(num y, num m, num d) {
this.year = y;
this.month = m;
this.day = d;
}
CustomDate addDays(num days) {
var newDay = this.day + days;
var newMonth = this.month + Math.floor(newDay / 30);
newDay = newDay % 30;
var newYear = this.year + Math.floor(newMonth / 12);
return new CustomDate(newYear, newMonth, newDay);
}
static CustomDate now() {
return new CustomDate(2014, 1, 28);
}
}
class RawEntity extends Object
with MapMixin<String, dynamic>
implements ObservableMap<String, dynamic> {
ObservableMap _data = new ObservableMap();
@override
Iterable<String> get keys => _data.keys;
@override
void clear() {
_data.clear();
}
@override
operator [](String key) {
if (!key.contains('.')) {
return _data[key];
}
var pieces = key.split('.');
var last = pieces.removeLast();
var target = _resolve(pieces, this);
if (target == null) {
return null;
}
return target[last];
}
@override
operator []=(String key, value) {
if (!key.contains('.')) {
_data[key] = value;
return;
}
var pieces = key.split('.');
var last = pieces.removeLast();
var target = _resolve(pieces, this);
target[last] = value;
}
dynamic get(String name) { return this[name]; }
set(String name, dynamic value) { this[name] = value; }
@override
remove(String key) {
if (!key.contains('.')) {
return _data.remove(key);
}
var pieces = key.split('.');
var last = pieces.removeLast();
var target = _resolve(pieces, this);
return target.remove(last);
}
_resolve(List<String> pieces, start) {
var cur = start;
for (var i = 0; i < pieces.length; i++) {
cur = cur[pieces[i]];
if (cur == null) {
return null;
}
}
return cur;
}
@override
Stream<List<ChangeRecord>> get changes => _data.changes;
@override
bool get hasObservers => _data.hasObservers;
@override
bool deliverChanges() => _data.deliverChanges();
@override
notifyPropertyChange(Symbol field, Object oldValue, Object newValue) =>
_data.notifyPropertyChange(field, oldValue, newValue);
@override
void notifyChange(ChangeRecord record) {
_data.notifyChange(record);
}
@override
void observed() {
_data.observed();
}
@override
void unobserved() {
_data.observed();
}
}
class Company extends RawEntity {
String get name {
return this.get("name");
}
set name(String val) {
this.set("name", val);
}
}
class Offering extends RawEntity {
String get name {
return this.get("name");
}
set name(String val) {
this.set("name", val);
}
Company get company {
return this.get("company");
}
set company(Company val) {
this.set("company", val);
}
Opportunity get opportunity {
return this.get("opportunity");
}
set opportunity(Opportunity val) {
this.set("opportunity", val);
}
Account get account {
return this.get("account");
}
set account(Account val) {
this.set("account", val);
}
num get basePoints {
return this.get("basePoints");
}
set basePoints(num val) {
this.set("basePoints", val);
}
num get kickerPoints {
return this.get("kickerPoints");
}
set kickerPoints(num val) {
this.set("kickerPoints", val);
}
String get status {
return this.get("status");
}
set status(String val) {
this.set("status", val);
}
String get bundles {
return this.get("bundles");
}
set bundles(String val) {
this.set("bundles", val);
}
CustomDate get dueDate {
return this.get("dueDate");
}
set dueDate(CustomDate val) {
this.set("dueDate", val);
}
CustomDate get endDate {
return this.get("endDate");
}
set endDate(CustomDate val) {
this.set("endDate", val);
}
String get aatStatus {
return this.get("aatStatus");
}
set aatStatus(String val) {
this.set("aatStatus", val);
}
}
class Opportunity extends RawEntity {
String get name {
return this.get("name");
}
set name(String val) {
this.set("name", val);
}
}
class Account extends RawEntity {
num get accountId {
return this.get("accountId");
}
set accountId(num val) {
this.set("accountId", val);
}
}

View File

@ -0,0 +1,14 @@
library benchmarks.src.naive_infinite_scroll.index;
import "package:angular2/bootstrap.dart" show bootstrap;
import "app.dart" show App;
import "package:angular2/src/core/linker/view_pool.dart"
show APP_VIEW_POOL_CAPACITY;
import "package:angular2/core.dart" show bind;
main() {
bootstrap(App, createBindings());
}
List<dynamic> createBindings() {
return [bind(APP_VIEW_POOL_CAPACITY).toValue(100000)];
}

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>AngularDart Scrolling Benchmark</title>
</head>
<body>
<scroll-app></scroll-app>
<script src="url_params_to_form.js" type="text/javascript"></script>
<script src="index.dart" type="application/dart"></script>
<script src="naive_infinite_scroll/packages/browser/dart.js" type="text/javascript"></script>
</body>
</html>

View File

@ -0,0 +1,86 @@
library benchmarks.src.naive_infinite_scroll.random_data;
import "package:angular2/src/core/facade/lang.dart" show StringWrapper;
import "package:angular2/src/core/facade/collection.dart" show List, ListWrapper;
import "common.dart"
show
CustomDate,
Offering,
Company,
Opportunity,
Account,
STATUS_LIST,
AAT_STATUS_LIST;
List<Offering> generateOfferings(int count) {
var res = [];
for (var i = 0; i < count; i++) {
res.add(generateOffering(i));
}
return res;
}
Offering generateOffering(int seed) {
var res = new Offering();
res.name = generateName(seed++);
res.company = generateCompany(seed++);
res.opportunity = generateOpportunity(seed++);
res.account = generateAccount(seed++);
res.basePoints = seed % 10;
res.kickerPoints = seed % 4;
res.status = STATUS_LIST[seed % STATUS_LIST.length];
res.bundles = randomString(seed++);
res.dueDate = randomDate(seed++);
res.endDate = randomDate(seed++, res.dueDate);
res.aatStatus = AAT_STATUS_LIST[seed % AAT_STATUS_LIST.length];
return res;
}
Company generateCompany(int seed) {
var res = new Company();
res.name = generateName(seed);
return res;
}
Opportunity generateOpportunity(int seed) {
var res = new Opportunity();
res.name = generateName(seed);
return res;
}
Account generateAccount(int seed) {
var res = new Account();
res.accountId = seed;
return res;
}
var names = [
"Foo",
"Bar",
"Baz",
"Qux",
"Quux",
"Garply",
"Waldo",
"Fred",
"Plugh",
"Xyzzy",
"Thud",
"Cruft",
"Stuff"
];
String generateName(int seed) {
return names[seed % names.length];
}
var offsets = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
CustomDate randomDate(int seed, [CustomDate minDate = null]) {
if (minDate == null) {
minDate = CustomDate.now();
}
return minDate.addDays(offsets[seed % offsets.length]);
}
var stringLengths = [5, 7, 9, 11, 13];
var charCodeOffsets = [0, 1, 2, 3, 4, 5, 6, 7, 8];
String randomString(int seed) {
var len = stringLengths[seed % 5];
var str = "";
for (var i = 0; i < len; i++) {
str += StringWrapper.fromCharCode(97 + charCodeOffsets[seed % 9] + i);
}
return str;
}

View File

@ -0,0 +1,71 @@
library benchmarks.src.naive_infinite_scroll.scroll_area;
import "package:angular2/src/core/facade/collection.dart" show ListWrapper;
import "package:angular2/src/core/facade/math.dart" show Math;
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
import "common.dart"
show
Offering,
ITEMS,
ITEM_HEIGHT,
VISIBLE_ITEMS,
VIEW_PORT_HEIGHT,
ROW_WIDTH,
HEIGHT;
import "random_data.dart" show generateOfferings;
import "scroll_item.dart" show ScrollItemComponent;
import "package:angular2/core.dart" show NgFor;
@Component(selector: "scroll-area", changeDetection: ChangeDetectionStrategy.OnPushObserve)
@View(directives: const [ScrollItemComponent, NgFor], template: '''
<div>
<div id="scrollDiv"
[style.height.px]="viewPortHeight"
style="width: 1000px; border: 1px solid #000; overflow: scroll"
on-scroll="onScroll(\$event)">
<div id="padding"></div>
<div id="inner">
<scroll-item
template="ng-for #item of visibleItems"
[offering]="item">
</scroll-item>
</div>
</div>
</div>''')
class ScrollAreaComponent {
List<Offering> _fullList;
List<Offering> visibleItems;
num viewPortHeight;
var paddingDiv;
var innerDiv;
ScrollAreaComponent() {
this._fullList = generateOfferings(ITEMS);
this.visibleItems = [];
this.viewPortHeight = VIEW_PORT_HEIGHT;
this.onScroll(null);
}
onScroll(evt) {
var scrollTop = 0;
if (evt != null) {
var scrollDiv = evt.target;
if (this.paddingDiv == null) {
this.paddingDiv = scrollDiv.querySelector("#padding");
}
if (this.innerDiv == null) {
this.innerDiv = scrollDiv.querySelector("#inner");
this.innerDiv.style.setProperty("width", '''${ ROW_WIDTH}px''');
}
scrollTop = scrollDiv.scrollTop;
}
var iStart = Math.floor(scrollTop / ITEM_HEIGHT);
var iEnd = Math.min(iStart + VISIBLE_ITEMS + 1, this._fullList.length);
var padding = iStart * ITEM_HEIGHT;
if (this.innerDiv != null) {
this.innerDiv.style.setProperty("height", '''${ HEIGHT - padding}px''');
}
if (this.paddingDiv != null) {
this.paddingDiv.style.setProperty("height", '''${ padding}px''');
}
this.visibleItems = ListWrapper.slice(this._fullList, iStart, iEnd);
}
}

View File

@ -0,0 +1,117 @@
library benchmarks.src.naive_infinite_scroll.scroll_item;
import "cells.dart"
show
CompanyNameComponent,
OpportunityNameComponent,
OfferingNameComponent,
StageButtonsComponent,
AccountCellComponent,
FormattedCellComponent;
import "package:angular2/angular2.dart" show Component, Directive, View, ChangeDetectionStrategy;
import "common.dart"
show
Offering,
ITEM_HEIGHT,
COMPANY_NAME_WIDTH,
OPPORTUNITY_NAME_WIDTH,
OFFERING_NAME_WIDTH,
ACCOUNT_CELL_WIDTH,
BASE_POINTS_WIDTH,
KICKER_POINTS_WIDTH,
STAGE_BUTTONS_WIDTH,
BUNDLES_WIDTH,
DUE_DATE_WIDTH,
END_DATE_WIDTH,
AAT_STATUS_WIDTH;
@Component(selector: "scroll-item", inputs: const ["offering"],
changeDetection: ChangeDetectionStrategy.OnPushObserve)
@View(
directives: const [
CompanyNameComponent,
OpportunityNameComponent,
OfferingNameComponent,
StageButtonsComponent,
AccountCellComponent,
FormattedCellComponent
],
template: '''
<div class="row"
[style.height.px]="itemHeight"
[style.line-height.px]="itemHeight"
style="font-size: 18px; display: flex; justify-content: space-between;">
<company-name [company]="offering.company"
[cell-width]="companyNameWidth">
</company-name>
<opportunity-name [opportunity]="offering.opportunity"
[cell-width]="opportunityNameWidth">
</opportunity-name>
<offering-name [offering]="offering"
[cell-width]="offeringNameWidth">
</offering-name>
<account-cell [account]="offering.account"
[cell-width]="accountCellWidth">
</account-cell>
<formatted-cell [value]="offering.basePoints"
[cell-width]="basePointsWidth">
</formatted-cell>
<formatted-cell [value]="offering.kickerPoints"
[cell-width]="kickerPointsWidth">
</formatted-cell>
<stage-buttons [offering]="offering"
[cell-width]="stageButtonsWidth">
</stage-buttons>
<formatted-cell [value]="offering.bundles"
[cell-width]="bundlesWidth">
</formatted-cell>
<formatted-cell [value]="offering.dueDate"
[cell-width]="dueDateWidth">
</formatted-cell>
<formatted-cell [value]="offering.endDate"
[cell-width]="endDateWidth">
</formatted-cell>
<formatted-cell [value]="offering.aatStatus"
[cell-width]="aatStatusWidth">
</formatted-cell>
</div>''')
class ScrollItemComponent {
Offering offering;
num itemHeight;
ScrollItemComponent() {
this.itemHeight = ITEM_HEIGHT;
}
get companyNameWidth {
return COMPANY_NAME_WIDTH;
}
get opportunityNameWidth {
return OPPORTUNITY_NAME_WIDTH;
}
get offeringNameWidth {
return OFFERING_NAME_WIDTH;
}
get accountCellWidth {
return ACCOUNT_CELL_WIDTH;
}
get basePointsWidth {
return BASE_POINTS_WIDTH;
}
get kickerPointsWidth {
return KICKER_POINTS_WIDTH;
}
get stageButtonsWidth {
return STAGE_BUTTONS_WIDTH;
}
get bundlesWidth {
return BUNDLES_WIDTH;
}
get dueDateWidth {
return DUE_DATE_WIDTH;
}
get endDateWidth {
return END_DATE_WIDTH;
}
get aatStatusWidth {
return AAT_STATUS_WIDTH;
}
}

View File

@ -0,0 +1,20 @@
// helper script that will read out the url parameters
// and store them in appropriate form fields on the page
(function() {
var regex = /(\w+)=(\w+)/g;
var search = decodeURIComponent(location.search);
while (match = regex.exec(search)) {
var name = match[1];
var value = match[2];
var els = document.querySelectorAll('input[name="'+name+'"]');
var el;
for (var i=0; i<els.length; i++) {
el = els[i];
if (el.type === 'radio' || el.type === 'checkbox') {
el.checked = el.value === value;
} else {
el.value = value;
}
}
}
})();

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Order Management</title>
<style>
.warning {
background-color: yellow;
}
</style>
</head>
<body>
<order-management-app>
Loading...
</order-management-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,205 @@
import {bootstrap} from 'angular2/bootstrap';
import {
NgIf,
NgFor,
Component,
Directive,
View,
Host,
forwardRef,
Provider,
EventEmitter,
FORM_DIRECTIVES,
Injectable
} from 'angular2/core';
import {ListWrapper} from 'angular2/src/core/facade/collection';
/**
* You can find the Angular 1 implementation of this example here:
* https://github.com/wardbell/ng1DataBinding
*/
// ---- model
class OrderItem {
constructor(public orderItemId: number, public orderId: number, public productName: string,
public qty: number, public unitPrice: number) {}
get total(): number { return this.qty * this.unitPrice; }
}
class Order {
constructor(public orderId: number, public customerName: string, public limit: number,
private _dataService: DataService) {}
get items(): OrderItem[] { return this._dataService.itemsFor(this); }
get total(): number { return this.items.map(i => i.total).reduce((a, b) => a + b); }
}
// ---- services
var _nextId = 1000;
@Injectable()
class DataService {
orderItems: OrderItem[];
orders: Order[];
currentOrder: Order = null;
constructor() {
this.orders = [
new Order(_nextId++, "J. Coltrane", 100, this),
new Order(_nextId++, "B. Evans", 200, this)
];
this.orderItems = [
new OrderItem(_nextId++, this.orders[0].orderId, "Bread", 5, 1),
new OrderItem(_nextId++, this.orders[0].orderId, "Brie", 5, 2),
new OrderItem(_nextId++, this.orders[0].orderId, "IPA", 5, 3),
new OrderItem(_nextId++, this.orders[1].orderId, "Mozzarella", 5, 2),
new OrderItem(_nextId++, this.orders[1].orderId, "Wine", 5, 3)
];
}
itemsFor(order: Order): OrderItem[] {
return ListWrapper.filter(this.orderItems, i => i.orderId === order.orderId);
}
addItemForOrder(order: Order): void {
this.orderItems.push(new OrderItem(_nextId++, order.orderId, "", 0, 0));
}
deleteItem(item: OrderItem): void { ListWrapper.remove(this.orderItems, item); }
}
// ---- components
@Component({selector: 'order-list-cmp'})
@View({
template: `
<h1>Orders</h1>
<div *ng-for="#order of orders" [class.warning]="order.total > order.limit">
<div>
<label>Customer name:</label>
{{order.customerName}}
</div>
<div>
<label>Limit: <input [(ng-model)]="order.limit" type="number" placeholder="Limit"></label>
</div>
<div>
<label>Number of items:</label>
{{order.items.length}}
</div>
<div>
<label>Order total:</label>
{{order.total}}
</div>
<button (click)="select(order)">Select</button>
</div>
`,
directives: [FORM_DIRECTIVES, NgFor]
})
class OrderListComponent {
orders: Order[];
constructor(private _service: DataService) { this.orders = _service.orders; }
select(order: Order): void { this._service.currentOrder = order; }
}
@Component({selector: 'order-item-cmp', inputs: ['item'], outputs: ['delete']})
@View({
template: `
<div>
<div>
<label>Product name: <input [(ng-model)]="item.productName" type="text" placeholder="Product name"></label>
</div>
<div>
<label>Quantity: <input [(ng-model)]="item.qty" type="number" placeholder="Quantity"></label>
</div>
<div>
<label>Unit Price: <input [(ng-model)]="item.unitPrice" type="number" placeholder="Unit price"></label>
</div>
<div>
<label>Total:</label>
{{item.total}}
</div>
<button (click)="onDelete()">Delete</button>
</div>
`,
directives: [FORM_DIRECTIVES]
})
class OrderItemComponent {
item: OrderItem;
delete = new EventEmitter();
onDelete(): void { this.delete.next(this.item); }
}
@Component({selector: 'order-details-cmp'})
@View({
template: `
<div *ng-if="order !== null">
<h1>Selected Order</h1>
<div>
<label>Customer name: <input [(ng-model)]="order.customerName" type="text" placeholder="Customer name"></label>
</div>
<div>
<label>Limit: <input [(ng-model)]="order.limit" type="number" placeholder="Limit"></label>
</div>
<div>
<label>Number of items:</label>
{{order.items.length}}
</div>
<div>
<label>Order total:</label>
{{order.total}}
</div>
<h2>Items</h2>
<button (click)="addItem()">Add Item</button>
<order-item-cmp *ng-for="#item of order.items" [item]="item" (delete)="deleteItem(item)"></order-item-cmp>
</div>
`,
directives: [FORM_DIRECTIVES, OrderItemComponent, NgFor, NgIf]
})
class OrderDetailsComponent {
constructor(private _service: DataService) {}
get order(): Order { return this._service.currentOrder; }
deleteItem(item: OrderItem): void { this._service.deleteItem(item); }
addItem(): void { this._service.addItemForOrder(this.order); }
}
@Component({selector: 'order-management-app', bindings: [DataService]})
@View({
template: `
<order-list-cmp></order-list-cmp>
<order-details-cmp></order-details-cmp>
`,
directives: [OrderListComponent, OrderDetailsComponent]
})
class OrderManagementApplication {
}
export function main() {
bootstrap(OrderManagementApplication);
}

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Person Management</title>
<style>
.ng-touched.ng-invalid {
border-color: red;
}
</style>
</head>
<body>
<person-management-app>
Loading...
</person-management-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,213 @@
import {bootstrap} from 'angular2/bootstrap';
import {
NgIf,
NgFor,
Component,
Directive,
View,
Host,
forwardRef,
Provider,
FORM_DIRECTIVES,
Injectable
} from 'angular2/core';
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
/**
* You can find the Angular 1 implementation of this example here:
* https://github.com/wardbell/ng1DataBinding
*/
// ---- model
var _nextId = 1;
class Person {
personId: number;
mom: Person;
dad: Person;
friends: Person[];
constructor(public firstName: string, public lastName: string, public yearOfBirth: number) {
this.personId = _nextId++;
this.firstName = firstName;
this.lastName = lastName;
this.mom = null;
this.dad = null;
this.friends = [];
this.personId = _nextId++;
}
get age(): number { return 2015 - this.yearOfBirth; }
get fullName(): string { return `${this.firstName} ${this.lastName}`; }
get friendNames(): string { return this.friends.map(f => f.fullName).join(', '); }
}
// ---- services
@Injectable()
class DataService {
currentPerson: Person;
persons: Person[];
constructor() {
this.persons = [
new Person('Victor', 'Savkin', 1930),
new Person('Igor', 'Minar', 1920),
new Person('John', 'Papa', 1910),
new Person('Nancy', 'Duarte', 1910),
new Person('Jack', 'Papa', 1910),
new Person('Jill', 'Papa', 1910),
new Person('Ward', 'Bell', 1910),
new Person('Robert', 'Bell', 1910),
new Person('Tracy', 'Ward', 1910),
new Person('Dan', 'Wahlin', 1910)
];
this.persons[0].friends = [0, 1, 2, 6, 9].map(_ => this.persons[_]);
this.persons[1].friends = [0, 2, 6, 9].map(_ => this.persons[_]);
this.persons[2].friends = [0, 1, 6, 9].map(_ => this.persons[_]);
this.persons[6].friends = [0, 1, 2, 9].map(_ => this.persons[_]);
this.persons[9].friends = [0, 1, 2, 6].map(_ => this.persons[_]);
this.persons[2].mom = this.persons[5];
this.persons[2].dad = this.persons[4];
this.persons[6].mom = this.persons[8];
this.persons[6].dad = this.persons[7];
this.currentPerson = this.persons[0];
}
}
// ---- components
@Component({selector: 'full-name-cmp'})
@View({
template: `
<h1>Edit Full Name</h1>
<div>
<form>
<div>
<label>
First: <input [(ng-model)]="person.firstName" type="text" placeholder="First name">
</label>
</div>
<div>
<label>
Last: <input [(ng-model)]="person.lastName" type="text" placeholder="Last name">
</label>
</div>
<div>
<label>{{person.fullName}}</label>
</div>
</form>
</div>
`,
directives: [FORM_DIRECTIVES]
})
class FullNameComponent {
constructor(private _service: DataService) {}
get person(): Person { return this._service.currentPerson; }
}
@Component({selector: 'person-detail-cmp'})
@View({
template: `
<h2>{{person.fullName}}</h2>
<div>
<form>
<div>
<label>First: <input [(ng-model)]="person.firstName" type="text" placeholder="First name"></label>
</div>
<div>
<label>Last: <input [(ng-model)]="person.lastName" type="text" placeholder="Last name"></label>
</div>
<div>
<label>Year of birth: <input [(ng-model)]="person.yearOfBirth" type="number" placeholder="Year of birth"></label>
Age: {{person.age}}
</div>\
<div *ng-if="person.mom != null">
<label>Mom:</label>
<input [(ng-model)]="person.mom.firstName" type="text" placeholder="Mom's first name">
<input [(ng-model)]="person.mom.lastName" type="text" placeholder="Mom's last name">
{{person.mom.fullName}}
</div>
<div *ng-if="person.dad != null">
<label>Dad:</label>
<input [(ng-model)]="person.dad.firstName" type="text" placeholder="Dad's first name">
<input [(ng-model)]="person.dad.lastName" type="text" placeholder="Dad's last name">
{{person.dad.fullName}}
</div>
<div *ng-if="person.friends.length > 0">
<label>Friends:</label>
{{person.friendNames}}
</div>
</form>
</div>
`,
directives: [FORM_DIRECTIVES, NgIf]
})
class PersonsDetailComponent {
constructor(private _service: DataService) {}
get person(): Person { return this._service.currentPerson; }
}
@Component({selector: 'persons-cmp'})
@View({
template: `
<h1>FullName Demo</h1>
<div>
<ul>
<li *ng-for="#person of persons">
<label (click)="select(person)">{{person.fullName}}</label>
</li>
</ul>
<person-detail-cmp></person-detail-cmp>
</div>
`,
directives: [FORM_DIRECTIVES, PersonsDetailComponent, NgFor]
})
class PersonsComponent {
persons: Person[];
constructor(private _service: DataService) { this.persons = _service.persons; }
select(person: Person): void { this._service.currentPerson = person; }
}
@Component({selector: 'person-management-app', viewBindings: [DataService]})
@View({
template: `
<button (click)="switchToEditName()">Edit Full Name</button>
<button (click)="switchToPersonList()">Person Array</button>
<full-name-cmp *ng-if="mode == 'editName'"></full-name-cmp>
<persons-cmp *ng-if="mode == 'personList'"></persons-cmp>
`,
directives: [FullNameComponent, PersonsComponent, NgIf]
})
class PersonManagementApplication {
mode: string;
switchToEditName(): void { this.mode = 'editName'; }
switchToPersonList(): void { this.mode = 'personList'; }
}
export function main() {
bootstrap(PersonManagementApplication);
}

View File

@ -0,0 +1,57 @@
body {
background:#eee;
color:black;
}
.inbox-list,
.inbox-list li {
list-style:none;
padding:0;
margin:0;
}
.inbox-list a {
padding:5px;
display:block;
}
inbox, drafts, inbox-side-menu {
display:block;
}
inbox-side-menu .link {
display:block;
text-align:center;
padding:1em;
}
inbox-side-menu .link.active {
background:white;
}
inbox-side-menu .link:hover {
background:#eee;
}
inbox-side-menu {
position:fixed;
left:0;
top:0;
bottom:0;
width:200px;
background:#ddd;
}
inbox-side-menu a {
display: block;
}
inbox, drafts, inbox-detail {
padding:1em;
margin-left:200px;
}
inbox-detail {
display:block;
margin-left:200px;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
<div ng-if="ready">
<h2 class="page-title">Drafts</h2>
<ol class="inbox-list">
<li *ng-for="#item of items" class="inbox-item-record">
<a id="item-{{ item.id }}"
[router-link]="['/DetailPage', {'id':item.id}]">
{{ item.subject }}</a>
</li>
</ol>
</div>

View File

@ -0,0 +1,5 @@
<inbox-side-menu class="inbox-aside">
<a [router-link]="['/Inbox']" class="link" [class.active]="inboxPageActive()">Inbox</a>
<a [router-link]="['/Drafts']" class="link" [class.active]="draftsPageActive()">Drafts</a>
</inbox-side-menu>
<router-outlet></router-outlet>

View File

@ -0,0 +1,161 @@
import {NgIf, NgFor, EventEmitter, Component, View, Inject, Injectable} from 'angular2/angular2';
import {
RouterLink,
RouteConfig,
Router,
Route,
RouterOutlet,
Location,
RouteParams
} from 'angular2/router';
import * as db from './data';
import {ObservableWrapper, PromiseWrapper, Promise} from 'angular2/src/core/facade/async';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {isPresent, DateWrapper} from 'angular2/src/core/facade/lang';
class InboxRecord {
id: string = '';
subject: string = '';
content: string = '';
email: string = '';
firstName: string = '';
lastName: string = '';
date: string;
draft: boolean = false;
constructor(data: {
id: string,
subject: string,
content: string,
email: string,
firstName: string,
lastName: string,
date: string, draft?: boolean
} = null) {
if (isPresent(data)) {
this.setData(data);
}
}
setData(record: {
id: string,
subject: string,
content: string,
email: string,
firstName: string,
lastName: string,
date: string, draft?: boolean
}) {
this.id = record['id'];
this.subject = record['subject'];
this.content = record['content'];
this.email = record['email'];
this.firstName = record['first-name'];
this.lastName = record['last-name'];
this.date = record['date'];
this.draft = record['draft'] == true;
}
}
@Injectable()
class DbService {
getData(): Promise<any[]> {
var p = PromiseWrapper.completer();
p.resolve(db.data);
return p.promise;
}
drafts(): Promise<any[]> {
return PromiseWrapper.then(this.getData(), (data) => {
return ListWrapper.filter(data,
(record => isPresent(record['draft']) && record['draft'] == true));
});
}
emails(): Promise<any[]> {
return PromiseWrapper.then(this.getData(), (data) => {
return ListWrapper.filter(data, (record => !isPresent(record['draft'])));
});
}
email(id): Promise<any> {
return PromiseWrapper.then(this.getData(), (data) => {
for (var i = 0; i < data.length; i++) {
var entry = data[i];
if (entry['id'] == id) {
return entry;
}
}
});
}
}
@Component({selector: 'inbox-detail'})
@View({templateUrl: "inbox-detail.html", directives: [NgFor, RouterLink]})
class InboxDetailCmp {
record: InboxRecord = new InboxRecord();
ready: boolean = false;
constructor(db: DbService, params: RouteParams) {
var id = params.get('id');
PromiseWrapper.then(db.email(id), (data) => { this.record.setData(data); });
}
}
@Component({selector: 'inbox'})
@View({templateUrl: "inbox.html", directives: [NgFor, RouterLink]})
class InboxCmp {
items: InboxRecord[] = [];
ready: boolean = false;
constructor(public router: Router, db: DbService, params: RouteParams) {
var sortType = params.get('sort');
var sortEmailsByDate = isPresent(sortType) && sortType == "date";
PromiseWrapper.then(db.emails(), emails => {
this.ready = true;
this.items = emails.map(data => new InboxRecord(data));
if (sortEmailsByDate) {
ListWrapper.sort(this.items,
(a, b) => DateWrapper.toMillis(DateWrapper.fromISOString(a.date)) <
DateWrapper.toMillis(DateWrapper.fromISOString(b.date)) ?
-1 :
1);
}
});
}
}
@Component({selector: 'drafts'})
@View({templateUrl: "drafts.html", directives: [NgFor, RouterLink]})
class DraftsCmp {
items: InboxRecord[] = [];
ready: boolean = false;
constructor(public router: Router, db: DbService) {
PromiseWrapper.then(db.drafts(), (drafts) => {
this.ready = true;
this.items = drafts.map(data => new InboxRecord(data));
});
}
}
@Component({selector: 'inbox-app', viewProviders: [DbService]})
@View({templateUrl: "inbox-app.html", directives: [RouterOutlet, RouterLink]})
@RouteConfig([
new Route({path: '/', component: InboxCmp, as: 'Inbox'}),
new Route({path: '/drafts', component: DraftsCmp, as: 'Drafts'}),
new Route({path: '/detail/:id', component: InboxDetailCmp, as: 'DetailPage'})
])
export class InboxApp {
router: Router;
location: Location;
constructor(router: Router, location: Location) {
this.router = router;
this.location = location;
}
inboxPageActive() { return this.location.path() == ''; }
draftsPageActive() { return this.location.path() == '/drafts'; }
}

View File

@ -0,0 +1,24 @@
<div ng-if="ready">
<h2 class="page-title">{{ record.subject }}</h2>
<ul>
<li id="record-id">ID: {{ record.id }}</li>
<li id="record-name">Name: {{ record.firstName }} {{ record.lastName }}</li>
<li id="record-email">Email: {{ record.email }}</li>
<li id="record-date">Date: {{ record.date }}</li>
</ul>
<p>
{{ record.content }}
</p>
<span class="btn medium primary">
<a [router-link]="record.draft ? ['../Drafts'] : ['../Inbox']" class="back-button">Back</a>
</span>
<hr />
<a [router-link]="['../Inbox', { sort: 'date'} ]" class="sort-button">
View Latest Messages
</a>
</div>

View File

@ -0,0 +1,10 @@
<div ng-if="ready">
<h2 class="page-title">Inbox</h2>
<ol class="inbox-list">
<li *ng-for="#item of items" class="inbox-item-record">
<a id="item-{{ item.id }}"
[router-link]="['/DetailPage', {'id':item.id}]">{{ item.subject }}</a>
</li>
</ol>
</div>

View File

@ -0,0 +1,14 @@
<!doctype html>
<html>
<title>Routing Example</title>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/gumby/2.6.0/css/gumby.css" />
<link rel="stylesheet" type="text/css" href="./css/app.css" />
<base href="/playground/src/routing/">
<body>
<inbox-app>
Loading...
</inbox-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,13 @@
import {InboxApp} from './inbox-app';
import {bind, provide} from 'angular2/angular2';
import {bootstrap} from 'angular2/bootstrap';
import {ROUTER_PROVIDERS, HashLocationStrategy, LocationStrategy} from 'angular2/router';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {ReflectionCapabilities} from 'angular2/src/core/reflection/reflection_capabilities';
export function main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrap(InboxApp,
[ROUTER_PROVIDERS, provide(LocationStrategy, {useClass: HashLocationStrategy})]);
}

View File

@ -0,0 +1,16 @@
<!doctype html>
<html>
<title>Sourcemaps</title>
<body>
<error-app>
Loading...
</error-app>
<p>
Please look into the console and check whether the stack trace is mapped
via source maps!
</p>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,18 @@
import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptions';
import {bootstrap} from 'angular2/bootstrap';
import {Component, View} from 'angular2/core';
@Component({
selector: 'error-app',
})
@View({
template: `
<button class="errorButton" (click)="createError()">create error</button>`
})
export class ErrorComponent {
createError(): void { throw new BaseException('Sourcemap test'); }
}
export function main() {
bootstrap(ErrorComponent);
}

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Template Driven Forms</title>
<style>
.ng-touched.ng-invalid {
border-color: red;
}
</style>
</head>
<body>
<template-driven-forms>
Loading...
</template-driven-forms>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,172 @@
import {bootstrap} from 'angular2/bootstrap';
import {
NgIf,
NgFor,
Component,
Directive,
View,
Host,
NG_VALIDATORS,
forwardRef,
Provider,
FORM_DIRECTIVES,
NgControl,
Validators,
NgForm
} from 'angular2/core';
import {RegExpWrapper, print, isPresent, CONST_EXPR} from 'angular2/src/core/facade/lang';
/**
* A domain model we are binding the form controls to.
*/
class CheckoutModel {
firstName: string;
middleName: string;
lastName: string;
country: string = "Canada";
creditCard: string;
amount: number;
email: string;
comments: string;
}
/**
* Custom validator.
*/
function creditCardValidator(c): {[key: string]: boolean} {
if (isPresent(c.value) && RegExpWrapper.test(/^\d{16}$/g, c.value)) {
return null;
} else {
return {"invalidCreditCard": true};
}
}
const creditCardValidatorBinding =
CONST_EXPR(new Provider(NG_VALIDATORS, {useValue: creditCardValidator, multi: true}));
@Directive({selector: '[credit-card]', bindings: [creditCardValidatorBinding]})
class CreditCardValidator {
}
/**
* This is a component that displays an error message.
*
* For instance,
*
* <show-error control="creditCard" [errors]="['required', 'invalidCreditCard']"></show-error>
*
* Will display the "is required" error if the control is empty, and "invalid credit card" if the
* control is not empty
* but not valid.
*
* In a real application, this component would receive a service that would map an error code to an
* actual error message.
* To make it simple, we are using a simple map here.
*/
@Component({selector: 'show-error', inputs: ['controlPath: control', 'errorTypes: errors']})
@View({
template: `
<span *ng-if="errorMessage !== null">{{errorMessage}}</span>
`,
directives: [NgIf]
})
class ShowError {
formDir;
controlPath: string;
errorTypes: string[];
constructor(@Host() formDir: NgForm) { this.formDir = formDir; }
get errorMessage(): string {
var control = this.formDir.form.find(this.controlPath);
if (isPresent(control) && control.touched) {
for (var i = 0; i < this.errorTypes.length; ++i) {
if (control.hasError(this.errorTypes[i])) {
return this._errorMessage(this.errorTypes[i]);
}
}
}
return null;
}
_errorMessage(code: string): string {
var config = {'required': 'is required', 'invalidCreditCard': 'is invalid credit card number'};
return config[code];
}
}
@Component({selector: 'template-driven-forms'})
@View({
template: `
<h1>Checkout Form</h1>
<form (ng-submit)="onSubmit()" #f="form">
<p>
<label for="firstName">First Name</label>
<input type="text" id="firstName" ng-control="firstName" [(ng-model)]="model.firstName" required>
<show-error control="firstName" [errors]="['required']"></show-error>
</p>
<p>
<label for="middleName">Middle Name</label>
<input type="text" id="middleName" ng-control="middleName" [(ng-model)]="model.middleName">
</p>
<p>
<label for="lastName">Last Name</label>
<input type="text" id="lastName" ng-control="lastName" [(ng-model)]="model.lastName" required>
<show-error control="lastName" [errors]="['required']"></show-error>
</p>
<p>
<label for="country">Country</label>
<select id="country" ng-control="country" [(ng-model)]="model.country">
<option *ng-for="#c of countries" [value]="c">{{c}}</option>
</select>
</p>
<p>
<label for="creditCard">Credit Card</label>
<input type="text" id="creditCard" ng-control="creditCard" [(ng-model)]="model.creditCard" required credit-card>
<show-error control="creditCard" [errors]="['required', 'invalidCreditCard']"></show-error>
</p>
<p>
<label for="amount">Amount</label>
<input type="number" id="amount" ng-control="amount" [(ng-model)]="model.amount" required>
<show-error control="amount" [errors]="['required']"></show-error>
</p>
<p>
<label for="email">Email</label>
<input type="email" id="email" ng-control="email" [(ng-model)]="model.email" required>
<show-error control="email" [errors]="['required']"></show-error>
</p>
<p>
<label for="comments">Comments</label>
<textarea id="comments" ng-control="comments" [(ng-model)]="model.comments">
</textarea>
</p>
<button type="submit" [disabled]="!f.form.valid">Submit</button>
</form>
`,
directives: [FORM_DIRECTIVES, NgFor, CreditCardValidator, ShowError]
})
class TemplateDrivenForms {
model = new CheckoutModel();
countries = ['US', 'Canada'];
onSubmit(): void {
print("Submitting:");
print(this.model);
}
}
export function main() {
bootstrap(TemplateDrivenForms);
}

View File

@ -0,0 +1,379 @@
@charset "utf-8";
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
-ms-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased;
}
button,
input[type="checkbox"] {
outline: none;
}
.hidden {
display: none;
}
.visible {
display: block !important;
}
#todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp h1 {
position: absolute;
top: -155px;
width: 100%;
font-size: 100px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
#new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-ms-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
}
#main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
label[for='toggle-all'] {
display: none;
}
#toggle-all {
position: absolute;
top: -55px;
left: -12px;
width: 60px;
height: 34px;
text-align: center;
border: none; /* Mobile Safari */
}
#toggle-all:before {
content: '';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
#toggle-all:checked:before {
color: #737373;
}
#todo-list {
margin: 0;
padding: 0;
list-style: none;
}
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.editing {
border-bottom: none;
padding: 0;
}
#todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
margin: 0 0 0 43px;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
-ms-appearance: none;
appearance: none;
}
#todo-list li .toggle:after {
content: url('data:image/svg+xml;charset=utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
}
#todo-list li .toggle:checked:after {
content: url('data:image/svg+xml;charset=utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
}
#todo-list li label {
white-space: pre;
word-break: break-word;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
#todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
#todo-list li .destroy:hover {
color: #af5b5e;
}
#todo-list li .destroy:after {
content: '×';
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li .edit {
display: none;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
#footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
#todo-count {
float: left;
text-align: left;
}
#todo-count strong {
font-weight: 300;
}
#filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
#filters li {
display: inline;
}
#filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
#filters li a.selected,
#filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
#filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
#clear-completed,
html #clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
visibility: hidden;
position: relative;
}
#clear-completed::after {
visibility: visible;
content: 'Clear completed';
position: absolute;
right: 0;
white-space: nowrap;
}
#clear-completed:hover::after {
text-decoration: underline;
}
#info {
margin: 65px auto 0;
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
#info p {
line-height: 1;
}
#info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
#info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all,
#todo-list li .toggle {
background: none;
}
#todo-list li .toggle {
height: 40px;
}
#toggle-all {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
@media (max-width: 430px) {
#footer {
height: 50px;
}
#filters {
bottom: 10px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,19 @@
html,
body {
margin: 0;
padding: 0;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eaeaea;
color: #4d4d4d;
width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}

View File

@ -0,0 +1,13 @@
<!doctype html>
<html>
<title>Todo Angular 2</title>
<link rel="stylesheet" href="css/main.css" media="screen" title="no title" charset="utf-8">
<body>
<todo-app>
Loading...
</todo-app>
$SCRIPTS$
</body>
</html>

View File

@ -0,0 +1,47 @@
import {bootstrap} from 'angular2/bootstrap';
import {NgFor, Component, View} from 'angular2/core';
import {Store, Todo, TodoFactory} from './services/TodoStore';
@Component({selector: 'todo-app', viewProviders: [Store, TodoFactory]})
@View({templateUrl: 'todo.html', directives: [NgFor]})
class TodoApp {
todoEdit: Todo = null;
constructor(public todoStore: Store, public factory: TodoFactory) {}
enterTodo(inputElement): void {
this.addTodo(inputElement.value);
inputElement.value = '';
}
editTodo(todo: Todo): void { this.todoEdit = todo; }
doneEditing($event, todo: Todo): void {
var which = $event.which;
var target = $event.target;
if (which === 13) {
todo.title = target.value;
this.todoEdit = null;
} else if (which === 27) {
this.todoEdit = null;
target.value = todo.title;
}
}
addTodo(newTitle: string): void { this.todoStore.add(this.factory.create(newTitle, false)); }
completeMe(todo: Todo): void { todo.completed = !todo.completed; }
deleteMe(todo: Todo): void { this.todoStore.remove(todo); }
toggleAll($event): void {
var isComplete = $event.target.checked;
this.todoStore.list.forEach((todo: Todo) => { todo.completed = isComplete; });
}
clearCompleted(): void { this.todoStore.removeBy((todo: Todo) => todo.completed); }
}
export function main() {
bootstrap(TodoApp);
}

View File

@ -0,0 +1,47 @@
import {Injectable} from 'angular2/angular2';
import {ListWrapper, Predicate} from 'angular2/src/core/facade/collection';
// base model for RecordStore
export class KeyModel {
constructor(public key: number) {}
}
export class Todo extends KeyModel {
constructor(key: number, public title: string, public completed: boolean) { super(key); }
}
@Injectable()
export class TodoFactory {
_uid: number = 0;
nextUid(): number { return ++this._uid; }
create(title: string, isCompleted: boolean): Todo {
return new Todo(this.nextUid(), title, isCompleted);
}
}
// Store manages any generic item that inherits from KeyModel
@Injectable()
export class Store {
list: KeyModel[] = [];
add(record: KeyModel): void { this.list.push(record); }
remove(record: KeyModel): void { this._spliceOut(record); }
removeBy(callback: Predicate<KeyModel>): void {
var records = ListWrapper.filter(this.list, callback);
ListWrapper.removeAll(this.list, records);
}
private _spliceOut(record: KeyModel) {
var i = this._indexFor(record);
if (i > -1) {
return ListWrapper.splice(this.list, i, 1)[0];
}
return null;
}
private _indexFor(record: KeyModel) { return this.list.indexOf(record); }
}

View File

@ -0,0 +1,71 @@
<style>@import "css/base.css";</style>
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input
id="new-todo"
placeholder="What needs to be done?"
autofocus
#newtodo
(keyup.enter)="enterTodo(newtodo)">
</header>
<section id="main">
<input id="toggle-all" type="checkbox" (click)="toggleAll($event)">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
<li *ng-for="#todo of todoStore.list">
<div class="view"
[class.hidden]="todoEdit == todo">
<input class="toggle" type="checkbox"
(click)="completeMe(todo)"
[checked]="todo.completed">
<label (dblclick)="editTodo(todo)">{{todo.title}}</label>
<button class="destroy" (click)="deleteMe(todo)"></button>
</div>
<div>
<input class="edit"
[class.visible]="todoEdit == todo"
[value]="todo.title"
(keyup)="doneEditing($event, todo)">
</div>
</li>
</ul>
</section>
<footer id="footer">
<span id="todo-count"></span>
<div [class.hidden]="true"></div>
<ul id="filters">
<li>
<a href="#/" class="selected">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<button id="clear-completed" (click)="clearCompleted()">Clear completed</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="http://twitter.com/angularjs">The Angular Team</a></p>
</footer>

View File

@ -0,0 +1,4 @@
declare module "B64" {
export function fromByteArray(arr: Uint8Array): string;
export function toByteArray(str: string): Uint8Array;
}

View File

@ -0,0 +1,13 @@
library playground.src.web_workers.images.background_index;
import "index_common.dart" show ImageDemo;
import "dart:isolate";
import "package:angular2/src/web_workers/worker/application.dart"
show bootstrapWebWorker;
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
import "package:angular2/src/core/reflection/reflection.dart";
main(List<String> args, SendPort replyTo) {
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrapWebWorker(replyTo, ImageDemo).catchError((error) => throw error);
}

View File

@ -0,0 +1,6 @@
import {bootstrapWebWorker} from "angular2/src/web_workers/worker/application";
import {ImageDemo} from "./index_common";
export function main() {
bootstrapWebWorker(ImageDemo);
}

View File

@ -0,0 +1,8 @@
declare class Bitmap {
constructor(width: number, height: number);
subsample(n: number): void;
dataURL(): string;
pixel:[any];
}

View File

@ -0,0 +1,127 @@
/*
Copyright 2011 Andrey Zholos
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
function Bitmap(width, height) {
this.width = width;
this.height = height;
this.pixel = new Array(width);
for (var x = 0; x < width; x++) {
this.pixel[x] = new Array(height);
for (var y = 0; y < height; y++) this.pixel[x][y] = [0, 0, 0, 0];
}
}
Bitmap.prototype.subsample =
function(n) {
var width = ~~(this.width / n);
var height = ~~(this.height / n);
var pixel = new Array(width);
for (var x = 0; x < width; x++) {
pixel[x] = new Array(height);
for (var y = 0; y < height; y++) {
var q = [0, 0, 0, 0];
for (var i = 0; i < n; i++)
for (var j = 0; j < n; j++) {
var r = this.pixel[x * n + i][y * n + j];
q[0] += r[3] * r[0];
q[1] += r[3] * r[1];
q[2] += r[3] * r[2];
q[3] += r[3];
}
if (q[3]) {
q[0] /= q[3];
q[1] /= q[3];
q[2] /= q[3];
q[3] /= n * n;
}
pixel[x][y] = q;
}
}
this.width = width;
this.height = height;
this.pixel = pixel;
}
Bitmap.prototype.dataURL = function() {
function sample(v) { return ~~(Math.max(0, Math.min(1, v)) * 255); }
function gamma(v) { return sample(Math.pow(v, .45455)); }
function row(pixel, width, y) {
var data = "\0";
for (var x = 0; x < width; x++) {
var r = pixel[x][y];
data += String.fromCharCode(gamma(r[0]), gamma(r[1]), gamma(r[2]), sample(r[3]));
}
return data;
}
function rows(pixel, width, height) {
var data = "";
for (var y = 0; y < height; y++) data += row(pixel, width, y);
return data;
}
function adler(data) {
var s1 = 1, s2 = 0;
for (var i = 0; i < data.length; i++) {
s1 = (s1 + data.charCodeAt(i)) % 65521;
s2 = (s2 + s1) % 65521;
}
return s2 << 16 | s1;
}
function hton(i) { return String.fromCharCode(i >>> 24, i >>> 16 & 255, i >>> 8 & 255, i & 255); }
function deflate(data) {
var len = data.length;
return "\170\1\1" + String.fromCharCode(len & 255, len >>> 8, ~len & 255, (~len >>> 8) & 255) +
data + hton(adler(data));
}
function crc32(data) {
var c = ~0;
for (var i = 0; i < data.length; i++)
for (var b = data.charCodeAt(i) | 0x100; b != 1; b >>>= 1)
c = (c >>> 1) ^ ((c ^ b) & 1 ? 0xedb88320 : 0);
return ~c;
}
function chunk(type, data) { return hton(data.length) + type + data + hton(crc32(type + data)); }
function base64(data) {
enc = "";
for (var i = 5, n = data.length * 8 + 5; i < n; i += 6)
enc += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
[(data.charCodeAt(~~(i / 8) - 1) << 8 | data.charCodeAt(~~(i / 8))) >> 7 - i % 8 & 63];
for (; enc.length % 4; enc += "=")
;
return enc;
}
var png = "\211PNG\r\n\32\n" +
chunk("IHDR", hton(this.width) + hton(this.height) + "\10\6\0\0\0") +
chunk("IDAT", deflate(rows(this.pixel, this.width, this.height))) + chunk("IEND", "");
return "data:image/png;base64," + base64(png);
}

View File

@ -0,0 +1,9 @@
export 'dart:html' show FileReader;
import 'dart:typed_data';
class Uint8ArrayWrapper {
static Uint8ClampedList create(ByteBuffer buffer) {
return new Uint8ClampedList.view(buffer);
}
}

View File

@ -0,0 +1,6 @@
var _FileReader = FileReader;
export {_FileReader as FileReader};
export class Uint8ArrayWrapper {
static create(buffer: ArrayBuffer) { return new Uint8Array(buffer); }
}

View File

@ -0,0 +1,30 @@
.hidden{
display: none !important;
}
#images {
width: 600px;
margin: 0 auto;
}
ul li {
list-style-type: none;
float: left;
margin-left: 20px;
width: 200px;
}
#main ul {
width: 700px;
}
.card-image .image-loader{
position: absolute;
bottom: 0;
margin: auto;
}
.card-image img.grey {
opacity: 0.4;
}
.fixed-action-btn.bottom {
bottom: 45px;
right: 24px;
}

View File

@ -0,0 +1,33 @@
<nav class="blue">
<div class="container">
<div class="nav-wrapper">
<a class="brand-logo">Angular 2 Image Demo</a>
</div>
</div>
</nav>
<section id="main" class="container">
<div class="row">
<div *ng-for="#image of images" class="col s12 m2">
<div class="card">
<div class="card-image">
<img [src]="image.src" [class.grey]="image.filtering"/>
<div class="image-loader progress" [class.hidden]="!image.filtering">
<div class="indeterminate"></div>
</div>
</div>
</div>
</div>
</div>
<div class="fixed-action-btn bottom" (click)="applyFilters()">
<a class="btn-floating btn-large blue darken-4" (click)="applyFilters()">
<i class="large material-icons" (click)="applyFilters()">invert_colors</i>
</a>
</div>
<div class="file-field">
<div class="btn blue darken-2">
<span>Select Images</span>
<input type="file" accept="image/bmp" multiple (change)="uploadFiles($event.target.files)" />
</div>
</div>
</section>

View File

@ -0,0 +1,10 @@
library angular2.examples.web_workers.images.index;
import "package:angular2/src/web_workers/ui/application.dart" show bootstrap;
import "package:angular2/src/core/reflection/reflection_capabilities.dart";
import "package:angular2/src/core/reflection/reflection.dart";
main() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
bootstrap("background_index.dart");
}

View File

@ -0,0 +1,18 @@
<html>
<head>
<link rel="stylesheet" href="image_demo.css" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<image-demo>
</image-demo>
$SCRIPTS$
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/css/materialize.min.css">
<!-- Compiled and minified JavaScript -->
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.0/js/materialize.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,2 @@
import {bootstrap} from "angular2/src/web_workers/ui/application";
bootstrap("loader.js");

View File

@ -0,0 +1,50 @@
import {NgZone, NgFor, Component, View, NgIf, FORM_DIRECTIVES} from 'angular2/angular2';
import {BitmapService} from './services/bitmap';
import {EventListener} from 'angular2/src/core/facade/browser';
import {FileReader, Uint8ArrayWrapper} from './file_api';
import {TimerWrapper} from 'angular2/src/core/facade/async';
@Component({selector: 'image-demo', viewProviders: [BitmapService]})
@View({templateUrl: 'image_demo.html', directives: [NgFor, NgIf, FORM_DIRECTIVES]})
export class ImageDemo {
images = [];
fileInput: String;
constructor(private _bitmapService: BitmapService) {}
uploadFiles(files) {
for (var i = 0; i < files.length; i++) {
var reader = new FileReader();
reader.addEventListener("load", this.handleReaderLoad(reader));
reader.readAsArrayBuffer(files[i]);
}
}
handleReaderLoad(reader: FileReader): EventListener {
return (e) => {
var buffer = reader.result;
this.images.push({
src: this._bitmapService.arrayBufferToDataUri(Uint8ArrayWrapper.create(reader.result)),
buffer: buffer,
filtering: false
});
};
}
applyFilters() {
for (var i = 0; i < this.images.length; i++) {
this.images[i].filtering = true;
TimerWrapper.setTimeout(this._filter(i), 0);
}
}
private _filter(i: number): (...args: any[]) => void {
return () => {
var imageData = this._bitmapService.convertToImageData(this.images[i].buffer);
imageData = this._bitmapService.applySepia(imageData);
this.images[i].src = this._bitmapService.toDataUri(imageData);
this.images[i].filtering = false;
};
}
}

View File

@ -0,0 +1,71 @@
body {
background: #eaecfa;
}
.loader {
width: 250px;
height: 50px;
line-height: 50px;
text-align: center;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-family: helvetica, arial, sans-serif;
text-transform: uppercase;
font-weight: 900;
color: #ce4233;
letter-spacing: 0.2em;
}
.loader::before, .loader::after {
content: "";
display: block;
width: 15px;
height: 15px;
background: #ce4233;
position: absolute;
-webkit-animation: load .7s infinite alternate ease-in-out;
animation: load .7s infinite alternate ease-in-out;
}
.loader::before {
top: 0;
}
.loader::after {
bottom: 0;
}
@-webkit-keyframes load {
0% {
left: 0;
height: 30px;
width: 15px;
}
50% {
height: 8px;
width: 40px;
}
100% {
left: 235px;
height: 30px;
width: 15px;
}
}
@keyframes load {
0% {
left: 0;
height: 30px;
width: 15px;
}
50% {
height: 8px;
width: 40px;
}
100% {
left: 235px;
height: 30px;
width: 15px;
}
}

View File

@ -0,0 +1,20 @@
$SCRIPTS$
importScripts("b64.js");
System.config({
baseURL: '/',
defaultJSExtensions: true
});
System.import("playground/src/web_workers/images/background_index")
.then(
function(m) {
console.log("running main");
try {
m.main();
} catch (e) {
console.error(e);
}
},
function(error) { console.error("error loading background", error); });

View File

@ -0,0 +1,23 @@
library angular2.examples.web_workers.images.bitmap_service;
import 'dart:html';
import 'dart:typed_data';
// TODO(jteplitz602) Implement this class #3493
class BitmapService {
ImageData applySepia(ImageData imageData) {
return null;
}
String arrayBufferToDataUri(Uint8ClampedList data) {
return null;
}
ImageData convertToImageData(ByteBuffer buffer) {
return null;
}
String toDataUri(ImageData imageData) {
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More