Skip to content

Commit

Permalink
Merge pull request #102 from aksonov/2.0
Browse files Browse the repository at this point in the history
2.0 version
  • Loading branch information
Pavlo Aksonov committed Jan 4, 2016
2 parents a6649ca + 9c808ee commit 50e322c
Show file tree
Hide file tree
Showing 9 changed files with 787 additions and 585 deletions.
90 changes: 90 additions & 0 deletions Actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import Route from './Route';
import Router from './Router';

function isNumeric(n){
return !isNaN(parseFloat(n)) && isFinite(n);
}

function filterParam(data){
if (data.toString()!='[object Object]')
return data;
if (!data){
return;
}
var proto = (data||{}).constructor.name;
// avoid passing React Native parameters
if (proto != 'Object'){
data = {};
}
if (data.data){
data.data = filterParam(data.data);
}
return data;
}

class Actions {
currentRouter: ?Router;

constructor(){
this.pop = this.pop.bind(this);
this.route = this.route.bind(this);
}

route(name: string, props: { [key: string]: any} = {}){
if (!this.currentRouter){
throw new Error("No current router is set");
}
if (props.toString()!='[object Object]')
props = {data : props};

props = filterParam(props);
// check if route is in children, current or parent routers
let router: Router = this.currentRouter;
// deep into child router
while (router.currentRoute.childRouter){
router = router.currentRoute.childRouter;
}
while (!router.routes[name]){
const route = router.parentRoute;
if (!route || !route.parent){
throw new Error("Cannot find router for route="+name);
}
router = route.parent;
}
if (router.route(name, props)){
this.currentRouter = router;
return true;
}
return false;
}
pop(num: number = 1){
if (!isNumeric(num)){
num = 1;
}
if (!this.currentRouter){
throw new Error("No current router is set");
}
if (num > 1){
for (let i=0;i<num;i++){
if (!Actions.pop()){
return false;
}
}
return true;
} else {
let router: Router = this.currentRouter;
while (router.stack.length <= 1 || router.currentRoute.type === 'switch'){
router = router.parentRoute.parent;
}
if (router.pop()){
this.currentRouter = router;
return true;
} else {
return false;
}

}
}
}

export default new Actions();
23 changes: 23 additions & 0 deletions Common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react-native';

// schema class represents schema for routes and it is processed inside Router component
export class Schema extends React.Component {
className(){
return "Schema";
}
render(){
return null;
}
}

// route class processed inside Router component
export class Route extends React.Component {
className(){
return "Route";
}
render(){
return null;
}

}

195 changes: 195 additions & 0 deletions ExRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import React from 'react-native';
import Router from './Router';
import Route from './Route';
import * as Components from './Common';
import ExNavigator from '@exponent/react-native-navigator';
import Animations from './Animations';
const {TouchableOpacity, StyleSheet, View, Text} = React;
import ReactRouter from './ReactRouter';

export class ExRoute {
name: string;
navigator: ExNavigator;
route: Route;
props: { [key: string]: any};

constructor(route: Route, props:{ [key: string]: any} = {}){
if (!route){
throw new Error("route is not defined ");
}
this.route = route;
this.name = route.name;
if (!this.name){
throw new Error("name is not defined for route");
}
this.props = props;
this.renderScene = this.renderScene.bind(this);
}

configureScene() {
return this.route.type === 'switch' ? Animations.None : this.route.props.sceneConfig || Animations.None;
}

renderScene(navigator) {
const Component = this.route.component;
const child = Component ?
!this.route.wrapRouter ? <Component key={this.route.name} name={this.route.name} {...this.route.props} {...this.props} route={this.route}/>:
<ReactRouter name={this.route.name+"Router"} {...this.route.props} {...this.props} route={this.route} router={ExRouter} >
<Components.Route {...this.route.props} {...this.props} component={Component} name={"_"+this.route.name} type="push" wrapRouter={false}/>
</ReactRouter>
:
React.cloneElement(React.Children.only(this.route.children), {...this.route.props, data:this.props, route:this.route});
return child;
}

getName(){
return this.route.name;
}

getTitle() {
return this.route.title || "";
}

getBackButtonTitle(navigator, index, state){
let previousIndex = index - 1;
let previousRoute = state.routeStack[previousIndex];
let title = previousRoute.getTitle(navigator, previousIndex, state);
return title.length>10 ? null : title;
}

renderRightButton() {
if (this.route.onRight && this.route.rightTitle){
return (<TouchableOpacity
touchRetentionOffset={ExNavigator.Styles.barButtonTouchRetentionOffset}
onPress={() => this.route.onRight({...this.route.props, ...this.props})}
style={[ExNavigator.Styles.barRightButton, this.route.rightButtonStyle]}>
<Text style={[ExNavigator.Styles.barRightButtonText, this.route.rightButtonTextStyle]}>{this.route.rightTitle}</Text>
</TouchableOpacity>);
} else {
return null;
}
}
}

