refactor(playground): make playground great again

This commit is contained in:
Joao Dias 2016-10-23 16:21:18 +02:00 committed by Victor Berchet
parent 69f87ca075
commit 3d9d839c6c
28 changed files with 212 additions and 382 deletions

View File

@ -13,7 +13,7 @@ describe('hello world', function() {
afterEach(verifyNoBrowserErrors);
describe('hello world app', function() {
var URL = 'all/playground/src/hello_world/index.html';
const URL = 'all/playground/src/hello_world/index.html';
it('should greet', function() {
browser.get(URL);
@ -31,15 +31,12 @@ describe('hello world', function() {
});
function getComponentText(selector: any /** TODO #9100 */, innerSelector: any /** TODO #9100 */) {
function getComponentText(selector: string, innerSelector: string) {
return browser.executeScript(
'return document.querySelector("' + selector + '").querySelector("' + innerSelector +
'").textContent');
`return document.querySelector("${selector}").querySelector("${innerSelector}").textContent`);
}
function clickComponentButton(
selector: any /** TODO #9100 */, innerSelector: any /** TODO #9100 */) {
function clickComponentButton(selector: string, innerSelector: string) {
return browser.executeScript(
'return document.querySelector("' + selector + '").querySelector("' + innerSelector +
'").click()');
`return document.querySelector("${selector}").querySelector("${innerSelector}").click()`);
}

View File

@ -13,7 +13,7 @@ describe('http', function() {
afterEach(verifyNoBrowserErrors);
describe('fetching', function() {
var URL = 'all/playground/src/http/index.html';
const URL = 'all/playground/src/http/index.html';
it('should fetch and display people', function() {
browser.get(URL);
@ -22,8 +22,7 @@ describe('http', function() {
});
});
function getComponentText(selector: any /** TODO #9100 */, innerSelector: any /** TODO #9100 */) {
function getComponentText(selector: string, innerSelector: string) {
return browser.executeScript(
'return document.querySelector("' + selector + '").querySelector("' + innerSelector +
'").textContent.trim()');
`return document.querySelector("${selector}").querySelector("${innerSelector}").textContent.trim()`);
}

View File

@ -13,7 +13,7 @@ describe('jsonp', function() {
afterEach(verifyNoBrowserErrors);
describe('fetching', function() {
var URL = 'all/playground/src/jsonp/index.html';
const URL = 'all/playground/src/jsonp/index.html';
it('should fetch and display people', function() {
browser.get(URL);
@ -22,8 +22,7 @@ describe('jsonp', function() {
});
});
function getComponentText(selector: any /** TODO #9100 */, innerSelector: any /** TODO #9100 */) {
function getComponentText(selector: string, innerSelector: string) {
return browser.executeScript(
'return document.querySelector("' + selector + '").querySelector("' + innerSelector +
'").textContent.trim()');
`return document.querySelector("${selector}").querySelector("${innerSelector}").textContent.trim()`);
}

View File

@ -8,8 +8,8 @@
import {verifyNoBrowserErrors} from 'e2e_util/e2e_util';
function waitForElement(selector: any /** TODO #9100 */) {
var EC = (<any>protractor).ExpectedConditions;
function waitForElement(selector: string) {
const EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
@ -18,7 +18,7 @@ describe('relative assets relative-app', () => {
afterEach(verifyNoBrowserErrors);
var URL = 'all/playground/src/relative_assets/';
const URL = 'all/playground/src/relative_assets/';
it('should load in the templateUrl relative to the my-cmp component', () => {
browser.get(URL);
@ -31,10 +31,9 @@ describe('relative assets relative-app', () => {
browser.get(URL);
waitForElement('my-cmp .inner-container');
var elem = element(by.css('my-cmp .inner-container'));
var width = browser.executeScript(function(e: any /** TODO #9100 */) {
return parseInt(window.getComputedStyle(e).width);
}, elem.getWebElement());
const elem = element(by.css('my-cmp .inner-container'));
const width = browser.executeScript(
(e: Element) => parseInt(window.getComputedStyle(e).width), elem.getWebElement());
expect(width).toBe(432);
});

View File

@ -8,8 +8,8 @@
import {verifyNoBrowserErrors} from 'e2e_util/e2e_util';
function waitForElement(selector: any /** TODO #9100 */) {
var EC = (<any>protractor).ExpectedConditions;
function waitForElement(selector: string) {
const EC = protractor.ExpectedConditions;
// Waits for the element with id 'abc' to be present on the dom.
browser.wait(EC.presenceOf($(selector)), 20000);
}
@ -19,7 +19,7 @@ describe('routing inbox-app', () => {
afterEach(verifyNoBrowserErrors);
describe('index view', () => {
var URL = 'all/playground/src/routing/';
const URL = 'all/playground/src/routing/';
it('should list out the current collection of items', () => {
browser.get(URL);

View File

@ -22,13 +22,13 @@ describe('WebWorker Router', () => {
let contentSelector = 'app main h1';
let navSelector = 'app nav ul';
var baseUrl = 'all/playground/src/web_workers/router/index.html';
const baseUrl = 'all/playground/src/web_workers/router/index.html';
it('should route on click', () => {
browser.get(baseUrl);
waitForElement(contentSelector);
var content = element(by.css(contentSelector));
let content = element(by.css(contentSelector));
expect(content.getText()).toEqual('Start');
let aboutBtn = element(by.css(navSelector + ' .about'));
@ -66,13 +66,13 @@ describe('WebWorker Router', () => {
function waitForElementText(contentSelector: string, expected: string): void {
browser.wait(() => {
let deferred = protractor.promise.defer();
var elem = element(by.css(contentSelector));
const elem = element(by.css(contentSelector));
elem.getText().then((text) => deferred.fulfill(text === expected));
return deferred.promise;
}, 5000);
}
function waitForUrl(regex: any /** TODO #9100 */): void {
function waitForUrl(regex: RegExp): void {
browser.wait(() => {
let deferred = protractor.promise.defer();
browser.getCurrentUrl().then((url) => deferred.fulfill(url.match(regex) !== null));

View File

@ -63,26 +63,26 @@ import {Component, animate, keyframes, state, style, transition, trigger} from '
]
})
export class AnimateApp {
public items: any[] /** TODO #9100 */ = [];
private _state: any /** TODO #9100 */;
public items: number[] = [];
private _state: ('start'|'active'|'void'|'default');
public bgStatus = 'focus';
remove(item: any) {
var index = this.items.indexOf(item);
remove(item: number) {
const index = this.items.indexOf(item);
if (index >= 0) {
this.items.splice(index, 1);
}
}
reorderAndRemove() {
this.items = this.items.sort((a: any, b: any) => Math.random() - 0.5);
this.items = this.items.sort((a, b) => Math.random() - 0.5);
this.items.splice(Math.floor(Math.random() * this.items.length), 1);
this.items.splice(Math.floor(Math.random() * this.items.length), 1);
this.items[Math.floor(Math.random() * this.items.length)] = 99;
}
bgStatusChanged(data: {[key: string]: any}, phase: string) {
bgStatusChanged(data: {[key: string]: string}, phase: string) {
alert(`backgroundAnimation has ${phase} from ${data['fromState']} to ${data['toState']}`);
}

View File

@ -39,9 +39,9 @@ class AsyncApplication {
val2: number = 0;
val3: number = 0;
val4: number = 0;
timeoutId: any /** TODO #9100 */ = null;
multiTimeoutId: any /** TODO #9100 */ = null;
intervalId: any /** TODO #9100 */ = null;
timeoutId: any = null;
multiTimeoutId: any = null;
intervalId: any = null;
increment(): void { this.val1++; };
@ -56,8 +56,8 @@ class AsyncApplication {
multiDelayedIncrements(i: number): void {
this.cancelMultiDelayedIncrements();
var self = this;
function helper(_i: any /** TODO #9100 */) {
const self = this;
function helper(_i: number) {
if (_i <= 0) {
self.multiTimeoutId = null;
return;

View File

@ -41,15 +41,10 @@
'@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js',
'@angular/upgrade/static': '/packages-dist/upgrade/bundles/upgrade-static.umd.js',
'rxjs': '/all/playground/vendor/rxjs',
// TODO(i): remove once playground apps no longer use facades directly
'@angular/core/src/facade': '/all/@angular/core/src/facade'
},
packages: {
'app': {defaultExtension: 'js'},
'rxjs': {defaultExtension: 'js'},
// TODO(i): remove once playground apps no longer use facades directly
'@angular/core/src/facade': {defaultExtension: 'js'}
}
});
} else {

View File

@ -9,8 +9,6 @@
import {Component, NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
// TODO: remove deep import by reimplementing the event name serialization
import {KeyEventsPlugin} from '@angular/platform-browser/src/dom/events/key_events';
@Component({
selector: 'key-events-app',
@ -28,17 +26,48 @@ class KeyEventsApp {
lastKey: string = '(none)';
shiftEnter: boolean = false;
onKeyDown(event: any /** TODO #9100 */): void {
this.lastKey = KeyEventsPlugin.getEventFullKey(event);
onKeyDown(event: KeyboardEvent): void {
this.lastKey = KeyEventsApp._getEventFullKey(event);
event.preventDefault();
}
onShiftEnter(event: any /** TODO #9100 */): void {
onShiftEnter(event: KeyboardEvent): void {
this.shiftEnter = true;
event.preventDefault();
}
resetShiftEnter(): void { this.shiftEnter = false; }
/**
* Get a more readable version of current pressed keys.
* @see KeyEventsPlugin.getEventFullKey
*/
private static _getEventFullKey(event: KeyboardEvent): string {
const modifierKeys = ['alt', 'control', 'meta', 'shift'];
const modifierKeyGetters: {[key: string]: (event: KeyboardEvent) => boolean} = {
'alt': (event: KeyboardEvent) => event.altKey,
'control': (event: KeyboardEvent) => event.ctrlKey,
'meta': (event: KeyboardEvent) => event.metaKey,
'shift': (event: KeyboardEvent) => event.shiftKey
};
let fullKey = '';
let key = event.key.toLowerCase();
if (key === ' ') {
key = 'space'; // for readability
} else if (key === '.') {
key = 'dot'; // because '.' is used as a separator in event names
}
modifierKeys.forEach(modifierName => {
if (modifierName != key) {
const modifierGetter = modifierKeyGetters[modifierName];
if (modifierGetter(event)) {
fullKey += modifierName + '.';
}
}
});
return fullKey + key;
}
}
@NgModule({declarations: [KeyEventsApp], bootstrap: [KeyEventsApp], imports: [BrowserModule]})

View File

@ -7,7 +7,6 @@
*/
import {Component, Host, NgModule} from '@angular/core';
import {isPresent, print} from '@angular/core/src/facade/lang';
import {AbstractControl, FormBuilder, FormGroup, FormGroupDirective, ReactiveFormsModule, Validators} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -18,7 +17,7 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
* Custom validator.
*/
function creditCardValidator(c: AbstractControl): {[key: string]: boolean} {
if (isPresent(c.value) && /^\d{16}$/.test(c.value)) {
if (c.value && /^\d{16}$/.test(c.value)) {
return null;
} else {
return {'invalidCreditCard': true};
@ -48,17 +47,17 @@ function creditCardValidator(c: AbstractControl): {[key: string]: boolean} {
`
})
class ShowError {
formDir: any /** TODO #9100 */;
formDir: FormGroupDirective;
controlPath: string;
errorTypes: string[];
constructor(@Host() formDir: FormGroupDirective) { this.formDir = formDir; }
get errorMessage(): string {
var form: FormGroup = this.formDir.form;
var control = form.get(this.controlPath);
if (isPresent(control) && control.touched) {
for (var i = 0; i < this.errorTypes.length; ++i) {
const form: FormGroup = this.formDir.form;
const control = form.get(this.controlPath);
if (control && control.touched) {
for (let i = 0; i < this.errorTypes.length; ++i) {
if (control.hasError(this.errorTypes[i])) {
return this._errorMessage(this.errorTypes[i]);
}
@ -68,8 +67,11 @@ class ShowError {
}
private _errorMessage(code: string): string {
var config = {'required': 'is required', 'invalidCreditCard': 'is invalid credit card number'};
return (config as any /** TODO #9100 */)[code];
const config: {[key: string]: string} = {
'required': 'is required',
'invalidCreditCard': 'is invalid credit card number',
};
return config[code];
}
}
@ -134,7 +136,7 @@ class ShowError {
`
})
class ReactiveForms {
form: any /** TODO #9100 */;
form: FormGroup;
countries = ['US', 'Canada'];
constructor(fb: FormBuilder) {
@ -151,8 +153,8 @@ class ReactiveForms {
}
onSubmit(): void {
print('Submitting:');
print(this.form.value);
console.log('Submitting:');
console.log(this.form.value);
}
}

View File

@ -7,7 +7,6 @@
*/
import {Component, EventEmitter, Injectable, Input, NgModule, Output} from '@angular/core';
import {ListWrapper} from '@angular/core/src/facade/collection';
import {FormsModule} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -40,7 +39,7 @@ class Order {
// ---- services
var _nextId = 1000;
let _nextId = 1000;
@Injectable()
class DataService {
orderItems: OrderItem[];
@ -70,7 +69,7 @@ class DataService {
this.orderItems.push(new OrderItem(_nextId++, order.orderId, '', 0, 0));
}
deleteItem(item: OrderItem): void { ListWrapper.remove(this.orderItems, item); }
deleteItem(item: OrderItem): void { this.orderItems.splice(this.orderItems.indexOf(item), 1); }
}

View File

@ -8,7 +8,6 @@
import {Component, Injectable} from '@angular/core';
import {isPresent} from '@angular/core/src/facade/lang';
import {ActivatedRoute, Router} from '@angular/router';
import * as db from './data';
@ -32,7 +31,7 @@ export class InboxRecord {
lastName: string,
date: string, draft?: boolean
} = null) {
if (isPresent(data)) {
if (data) {
this.setData(data);
}
}
@ -46,42 +45,42 @@ export class InboxRecord {
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 as any /** TODO #9100 */)['first-name'];
this.lastName = (record as any /** TODO #9100 */)['last-name'];
this.date = record['date'];
this.draft = record['draft'] == true;
this.id = record.id;
this.subject = record.subject;
this.content = record.content;
this.email = record.email;
this.firstName = record.firstName;
this.lastName = record.lastName;
this.date = record.date;
this.draft = record.draft === true;
}
}
@Injectable()
export class DbService {
getData(): Promise<any[]> { return Promise.resolve(db.data); }
drafts(): Promise<any[]> {
return this.getData().then(
(data: any[]): any[] =>
data.filter(record => isPresent(record['draft']) && record['draft'] == true));
getData(): Promise<InboxRecord[]> {
return Promise.resolve(db.data.map((entry: {[key: string]: any}) => new InboxRecord({
id: entry['id'],
subject: entry['subject'],
content: entry['content'],
email: entry['email'],
firstName: entry['first-name'],
lastName: entry['last-name'],
date: entry['date'],
draft: entry['draft'],
})));
}
emails(): Promise<any[]> {
return this.getData().then(
(data: any[]): any[] => data.filter(record => !isPresent(record['draft'])));
drafts(): Promise<InboxRecord[]> {
return this.getData().then((data) => data.filter(record => record.draft));
}
email(id: any /** TODO #9100 */): Promise<any> {
return this.getData().then((data: any[]) => {
for (var i = 0; i < data.length; i++) {
var entry = data[i];
if (entry['id'] == id) {
return entry;
}
}
return null;
});
emails(): Promise<InboxRecord[]> {
return this.getData().then((data) => data.filter(record => !record.draft));
}
email(id: string): Promise<InboxRecord> {
return this.getData().then((data) => data.find((entry) => entry.id == id));
}
}
@ -92,17 +91,15 @@ export class InboxCmp {
constructor(public router: Router, db: DbService, route: ActivatedRoute) {
route.params.forEach(p => {
const sortType = p['sort'];
const sortEmailsByDate = isPresent(sortType) && sortType == 'date';
const sortEmailsByDate = p['sort'] === 'date';
db.emails().then((emails: any[]) => {
db.emails().then((emails) => {
this.ready = true;
this.items = emails.map(data => new InboxRecord(data));
this.items = emails;
if (sortEmailsByDate) {
this.items.sort(
(a: InboxRecord, b: InboxRecord) =>
new Date(a.date).getTime() < new Date(b.date).getTime() ? -1 : 1);
(a, b) => new Date(a.date).getTime() < new Date(b.date).getTime() ? -1 : 1);
}
});
});
@ -116,9 +113,9 @@ export class DraftsCmp {
private ready: boolean = false;
constructor(private router: Router, db: DbService) {
db.drafts().then((drafts: any[]) => {
db.drafts().then((drafts) => {
this.ready = true;
this.items = drafts.map(data => new InboxRecord(data));
this.items = drafts;
});
}
}

View File

@ -8,8 +8,7 @@
import {Component, Directive, Host, NgModule} from '@angular/core';
import {isPresent, print} from '@angular/core/src/facade/lang';
import {FormGroup, FormsModule, NG_VALIDATORS, NgForm} from '@angular/forms';
import {FormControl, FormGroup, FormsModule, NG_VALIDATORS, NgForm} from '@angular/forms';
import {BrowserModule} from '@angular/platform-browser';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
@ -33,8 +32,8 @@ class CheckoutModel {
/**
* Custom validator.
*/
function creditCardValidator(c: any /** TODO #9100 */): {[key: string]: boolean} {
if (isPresent(c.value) && /^\d{16}$/.test(c.value)) {
function creditCardValidator(c: FormControl): {[key: string]: boolean} {
if (c.value && /^\d{16}$/.test(c.value)) {
return null;
} else {
return {'invalidCreditCard': true};
@ -74,17 +73,17 @@ class CreditCardValidator {
`
})
class ShowError {
formDir: any /** TODO #9100 */;
formDir: NgForm;
controlPath: string;
errorTypes: string[];
constructor(@Host() formDir: NgForm) { this.formDir = formDir; }
get errorMessage(): string {
var form: FormGroup = this.formDir.form;
var control = form.get(this.controlPath);
if (isPresent(control) && control.touched) {
for (var i = 0; i < this.errorTypes.length; ++i) {
const form: FormGroup = this.formDir.form;
const control = form.get(this.controlPath);
if (control && control.touched) {
for (let i = 0; i < this.errorTypes.length; ++i) {
if (control.hasError(this.errorTypes[i])) {
return this._errorMessage(this.errorTypes[i]);
}
@ -94,8 +93,11 @@ class ShowError {
}
private _errorMessage(code: string): string {
var config = {'required': 'is required', 'invalidCreditCard': 'is invalid credit card number'};
return (config as any /** TODO #9100 */)[code];
const config: {[key: string]: string} = {
'required': 'is required',
'invalidCreditCard': 'is invalid credit card number',
};
return config[code];
}
}
@ -163,8 +165,8 @@ class TemplateDrivenForms {
countries = ['US', 'Canada'];
onSubmit(): void {
print('Submitting:');
print(this.model);
console.log('Submitting:');
console.log(this.model);
}
}
@NgModule({

View File

@ -7,7 +7,6 @@
*/
import {Injectable} from '@angular/core';
import {ListWrapper, Predicate} from '@angular/core/src/facade/collection';
// base model for RecordStore
export abstract class KeyModel {
@ -36,20 +35,9 @@ export class Store<T extends KeyModel> {
add(record: T): void { this.list.push(record); }
remove(record: T): void { this._spliceOut(record); }
remove(record: T): void { this.removeBy((item) => item === record); }
removeBy(callback: Predicate<T>): void {
var records = this.list.filter(callback);
ListWrapper.removeAll(this.list, records);
removeBy(callback: (record: T) => boolean): void {
this.list = this.list.filter((record) => !callback(record));
}
private _spliceOut(record: T) {
var i = this._indexFor(record);
if (i > -1) {
return this.list.splice(i, 1)[0];
}
return null;
}
private _indexFor(record: T) { return this.list.indexOf(record); }
}

View File

@ -18,16 +18,16 @@ class TodoApp {
constructor(public todoStore: Store<Todo>, public factory: TodoFactory) {}
enterTodo(inputElement: any /** TODO #9100 */): void {
enterTodo(inputElement: HTMLInputElement): void {
this.addTodo(inputElement.value);
inputElement.value = '';
}
editTodo(todo: Todo): void { this.todoEdit = todo; }
doneEditing($event: any /** TODO #9100 */, todo: Todo): void {
var which = $event.which;
var target = $event.target;
doneEditing($event: KeyboardEvent, todo: Todo): void {
const which = $event.which;
const target = $event.target as HTMLInputElement;
if (which === 13) {
todo.title = target.value;
this.todoEdit = null;
@ -43,8 +43,8 @@ class TodoApp {
deleteMe(todo: Todo): void { this.todoStore.remove(todo); }
toggleAll($event: any /** TODO #9100 */): void {
var isComplete = $event.target.checked;
toggleAll($event: MouseEvent): void {
const isComplete = ($event.target as HTMLInputElement).checked;
this.todoStore.list.forEach((todo: Todo) => { todo.completed = isComplete; });
}

View File

@ -10,10 +10,10 @@ import {Component, EventEmitter, Input, NgModule, Output, forwardRef} from '@ang
import {BrowserModule} from '@angular/platform-browser';
import {UpgradeAdapter} from '@angular/upgrade';
declare var angular: any;
declare const angular: any;
var styles = [`
const styles = [`
.border {
border: solid 2px DodgerBlue;
}
@ -27,10 +27,10 @@ var styles = [`
}
`];
var adapter = new UpgradeAdapter(forwardRef(() => Ng2AppModule));
var ng1module = angular.module('myExample', []);
const adapter = new UpgradeAdapter(forwardRef(() => Ng2AppModule));
const ng1module = angular.module('myExample', []);
ng1module.controller('Index', function($scope: any /** TODO #9100 */) { $scope.name = 'World'; });
ng1module.controller('Index', function($scope: any) { $scope.name = 'World'; });
ng1module.directive('ng1User', function() {
return {

View File

@ -6,7 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
declare module 'B64' {
export function fromByteArray(arr: Uint8Array): string;
export function toByteArray(str: string): Uint8Array;
}
declare namespace base64js {
function fromByteArray(arr: Uint8Array): string;
function toByteArray(str: string): Uint8Array;
}
export = base64js;

View File

@ -1,16 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
declare class Bitmap {
constructor(width: number, height: number);
subsample(n: number): void;
dataURL(): string;
pixel: [any];
}

View File

@ -1,127 +0,0 @@
/*
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

@ -1,14 +0,0 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
var _FileReader = FileReader;
export {_FileReader as FileReader};
export class Uint8ArrayWrapper {
static create(buffer: ArrayBuffer) { return new Uint8Array(buffer); }
}

View File

@ -8,20 +8,19 @@
import {Component} from '@angular/core';
import {FileReader, Uint8ArrayWrapper} from './file_api';
import {BitmapService} from './services/bitmap';
@Component({selector: 'image-demo', viewProviders: [BitmapService], templateUrl: 'image_demo.html'})
export class ImageDemo {
images: any[] /** TODO #9100 */ = [];
images: {src: string, buffer: ArrayBuffer, filtering: boolean}[] = [];
fileInput: String;
constructor(private _bitmapService: BitmapService) {}
uploadFiles(files: any /** TODO #9100 */) {
for (var i = 0; i < files.length; i++) {
var reader = new FileReader();
uploadFiles(files: FileList) {
for (let i = 0; i < files.length; i++) {
const reader = new FileReader();
reader.addEventListener('load', this.handleReaderLoad(reader));
reader.readAsArrayBuffer(files[i]);
}
@ -29,9 +28,9 @@ export class ImageDemo {
handleReaderLoad(reader: FileReader): EventListener {
return (e) => {
var buffer = reader.result;
const buffer = reader.result as ArrayBuffer;
this.images.push({
src: this._bitmapService.arrayBufferToDataUri(Uint8ArrayWrapper.create(reader.result)),
src: this._bitmapService.arrayBufferToDataUri(new Uint8Array(buffer)),
buffer: buffer,
filtering: false
});
@ -39,16 +38,16 @@ export class ImageDemo {
}
applyFilters() {
for (var i = 0; i < this.images.length; i++) {
for (let i = 0; i < this.images.length; i++) {
this.images[i].filtering = true;
setTimeout(this._filter(i), 0);
}
}
private _filter(i: number): (...args: any[]) => void {
private _filter(i: number): () => void {
return () => {
var imageData = this._bitmapService.convertToImageData(this.images[i].buffer);
let 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

@ -22,6 +22,7 @@ System.config({
'@angular/compiler': {main: 'index.js', defaultExtension: 'js'},
'@angular/common': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-webworker': {main: 'index.js', defaultExtension: 'js'},
'@angular/platform-webworker-dynamic': {main: 'index.js', defaultExtension: 'js'},
'@angular/router': {main: 'index.js', defaultExtension: 'js'},

View File

@ -6,31 +6,25 @@
* found in the LICENSE file at https://angular.io/license
*/
/// <reference path="../bitmap.d.ts" /> /// <reference path="../b64.d.ts" />
import {Injectable} from '@angular/core';
declare var base64js: any /** TODO #9100 */;
// Temporary fix for Typescript issue #4220 (https://github.com/Microsoft/TypeScript/issues/4220)
// var _ImageData: (width: number, height: number) => void = <any>postMessage;
var _ImageData: {prototype: ImageData, new (width: number, height: number): ImageData;} = ImageData;
import * as base64js from '../b64';
// This class is based on the Bitmap examples at:
// http://www.i-programmer.info/projects/36-web/6234-reading-a-bmp-file-in-javascript.html
// and
// http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
// and http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
@Injectable()
export class BitmapService {
convertToImageData(buffer: ArrayBuffer): ImageData {
var bmp = this._getBMP(buffer);
const bmp = this._getBMP(buffer);
return this._BMPToImageData(bmp);
}
applySepia(imageData: ImageData): ImageData {
var buffer = imageData.data;
for (var i = 0; i < buffer.length; i += 4) {
var r = buffer[i];
var g = buffer[i + 1];
var b = buffer[i + 2];
const buffer = imageData.data;
for (let i = 0; i < buffer.length; i += 4) {
const r = buffer[i];
const g = buffer[i + 1];
const b = buffer[i + 2];
buffer[i] = (r * .393) + (g * .769) + (b * .189);
buffer[i + 1] = (r * .349) + (g * .686) + (b * .168);
buffer[i + 2] = (r * .272) + (g * .534) + (b * .131);
@ -39,7 +33,7 @@ export class BitmapService {
}
toDataUri(imageData: ImageData): string {
var header = this._createBMPHeader(imageData);
const header = this._createBMPHeader(imageData);
imageData = this._imageDataToBMP(imageData);
return 'data:image/bmp;base64,' + btoa(header) + base64js.fromByteArray(imageData.data);
}
@ -51,14 +45,14 @@ export class BitmapService {
// returns a UInt8Array in BMP order (starting from the bottom)
private _imageDataToBMP(imageData: ImageData): ImageData {
var width = imageData.width;
var height = imageData.height;
const width = imageData.width;
const height = imageData.height;
var data = imageData.data;
for (var y = 0; y < height / 2; ++y) {
var topIndex = y * width * 4;
var bottomIndex = (height - y) * width * 4;
for (var i = 0; i < width * 4; i++) {
const data = imageData.data;
for (let y = 0; y < height / 2; ++y) {
let topIndex = y * width * 4;
let bottomIndex = (height - y) * width * 4;
for (let i = 0; i < width * 4; i++) {
this._swap(data, topIndex, bottomIndex);
topIndex++;
bottomIndex++;
@ -69,7 +63,7 @@ export class BitmapService {
}
private _swap(data: Uint8Array|Uint8ClampedArray|number[], index1: number, index2: number) {
var temp = data[index1];
const temp = data[index1];
data[index1] = data[index2];
data[index2] = temp;
}
@ -77,9 +71,9 @@ export class BitmapService {
// Based on example from
// http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
private _createBMPHeader(imageData: ImageData): string {
var numFileBytes = this._getLittleEndianHex(imageData.width * imageData.height);
var w = this._getLittleEndianHex(imageData.width);
var h = this._getLittleEndianHex(imageData.height);
const numFileBytes = this._getLittleEndianHex(imageData.width * imageData.height);
const w = this._getLittleEndianHex(imageData.width);
const h = this._getLittleEndianHex(imageData.height);
return 'BM' + // Signature
numFileBytes + // size of the file (bytes)*
'\x00\x00' + // reserved
@ -99,18 +93,18 @@ export class BitmapService {
}
private _BMPToImageData(bmp: BitmapFile): ImageData {
var width = bmp.infoHeader.biWidth;
var height = bmp.infoHeader.biHeight;
var imageData = new _ImageData(width, height);
const width = bmp.infoHeader.biWidth;
const height = bmp.infoHeader.biHeight;
const imageData = new ImageData(width, height);
var data = imageData.data;
var bmpData = bmp.pixels;
var stride = bmp.stride;
const data = imageData.data;
const bmpData = bmp.pixels;
const stride = bmp.stride;
for (var y = 0; y < height; ++y) {
for (var x = 0; x < width; ++x) {
var index1 = (x + width * (height - y)) * 4;
var index2 = x * 3 + stride * y;
for (let y = 0; y < height; ++y) {
for (let x = 0; x < width; ++x) {
const index1 = (x + width * (height - y)) * 4;
const index2 = x * 3 + stride * y;
data[index1] = bmpData[index2 + 2];
data[index1 + 1] = bmpData[index2 + 1];
data[index1 + 2] = bmpData[index2];
@ -121,8 +115,8 @@ export class BitmapService {
}
private _getBMP(buffer: ArrayBuffer): BitmapFile {
var datav = new DataView(buffer);
var bitmap: BitmapFile = {
const datav = new DataView(buffer);
const bitmap: BitmapFile = {
fileHeader: {
bfType: datav.getUint16(0, true),
bfSize: datav.getUint32(2, true),
@ -146,7 +140,7 @@ export class BitmapService {
stride: null,
pixels: null
};
var start = bitmap.fileHeader.bfOffBits;
const start = bitmap.fileHeader.bfOffBits;
bitmap.stride =
Math.floor((bitmap.infoHeader.biBitCount * bitmap.infoHeader.biWidth + 31) / 32) * 4;
bitmap.pixels = new Uint8Array(datav.buffer, start);
@ -156,9 +150,9 @@ export class BitmapService {
// Based on example from
// http://www.worldwidewhat.net/2012/07/how-to-draw-bitmaps-using-javascript/
private _getLittleEndianHex(value: number): string {
var result: any[] /** TODO #9100 */ = [];
const result: string[] = [];
for (var bytes = 4; bytes > 0; bytes--) {
for (let bytes = 4; bytes > 0; bytes--) {
result.push(String.fromCharCode(value & 255));
value >>= 8;
}

View File

@ -26,7 +26,7 @@ export class InputCmp {
inputVal = '';
textareaVal = '';
inputChanged(e: any /** TODO #9100 */) { this.inputVal = e.target.value; }
inputChanged(e: Event) { this.inputVal = (e.target as HTMLInputElement).value; }
textAreaChanged(e: any /** TODO #9100 */) { this.textareaVal = e.target.value; }
textAreaChanged(e: Event) { this.textareaVal = (e.target as HTMLTextAreaElement).value; }
}

View File

@ -23,7 +23,6 @@ export class RedDec {
constructor(el: ElementRef, renderer: Renderer) {
renderer.setElementStyle(el.nativeElement, 'color', 'red');
}
// constructor(renderer: Renderer) {}
}
// Angular 2.0 supports 2 basic types of directives:
@ -54,7 +53,5 @@ export class HelloCmp {
changeGreeting(): void { this.greeting = 'howdy'; }
onKeyDown(event: any /** TODO #9100 */): void {
this.lastKey = String.fromCharCode(event.keyCode);
}
onKeyDown(event: KeyboardEvent): void { this.lastKey = String.fromCharCode(event.keyCode); }
}

View File

@ -18,15 +18,15 @@ export class TodoApp {
hideCompleted: boolean = false;
isComplete: boolean = false;
constructor(public todoStore: Store, public factory: TodoFactory) {}
constructor(public todoStore: Store<Todo>, public factory: TodoFactory) {}
enterTodo(): void {
this.addTodo(this.inputValue);
this.inputValue = '';
}
doneEditing($event: any /** TODO #9100 */, todo: Todo): void {
var which = $event.keyCode;
doneEditing($event: KeyboardEvent, todo: Todo): void {
const which = $event.keyCode;
if (which === 13) {
todo.title = todo.editTitle;
this.todoEdit = null;
@ -59,7 +59,7 @@ export class TodoApp {
deleteMe(todo: Todo): void { this.todoStore.remove(todo); }
toggleAll($event: any /** TODO #9100 */): void {
toggleAll($event: MouseEvent): void {
this.isComplete = !this.isComplete;
this.todoStore.list.forEach((todo: Todo) => { todo.completed = this.isComplete; });
}

View File

@ -7,7 +7,6 @@
*/
import {Injectable} from '@angular/core';
import {ListWrapper, Predicate} from '@angular/core/src/facade/collection';
// base model for RecordStore
export class KeyModel {
@ -35,25 +34,14 @@ export class TodoFactory {
// Store manages any generic item that inherits from KeyModel
@Injectable()
export class Store {
list: KeyModel[] = [];
export class Store<T extends KeyModel> {
list: T[] = [];
add(record: KeyModel): void { this.list.push(record); }
add(record: T): void { this.list.push(record); }
remove(record: KeyModel): void { this._spliceOut(record); }
remove(record: T): void { this.removeBy((item) => item === record); }
removeBy(callback: Predicate<KeyModel>): void {
var records = this.list.filter(callback);
ListWrapper.removeAll(this.list, records);
removeBy(callback: (record: T) => boolean): void {
this.list = this.list.filter((record) => !callback(record));
}
private _spliceOut(record: KeyModel) {
var i = this._indexFor(record);
if (i > -1) {
return this.list.splice(i, 1)[0];
}
return null;
}
private _indexFor(record: KeyModel) { return this.list.indexOf(record); }
}