diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bc06953..8b6d183 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -222,4 +222,4 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html [js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml [stackoverflow]: http://stackoverflow.com/questions/tagged/angular -[seed]: https://github.com/mlaval/angular2-react-native-seed +[seed]: https://github.com/mlaval/angular-react-native-seed diff --git a/README.md b/README.md index c882ea8..97a6894 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ [![Join the chat at https://gitter.im/angular/react-native-renderer](https://badges.gitter.im/angular/react-native-renderer.svg)](https://gitter.im/angular/react-native-renderer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/angular/react-native-renderer.svg?branch=master)](https://travis-ci.org/angular/react-native-renderer) -# angular2-react-native +# angular-react-native -Use Angular 2 and React Native to build applications for Android and iOS. +Use Angular and React Native to build applications for Android and iOS. ## Documentation http://angular.github.io/react-native-renderer/ @@ -13,7 +13,7 @@ http://angular.github.io/react-native-renderer/ ### Preparing your environment * Set up React Native for iOS and/or Android following [Getting started](https://facebook.github.io/react-native/docs/getting-started.html) and [Android setup](https://facebook.github.io/react-native/docs/android-setup.htmlt) * Clone this repository or a fork of it -* Install Gulp, React Native CLI and Typings globally: `npm install -g gulp react-native-cli typings` +* Install Gulp and React Native CLI globally: `npm install -g gulp react-native-cli` * Install local npm modules: `npm install` ### Running scripts diff --git a/doc/pages/_layout.jade b/doc/pages/_layout.jade index 6510a65..457752b 100644 --- a/doc/pages/_layout.jade +++ b/doc/pages/_layout.jade @@ -5,7 +5,7 @@ html(lang=en) meta(http-equiv="X-UA-Compatible" content="IE=edge") meta(name="viewport" content="width=device-width, initial-scale=1") title react-native-renderer - link(rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css") + link(rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css") style(type='text/css'). body { padding-top: 50px; diff --git a/doc/pages/apis.jade b/doc/pages/apis.jade index dc39d8d..3f71aa7 100644 --- a/doc/pages/apis.jade +++ b/doc/pages/apis.jade @@ -8,7 +8,7 @@ block content # APIs and polyfills React Native provides a set of APIs and polyfills which allow applications to access native features from JavaScript. - All of them can be directly used within an Angular 2 application. + All of them can be directly used within an Angular application. When needed, they are patched so that callbacks are executed in the Angular [Zone](https://github.com/angular/zone.js). diff --git a/doc/pages/bootstrap.jade b/doc/pages/bootstrap.jade index 3c72c88..2351c9e 100644 --- a/doc/pages/bootstrap.jade +++ b/doc/pages/bootstrap.jade @@ -12,7 +12,7 @@ block content To bootstrap an application with JIT compilation, you must use the special methods `bootstrapReactNativeJIT`. ``` - import {bootstrapReactNativeJIT} from 'angular2-react-native/jit'; + import {bootstrapReactNativeJIT} from 'angular-react-native/jit'; import {MyAppModule} from "./app/module"; bootstrapReactNativeJIT('myApp', MyAppModule); @@ -23,7 +23,7 @@ block content To bootstrap an application with AOT compilation, you must use the special methods `bootstrapReactNativeAOT`. ``` - import {bootstrapReactNativeAOT} from 'angular2-react-native/aot'; + import {bootstrapReactNativeAOT} from 'angular-react-native/aot'; import {MyAppModuleNgFactory} from "./app/module.ngfactory"; bootstrapReactNativeAOT('myApp', MyAppModule); diff --git a/doc/pages/getting_started.jade b/doc/pages/getting_started.jade index 2d2aa05..be95d2e 100644 --- a/doc/pages/getting_started.jade +++ b/doc/pages/getting_started.jade @@ -7,13 +7,13 @@ block content :marked # Getting started - Creating an application with Angular 2 and React Native means creating an actual React Native project, in which an Angular 2 application runs. + Creating an application with Angular and React Native means creating an actual React Native project, in which an Angular application runs. - As a consequence, all the Angular 2 features are available to you: http, router, directives, dependency injection, etc. + As a consequence, all the Angular features are available to you: http, router, directives, dependency injection, etc. And, at the same time, all the React Native tools and features are also available. The only exception are the high-level React components (View, Picker, Text, Image, etc), - but they all exist as ambient Angular2 components that can be used in applications. + but they all exist as ambient Angular components that can be used in applications. ## Setup Please check the React Native documentation for: @@ -23,12 +23,12 @@ block content - [Linux and Windows support](https://facebook.github.io/react-native/docs/linux-windows-support.html#content) ## First application - For a quick start, clone the [seed application](https://github.com/mlaval/angular2-react-native-seed) and follow the instructions in the README. + For a quick start, clone the [seed application](https://github.com/mlaval/angular-react-native-seed) and follow the instructions in the README. The steps are: ``` - git clone https://github.com/mlaval/angular2-react-native-seed.git - cd angular2-react-native-seed + git clone https://github.com/mlaval/angular-react-native-seed.git + cd angular-react-native-seed npm install -g gulp react-native-cli typings npm install gulp init @@ -38,5 +38,5 @@ block content ``` ## Going further - Most guides from the [React Native documentation](https://facebook.github.io/react-native/docs/) are applicable. + Most guides from the [React Native documentation](https://facebook.github.io/react-native/docs/getting-started.html) are applicable. They are a valuable source of information, expecially when it comes to performance, debugging, etc. diff --git a/doc/pages/http.jade b/doc/pages/http.jade index 4d24f8f..b37caf3 100644 --- a/doc/pages/http.jade +++ b/doc/pages/http.jade @@ -7,7 +7,7 @@ block content :marked # Http - The http module of Angular 2 can be used as is in applications. + The http module of Angular can be used as is in applications. The only thing to be done is to import `ReactNativeHttpModule` in the main module of the application (see below). Behind the scene, it uses the [Network polyfill](https://facebook.github.io/react-native/docs/network.html) provided by React Native. @@ -28,7 +28,7 @@ block content import {NgFor} from '@angular/common'; import {Http} from '@angular/http'; import 'rxjs/add/operator/map'; - import {TextInput} from 'angular2-react-native'; + import {TextInput} from 'angular-react-native'; @Component({ selector: 'example', diff --git a/doc/pages/index.jade b/doc/pages/index.jade index ebe621a..2c0c68e 100644 --- a/doc/pages/index.jade +++ b/doc/pages/index.jade @@ -8,6 +8,6 @@ block content h1 | => img(src="./assets/phone.png", style="top:0px") - h3(style="margin-bottom:50px;") Angular 2 and React Native to build applications for Android and iOS + h3(style="margin-bottom:50px;") Angular and React Native to build applications for Android and iOS a(href="./getting_started.html", style="padding: 20px;background-color:#0273D4;color:white;display: block;width: 150px;border-radius: 10px;text-align: center; font-size: 20px;margin: auto;") Get started diff --git a/doc/pages/router.jade b/doc/pages/router.jade index d41a656..d5bae69 100644 --- a/doc/pages/router.jade +++ b/doc/pages/router.jade @@ -7,7 +7,7 @@ block content :marked # Router - The rooter module of Angular 2 can be used as is in applications. + The rooter module of Angular can be used as is in applications. The only thing to be done is to import `ReactNativeRouterModule` in the main module of the application (see below), and use the static `RouterModule.forRoot` method to configure routes. diff --git a/doc/pages/style.jade b/doc/pages/style.jade index 2ba3622..6a2b40c 100644 --- a/doc/pages/style.jade +++ b/doc/pages/style.jade @@ -9,7 +9,7 @@ block content React Native provides a styling mechanism which relies on JavaScript. Read more about it in the [documentation about Style](https://facebook.github.io/react-native/docs/style.html). - In all the Angular 2 components, there are 2 properties related to style: + In all the Angular components, there are 2 properties related to style: - `styleSheet`: it takes one or more `StyleSheet` created with the React Native's API. - `style`: it takes a set of styling properties as a JSON object. ***It overrides what has been defined in `styleSheet`*** diff --git a/doc/parser.js b/doc/parser.js index f74a66d..fc87c9a 100644 --- a/doc/parser.js +++ b/doc/parser.js @@ -35,11 +35,11 @@ function visit(sourceFile) { return data; function visitNode(node) { - var commentRanges = ts.getJsDocComments(node, sourceFile); - if (commentRanges) { - commentRanges.forEach(function (commentRange) { + var jsDocs = ts.getJSDocs(node); + if (jsDocs) { + jsDocs.forEach(function (jsDoc) { var content = sourceFile.text - .substring(commentRange.pos + 3, commentRange.end - 2) + .substring(jsDoc.pos + 3, jsDoc.end - 2) .replace(LEADING_STAR_REGEX, '') .trim(); if (content) { diff --git a/gulpfile.js b/gulpfile.js index 6a2705c..c6fb9a7 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,7 +1,6 @@ var fs = require('fs'); var gulp = require('gulp'); -const babel = require('gulp-babel'); var jade = require('gulp-jade'); var rename = require('gulp-rename'); var typescript = require('gulp-typescript'); @@ -34,20 +33,11 @@ var PATHS = { tmp: 'dist/tmp', publish: 'dist/publish', modules: [ + 'node_modules/@angular/**/*', 'node_modules/hammerjs/**/*', 'node_modules/reflect-metadata/**/*', 'node_modules/rxjs/**/*', 'node_modules/zone.js/**/*' - ], - es6Modules: [ - 'node_modules/@angular/common/**/*.js', '!node_modules/@angular/common/bundles/*', - 'node_modules/@angular/compiler/**/*.js', '!node_modules/@angular/compiler/bundles/*', - 'node_modules/@angular/core/**/*.js', '!node_modules/@angular/core/bundles/*', - 'node_modules/@angular/http/**/*.js', '!node_modules/@angular/http/bundles/*', - 'node_modules/@angular/platform-browser/**/*.js', '!node_modules/@angular/platform-browser/bundles/*', - 'node_modules/@angular/platform-browser-dynamic/**/*.js', '!node_modules/@angular/platform-browser-dynamic/bundles/*', - 'node_modules/@angular/platform-server/**/*.js', '!node_modules/@angular/platform-server/bundles/*', - 'node_modules/@angular/router/**/*.js', '!node_modules/@angular/router/bundles/*', ] }; @@ -64,22 +54,18 @@ gulp.task('!create', ['clean'], function(done) { executeInAppDir('react-native init ' + APP_NAME, done, true); }); gulp.task('!postcreate', ['!create'], function() { + gulp.src(PATHS.app + '/' + APP_NAME + '/node_modules/react-native/Libraries/Renderer/ReactNativeStack*') + .pipe(transformReactNativeStack()) + .pipe(gulp.dest(PATHS.app + '/' + APP_NAME + '/node_modules/react-native/Libraries/Renderer/')); return gulp.src(PATHS.app + '/' + APP_NAME + '/android/app/src/main/AndroidManifest.xml') .pipe(transformAndroidManifest()) .pipe(gulp.dest(PATHS.app + '/' + APP_NAME + '/android/app/src/main/')); }); -gulp.task('!ng2commonjs', ['!postcreate'], function() { - return gulp.src(PATHS.es6Modules, {base: 'node_modules'}) - .pipe(babel({ - presets: ['es2015'] - })) +gulp.task('init', ['!postcreate'], function() { + return gulp.src(PATHS.modules, { base: './node_modules/' }) .pipe(gulp.dest(PATHS.app + '/' + APP_NAME + '/node_modules')); }); -gulp.task('init', ['!ng2commonjs'], function() { - var copier = require('./tools/copy-dependencies'); - return copier.doCopy(PATHS.modules, PATHS.app + '/' + APP_NAME + '/node_modules'); -}); //--------------------------- JIT compilation--------------------------- gulp.task('!assets', function () { @@ -89,7 +75,7 @@ gulp.task('!transpile', ['!assets'], function () { return ts2js([PATHS.sources.sample, PATHS.sources.src], PATHS.tmp, false, false); }); gulp.task('!copyToNodeModules', ['!transpile'], function () { - return gulp.src(PATHS.tmp + '/src/**/*').pipe(gulp.dest(PATHS.app + '/' + APP_NAME + '/node_modules/angular2-react-native')); + return gulp.src(PATHS.tmp + '/src/**/*').pipe(gulp.dest(PATHS.app + '/' + APP_NAME + '/node_modules/angular-react-native')); }); gulp.task('compile.jit', ['!copyToNodeModules'], function () { return gulp.src(PATHS.tmp + '/sample/**/*').pipe(gulp.dest(PATHS.app + '/' + APP_NAME)); @@ -259,10 +245,10 @@ systemBuilder.config({ defaultJSExtensions: true }); gulp.task('!pre-bundle', ['ts2system'], function () { - return gulp.src(PATHS.destination + '/src/**/*').pipe(gulp.dest(PATHS.destination + '/angular2-react-native')); + return gulp.src(PATHS.destination + '/src/**/*').pipe(gulp.dest(PATHS.destination + '/angular-react-native')); }); gulp.task('bundle', ['!pre-bundle'], function(done) { - return systemBuilder.bundle('angular2-react-native/testing', path.join(PATHS.publish, 'bundles/testing.dev.js'), + return systemBuilder.bundle('angular-react-native/testing', path.join(PATHS.publish, 'bundles/testing.dev.js'), {}).catch(function (e) { console.log(e); }); }); @@ -308,7 +294,7 @@ gulp.task('publish.ngc.src', ['publish.transform'], function (done) { }); }); gulp.task('publish', ['publish.ngc.src'], function (done) { - return gulp.src(PATHS.tmp + '/node_modules/angular2-react-native/**/*').pipe(gulp.dest(PATHS.publish)); + return gulp.src(PATHS.tmp + '/node_modules/angular-react-native/**/*').pipe(gulp.dest(PATHS.publish)); }); /**********************************************************************************/ @@ -425,7 +411,7 @@ function executeInAppDir(command, done, inParentFolder) { } function ts2js(path, dest, toSystem, withDeclaration) { - var tsResult = gulp.src(path.concat(['typings/index.d.ts', 'src/angular2-react-native.d.ts', 'src/angular2-react-native-android.d.ts', 'src/angular2-react-native-ios.d.ts']), {base: './'}) + var tsResult = gulp.src(path.concat(['typings/index.d.ts', 'src/angular-react-native.d.ts', 'src/angular-react-native-android.d.ts', 'src/angular-react-native-ios.d.ts']), {base: './'}) .pipe(typescript({ noImplicitAny: true, module: toSystem ? 'system' : 'commonjs', @@ -471,16 +457,31 @@ function transformAndroidManifest() { }); } +function transformReactNativeStack() { + return through2.obj(function (file, encoding, done) { + var content = String(file.contents); + content = content.replace('module.exports = ReactNativeStackEntry;', + `ReactNativeStackEntry.ReactNativeEventEmitter = ReactNativeEventEmitter_1; +ReactNativeStackEntry.ReactNativeTagHandles = ReactNativeTagHandles_1; +ReactNativeStackEntry.ReactNativeAttributePayload = ReactNativeAttributePayload_1; + +module.exports = ReactNativeStackEntry;`); + file.contents = new Buffer(content); + this.push(file); + done(); + }); +} + function customReporter() { return { error: (error) => { if (error.relativeFilename && error.message.indexOf(`Module '"react-native"' has no exported member`) == -1 && - error.message.indexOf(`Module ''angular2-react-native'' has no exported member`) == -1 && - error.message.indexOf(`Module ''angular2-react-native/android'' has no exported member`) == -1 && - error.message.indexOf(`Module ''angular2-react-native/ios'' has no exported member`) == -1 && - error.message.indexOf(`src\\angular2-react-native.d.ts`) == -1 && - error.message.indexOf(`src\\angular2-react-native-android.d.ts`) == -1 && - error.message.indexOf(`src\\angular2-react-native-ios.d.ts`) == -1 && + error.message.indexOf(`Module ''angular-react-native'' has no exported member`) == -1 && + error.message.indexOf(`Module ''angular-react-native/android'' has no exported member`) == -1 && + error.message.indexOf(`Module ''angular-react-native/ios'' has no exported member`) == -1 && + error.message.indexOf(`src\\angular-react-native.d.ts`) == -1 && + error.message.indexOf(`src\\angular-react-native-android.d.ts`) == -1 && + error.message.indexOf(`src\\angular-react-native-ios.d.ts`) == -1 && error.message.indexOf(`does not exist on type 'Global'.`) == -1) { console.error(error.message); } diff --git a/karma-test-shim.js b/karma-test-shim.js index d987e36..5d0e3cb 100644 --- a/karma-test-shim.js +++ b/karma-test-shim.js @@ -37,15 +37,19 @@ System.config( }, map: { // angular bundles + '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js', + '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js', '@angular/core': 'npm:@angular/core/bundles/core.umd.js', '@angular/common': 'npm:@angular/common/bundles/common.umd.js', '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', '@angular/router': 'npm:@angular/router/bundles/router.umd.js', // angular testing umd bundles + '@angular/animations/browser/testing': 'npm:@angular/animations/bundles/animations-browser-testing.umd.js', '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', @@ -66,11 +70,15 @@ System.config( System.import('@angular/core/testing') .then(function(coreTesting){ - return System.import('@angular/platform-browser-dynamic/testing') - .then(function(browserTesting) { + return Promise + .all([ + System.import('@angular/platform-browser-dynamic/testing'), + System.import('@angular/platform-browser/animations') + ]) + .then(function(mods) { coreTesting.TestBed.initTestEnvironment( - browserTesting.BrowserDynamicTestingModule, - browserTesting.platformBrowserDynamicTesting()); + [mods[0].BrowserDynamicTestingModule, mods[1].NoopAnimationsModule], + mods[0].platformBrowserDynamicTesting()); }); }) .then(function() { @@ -80,4 +88,4 @@ System.import('@angular/core/testing') allSpecFiles.map(function (moduleName) { return System.import(moduleName); })); -}).then(__karma__.start, __karma__.error); \ No newline at end of file +}).then(function() { __karma__.start(); }, function(error) { console.error(error); }); \ No newline at end of file diff --git a/package.json b/package.json index 0fc549f..868822e 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,16 @@ { - "name": "angular2-react-native", - "version": "0.0.1-alpha.20", - "description": "A React Native renderer for Angular 2", + "name": "angular-react-native", + "version": "0.0.1-alpha.22", + "description": "A React Native renderer for Angular", "scripts": { - "test": "gulp test.browser/ci", - "postinstall": "typings install" + "test": "gulp test.browser/ci" }, "repository": { "type": "git", "url": "git+https://github.com/angular/react-native-renderer.git" }, "keywords": [ - "Angular2", + "Angular", "renderer", "react-native" ], @@ -25,45 +24,47 @@ }, "homepage": "https://github.com/angular/react-native-renderer/", "devDependencies": { - "@angular/compiler-cli": "2.4.1", - "babel-preset-es2015": "^6.14.0", + "@angular/compiler-cli": "4.3.2", "del": "^1.2.0", "glob": "^4.0.6", "gulp": "^3.9.0", - "gulp-babel": "^6.1.2", "gulp-filter": "^3.0.1", "gulp-jade": "^1.1.0", "gulp-rename": "^1.2.2", "gulp-strip-comments": "^2.2.1", "gulp-typescript": "^2.12.2", "gulp-watch": "~4.3.5", - "jasmine": "2.4.1", + "jasmine": "2.6.0", "jstransformer-marked": "^1.0.1", "karma": "^0.13.21", "karma-chrome-launcher": "^0.2.2", "karma-jasmine": "^0.3.6", "marked": "^0.3.5", "merge2": "1.0.2", - "parse5": "1.5.0", + "parse5": "3.0.2", "run-sequence": "~1.1.2", - "systemjs": "^0.19.9", - "systemjs-builder": "^0.15.14", + "systemjs": "0.19.41", + "systemjs-builder": "0.15.35", "through2": "~0.6.3", - "typescript": "2.0.10" + "typescript": "2.3.4" }, "dependencies": { - "@angular/common": "2.4.1", - "@angular/compiler": "2.4.1", - "@angular/core": "2.4.1", - "@angular/http": "2.4.1", - "@angular/platform-browser": "2.4.1", - "@angular/platform-browser-dynamic": "2.4.1", - "@angular/platform-server": "2.4.1", - "@angular/router": "3.4.1", - "hammerjs": "2.0.6", - "react-native": "0.39.2", - "reflect-metadata": "0.1.8", - "rxjs": "5.0.1", - "zone.js": "0.7.4" + "@angular/animations": "4.3.2", + "@angular/common": "4.3.2", + "@angular/compiler": "4.3.2", + "@angular/core": "4.3.2", + "@angular/http": "4.3.2", + "@angular/platform-browser": "4.3.2", + "@angular/platform-browser-dynamic": "4.3.2", + "@angular/platform-server": "4.3.2", + "@angular/router": "4.3.2", + "@types/jasmine": "^2.5.53", + "@types/node": "^8.0.19", + "@types/react-native": "^0.46.11", + "hammerjs": "2.0.8", + "react-native": "0.47.1", + "reflect-metadata": "0.1.9", + "rxjs": "5.4.2", + "zone.js": "0.8.16" } } diff --git a/sample/index.android.aot.js b/sample/index.android.aot.js index fe35c2a..87a2143 100644 --- a/sample/index.android.aot.js +++ b/sample/index.android.aot.js @@ -1,4 +1,4 @@ -import {bootstrapReactNativeAOT} from 'angular2-react-native/aot'; +import {bootstrapReactNativeAOT} from 'angular-react-native/aot'; import {KitchenSinkModuleNgFactory} from "./samples/android/module.ngfactory"; bootstrapReactNativeAOT('ngReactNative', KitchenSinkModuleNgFactory); \ No newline at end of file diff --git a/sample/index.android.ts b/sample/index.android.ts index 2989aea..c3319a3 100644 --- a/sample/index.android.ts +++ b/sample/index.android.ts @@ -1,4 +1,4 @@ -import {bootstrapReactNativeJIT} from 'angular2-react-native/jit'; +import {bootstrapReactNativeJIT} from 'angular-react-native/jit'; import {KitchenSinkModule} from "./samples/android/module"; bootstrapReactNativeJIT('ngReactNative', KitchenSinkModule); \ No newline at end of file diff --git a/sample/index.ios.aot.js b/sample/index.ios.aot.js index 98f4e2a..fd038f2 100644 --- a/sample/index.ios.aot.js +++ b/sample/index.ios.aot.js @@ -1,4 +1,4 @@ -import {bootstrapReactNativeAOT} from 'angular2-react-native/aot'; +import {bootstrapReactNativeAOT} from 'angular-react-native/aot'; import {KitchenSinkModuleNgFactory} from "./samples/ios/module.ngfactory"; bootstrapReactNativeAOT('ngReactNative', KitchenSinkModuleNgFactory); \ No newline at end of file diff --git a/sample/index.ios.ts b/sample/index.ios.ts index 380414b..5c150c6 100644 --- a/sample/index.ios.ts +++ b/sample/index.ios.ts @@ -1,4 +1,4 @@ -import {bootstrapReactNativeJIT} from 'angular2-react-native/jit'; +import {bootstrapReactNativeJIT} from 'angular-react-native/jit'; import {KitchenSinkModule} from "./samples/ios/module"; bootstrapReactNativeJIT('ngReactNative', KitchenSinkModule); \ No newline at end of file diff --git a/sample/samples/android/http.ts b/sample/samples/android/http.ts index 3d3adc2..b3f18ed 100644 --- a/sample/samples/android/http.ts +++ b/sample/samples/android/http.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {Http} from '@angular/http'; import 'rxjs/add/operator/map'; -import {TextInput} from 'angular2-react-native/android'; +import {TextInput} from 'angular-react-native/android'; @Component({ selector: 'http-app', diff --git a/sample/samples/android/kitchensink.ts b/sample/samples/android/kitchensink.ts index 72a2bd1..112bb58 100644 --- a/sample/samples/android/kitchensink.ts +++ b/sample/samples/android/kitchensink.ts @@ -2,7 +2,7 @@ import {Component, ElementRef, ViewChild} from '@angular/core'; import {Router, NavigationEnd} from '@angular/router'; import {LocationStrategy} from '@angular/common'; import {StyleSheet, BackAndroid, Alert, NativeModules, processColor} from 'react-native'; -import {DrawerLayout, Toolbar} from 'angular2-react-native/android'; +import {DrawerLayout, Toolbar} from 'angular-react-native/android'; import {TodoMVC} from "./todomvc"; diff --git a/sample/samples/android/module.ts b/sample/samples/android/module.ts index d3f467b..95e0350 100644 --- a/sample/samples/android/module.ts +++ b/sample/samples/android/module.ts @@ -1,7 +1,7 @@ import {NgModule, Provider} from '@angular/core'; import {CommonModule, LocationStrategy} from '@angular/common'; import {RouterModule, Routes} from '@angular/router'; -import {ReactNativeAndroidModule, ReactNativeRouterModule, ReactNativeHttpModule, ReactNativeLocationStrategy} from 'angular2-react-native'; +import {ReactNativeAndroidModule, ReactNativeRouterModule, ReactNativeHttpModule, ReactNativeLocationStrategy} from 'angular-react-native'; import {KitchenSinkApp} from './kitchensink'; import {HelloApp} from "./hello"; diff --git a/sample/samples/android/todomvc.ts b/sample/samples/android/todomvc.ts index 0c4697d..b45113f 100644 --- a/sample/samples/android/todomvc.ts +++ b/sample/samples/android/todomvc.ts @@ -1,6 +1,6 @@ import {Component, Input, Output, EventEmitter, ViewChild} from '@angular/core'; import {StyleSheet, AsyncStorage} from 'react-native'; -import {TextInput} from 'angular2-react-native/android'; +import {TextInput} from 'angular-react-native/android'; class Palette { static background: string = '#005eb8'; @@ -218,7 +218,7 @@ export class TodoMVC { reset() { this.todos = this.filteredTodos = [ - new Todo("Angular 2", false, false), + new Todo("Angular", false, false), new Todo("React Native", false, false), new Todo("Android", false, false), new Todo("iOS", true, false) diff --git a/sample/samples/android/webview.ts b/sample/samples/android/webview.ts index 22e4e07..0c28b93 100644 --- a/sample/samples/android/webview.ts +++ b/sample/samples/android/webview.ts @@ -1,6 +1,6 @@ import {Component, ElementRef, ViewChild} from '@angular/core'; import {StyleSheet} from 'react-native'; -import {WebView} from 'angular2-react-native/android'; +import {WebView} from 'angular-react-native/android'; @Component({ selector: 'webview-app', diff --git a/sample/samples/ios/http.ts b/sample/samples/ios/http.ts index ea22f3f..8877799 100644 --- a/sample/samples/ios/http.ts +++ b/sample/samples/ios/http.ts @@ -2,7 +2,7 @@ import {Component, ViewChild} from '@angular/core'; import {Http} from '@angular/http'; import 'rxjs/add/operator/map'; -import {TextInput} from 'angular2-react-native/ios'; +import {TextInput} from 'angular-react-native/ios'; @Component({ selector: 'http-app', diff --git a/sample/samples/ios/kitchensink.ts b/sample/samples/ios/kitchensink.ts index 7d78e0f..fb4554d 100644 --- a/sample/samples/ios/kitchensink.ts +++ b/sample/samples/ios/kitchensink.ts @@ -1,6 +1,6 @@ import {Component, ViewChild} from '@angular/core'; import {ActionSheetIOS} from 'react-native'; -import {Navigator} from 'angular2-react-native/ios'; +import {Navigator} from 'angular-react-native/ios'; import {TodoMVC} from "./todomvc"; @Component({ diff --git a/sample/samples/ios/module.ts b/sample/samples/ios/module.ts index 95eede0..89a3002 100644 --- a/sample/samples/ios/module.ts +++ b/sample/samples/ios/module.ts @@ -1,7 +1,7 @@ import {NgModule, Provider} from '@angular/core'; import {CommonModule, LocationStrategy} from '@angular/common'; import {RouterModule, Routes} from '@angular/router'; -import {ReactNativeiOSModule, ReactNativeRouterModule, ReactNativeHttpModule, ReactNativeLocationStrategy} from 'angular2-react-native'; +import {ReactNativeiOSModule, ReactNativeRouterModule, ReactNativeHttpModule, ReactNativeLocationStrategy} from 'angular-react-native'; import {KitchenSinkApp} from './kitchensink'; import {HelloApp} from "./hello"; diff --git a/sample/samples/ios/todomvc.ts b/sample/samples/ios/todomvc.ts index b318643..eb40f4a 100644 --- a/sample/samples/ios/todomvc.ts +++ b/sample/samples/ios/todomvc.ts @@ -1,6 +1,6 @@ import {Component, Input, Output, EventEmitter, ViewChild} from '@angular/core'; import {StyleSheet, AsyncStorage} from 'react-native'; -import {TextInput} from 'angular2-react-native/ios'; +import {TextInput} from 'angular-react-native/ios'; class Palette { static background: string = '#005eb8'; @@ -218,7 +218,7 @@ export class TodoMVC { reset() { this.todos = this.filteredTodos = [ - new Todo("Angular 2", false, false), + new Todo("Angular", false, false), new Todo("React Native", false, false), new Todo("Android", false, false), new Todo("iOS", true, false) diff --git a/sample/samples/ios/webview.ts b/sample/samples/ios/webview.ts index bb308af..250297d 100644 --- a/sample/samples/ios/webview.ts +++ b/sample/samples/ios/webview.ts @@ -1,6 +1,6 @@ import {Component, ElementRef, ViewChild} from '@angular/core'; import {StyleSheet} from 'react-native'; -import {WebView} from 'angular2-react-native/ios'; +import {WebView} from 'angular-react-native/ios'; @Component({ selector: 'webview-app', diff --git a/sample/samples/ios/widgets.ts b/sample/samples/ios/widgets.ts index 05f91c4..9b89ea0 100644 --- a/sample/samples/ios/widgets.ts +++ b/sample/samples/ios/widgets.ts @@ -50,12 +50,6 @@ import {StyleSheet} from 'react-native'; Date picker ({{selectedDate}}) - - - Map view - - ` }) diff --git a/sample/tsconfig.json b/sample/tsconfig.json index 5c7bb80..3596332 100644 --- a/sample/tsconfig.json +++ b/sample/tsconfig.json @@ -17,7 +17,6 @@ "index.android.ts", "index.ios.ts", "../../../node_modules/zone.js/dist/zone.js.d.ts", - "../../../typings/globals/node/index.d.ts", "../../../fake-react-native.d.ts" ], diff --git a/src/angular-react-native-android.d.ts b/src/angular-react-native-android.d.ts new file mode 100644 index 0000000..32a1f61 --- /dev/null +++ b/src/angular-react-native-android.d.ts @@ -0,0 +1,5 @@ +declare module 'angular-react-native/android' { + + export * from './android'; +} + diff --git a/src/angular-react-native-ios.d.ts b/src/angular-react-native-ios.d.ts new file mode 100644 index 0000000..dbcb34d --- /dev/null +++ b/src/angular-react-native-ios.d.ts @@ -0,0 +1,5 @@ +declare module 'angular-react-native/ios' { + + export * from './ios'; +} + diff --git a/src/angular-react-native.d.ts b/src/angular-react-native.d.ts new file mode 100644 index 0000000..281c105 --- /dev/null +++ b/src/angular-react-native.d.ts @@ -0,0 +1,5 @@ +declare module 'angular-react-native' { + + export * from './index'; +} + diff --git a/src/angular2-react-native-android.d.ts b/src/angular2-react-native-android.d.ts deleted file mode 100644 index dd69d74..0000000 --- a/src/angular2-react-native-android.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'angular2-react-native/android' { - - export * from './android'; -} - diff --git a/src/angular2-react-native-ios.d.ts b/src/angular2-react-native-ios.d.ts deleted file mode 100644 index 8e54cd3..0000000 --- a/src/angular2-react-native-ios.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'angular2-react-native/ios' { - - export * from './ios'; -} - diff --git a/src/angular2-react-native.d.ts b/src/angular2-react-native.d.ts deleted file mode 100644 index 50eb54f..0000000 --- a/src/angular2-react-native.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'angular2-react-native' { - - export * from './index'; -} - diff --git a/src/components/ios/map_view.ts b/src/components/ios/map_view.ts deleted file mode 100644 index 8b9b859..0000000 --- a/src/components/ios/map_view.ts +++ /dev/null @@ -1,217 +0,0 @@ -import {Component, Inject, Output, EventEmitter} from "@angular/core"; -import {HighLevelComponent, GENERIC_INPUTS, GENERIC_BINDINGS} from "../common/component"; -import {REACT_NATIVE_WRAPPER} from "./../../renderer/renderer"; -import {ReactNativeWrapper} from "../../wrapper/wrapper"; - -/** - * A component for displaying a map. - * - * ``` - @Component({ - selector: 'sample', - template: `` -}) - export class Sample {} - * ``` - * @style https://facebook.github.io/react-native/docs/view.html#style - * @platform ios - */ -@Component({ - selector: 'MapView', - inputs: [ - 'pitchEnabled', 'region', 'rotateEnabled', 'scrollEnabled', 'showsUserLocation', 'zoomEnabled', - 'annotations', 'followUserLocation', 'legalLabelInsets', 'mapType', 'maxDelta', 'minDelta', - 'overlays', 'showsCompass', 'showsPointsOfInterest' - ].concat(GENERIC_INPUTS), - template: `` -}) -export class MapView extends HighLevelComponent { - constructor(@Inject(REACT_NATIVE_WRAPPER) wrapper: ReactNativeWrapper) { - super(wrapper); - } - - //Events - /** - * To be documented - */ - @Output() change: EventEmitter = new EventEmitter(); - /** - * To be documented - * {annotation: Annotation, action: "annotation-click"} - */ - @Output() annotationPress: EventEmitter = new EventEmitter(); - /** - * To be documented - * {annotation: Annotation} - */ - @Output() annotationFocus: EventEmitter = new EventEmitter(); - /** - * To be documented - * {annotation: Annotation} - */ - @Output() annotationBlur: EventEmitter = new EventEmitter(); - /** - * To be documented - * {annotation: Annotation} - */ - @Output() annotationDragStateChange: EventEmitter = new EventEmitter(); - - //Properties - public _pitchEnabled: boolean; - public _region: any; - public _rotateEnabled: boolean; - public _scrollEnabled: boolean; - public _showsUserLocation: boolean; - public _zoomEnabled: boolean; - /** - * To be documented - */ - set pitchEnabled(value: any) {this._pitchEnabled = this.processBoolean(value);} - /** - * To be documented - * {latitude: number, longitude: number, latitudeDelta: number, longitudeDelta: number} - */ - set region(value: any) {this._region = value;} - /** - * To be documented - */ - set rotateEnabled(value: any) {this._rotateEnabled = this.processBoolean(value);} - /** - * To be documented - */ - set scrollEnabled(value: any) {this._scrollEnabled = this.processBoolean(value);} - /** - * To be documented - */ - set showsUserLocation(value: any) {this._showsUserLocation = this.processBoolean(value);} - /** - * To be documented - */ - set zoomEnabled(value: any) {this._zoomEnabled = this.processBoolean(value);} - - //TODO: manage views and events on annotations - public _annotations: Array; - public _annotationEventsEnabled: boolean = false; - public _annotationMap: Map; - public _followUserLocation: boolean; - public _legalLabelInsets: any; - public _mapType: string; - public _maxDelta: number; - public _minDelta: number; - public _overlays: Array; - public _showsCompass: boolean; - public _showsPointsOfInterest: boolean; - /** - * To be documented - * [{latitude: number, longitude: number, animateDrop: bool, draggable: bool, title: string, subtitle: string, - * tintColor: color, image: source, id: string}] - * Custom views in annotations are not yet managed. - */ - set annotations(value: Array) { - if(value) { - this._annotationEventsEnabled = true; - this._annotationMap = new Map(); - this._annotations = value.map((annotation) => { - var res = annotation; - res['id'] = annotation.id || encodeURIComponent(JSON.stringify(annotation)); - this._annotationMap.set(res['id'], res); - if (annotation.tintColor) { - res['tintColor'] = this.processColor(annotation.tintColor); - } - if (annotation.image) { - res['image'] = this.resolveAssetSource(annotation.image); - } - return res; - }); - } else { - this._annotationEventsEnabled = false; - delete this._annotations; - } - } - /** - * To be documented - */ - set followUserLocation(value: any) {this._followUserLocation = this.processBoolean(value);} - /** - * To be documented - * {top: number, left: number, bottom: number, right: number} - */ - set legalLabelInsets(value: any) {this._legalLabelInsets = value;} - /** - * To be documented - */ - set mapType(value: string) {this._mapType = this.processEnum(value, ['standard', 'satellite', 'hybrid']);} - /** - * To be documented - */ - set maxDelta(value: any) {this._maxDelta = this.processNumber(value);} - /** - * To be documented - */ - set minDelta(value: any) {this._minDelta = this.processNumber(value);} - /** - * To be documented - * [{coordinates: [{latitude: number, longitude: number}], lineWidth: number, strokeColor: color, fillColor: color, id: string}] - */ - set overlays(value: Array) { - if(value) { - this._overlays = value.map((overlay) => { - var res = overlay; - res['id'] = overlay.id || encodeURIComponent(JSON.stringify(overlay)); - this._annotationMap.set(res['id'], res); - if (overlay.strokeColor) { - res['strokeColor'] = this.processColor(overlay.strokeColor); - } - if (overlay.fillColor) { - res['fillColor'] = this.processColor(overlay.fillColor); - } - return res; - }); - } else { - delete this._overlays; - } - } - /** - * To be documented - */ - set showsCompass(value: any) {this._showsCompass = this.processBoolean(value);} - /** - * To be documented - */ - set showsPointsOfInterest(value: any) {this._showsPointsOfInterest = this.processBoolean(value);} - - - _handleChange(event: any) { - //Event example: {region: {latitude: 45, longitude: 0, latitudeDelta: 9, longitudeDelta: 73}, continuous: true} - this.change.emit(event); - } - - _handlePress(event: any) { - //Event example: {annotation: Object, action: "annotation-click", target: 22} - this.annotationPress.emit({annotation: event.annotation, action: event.action}) - } - - _handleAnnotationFocus(event: any) { - //Event example: {target: 22, annotationId: "fdsfs"} - this.annotationFocus.emit({annotation: this._annotationMap.get(event.annotationId)}); - } - - _handleAnnotationBlur(event: any) { - //Event example: {target: 22, annotationId: "fdsfs"} - this.annotationFocus.emit({annotation: this._annotationMap.get(event.annotationId)}); - } - - _handleAnnotationDragStateChange(event: any) { - //Event example: {target: 22, annotationId: "fdsfs"} - this.annotationDragStateChange.emit({annotation: this._annotationMap.get(event.annotationId)}); - } -} diff --git a/src/components/ios/navigator.ts b/src/components/ios/navigator.ts index 9dd631b..3de87fd 100644 --- a/src/components/ios/navigator.ts +++ b/src/components/ios/navigator.ts @@ -13,7 +13,7 @@ import { AfterViewInit, OnDestroy, ResolvedReflectiveProvider } from "@angular/core"; import {LocationStrategy} from "@angular/common"; -import {Router, ActivatedRoute, RouterOutletMap, PRIMARY_OUTLET} from "@angular/router"; +import {Router, ActivatedRoute, ChildrenOutletContexts, PRIMARY_OUTLET} from "@angular/router"; import {HighLevelComponent, GENERIC_INPUTS, GENERIC_BINDINGS} from "../common/component"; import {REACT_NATIVE_WRAPPER} from "./../../renderer/renderer"; import {ReactNativeWrapper} from "../../wrapper/wrapper"; @@ -183,20 +183,18 @@ export class Navigator extends HighLevelComponent implements OnDestroy { private __wrapper: ReactNativeWrapper; constructor(private router: Router, private zone: NgZone, private locationStrategy: LocationStrategy, private elementRef: ElementRef, - private parentOutletMap: RouterOutletMap, @Inject(REACT_NATIVE_WRAPPER) wrapper: ReactNativeWrapper) { + private parentContexts: ChildrenOutletContexts, @Inject(REACT_NATIVE_WRAPPER) wrapper: ReactNativeWrapper) { super(wrapper); this.__wrapper = wrapper; - parentOutletMap.registerOutlet(PRIMARY_OUTLET, this); + parentContexts.onChildOutletCreated(PRIMARY_OUTLET, this); this.setDefaultStyle({flex: 1}); } - activate(activatedRoute: ActivatedRoute, loadedResolver: ComponentFactoryResolver, - loadedInjector: Injector, providers: ResolvedReflectiveProvider[], - outletMap: RouterOutletMap): void { + activateWith(activatedRoute: ActivatedRoute, loadedResolver: ComponentFactoryResolver): void { if (this._stack.length == 0) { this._stack.push(activatedRoute); } else { - var navigator: Node = this.elementRef.nativeElement.children[1]; + var navigator: Node = this.elementRef.nativeElement.children[0]; setTimeout(()=> { this.__wrapper.requestNavigatorLock(navigator.nativeTag, (lockAcquired) => this._handleNavigation(lockAcquired, navigator, activatedRoute)); }, 0) @@ -205,7 +203,7 @@ export class Navigator extends HighLevelComponent implements OnDestroy { deactivate(): void {} - ngOnDestroy(): void { this.parentOutletMap.removeOutlet(PRIMARY_OUTLET); } + ngOnDestroy(): void { this.parentContexts.onChildOutletDestroyed(PRIMARY_OUTLET); } _handleNavigation(lockAcquired: boolean, navigator: Node, activatedRoute: ActivatedRoute): void { this.zone.run(() => { diff --git a/src/events/hammer.ts b/src/events/hammer.ts index b22ebba..02233cb 100644 --- a/src/events/hammer.ts +++ b/src/events/hammer.ts @@ -1,9 +1,6 @@ -declare var global: any; -declare var require: any; - -if (typeof global.window === "undefined") global.window = global; -if (typeof global.document === "undefined") global.document = {createElement: () => {return {style: {}};}}; -var hammer = (typeof global.window.Hammer === "undefined") ? require('hammerjs') : global.window.Hammer; +if (typeof global['window'] === "undefined") global['window'] = global; +if (typeof global['document'] === "undefined") global['document'] = {createElement: () => {return {style: {}};}}; +var hammer = (typeof global['window'].Hammer === "undefined") ? require('hammerjs') : global['window'].Hammer; var EVENT_RECOGNIZER_MAP: {[s: string]: string } = { //doubletap @@ -155,7 +152,7 @@ var NATIVE_INPUT_MAP: {[s: string]: any } = { var NATIVE_TARGET_EVENTS = 'topTouchStart topTouchMove topTouchEnd topTouchCancel'; -function NativeInput() { +export function NativeInput() { this.evTarget = NATIVE_TARGET_EVENTS; this.targetIds = {}; diff --git a/src/ios.ts b/src/ios.ts index a50fab4..c99e68f 100644 --- a/src/ios.ts +++ b/src/ios.ts @@ -11,7 +11,6 @@ export {View} from './components/ios/_view'; export {WebView} from './components/ios/_webview'; export {DatePicker} from './components/ios/date_picker'; -export {MapView} from './components/ios/map_view'; export {Navigator} from './components/ios/navigator'; export {ProgressView} from './components/ios/progress_view'; export {SegmentedControl} from './components/ios/segmented_control'; diff --git a/src/modules/ios_module.ts b/src/modules/ios_module.ts index af258c4..fd25283 100644 --- a/src/modules/ios_module.ts +++ b/src/modules/ios_module.ts @@ -15,7 +15,6 @@ import {View} from "../components/ios/_view"; import {WebView} from "../components/ios/_webview"; import {DatePicker} from "../components/ios/date_picker"; -import {MapView} from "../components/ios/map_view"; import {Navigator, NavigatorItem} from "../components/ios/navigator"; import {ProgressView} from "../components/ios/progress_view"; import {SegmentedControl} from "../components/ios/segmented_control"; @@ -24,9 +23,9 @@ import {TabBarItem} from "../components/ios/tabbar_item"; @NgModule({ declarations: [ActivityIndicator, Image, Picker, RefreshControl, ScrollView, Slider, Switch, Text, TextInput, View, WebView, - DatePicker, MapView, Navigator, NavigatorItem, ProgressView, SegmentedControl, TabBar, TabBarItem], + DatePicker, Navigator, NavigatorItem, ProgressView, SegmentedControl, TabBar, TabBarItem], exports: [ActivityIndicator, Image, Picker, RefreshControl, ScrollView, Slider, Switch, Text, TextInput, View, WebView, - DatePicker, MapView, Navigator, ProgressView, SegmentedControl, TabBar, TabBarItem], + DatePicker, Navigator, ProgressView, SegmentedControl, TabBar, TabBarItem], imports: [CommonModule, ApplicationModule], schemas: [CUSTOM_ELEMENTS_SCHEMA] }) diff --git a/src/renderer/bootstrap_aot.ts b/src/renderer/bootstrap_aot.ts index a603ca6..5ddbb70 100644 --- a/src/renderer/bootstrap_aot.ts +++ b/src/renderer/bootstrap_aot.ts @@ -6,26 +6,21 @@ import {ReactNativeWrapperImpl} from "./../wrapper/wrapper_impl"; //Dependencies import "reflect-metadata"; -//Zone.js, patching RN's polyfill of XMLHttpRequest is needed to make it compatible with Zone.js -var onreadystatechangeGetter = function() {return this._onreadystatechange;}; -var onreadystatechangeSetter = function(v: any) {this._onreadystatechange = v;}; -Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', { - get: onreadystatechangeGetter, - set: onreadystatechangeSetter, - configurable: true -}); +//Zone.js, working around some patches +if (!global.hasOwnProperty) { + global.hasOwnProperty = () => false; +} +var oldSend = XMLHttpRequest.prototype.send; require("zone.js/dist/zone.js"); -Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', { - get: onreadystatechangeGetter, -}); +require("zone.js/dist/long-stack-trace-zone.js") +XMLHttpRequest.prototype.send = oldSend; // Finally, define the bootstrap -import {RootRenderer, NgZone, enableProdMode, NgModuleRef, Sanitizer, ErrorHandler} from "@angular/core"; +import {RendererFactory2, NgZone, enableProdMode, NgModuleRef, Sanitizer, ErrorHandler} from "@angular/core"; import { platformBrowser } from '@angular/platform-browser'; -import {ElementSchemaRegistry} from "@angular/compiler"; +import {DomElementSchemaRegistry} from "@angular/compiler"; import { ReactNativeRootRenderer, - ReactNativeRootRenderer_, ReactNativeElementSchemaRegistry, ReactNativeSanitizer, REACT_NATIVE_WRAPPER @@ -39,19 +34,19 @@ export function bootstrapReactNativeAOT(appName:string, factory: any, customProv [ReactNativeWrapperImpl], {provide: REACT_NATIVE_WRAPPER, useExisting: ReactNativeWrapperImpl}, [ReactNativeElementSchemaRegistry], - {provide: ElementSchemaRegistry, useExisting: ReactNativeElementSchemaRegistry}, + {provide: DomElementSchemaRegistry, useExisting: ReactNativeElementSchemaRegistry}, ReactNativeSanitizer, {provide: Sanitizer, useExisting: ReactNativeSanitizer}, - {provide: ReactNativeRootRenderer, useClass: ReactNativeRootRenderer_}, - {provide: RootRenderer, useExisting: ReactNativeRootRenderer} + [ReactNativeRootRenderer], + {provide: RendererFactory2, useExisting: ReactNativeRootRenderer} ].concat(customProviders || [])). bootstrapModuleFactory(factory). then((ngModuleRef: NgModuleRef) => { var zone: NgZone = ngModuleRef.injector.get(NgZone); - var rootRenderer = ngModuleRef.injector.get(RootRenderer); - rootRenderer.zone = zone; - rootRenderer.executeCommands(); - zone.onStable.subscribe(() => { rootRenderer.executeCommands(); }); + var rendererFactory = ngModuleRef.injector.get(RendererFactory2); + rendererFactory.zone = zone; + rendererFactory.executeCommands(); + zone.onStable.subscribe(() => { rendererFactory.executeCommands(); }); ngModuleRef.injector.get(ReactNativeWrapperImpl).patchReactNativeWithZone(zone); }); }); diff --git a/src/renderer/bootstrap_jit.ts b/src/renderer/bootstrap_jit.ts index f332b5f..b5202c2 100644 --- a/src/renderer/bootstrap_jit.ts +++ b/src/renderer/bootstrap_jit.ts @@ -6,26 +6,20 @@ import {ReactNativeWrapperImpl} from "./../wrapper/wrapper_impl"; //Dependencies import "reflect-metadata"; -//Zone.js, patching RN's polyfill of XMLHttpRequest is needed to make it compatible with Zone.js -var onreadystatechangeGetter = function() {return this._onreadystatechange;}; -var onreadystatechangeSetter = function(v: any) {this._onreadystatechange = v;}; -Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', { - get: onreadystatechangeGetter, - set: onreadystatechangeSetter, - configurable: true -}); +//Zone.js, working around some patches +if (!global.hasOwnProperty) { + global.hasOwnProperty = () => false; +} +var oldSend = XMLHttpRequest.prototype.send; require("zone.js/dist/zone.js"); -Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', { - get: onreadystatechangeGetter, -}); +XMLHttpRequest.prototype.send = oldSend; // Finally, define the bootstrap -import {RootRenderer, NgZone, enableProdMode, NgModuleRef, Sanitizer, ErrorHandler} from "@angular/core"; +import {RendererFactory2, NgZone, enableProdMode, NgModuleRef, Sanitizer, ErrorHandler} from "@angular/core"; import {platformBrowserDynamic} from "@angular/platform-browser-dynamic"; -import {ElementSchemaRegistry} from "@angular/compiler"; +import {DomElementSchemaRegistry} from "@angular/compiler"; import { ReactNativeRootRenderer, - ReactNativeRootRenderer_, ReactNativeElementSchemaRegistry, ReactNativeSanitizer, REACT_NATIVE_WRAPPER @@ -39,19 +33,19 @@ export function bootstrapReactNativeJIT(appName:string, module: any, customProvi [ReactNativeWrapperImpl], {provide: REACT_NATIVE_WRAPPER, useExisting: ReactNativeWrapperImpl}, [ReactNativeElementSchemaRegistry], - {provide: ElementSchemaRegistry, useExisting: ReactNativeElementSchemaRegistry}, + {provide: DomElementSchemaRegistry, useExisting: ReactNativeElementSchemaRegistry}, ReactNativeSanitizer, {provide: Sanitizer, useExisting: ReactNativeSanitizer}, - {provide: ReactNativeRootRenderer, useClass: ReactNativeRootRenderer_}, - {provide: RootRenderer, useExisting: ReactNativeRootRenderer} + [ReactNativeRootRenderer], + {provide: RendererFactory2, useExisting: ReactNativeRootRenderer} ].concat(customProviders || [])). bootstrapModule(module). then((ngModuleRef: NgModuleRef) => { var zone: NgZone = ngModuleRef.injector.get(NgZone); - var rootRenderer = ngModuleRef.injector.get(RootRenderer); - rootRenderer.zone = zone; - rootRenderer.executeCommands(); - zone.onStable.subscribe(() => { rootRenderer.executeCommands(); }); + var rendererFactory = ngModuleRef.injector.get(RendererFactory2); + rendererFactory.zone = zone; + rendererFactory.executeCommands(); + zone.onStable.subscribe(() => { rendererFactory.executeCommands(); }); ngModuleRef.injector.get(ReactNativeWrapperImpl).patchReactNativeWithZone(zone); }); }); diff --git a/src/renderer/node.ts b/src/renderer/node.ts index 4c1e5c4..482b0dd 100644 --- a/src/renderer/node.ts +++ b/src/renderer/node.ts @@ -274,7 +274,7 @@ export class ElementNode extends Node { //TODO: generalize the mechanism (list? regexp? meta data?) if (['dummy-anchor-for-dynamic-loader', 'View', 'Text', 'Switch', 'TextInput', 'WebView', 'Image', 'ProgressBar', 'PagerLayout', 'Picker', 'ScrollView', 'DrawerLayout', 'DrawerLayoutSide', 'DrawerLayoutContent', 'RefreshControl', 'Toolbar', - 'ActivityIndicator', 'DatePicker', 'MapView', 'Navigator', 'NavigatorItem', 'ProgressView', 'SegmentedControl', 'Slider', 'TabBar', 'TabBarItem'].indexOf(tagName) > -1) { + 'ActivityIndicator', 'DatePicker', 'Navigator', 'NavigatorItem', 'ProgressView', 'SegmentedControl', 'Slider', 'TabBar', 'TabBarItem'].indexOf(tagName) > -1) { this.isVirtual = true; } } @@ -294,6 +294,6 @@ export class TextNode extends Node { } } -export class AnchorNode extends Node { +export class CommentNode extends Node { constructor(wrapper: ReactNativeWrapper, zoneHolder: any) { super(wrapper, zoneHolder); this.isVirtual = true;} } diff --git a/src/renderer/renderer.ts b/src/renderer/renderer.ts index 914c400..b80e4a4 100644 --- a/src/renderer/renderer.ts +++ b/src/renderer/renderer.ts @@ -1,18 +1,20 @@ import { - RootRenderer, - Renderer, - RenderComponentType, - OpaqueToken, + RendererFactory2, + Renderer2, + RendererType2, + RendererStyleFlags2, + InjectionToken, Inject, Injectable, NgZone, Sanitizer, SecurityContext, AnimationPlayer, - SchemaMetadata + SchemaMetadata, + Compiler } from "@angular/core"; import {ElementSchemaRegistry} from "@angular/compiler"; -import {Node, ElementNode, AnchorNode, TextNode, nodeMap} from "./node"; +import {Node, ElementNode, TextNode, nodeMap, CommentNode} from "./node"; import {ReactNativeWrapper} from "./../wrapper/wrapper"; import { NativeCommand, @@ -23,7 +25,7 @@ import { NativeCommandAttachAfter } from "./native_command"; -export const REACT_NATIVE_WRAPPER: OpaqueToken = new OpaqueToken("ReactNativeWrapper"); +export const REACT_NATIVE_WRAPPER: InjectionToken = new InjectionToken("ReactNativeWrapper"); export class ReactNativeElementSchemaRegistry extends ElementSchemaRegistry { getDefaultComponentElementName(): string { @@ -66,8 +68,10 @@ export class ReactNativeSanitizer implements Sanitizer { } } -export class ReactNativeRootRenderer implements RootRenderer { +@Injectable() +export class ReactNativeRootRenderer implements RendererFactory2 { public zone: NgZone; + public wrapper: ReactNativeWrapper; private _registeredComponents: Map = new Map(); @@ -77,17 +81,13 @@ export class ReactNativeRootRenderer implements RootRenderer { private _attachAfterCommands: Map = new Map(); private _detachCommands: Map = new Map(); - constructor(public wrapper: ReactNativeWrapper) { - wrapper.patchReactNativeEventEmitter(nodeMap); + constructor(@Inject(REACT_NATIVE_WRAPPER) _wrapper: ReactNativeWrapper) { + this.wrapper = _wrapper; + this.wrapper.patchReactNativeEventEmitter(nodeMap); } - renderComponent(componentType: RenderComponentType): Renderer { - var renderer = this._registeredComponents.get(componentType.id); - if (renderer == null) { - renderer = new ReactNativeRenderer(this, componentType); - this._registeredComponents.set(componentType.id, renderer); - } - return renderer; + createRenderer(hostElement: any, type: RendererType2 | any): Renderer2 { + return new ReactNativeRenderer(this); } addCreateCommand(node: Node, props: {[s: string]: any } = null) { @@ -138,190 +138,167 @@ export class ReactNativeRootRenderer implements RootRenderer { } } -@Injectable() -export class ReactNativeRootRenderer_ extends ReactNativeRootRenderer { - constructor(@Inject(REACT_NATIVE_WRAPPER) _wrapper: ReactNativeWrapper) { - super(_wrapper); - } -} - -export class ReactNativeRenderer implements Renderer { +export class ReactNativeRenderer implements Renderer2 { + data: {[key: string]: any;} = {}; - constructor(private _rootRenderer: ReactNativeRootRenderer, private componentProto: RenderComponentType) { } - - renderComponent(componentType: RenderComponentType):Renderer { - return this._rootRenderer.renderComponent(componentType); - } + constructor(private _rootRenderer: ReactNativeRootRenderer) {} selectRootElement(selector: string): Node { - var root = this.createElement(null, selector.startsWith('#root') ? 'test-cmp' : selector); + const root = this.createElement(selector.startsWith('#root') ? 'test-cmp' : selector); this._createElementCommand(root); this._rootRenderer.addAttachCommand(root, true); return root; } - createElement(parentElement: Node, name: string): Node { - var node = new ElementNode(name, this._rootRenderer.wrapper, this._rootRenderer); - node.attachTo(parentElement); - if (!node.isVirtual && node.getAncestorWithNativeCreated()) { - this._createElementCommand(node); - this._rootRenderer.addAttachCommand(node, false); - } - return node; + createElement(name: string, namespace?: string | any): Node { + //console.log('createElement:' + name); + return new ElementNode(name, this._rootRenderer.wrapper, this._rootRenderer); } - private _createElementCommand(node: Node): void { - this._rootRenderer.addCreateCommand(node); - node.isCreated = true; + createComment(value: string): any { + return new CommentNode(this._rootRenderer.wrapper, this._rootRenderer); } - createViewRoot(hostElement: Node): Node { - return hostElement; + createText(value: string): Node { + //console.log('createText:' + value); + return new TextNode(value, this._rootRenderer.wrapper, this._rootRenderer); } - createTemplateAnchor(parentElement: Node): Node { - var node = new AnchorNode(this._rootRenderer.wrapper, this._rootRenderer); - node.attachTo(parentElement); - return node; + destroyNode(node: Node): any { + node.toBeDestroyed = true; } - createText(parentElement: Node, value: string): Node { - var node = new TextNode(value, this._rootRenderer.wrapper, this._rootRenderer); - if (parentElement && parentElement.isCreated) { - this._createTextCommand(node); - this._rootRenderer.addAttachCommand(node, false); - } - node.attachTo(parentElement); - return node; + destroy(): void { + //console.log('NOT IMPLEMENTED: destroy', arguments); } - private _createTextCommand(node: TextNode): void { - this._rootRenderer.addCreateCommand(node, {text: node.properties['text']}); - var cmd = new NativeCommandCreate(node); - node.isCreated = true; - } - - projectNodes(parentElement: Node, nodes: Node[]): void { - if (parentElement) { - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - node.attachTo(parentElement); - if (node.getAncestorWithNativeCreated()) { - if (this._createNativeRecursively(node)) { - this._rootRenderer.addAttachCommand(node, false); - } - } + appendChild(parent: Node, newChild: Node): void { + //console.log('appendChild'); + newChild.attachTo(parent); + if (newChild.getAncestorWithNativeCreated()) { + if (this._createNativeRecursively(newChild)) { + this._rootRenderer.addAttachCommand(newChild, false); } } } - attachViewAfter(node: Node, viewRootNodes: Node[]): void { - if (viewRootNodes.length > 0) { - var index = node.parent.children.indexOf(node); - for (var i = 0; i < viewRootNodes.length; i++) { - var viewRootNode = viewRootNodes[i]; - viewRootNode.attachToAt(node.parent, index + i + 1); - if (viewRootNode.getAncestorWithNativeCreated()) { - if (this._createNativeRecursively(viewRootNode)) { - this._rootRenderer.addAttachAfterCommand(viewRootNode, node); - } - } + insertBefore(parent: any, newChild: any, refChild: any): void { + //console.log('insertBefore'); + const index = parent.children.indexOf(refChild); + newChild.attachToAt(parent, index); + if (newChild.getAncestorWithNativeCreated()) { + if (this._createNativeRecursively(newChild)) { + this._rootRenderer.addAttachCommand(newChild, false); } } } - private _createNativeRecursively(node: Node, isRoot: boolean = true): boolean { - var didCreate: boolean = false; - if (!node.isCreated) { - if (!node.isVirtual) { - node instanceof TextNode ? this._createTextCommand(node) : this._createElementCommand(node); - didCreate = !(node instanceof TextNode) || isRoot; - } - for (var i = 0; i < node.children.length; i++) { - var child = node.children[i]; - didCreate = this._createNativeRecursively(child, false) || didCreate; - if (!child.isVirtual && !(isRoot && node.isVirtual)) { - this._rootRenderer.addAttachCommand(child, false); - } - } - } - return didCreate; + removeChild(parent: any, oldChild: any): void { + const index = parent.children.indexOf(oldChild); + parent.children.splice(index, 1); + this._rootRenderer.addDetachCommand(oldChild); } - detachView(viewRootNodes: Node[]): void { - for (var i = 0; i < viewRootNodes.length; i++) { - var node = viewRootNodes[i]; - var parent = node.parent; - if (parent) { - var index = parent.children.indexOf(node); - parent.children.splice(index, 1); - this._rootRenderer.addDetachCommand(node); - } - } + parentNode(node: Node): Node { + return node.parent; } - destroyView(hostElement: any, viewAllNodes: Node[]): void { - for (var i = 0; i < viewAllNodes.length; i++) { - var node = viewAllNodes[i]; - node.toBeDestroyed = true; + nextSibling(node: Node): any { + let res = null; + const parent = node.parent; + if (parent) { + const index = parent.children.indexOf(node) + 1; + if (parent.children.length > index) { + res = parent.children[index]; + } } + return res; } - listen(renderElement: Node, name: string, callback: Function): Function { - renderElement.addEventListener(name, callback); - return () => {renderElement.removeEventListener(name, callback);}; + setAttribute(el: Node, name: string, value: string, namespace?: string | any): void { + var val: any = value; + if (name == "ng-version") return; + if (value == "false") val = false; + if (value == "true") val = true; + if (value == "null") val = null; + if (!isNaN(parseInt(val))) val = parseInt(val); + if (value.startsWith('#')) val = this._rootRenderer.wrapper.processColor(value); + this.setProperty(el, name, val); } - listenGlobal(target: string, name: string, callback: Function): Function { - console.error('NOT IMPLEMENTED: listenGlobal', arguments); - return () => {}; + removeAttribute(el: any, name: string, namespace?: string | any): void { } - setElementProperty(renderElement: Node, propertyName: string, propertyValue: any): void { - if (typeof propertyValue !== 'undefined') { - const cleanPropertyName = propertyName.startsWith('_on') ? propertyName.substr(1) : propertyName; - renderElement.setProperty(cleanPropertyName, propertyValue, false); - if (renderElement.isCreated) { - this._rootRenderer.addUpdateCommand(renderElement, cleanPropertyName, propertyValue); - } - } + addClass(el: any, name: string): void { + console.error('NOT IMPLEMENTED: addClass', arguments); } - setElementAttribute(renderElement: Node, attributeName: string, attributeValue: string): void { - var val: any = attributeValue; - if (attributeName == "ng-version") return; - if (attributeValue == "false") val = false; - if (attributeValue == "true") val = true; - if (attributeValue == "null") val = null; - if (!isNaN(parseInt(val))) val = parseInt(val); - if (attributeValue.startsWith('#')) val = this._rootRenderer.wrapper.processColor(attributeValue); - this.setElementProperty(renderElement, attributeName, val); + removeClass(el: any, name: string): void { + console.error('NOT IMPLEMENTED: removeClass', arguments); } - setBindingDebugInfo(renderElement: Node, propertyName: string, propertyValue: string): void { - //this.setElementProperty(renderElement, propertyName, propertyValue); + setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void { + console.error('NOT IMPLEMENTED: setStyle', arguments); } - setElementClass(renderElement:any, className:string, isAdd:boolean):any { - console.error('NOT IMPLEMENTED: setElementClass', arguments); + removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void { + console.error('NOT IMPLEMENTED: removeStyle', arguments); } - setElementStyle(renderElement:any, styleName:string, styleValue:string):any { - console.error('NOT IMPLEMENTED: setElementStyle', arguments); + setProperty(el: Node, name: string, value: any): void { + if (typeof value !== 'undefined') { + const cleanPropertyName = name.startsWith('_on') ? name.substr(1) : name; + el.setProperty(cleanPropertyName, value, false); + if (el.isCreated) { + this._rootRenderer.addUpdateCommand(el, cleanPropertyName, value); + } + } } - invokeElementMethod(renderElement: Node, methodName: string, args: any[]): void { - renderElement.dispatchCommand(methodName, args); + setValue(node: Node, value: string): void { + if (node instanceof TextNode) { + const trimedText = node.setText(value); + this.setProperty(node, 'text', trimedText); + } } - setText(renderNode: Node, text: string): void { - if (renderNode instanceof TextNode) { - var trimedText = renderNode.setText(text); - this.setElementProperty(renderNode, 'text', trimedText); + listen(target: 'window' | 'document' | 'body' | Node, eventName: string, callback: (event: any) => boolean | void): () => void { + if (target === 'window' || target == 'document' || target == 'body') { + console.error('NOT IMPLEMENTED: listen on ' + target, arguments); + return () => {}; + } else { + target.addEventListener(eventName, callback); + return () => {target.removeEventListener(eventName, callback);}; } + + } + + private _createElementCommand(node: Node): void { + this._rootRenderer.addCreateCommand(node); + node.isCreated = true; } - animate(element:any, startingStyles: any, keyframes: any[], duration: number, delay: number, easing: string): AnimationPlayer { - return undefined; + private _createTextCommand(node: TextNode): void { + this._rootRenderer.addCreateCommand(node, {text: node.properties['text']}); + var cmd = new NativeCommandCreate(node); + node.isCreated = true; + } + + private _createNativeRecursively(node: Node, isRoot: boolean = true): boolean { + var didCreate: boolean = false; + if (!node.isCreated) { + if (!node.isVirtual) { + node instanceof TextNode ? this._createTextCommand(node) : this._createElementCommand(node); + didCreate = !(node instanceof TextNode) || isRoot; + } + for (var i = 0; i < node.children.length; i++) { + var child = node.children[i]; + didCreate = this._createNativeRecursively(child, false) || didCreate; + if (!child.isVirtual && !(isRoot && node.isVirtual)) { + this._rootRenderer.addAttachCommand(child, false); + } + } + } + return didCreate; } } \ No newline at end of file diff --git a/src/router/router_outlet.ts b/src/router/router_outlet.ts index 259797b..ba81cfc 100644 --- a/src/router/router_outlet.ts +++ b/src/router/router_outlet.ts @@ -1,31 +1,72 @@ -import {Attribute, ComponentFactory, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core'; -import {RouterOutletMap, ActivatedRoute, PRIMARY_OUTLET} from '@angular/router'; +import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef} from '@angular/core'; +import {ChildrenOutletContexts, ActivatedRoute, PRIMARY_OUTLET} from '@angular/router'; @Directive({selector: 'router-outlet'}) -export class RouterOutlet implements OnDestroy { - private activated: ComponentRef; - private _activatedRoute: ActivatedRoute; - public outletMap: RouterOutletMap; +export class RouterOutlet implements OnDestroy, OnInit { + private activated: ComponentRef = null; + private _activatedRoute: ActivatedRoute = null; + private name: string; @Output('activate') activateEvents = new EventEmitter(); @Output('deactivate') deactivateEvents = new EventEmitter(); constructor( - private parentOutletMap: RouterOutletMap, private location: ViewContainerRef, - private resolver: ComponentFactoryResolver, @Attribute('name') private name: string) { - parentOutletMap.registerOutlet(name ? name : PRIMARY_OUTLET, this); + private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef, + private resolver: ComponentFactoryResolver, @Attribute('name') name: string) { + this.name = name || PRIMARY_OUTLET; + parentContexts.onChildOutletCreated(this.name, this); } - ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this.name ? this.name : PRIMARY_OUTLET); } + ngOnDestroy(): void { this.parentContexts.onChildOutletDestroyed(this.name); } + + ngOnInit(): void { + if (!this.activated) { + // If the outlet was not instantiated at the time the route got activated we need to populate + // the outlet when it is initialized. + const context = this.parentContexts.getContext(this.name); + if (context && context.route) { + if (context.attachRef) { + // `attachRef` is populated when there is an existing component to mount + this.attach(context.attachRef, context.route); + } else { + // otherwise the component defined in the configuration is created + this.activateWith(context.route, context.resolver || null); + } + } + } + } get isActivated(): boolean { return !!this.activated; } + get component(): Object { if (!this.activated) throw new Error('Outlet is not activated'); return this.activated.instance; } + get activatedRoute(): ActivatedRoute { if (!this.activated) throw new Error('Outlet is not activated'); - return this._activatedRoute; + return this._activatedRoute as ActivatedRoute; + } + + /** + * Called when the `RouteReuseStrategy` instructs to detach the subtree + */ + detach(): ComponentRef { + if (!this.activated) throw new Error('Outlet is not activated'); + this.location.detach(); + const cmp = this.activated; + this.activated = null; + this._activatedRoute = null; + return cmp; + } + + /** + * Called when the `RouteReuseStrategy` instructs to re-attach a previously detached subtree + */ + attach(ref: ComponentRef, activatedRoute: ActivatedRoute) { + this.activated = ref; + this._activatedRoute = activatedRoute; + this.location.insert(ref.hostView); } deactivate(): void { @@ -33,31 +74,41 @@ export class RouterOutlet implements OnDestroy { const c = this.component; this.activated.destroy(); this.activated = null; + this._activatedRoute = null; this.deactivateEvents.emit(c); } } - activate( - activatedRoute: ActivatedRoute, loadedResolver: ComponentFactoryResolver, - loadedInjector: Injector, providers: ResolvedReflectiveProvider[], - outletMap: RouterOutletMap): void { - this.outletMap = outletMap; + activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver) { + if (this.isActivated) { + throw new Error('Cannot activate an already activated outlet'); + } this._activatedRoute = activatedRoute; + const snapshot = activatedRoute['_futureSnapshot']; + const component = snapshot._routeConfig.component; + resolver = resolver || this.resolver; + const factory = resolver.resolveComponentFactory(component); + const childContexts = this.parentContexts.getOrCreateContext(this.name).children; + const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector); + this.activated = this.location.createComponent(factory, this.location.length, injector); + this.activateEvents.emit(this.activated.instance); + } +} - const component: any = activatedRoute.routeConfig.component; +class OutletInjector implements Injector { + constructor( + private route: ActivatedRoute, private childContexts: ChildrenOutletContexts, + private parent: Injector) {} - let factory: ComponentFactory; - if (loadedResolver) { - factory = loadedResolver.resolveComponentFactory(component); - } else { - factory = this.resolver.resolveComponentFactory(component); + get(token: any, notFoundValue?: any): any { + if (token === ActivatedRoute) { + return this.route; } - const injector = loadedInjector ? loadedInjector : this.location.parentInjector; - const inj = ReflectiveInjector.fromResolvedProviders(providers, injector); - this.activated = this.location.createComponent(factory, this.location.length, inj, []); - this.activated.changeDetectorRef.detectChanges(); + if (token === ChildrenOutletContexts) { + return this.childContexts; + } - this.activateEvents.emit(this.activated.instance); + return this.parent.get(token, notFoundValue); } } diff --git a/src/test_helpers/router_testing_module.ts b/src/test_helpers/router_testing_module.ts index 1f47f25..2cbeef0 100644 --- a/src/test_helpers/router_testing_module.ts +++ b/src/test_helpers/router_testing_module.ts @@ -1,6 +1,6 @@ import {Location, LocationStrategy} from '@angular/common'; import {Compiler, Injectable, Injector, ModuleWithProviders, NgModule, NgModuleFactory, NgModuleFactoryLoader} from '@angular/core'; -import {Route, Router, RouterOutletMap, Routes, UrlSerializer, provideRoutes, __router_private__, PreloadingStrategy, NoPreloading} from '@angular/router'; +import {Route, Router, Routes, UrlSerializer, provideRoutes, PreloadingStrategy, NoPreloading, ChildrenOutletContexts, ɵflatten, ɵROUTER_PROVIDERS, ROUTES} from '@angular/router'; import {ReactNativeRouterModule} from './../router/router_module'; import {ReactNativeLocationStrategy} from './../router/location_strategy'; @@ -20,23 +20,23 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader { } export function setupTestingRouter( - urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, + urlSerializer: UrlSerializer, childrenOutletContexts: ChildrenOutletContexts, location: Location, loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][]) { return new Router( - null, urlSerializer, outletMap, location, injector, loader, compiler, __router_private__.flatten(routes)); + null, urlSerializer, childrenOutletContexts, location, injector, loader, compiler, ɵflatten(routes)); } @NgModule({ exports: [ReactNativeRouterModule], providers: [ - __router_private__.ROUTER_PROVIDERS, + ɵROUTER_PROVIDERS, {provide: LocationStrategy, useClass: ReactNativeLocationStrategy }, {provide: NgModuleFactoryLoader, useClass: SpyNgModuleFactoryLoader}, { provide: Router, useFactory: setupTestingRouter, deps: [ - UrlSerializer, RouterOutletMap, Location, NgModuleFactoryLoader, Compiler, Injector, __router_private__.ROUTES + UrlSerializer, ChildrenOutletContexts, Location, NgModuleFactoryLoader, Compiler, Injector, ROUTES ] }, {provide: PreloadingStrategy, useExisting: NoPreloading}, diff --git a/src/test_helpers/utils.ts b/src/test_helpers/utils.ts index 5e29ffd..f338cc8 100644 --- a/src/test_helpers/utils.ts +++ b/src/test_helpers/utils.ts @@ -1,11 +1,10 @@ import {MockApplicationRef} from "./mock_application_ref"; -import {RootRenderer, ApplicationRef, Sanitizer, CUSTOM_ELEMENTS_SCHEMA, NgZone} from "@angular/core"; +import {RendererFactory2, ApplicationRef, Sanitizer, CUSTOM_ELEMENTS_SCHEMA, NgZone} from "@angular/core"; import {TestBed, getTestBed, ComponentFixture} from "@angular/core/testing"; import {LocationStrategy} from "@angular/common"; import {ElementSchemaRegistry} from "@angular/compiler"; import { ReactNativeRootRenderer, - ReactNativeRootRenderer_, ReactNativeElementSchemaRegistry, ReactNativeSanitizer, REACT_NATIVE_WRAPPER @@ -15,7 +14,6 @@ import {ReactNativeWrapper} from "../wrapper/wrapper"; import {Node} from "../renderer/node"; import {ReactNativeAndroidModule} from "../modules/android_module"; import {DatePicker} from "./../components/ios/date_picker"; -import {MapView} from "./../components/ios/map_view"; import {Navigator, NavigatorItem} from "./../components/ios/navigator"; import {ProgressView} from "./../components/ios/progress_view"; import {SegmentedControl} from "./../components/ios/segmented_control"; @@ -27,7 +25,7 @@ export function configureTestingModule(mock: ReactNativeWrapper, testCpt: any, d imports: [ReactNativeAndroidModule].concat(modules), providers: getTestingProviders(mock, testCpt), schemas: [CUSTOM_ELEMENTS_SCHEMA], - declarations: [DatePicker, MapView, Navigator, NavigatorItem, ProgressView, SegmentedControl, TabBar, TabBarItem, testCpt].concat(declarations) + declarations: [DatePicker, Navigator, NavigatorItem, ProgressView, SegmentedControl, TabBar, TabBarItem, testCpt].concat(declarations) }); // return tb; @@ -52,8 +50,8 @@ function getTestingProviders(mock: ReactNativeWrapper, testCpt: any): Array {provide: ElementSchemaRegistry, useExisting: ReactNativeElementSchemaRegistry}, ReactNativeSanitizer, {provide: Sanitizer, useExisting: ReactNativeSanitizer}, - {provide: ReactNativeRootRenderer, useClass: ReactNativeRootRenderer_}, - {provide: RootRenderer, useExisting: ReactNativeRootRenderer} + [ReactNativeRootRenderer], + {provide: RendererFactory2, useExisting: ReactNativeRootRenderer} ]; } diff --git a/src/testing.ts b/src/testing.ts index e5c7b2e..da56385 100644 --- a/src/testing.ts +++ b/src/testing.ts @@ -21,7 +21,6 @@ export * from './components/android/progress_bar'; export * from './components/android/toolbar'; export * from './components/ios/date_picker'; -export * from './components/ios/map_view'; export * from './components/ios/navigator'; export * from './components/ios/progress_view'; export * from './components/ios/segmented_control'; diff --git a/src/tsconfig.json b/src/tsconfig.json index 3fcddd1..590ab4b 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -6,7 +6,7 @@ "experimentalDecorators": true, "module": "es2015", "moduleResolution": "node", - "outDir": "../node_modules/angular2-react-native", + "outDir": "../node_modules/angular-react-native", "rootDir": ".", "sourceMap": true, "inlineSources": true, diff --git a/src/wrapper/wrapper_impl.ts b/src/wrapper/wrapper_impl.ts index be30ec8..bb497e2 100644 --- a/src/wrapper/wrapper_impl.ts +++ b/src/wrapper/wrapper_impl.ts @@ -9,9 +9,11 @@ var UIManager = ReactNative.NativeModules.UIManager; var resolveAssetSource = require('react-native/Libraries/Image/resolveAssetSource'); var dismissKeyboard = require('react-native/Libraries/Utilities/dismissKeyboard'); -var ReactNativeEventEmitter = require('react-native/Libraries/Renderer/src/renderers/native/ReactNativeEventEmitter'); -var ReactNativeTagHandles = require('react-native/Libraries/Renderer/src/renderers/native/ReactNativeTagHandles'); -var ReactNativeAttributePayload = require('react-native/Libraries/Renderer/src/renderers/native/ReactNativeAttributePayload'); +var ReactNativeStackEntry = require('react-native/Libraries/Renderer/ReactNativeStack-dev'); + +var ReactNativeEventEmitter = ReactNativeStackEntry.ReactNativeEventEmitter; +var ReactNativeTagHandles = ReactNativeStackEntry.ReactNativeTagHandles; +var ReactNativeAttributePayload = ReactNativeStackEntry.ReactNativeAttributePayload; var ReactNativeViewAttributes = require('react-native/Libraries/Components/View/ReactNativeViewAttributes'); overridePlatform(ReactNative.Platform.OS); @@ -53,7 +55,6 @@ const RCT_VIEW_NAMES: { [s: string]: string } = ReactNative.Platform.OS == 'andr 'native-dialogpicker': 'RCTPicker', 'native-activityindicator': 'RCTActivityIndicatorView', 'native-datepicker': 'RCTDatePicker', - 'native-mapview': 'RCTMap', 'native-navigator': 'RCTNavigator', 'native-navitem': 'RCTNavItem', 'native-progressview': 'RCTProgressView', diff --git a/test/components/android/drawer_layout_spec.ts b/test/components/android/drawer_layout_spec.ts index b759d2c..7775229 100644 --- a/test/components/android/drawer_layout_spec.ts +++ b/test/components/android/drawer_layout_spec.ts @@ -14,8 +14,8 @@ describe('DrawerLayout component (Android)', () => { initTest(TestComponent, ``); expect(mock.commandLogs.toString()).toEqual( 'CREATE+2+test-cmp+{},CREATE+3+native-drawerlayout+{"drawerWidth":250},CREATE+4+native-view+{"bottom":0,"collapsable":false,"left":0,"position":"absolute","right":0,"top":0},' + - 'CREATE+5+native-view+{},CREATE+6+native-view+{"bottom":0,"collapsable":false,"position":"absolute","top":0,"width":250},CREATE+7+native-view+{},' + - 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+6+1,ATTACH+4+5+0,ATTACH+6+7+0'); + 'CREATE+5+native-view+{"bottom":0,"collapsable":false,"position":"absolute","top":0,"width":250},CREATE+6+native-view+{},CREATE+7+native-view+{},' + + 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+5+1,ATTACH+4+6+0,ATTACH+5+7+0'); }); it('should render with properties', () => { diff --git a/test/components/ios/map_view_spec.ts b/test/components/ios/map_view_spec.ts deleted file mode 100644 index 01ba25a..0000000 --- a/test/components/ios/map_view_spec.ts +++ /dev/null @@ -1,61 +0,0 @@ -import {Component, ViewChild} from "@angular/core"; -import {MockReactNativeWrapper} from "./../../../src/wrapper/wrapper_mock"; -import {fireFunctionalEvent, configureTestingModule, initTest} from "../../../src/test_helpers/utils"; -import {MapView} from "../../../src/components/ios/map_view"; - -describe('DatePicker component (iOS)', () => { - const mock: MockReactNativeWrapper = new MockReactNativeWrapper(); - beforeEach(() => { - mock.reset(); - configureTestingModule(mock, TestComponent); - }); - - it('should render', () => { - initTest(TestComponent, ``); - expect(mock.commandLogs.toString()).toEqual( - 'CREATE+2+test-cmp+{},CREATE+3+native-mapview+{"onChange":true,"onPress":false,"onAnnotationDragStateChange":false,"onAnnotationFocus":false,"onAnnotationBlur":false},' + - 'ATTACH+1+2+0,ATTACH+2+3+0'); - }); - - it('should render with properties', () => { - initTest(TestComponent, ``); - expect(mock.commandLogs.toString()).toEqual( - 'CREATE+2+test-cmp+{},CREATE+3+native-mapview+{"onChange":true,' + - '"annotations":[{"longitude":1,"latitude":2,"tintColor":42,"id":"%7B%22longitude%22%3A1%2C%22latitude%22%3A2%2C%22tintColor%22%3A%22%23123456%22%7D"}],' + - '"onPress":true,"onAnnotationDragStateChange":true,"onAnnotationFocus":true,"onAnnotationBlur":true,"accessible":true,"testID":"foo"},ATTACH+1+2+0,ATTACH+2+3+0'); - }); - - it('should render with styles', () => { - initTest(TestComponent, ``); - expect(mock.commandLogs.toString()).toEqual( - 'CREATE+2+test-cmp+{},CREATE+3+native-mapview+{"onChange":true,"onPress":false,"onAnnotationDragStateChange":false,' + - '"onAnnotationFocus":false,"onAnnotationBlur":false,"flex":1,"collapse":true,"margin":42},ATTACH+1+2+0,ATTACH+2+3+0'); - }); - - it('should fire change event', () => { - const {fixture, rootRenderer} = initTest(TestComponent, ``); - mock.clearLogs(); - - const target = fixture.elementRef.nativeElement.children[0].children[0]; - fireFunctionalEvent('topChange', target, {annotation: {}, action: 'click'}); - - fixture.whenStable().then(() => { - expect(fixture.componentInstance.log.join(',')).toEqual('click'); - }); - - }); - -}); - -@Component({ - selector: 'test-cmp', - template: `to be overriden` -}) -class TestComponent { - @ViewChild(MapView) mapView: MapView; - log: Array = []; - - handleChange(event: any) { - this.log.push(event.action); - } -} \ No newline at end of file diff --git a/test/components/ios/navigator_spec.ts b/test/components/ios/navigator_spec.ts index 0e68030..d9cae87 100644 --- a/test/components/ios/navigator_spec.ts +++ b/test/components/ios/navigator_spec.ts @@ -28,7 +28,7 @@ describe('Navigator component (iOS)', () => { expect(mock.commandLogs.toString()).toEqual( 'CREATE+2+test-cmp+{},ATTACH+1+2+0,CREATE+3+native-navigator+{"onNavigationComplete":true,"flex":1},' + 'CREATE+4+native-navitem+{"onLeftButtonPress":true,"onRightButtonPress":true,"title":"aaa","backgroundColor":"white","overflow":"hidden","position":"absolute","top":0,"left":0,"right":0,"bottom":64,"padding":37},' + - 'CREATE+5+cmp-a+{},CREATE+6+native-text+{},CREATE+7+native-rawtext+{"text":"a"},ATTACH+6+7+0,ATTACH+5+6+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+4+5+0'); + 'CREATE+5+cmp-a+{},CREATE+6+native-text+{},CREATE+7+native-rawtext+{"text":"a"},ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+6+7+0,ATTACH+5+6+0,ATTACH+4+5+0'); })); it('should navigate to another route', fakeAsync(() => { @@ -47,7 +47,7 @@ describe('Navigator component (iOS)', () => { expect(mock.commandLogs.toString()).toEqual( 'REQUEST_NAVIGATOR_LOCK+3+,UPDATE+3+native-navigator+{"requestedTopOfStack":1},' + 'CREATE+8+native-navitem+{"onLeftButtonPress":true,"onRightButtonPress":true,"title":"bbb","backgroundColor":"white","overflow":"hidden","position":"absolute","top":0,"left":0,"right":0,"bottom":64},' + - 'CREATE+9+cmp-b+{},CREATE+10+native-text+{},CREATE+11+native-rawtext+{"text":"b"},ATTACH+10+11+0,ATTACH+9+10+0,ATTACH+3+8+1,ATTACH+8+9+0'); + 'CREATE+9+cmp-b+{},CREATE+10+native-text+{},CREATE+11+native-rawtext+{"text":"b"},ATTACH+3+8+1,ATTACH+10+11+0,ATTACH+9+10+0,ATTACH+8+9+0'); }); })); @@ -66,7 +66,7 @@ describe('Navigator component (iOS)', () => { rootRenderer.executeCommands(); mock.clearLogs(); - const target = fixture.nativeElement.children[0].children[1]; + const target = fixture.nativeElement.children[0].children[0]; fireFunctionalEvent('topNavigationComplete', target, {stackLength: 1}); tick(); @@ -88,7 +88,7 @@ describe('Navigator component (iOS)', () => { 'CREATE+2+test-cmp+{},ATTACH+1+2+0,' + 'CREATE+3+native-navigator+{"onNavigationComplete":true,"flex":1},' + 'CREATE+4+native-navitem+{"onLeftButtonPress":true,"onRightButtonPress":true,"title":"aaa","backgroundColor":"white","overflow":"hidden","position":"absolute","top":0,"left":0,"right":0,"bottom":64,"margin":42,"padding":37},' + - 'CREATE+5+cmp-a+{},CREATE+6+native-text+{},CREATE+7+native-rawtext+{"text":"a"},ATTACH+6+7+0,ATTACH+5+6+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+4+5+0'); + 'CREATE+5+cmp-a+{},CREATE+6+native-text+{},CREATE+7+native-rawtext+{"text":"a"},ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+6+7+0,ATTACH+5+6+0,ATTACH+4+5+0'); })); it('should fire button press events', fakeAsync(() => { @@ -99,7 +99,7 @@ describe('Navigator component (iOS)', () => { fixture.detectChanges(); rootRenderer.executeCommands(); - const target = fixture.elementRef.nativeElement.children[0].children[1].children[2].children[0]; + const target = fixture.elementRef.nativeElement.children[0].children[0].children[2].children[0]; fireFunctionalEvent('topLeftButtonPress', target, {}); tick(); diff --git a/test/renderer/component_without_host_spec.ts b/test/renderer/component_without_host_spec.ts index ab2c60a..b92b228 100644 --- a/test/renderer/component_without_host_spec.ts +++ b/test/renderer/component_without_host_spec.ts @@ -29,14 +29,14 @@ describe('Component without host', () => { expect(mock.commandLogs.toString()).toEqual( 'CREATE+2+test-cmp+{},CREATE+3+native-view+{},CREATE+4+native-view+{},' + 'CREATE+5+native-view+{},CREATE+6+native-view+{},CREATE+7+native-view+{},' + - 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+6+7+0,ATTACH+5+6+0,ATTACH+4+5+0,ATTACH+3+4+0'); + 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+4+5+0,ATTACH+5+6+0,ATTACH+6+7+0'); }); it('should support sub-components', () => { const {fixture, rootRenderer} = initTest(TestComponent, ``); rootRenderer.executeCommands(); expect(mock.commandLogs.toString()).toEqual( - 'CREATE+2+test-cmp+{},CREATE+3+native-view+{},CREATE+4+sub+{},CREATE+5+native-view+{},ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+4+5+0,ATTACH+3+4+0'); + 'CREATE+2+test-cmp+{},CREATE+3+native-view+{},CREATE+4+sub+{},CREATE+5+native-view+{},ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+4+5+0'); }); it('should support ngIf', () => { @@ -107,7 +107,7 @@ describe('Component without host', () => { const {fixture, rootRenderer} = initTest(TestComponent, ``); rootRenderer.executeCommands(); expect(mock.commandLogs.toString()).toEqual( - 'CREATE+2+test-cmp+{},CREATE+3+proj+{},CREATE+4+native-text+{},CREATE+5+sub+{},CREATE+6+native-view+{},ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+5+1,ATTACH+5+6+0'); + 'CREATE+2+test-cmp+{},CREATE+3+proj+{},CREATE+4+sub+{},CREATE+5+native-view+{},CREATE+6+native-text+{},ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+6+1,ATTACH+4+5+0'); }); it('should support components with ngIf in their templates', () => { @@ -122,7 +122,7 @@ describe('Component without host', () => { rootRenderer.executeCommands(); expect(mock.commandLogs.toString()).toEqual( 'CREATE+2+test-cmp+{},CREATE+3+sub-with-if+{},CREATE+4+native-view+{},CREATE+5+native-view+{},CREATE+6+native-text+{},' + - 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+5+2,ATTACH+3+6+1'); + 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+5+1,ATTACH+3+6+2'); }); it('should not attach twice components with ngIf in their templates', () => { @@ -130,7 +130,7 @@ describe('Component without host', () => { rootRenderer.executeCommands(); expect(mock.commandLogs.toString()).toEqual( 'CREATE+2+test-cmp+{},CREATE+3+native-view+{},CREATE+4+native-view+{},CREATE+5+native-view+{},CREATE+6+native-dialogpicker+{"items":[],"mode":"dialog","height":50},' + - 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+5+2,ATTACH+3+6+1'); + 'ATTACH+1+2+0,ATTACH+2+3+0,ATTACH+3+4+0,ATTACH+3+5+1,ATTACH+3+6+2'); }); }); diff --git a/test/renderer/element_spec.ts b/test/renderer/element_spec.ts index 4615956..471a66b 100644 --- a/test/renderer/element_spec.ts +++ b/test/renderer/element_spec.ts @@ -129,19 +129,19 @@ describe('Element', () => { expect(mock.nativeElementMap.get(1).children[0].children.map((a: NativeElement) => a.children[0].properties['text']).join(',')).toEqual('8'); }); - it('should support NgFor in a