const defaultCreateRoute = function(route, data){
return new ExRoute(route, data);
};

export default class ExRouter extends React.Component {
router: Router;

constructor(props){
super(props);
this.onPop = this.onPop.bind(this);
this.onPush = this.onPush.bind(this);
this.onPop = this.onPop.bind(this);
this.onPush = this.onPush.bind(this);
this.onReplace = this.onReplace.bind(this);
this.onJump = this.onJump.bind(this);
}

onPush(route: Route, props:{ [key: string]: any}):boolean {
if (this.props.onPush){
const res = this.props.onPush(route, props);
if (!res){
return false;
}
}
this.refs.nav.push(new ExRoute(route, props));
return true;
}

onReplace(route: Route, props:{ [key: string]: any}):boolean {
if (this.props.onReplace){
const res = this.props.onReplace(route, props);
if (!res){
return false;
}
}
this.refs.nav.replace(new ExRoute(route, props));
return true;
}

onJump(route: Route, props:{ [key: string]: any}):boolean {
if (this.props.onJump){
const res = this.props.onJump(route, props);
if (!res){
return false;
}
}
const navigator = this.refs.nav;
const routes = navigator.getCurrentRoutes();
const exist = routes.filter(el=>el.getName()==route.name);
if (exist.length){
navigator.jumpTo(exist[0]);
} else {
navigator.push(new ExRoute(route, props));

}
this.setState({selected: route.name});
return true;
}

onPop(num: number){
if (this.props.onPop){
const res = this.props.onPop(num);
if (!res){
return false;
}
}
this.refs.nav.pop();
return true;
}

render() {
const router = this.props.router;
if (!router){
throw new Error("No router is defined");
}
const Header = this.props.header;
const header = Header ? <Header {...this.props} {...this.state}/> : null;

const Footer = this.props.footer;
const footer = Footer ? <Footer {...this.props} {...this.state}/> : null;

return (
<View style={styles.transparent}>
{header}
<ExNavigator ref="nav" initialRouteStack={router.stack.map(route => new ExRoute(router.routes[route]))}
style={styles.transparent}
sceneStyle={{ paddingTop: 0 }}
showNavigationBar={!this.props.hideNavBar}
{...this.props}
/>
{footer}
</View>
);
}


}


var styles = StyleSheet.create({
container: {
position: 'absolute',
top:0,
bottom:0,
left:0,
right:0,
backgroundColor:'transparent',
justifyContent: 'center',
alignItems: 'center',
},
transparent: {
flex:1,
backgroundColor: "transparent"
},
barTitleText: {
fontFamily: '.HelveticaNeueInterface-MediumP4',
fontSize: 17,
marginTop: 11,
},

});

37 changes: 37 additions & 0 deletions ReactRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) 2015-present, Pavel Aksonov
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*
*/

import React from 'react-native'
import Router from './Router';
import ExRouter from './ExRouter';
const {StyleSheet, View} = React;
import Actions from './Actions';
export default class extends React.Component {

constructor(props){
super(props);
const createRouter = props.createRouter || this.createRouter;
this.router = createRouter(props);
}

createRouter(props){
const schemas = React.Children.map(props.children, child=>child).filter(child=>child.type.prototype.className() === "Schema").map(child=>child.props);
const routes = React.Children.map(props.children, child=>child).filter(child=>child.type.prototype.className() === "Route").map(child=>child.props);
return new Router(routes, schemas, props.initialRoutes || (props.initial && [props.initial]), props);
}

componentDidMount(){
this.router.delegate = this.refs.router;
}

render(){
const Component = this.props.router || ExRouter;
return (<Component ref="router" {...this.props} router={this.router} />);
}
}
Loading

0 comments on commit 50e322c

Please sign in to comment.