Skip to content

Instantly share code, notes, and snippets.

@mndvns
Created January 11, 2015 06:37
Show Gist options
  • Save mndvns/8ff5885673075cbd95a4 to your computer and use it in GitHub Desktop.
Save mndvns/8ff5885673075cbd95a4 to your computer and use it in GitHub Desktop.
/**
* Module dependencies
*/
var React = require('react');
var dom = React.createElement;
var Router = require('react-router');
var RouteHandler = Router.RouteHandler;
var Link = Router.Link;
var Store = require('./store');
var T = require('./translate');
var Form = require('./form');
var Input = require('./input');
var LoadingStatusMixin = require('react-loading-status-mixin');
/**
* Slice
*/
var slice = Array.prototype.slice;
/**
*
*/
var ReactObject = React.PropTypes.object;
module.exports = function(name, render, renderError, subs) {
var wrappedRenderError = wrapRenderError(renderError);
var className = name.toLowerCase() + '-component';
return React.createClass({
displayName: name,
mixins: [ Router.State, LoadingStatusMixin ],
componentWillMount: function() {
var self = this;
var store = self.store = Store(self);
store.bind(self);
self.t = T(store);
store.on('complete', function() {
self.setIsLoaded(true);
});
if (module.hot) {
if (subs) subs[self._nodeID] = function() {
self.forceUpdate();
};
}
},
componentWillUnmount: module.hot && function() {
if (subs) delete subs[this._nodeID];
},
yieldFn: function() {
var c = this.props.children;
return c ? c : dom(RouteHandler);
},
domFn: function(tag, props, children) {
var a = arguments;
if (process.env.NODE_ENV !== 'production' && tag === 'json')
return dom('pre', props, JSON.stringify(children, null, ' '));
if (tag === 'form' && props && props.template) return dom(Form, props, slice.call(a, 2));
if (tag === 'input') return dom(Input, props, slice.call(a, 2));
if (tag !== 'a' || !props || !props.to) return dom.apply(null, a);
var params = props.params = encode(props.params);
if (!params) {
delete props.to;
return dom.apply(null, a);
}
return dom(Link, props, slice.call(a, 2));
},
shouldComponentUpdate: function(nextProps, nextState) {
var self = this;
var path = self.context.getCurrentPath();
if (path !== self._prevPath) delete self._cache;
self._prevPath = path;
// TODO compare props and state to delete the cache
return true;
},
renderFn: function() {
var self = this;
var domFn = self.domFn;
var store = self.store;
var get = store.get;
var yieldFn = self.yieldFn;
var props = self.props;
var state = self.state;
var t = self.t;
store.start();
var params = decode(self.getParams());
var children, hasError;
try {
children = render(domFn, get, yieldFn, props, state, params, t);
} catch (err) {
console.error(err.stack || err);
hasError = true;
children = wrappedRenderError(domFn, get, yieldFn, props, state, params, t, err);
}
store.stop();
var loadedState = hasError || self.isLoaded() ? 'loaded' : 'loading';
return dom('div', {className: className + ' ' + loadedState}, children);
},
render: function() {
var self = this;
// return self._cache = self._cache || self.renderFn();
return self.renderFn();
}
});
};
function wrapRenderError(renderError) {
if (!renderError) return renderGenericError;
return function(dom, get, yieldFn, props, state, params, t, err) {
try {
return renderError(dom, get, yieldFn, props, state, params, t);
} catch (e) {
return renderGenericError.apply(null, arguments);
}
};
}
function renderGenericError(dom, get, yieldFn, props, state, params, t, err) {
return process.env.NODE_ENV === 'production' ?
dom('div', {className: 'error'}, t('error.generic')) :
dom('pre', {className: 'error'}, (err.stack || err.message));
}
function encode(params) {
var obj = {}, v;
for (var k in params) {
v = obj[k] = Store.URL.encode(params[k]);
if (!v) return;
}
return obj;
}
function decode(params) {
// TODO check if there are any invalid params
// there's a lot of pooly implemented bots that lowercase
// all of their urls
var obj = {};
for (var k in params) {
obj[k] = Store.URL.decode(params[k]);
}
return obj;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment