Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions nativescript-angular/animation-driver.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { AnimationKeyframe } from '@angular/core/src/animation/animation_keyframe';
import { AnimationPlayer } from '@angular/core/src/animation/animation_player';
import { AnimationStyles } from '@angular/core/src/animation/animation_styles';
import { AnimationDriver } from '@angular/platform-browser/src/dom/animation_driver';
import { AnimationPlayer, AnimationStyles, AnimationKeyframe } from "./private_import_core";
import { NativeScriptAnimationPlayer } from './animation-player';
import {View} from "ui/core/view";
import styleProperty = require('ui/styling/style-property');

export abstract class AnimationDriver {
abstract animate(
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
duration: number, delay: number, easing: string): AnimationPlayer;
}

export class NativeScriptAnimationDriver implements AnimationDriver {

computeStyle(element: any, prop: string): string {
Expand Down
23 changes: 16 additions & 7 deletions nativescript-angular/animation-player.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AnimationKeyframe } from '@angular/core/src/animation/animation_keyframe';
import { AnimationPlayer } from '@angular/core/src/animation/animation_player';
import { AnimationPlayer, AnimationKeyframe } from "./private_import_core";
import { KeyframeAnimation, KeyframeAnimationInfo, KeyframeInfo, KeyframeDeclaration } from 'ui/animation/keyframe-animation';
import { View } from "ui/core/view";
import enums = require("ui/enums");
Expand All @@ -11,7 +10,8 @@ export class NativeScriptAnimationPlayer implements AnimationPlayer {

public parentPlayer: AnimationPlayer;

private _subscriptions: Function[] = [];
private _startSubscriptions: Function[] = [];
private _doneSubscriptions: Function[] = [];
private _finished = false;
private _started = false;
private animation: KeyframeAnimation;
Expand Down Expand Up @@ -72,20 +72,29 @@ export class NativeScriptAnimationPlayer implements AnimationPlayer {
}


onDone(fn: Function): void { this._subscriptions.push(fn); }
onStart(fn: Function): void { this._startSubscriptions.push(fn); }
onDone(fn: Function): void { this._doneSubscriptions.push(fn); }

private _onStart() {
if (!this._started) {
this._started = true;
this._startSubscriptions.forEach(fn => fn());
this._startSubscriptions = [];
}
}

private _onFinish() {
if (!this._finished) {
this._finished = true;
this._started = false;
this._subscriptions.forEach(fn => fn());
this._subscriptions = [];
this._doneSubscriptions.forEach(fn => fn());
this._doneSubscriptions = [];
}
}

play(): void {
if (this.animation) {
this._started = true;
this._onStart();
this.animation.play(this.target)
.then(() => { this._onFinish(); })
.catch((e) => { });
Expand Down
196 changes: 196 additions & 0 deletions nativescript-angular/collection-facade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
//Copied unexported functions from @angular/core/src/facade/collection
import {
isJsObject, isArray, getSymbolIterator,
isPresent, isBlank
} from "./lang-facade";

export function isListLikeIterable(obj: any): boolean {
if (!isJsObject(obj)) return false;
return isArray(obj) ||
(!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v]
getSymbolIterator() in obj); // JS Iterable have a Symbol.iterator prop
}

export class ListWrapper {
// JS has no way to express a statically fixed size list, but dart does so we
// keep both methods.
static createFixedSize(size: number): any[] { return new Array(size); }
static createGrowableSize(size: number): any[] { return new Array(size); }
static clone<T>(array: T[]): T[] { return array.slice(0); }
static forEachWithIndex<T>(array: T[], fn: (t: T, n: number) => void) {
for (var i = 0; i < array.length; i++) {
fn(array[i], i);
}
}
static first<T>(array: T[]): T {
if (!array) return null;
return array[0];
}
static last<T>(array: T[]): T {
if (!array || array.length == 0) return null;
return array[array.length - 1];
}
static indexOf<T>(array: T[], value: T, startIndex: number = 0): number {
return array.indexOf(value, startIndex);
}
static contains<T>(list: T[], el: T): boolean { return list.indexOf(el) !== -1; }
static reversed<T>(array: T[]): T[] {
var a = ListWrapper.clone(array);
return a.reverse();
}
static concat(a: any[], b: any[]): any[] { return a.concat(b); }
static insert<T>(list: T[], index: number, value: T) { list.splice(index, 0, value); }
static removeAt<T>(list: T[], index: number): T {
var res = list[index];
list.splice(index, 1);
return res;
}
static removeAll<T>(list: T[], items: T[]) {
for (var i = 0; i < items.length; ++i) {
var index = list.indexOf(items[i]);
list.splice(index, 1);
}
}
static remove<T>(list: T[], el: T): boolean {
var index = list.indexOf(el);
if (index > -1) {
list.splice(index, 1);
return true;
}
return false;
}
static clear(list: any[]) { list.length = 0; }
static isEmpty(list: any[]): boolean { return list.length == 0; }
static fill(list: any[], value: any, start: number = 0, end: number = null) {
(<any>list).fill(value, start, end === null ? list.length : end);
}
static equals(a: any[], b: any[]): boolean {
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
static slice<T>(l: T[], from: number = 0, to: number = null): T[] {
return l.slice(from, to === null ? undefined : to);
}
static splice<T>(l: T[], from: number, length: number): T[] { return l.splice(from, length); }
static sort<T>(l: T[], compareFn?: (a: T, b: T) => number) {
if (isPresent(compareFn)) {
l.sort(compareFn);
} else {
l.sort();
}
}
static toString<T>(l: T[]): string { return l.toString(); }
static toJSON<T>(l: T[]): string { return JSON.stringify(l); }

static maximum<T>(list: T[], predicate: (t: T) => number): T {
if (list.length == 0) {
return null;
}
var solution: any /** TODO #???? */ = null;
var maxValue = -Infinity;
for (var index = 0; index < list.length; index++) {
var candidate = list[index];
if (isBlank(candidate)) {
continue;
}
var candidateValue = predicate(candidate);
if (candidateValue > maxValue) {
solution = candidate;
maxValue = candidateValue;
}
}
return solution;
}

static flatten<T>(list: Array<T|T[]>): T[] {
var target: any[] = [];
_flattenArray(list, target);
return target;
}

static addAll<T>(list: Array<T>, source: Array<T>): void {
for (var i = 0; i < source.length; i++) {
list.push(source[i]);
}
}
}

function _flattenArray(source: any[], target: any[]): any[] {
if (isPresent(source)) {
for (var i = 0; i < source.length; i++) {
var item = source[i];
if (isArray(item)) {
_flattenArray(item, target);
} else {
target.push(item);
}
}
}
return target;
}

export class StringMapWrapper {
static create(): {[k: /*any*/ string]: any} {
// Note: We are not using Object.create(null) here due to
// performance!
// http://jsperf.com/ng2-object-create-null
return {};
}
static contains(map: {[key: string]: any}, key: string): boolean {
return map.hasOwnProperty(key);
}
static get<V>(map: {[key: string]: V}, key: string): V {
return map.hasOwnProperty(key) ? map[key] : undefined;
}
static set<V>(map: {[key: string]: V}, key: string, value: V) { map[key] = value; }

static keys(map: {[key: string]: any}): string[] { return Object.keys(map); }
static values<T>(map: {[key: string]: T}): T[] {
return Object.keys(map).map((k: string): T => map[k]);
}
static isEmpty(map: {[key: string]: any}): boolean {
for (var prop in map) {
return false;
}
return true;
}
static delete (map: {[key: string]: any}, key: string) { delete map[key]; }
static forEach<K, V>(map: {[key: string]: V}, callback: (v: V, K: string) => void) {
for (let k of Object.keys(map)) {
callback(map[k], k);
}
}

static merge<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): {[key: string]: V} {
var m: {[key: string]: V} = {};

for (let k of Object.keys(m1)) {
m[k] = m1[k];
}

for (let k of Object.keys(m2)) {
m[k] = m2[k];
}

return m;
}

static equals<V>(m1: {[key: string]: V}, m2: {[key: string]: V}): boolean {
var k1 = Object.keys(m1);
var k2 = Object.keys(m2);
if (k1.length != k2.length) {
return false;
}
var key: any /** TODO #???? */;
for (var i = 0; i < k1.length; i++) {
key = k1[i];
if (m1[key] !== m2[key]) {
return false;
}
}
return true;
}
}
71 changes: 21 additions & 50 deletions nativescript-angular/common/detached-loader.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {ComponentRef, ComponentFactory, ViewContainerRef, Component,
Type, ViewChild, ComponentResolver, ChangeDetectorRef, Host} from '@angular/core';
import {
ComponentRef, ComponentFactory, ViewContainerRef,
Component, Type, ViewChild, Compiler,
ComponentFactoryResolver, ChangeDetectorRef, Host
} from '@angular/core';
import trace = require("trace");

type AnyComponentRef = ComponentRef<any>;
interface PendingLoadEntry {
componentType: Type;
componentType: Type<any>;
resolveCallback: (AnyComponentRef) => void;
}

Expand All @@ -23,58 +26,26 @@ function log(message: string) {
template: `<Placeholder #loader></Placeholder>`
})
export class DetachedLoader {
@ViewChild('loader', { read: ViewContainerRef }) childContainerRef: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver, private changeDetector: ChangeDetectorRef, private containerRef: ViewContainerRef) { }

private viewLoaded = false;
private pendingLoads: PendingLoadEntry[] = [];
private loadInLocation(componentType: Type<any>): Promise<ComponentRef<any>> {
const factory = this.resolver.resolveComponentFactory(componentType)
const componentRef = this.containerRef.createComponent(
factory, this.containerRef.length, this.containerRef.parentInjector);

constructor(private compiler: ComponentResolver, private changeDetector: ChangeDetectorRef, private containerRef: ViewContainerRef) { }
// Component is created, buit may not be checked if we are loading
// inside component with OnPush CD strategy. Mark us for check to be sure CD will reach us.
// We are inside a promise here so no need for setTimeout - CD should trigger after the promise.
log("DetachedLoader.loadInLocation component loaded -> markForCheck");
this.changeDetector.markForCheck();

public ngAfterViewInit() {
log("DetachedLoader.ngAfterViewInit");

this.viewLoaded = true;
this.pendingLoads.forEach(loadEntry => {
this.loadInLocation(loadEntry.componentType).then(loadedRef => {
loadEntry.resolveCallback(loadedRef);
});
});
}

private loadInLocation(componentType: Type): Promise<ComponentRef<any>> {
return this.compiler.resolveComponent(componentType).then((componentFactory) => {
return this.childContainerRef.createComponent(componentFactory, this.childContainerRef.length, this.childContainerRef.parentInjector, null);
}).then((compRef) => {
log("DetachedLoader.loadInLocation component loaded -> markForCheck");
// Component is created, buit may not be checked if we are loading
// inside component with OnPush CD strategy. Mark us for check to be sure CD will reach us.
// We are inside a promise here so no need for setTimeout - CD should trigger after the promise.
this.changeDetector.markForCheck();
return compRef;
})
return Promise.resolve(componentRef);
}

public loadComponent(componentType: Type): Promise<ComponentRef<any>> {
log("DetachedLoader.loadComponent viewLoaded: " + this.viewLoaded);

// Check if called before placeholder is initialized.
// Delay load if so.
if (this.viewLoaded) {
return this.loadInLocation(componentType);
} else {
// loadComponent called, but detached-loader is still not initialized.
// Mark it for change and trigger change detection to be sure it will be initialized,
// so that loading can conitionue.
log("DetachedLoader.loadComponent -> markForCheck(with setTimeout())")
setTimeout(() => this.changeDetector.markForCheck(), 0);

return new Promise((resolve, reject) => {
this.pendingLoads.push({
componentType: componentType,
resolveCallback: resolve
});
});
}
//TODO: change this API -- async promises not needed here anymore.
public loadComponent(componentType: Type<any>): Promise<ComponentRef<any>> {
log("DetachedLoader.loadComponent");
return this.loadInLocation(componentType);
}

public loadWithFactory<T>(factory: ComponentFactory<T>): ComponentRef<T> {
Expand Down
4 changes: 2 additions & 2 deletions nativescript-angular/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {isBlank, isNumber} from '@angular/core/src/facade/lang';
import {isBlank, isNumber} from "../lang-facade";

export function convertToInt(value): number {
let normalizedValue;
Expand All @@ -13,4 +13,4 @@ export function convertToInt(value): number {
}
}
return Math.round(normalizedValue);
}
}
6 changes: 2 additions & 4 deletions nativescript-angular/directives.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import {Type} from '@angular/core/src/facade/lang';
import {ListViewComponent, SetupItemViewArgs} from './directives/list-view-comp';
import {TabViewDirective, TabViewItemDirective} from './directives/tab-view';
import {ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective} from './directives/action-bar';
import {AndroidFilterComponent, IosFilterComponent} from './directives/platform-filters';


export const NS_DIRECTIVES: Type[] = [
export const NS_DIRECTIVES = [
ListViewComponent,
TabViewDirective,
TabViewItemDirective,
Expand All @@ -14,7 +12,7 @@ export const NS_DIRECTIVES: Type[] = [
ActionItemDirective,
NavigationButtonDirective,
AndroidFilterComponent,
IosFilterComponent
IosFilterComponent,
];

export {ListViewComponent, SetupItemViewArgs} from './directives/list-view-comp';
Expand Down
Loading