1 | var React = require('react');
|
2 | var createElement = React.createElement;
|
3 | var types = React.PropTypes;
|
4 | var URL = require('url');
|
5 | var Emitter = require('events');
|
6 |
|
7 | var Application = module.exports = React.createClass({
|
8 | displayName: 'Application',
|
9 |
|
10 | componentWillMount: function() {
|
11 | var self = this;
|
12 | var props = self.props;
|
13 | self.streams = new Emitter();
|
14 | self.client = props.createClient(props.src, props.props, self);
|
15 | if (process.env.NODE_ENV == 'development') {
|
16 | this.history = [];
|
17 | this.tt = function tt(i) {
|
18 | if (i >= this.history.length) throw Error('History out of bounds');
|
19 | this.setState({tree: this.history[i]});
|
20 | };
|
21 | }
|
22 | },
|
23 |
|
24 | componentWillReceiveProps: function(newProps) {
|
25 | var props = this.props;
|
26 | if (props.src !== newProps.src ||
|
27 | JSON.stringify(props.props) !== JSON.stringify(newProps.props)) {
|
28 | this.client.mount(newProps.src, newProps.props);
|
29 | }
|
30 | },
|
31 |
|
32 | componentWillUnmount: function() {
|
33 | this.client.unmount();
|
34 | },
|
35 |
|
36 | childContextTypes: {
|
37 | action: types.func,
|
38 | authenticate: types.func,
|
39 | tree: types.object,
|
40 | transclude: types.func,
|
41 | appSrc: types.string,
|
42 | streams: types.object
|
43 | },
|
44 |
|
45 | getChildContext: function() {
|
46 | var client = this.client;
|
47 | var props = this.props;
|
48 | return {
|
49 | action: client.action,
|
50 | authenticate: client.authenticate,
|
51 | tree: this.state.tree,
|
52 | transclude: this.transclude,
|
53 | appSrc: props.src,
|
54 | streams: this.streams
|
55 | };
|
56 | },
|
57 |
|
58 | transclude: function(src, appProps) {
|
59 | var props = this.props;
|
60 |
|
61 | if (src && src.charAt(0) == '/') {
|
62 | var url = URL.parse(src);
|
63 | url.pathname = url.path = src;
|
64 | src = URL.format(url);
|
65 | }
|
66 |
|
67 | return createElement(Application, Object.assign({}, props, {
|
68 | src: src,
|
69 | props: appProps
|
70 | }));
|
71 | },
|
72 |
|
73 | getInitialState: function() {
|
74 | return {
|
75 | tree: {
|
76 | components: {
|
77 | $root: null
|
78 | },
|
79 | schemas: {}
|
80 | },
|
81 | error: null
|
82 | };
|
83 | },
|
84 |
|
85 | render: function() {
|
86 | var state = this.state;
|
87 | var error = state.error;
|
88 | return error ?
|
89 | createElement('pre', {
|
90 | style: {
|
91 | color: 'red',
|
92 | 'font-family': 'monospace'
|
93 | }
|
94 | }, error) :
|
95 | state.tree.components.$root;
|
96 | },
|
97 |
|
98 |
|
99 | mount: function(message) {
|
100 | var init = process.env.NODE_ENV == 'development' ?
|
101 | this.history[0] :
|
102 | this.state.tree;
|
103 |
|
104 | var tree = message.body.reduce(function(acc, fun) {
|
105 | return fun(acc, init);
|
106 | }, init);
|
107 |
|
108 | if (process.env.NODE_ENV == 'development') this.history.unshift(tree);
|
109 |
|
110 | this.setState({tree: tree, error: null});
|
111 | },
|
112 |
|
113 | unmount: function() {
|
114 |
|
115 | },
|
116 |
|
117 | notFound: function(message) {
|
118 | this.setState({error: 'Not found: ' + message.path});
|
119 | },
|
120 |
|
121 | authenticationRequired: function() {
|
122 |
|
123 | },
|
124 |
|
125 | unauthorized: function() {
|
126 |
|
127 | },
|
128 |
|
129 | info: function(message) {
|
130 | var self = this;
|
131 | var props = self.props;
|
132 | var name = message.name;
|
133 | var data = message.data || {};
|
134 | var obj = {};
|
135 | if (name === '_emit') {
|
136 | var streams = self.streams;
|
137 | return Object.keys(data).forEach(function(id) {
|
138 | data[id].forEach(function(event) {
|
139 | streams.emit(id, event);
|
140 | });
|
141 | });
|
142 | }
|
143 | if (name === 'event') obj = props.events || {};
|
144 | var call = obj[data.type];
|
145 | if (call) call(data.props);
|
146 | },
|
147 |
|
148 | call: function(message, cb) {
|
149 |
|
150 | },
|
151 |
|
152 | error: function(message) {
|
153 | this.setState({error: message.info});
|
154 | }
|
155 | });
|