From 920366660296748a78f3cf193249db41bbce6fe3 Mon Sep 17 00:00:00 2001 From: kaesonho Date: Mon, 8 Aug 2016 17:22:16 -0700 Subject: [PATCH] rollback breaking change, add doc for the change --- README.md | 1 - docs/api/setupI13n.md | 9 +++++++++ src/libs/ReactI13n.js | 15 ++++++++++++++- src/mixins/I13nMixin.js | 3 ++- src/mixins/I13nUtils.js | 24 ++++++++++++++++++------ src/utils/setupI13n.js | 2 +- tests/unit/utils/setupI13n.js | 2 +- 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 16dbeb0a..1d7cb8ba 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ var I13nDempApp = setupI13n(DemoApp, { Or follow our guide and [create your own](./docs/guides/createPlugins.md). - ## I13n Tree ![I13n Tree](https://cloud.githubusercontent.com/assets/3829183/7980892/0b38eb70-0a60-11e5-8cc2-712ec42089fc.png) diff --git a/docs/api/setupI13n.md b/docs/api/setupI13n.md index a7b7811d..bbd68244 100644 --- a/docs/api/setupI13n.md +++ b/docs/api/setupI13n.md @@ -27,6 +27,15 @@ var I13nDempApp = setupI13n(DemoApp, { }, [someReactI13nPlugin]); // then you could use I13nDemoApp to render you app + +### Create and access the ReactI13n instance + +What we do with `setupI13n` is that we will create the `ReactI13n` instance, along with a root node of the I13nTree, passing them via component context to the children. + +It's designed to work within React components, you should be able to just [utilFuctions](https://github.com/yahoo/react-i13n/blob/master/docs/guides/utilFunctions.md) and trigger i13n events. In case you want to do this out of React components, you can access `window._reactI13nInstance` directly. + +If you have multiple react trees in one page, we will create multiple i13n trees based on how many react tree you have. On client side the [utilFuctions](https://github.com/yahoo/react-i13n/blob/master/docs/guides/utilFunctions.md) still work based on the global instance object, while on server side, only the children under `setupI13n` can get the react i13n instance as we don't have a proper way to share the reactI13n instance without causing [memory leak](https://github.com/yahoo/react-i13n/pull/100). + ``` ### Util Functions diff --git a/src/libs/ReactI13n.js b/src/libs/ReactI13n.js index c47e8c42..b273a9f6 100644 --- a/src/libs/ReactI13n.js +++ b/src/libs/ReactI13n.js @@ -23,6 +23,7 @@ if ('client' === ENVIRONMENT) { * @param {Object} options options object * @param {Boolean} options.isViewportEnabled if enable viewport checking * @param {Object} options.rootModelData model data of root i13n node + * @param {Object} options.i13nNodeClass the i13nNode class, you can inherit it with your own functionalities * @param {String} options.scrollableContainerId id of the scrollable element that your components * reside within. Normally, you won't need to provide a value for this. This is only to * support viewport checking when your components are contained within a scrollable element. @@ -32,6 +33,7 @@ if ('client' === ENVIRONMENT) { var ReactI13n = function ReactI13n (options) { debug('init', options); options = options || {}; + this._i13nNodeClass = 'function' === typeof options.i13nNodeClass ? options.i13nNodeClass : I13nNode; this._plugins = {}; this._eventsQueues = {}; this._isViewportEnabled = options.isViewportEnabled || false; @@ -45,7 +47,8 @@ var ReactI13n = function ReactI13n (options) { * @method createRootI13nNode */ ReactI13n.prototype.createRootI13nNode = function createRootI13nNode () { - this._rootI13nNode = new I13nNode(null, this._rootModelData, false); + var I13nNodeClass = this.getI13nNodeClass(); + this._rootI13nNode = new I13nNodeClass(null, this._rootModelData, false); if ('client' === ENVIRONMENT) { this._rootI13nNode.setDOMNode(document.body); } @@ -128,6 +131,15 @@ ReactI13n.prototype.getEventHandlers = function getEventHandlers (eventName, pay return promiseHandlers; }; +/** + * Get I13n node class + * @method getI13nNodeClass + * @return {Object} I13nNode class + */ +ReactI13n.prototype.getI13nNodeClass = function getI13nNodeClass () { + return this._i13nNodeClass; +}; + /** * Get isViewportEnabled value * @method isViewportEnabled @@ -175,6 +187,7 @@ ReactI13n.prototype.getRootI13nNode = function getRootI13nNode () { ReactI13n.prototype.updateOptions = function updateOptions (options) { debug('updated', options); options = options || {}; + this._i13nNodeClass = 'function' === typeof options.i13nNodeClass ? options.i13nNodeClass : this._i13nNodeClass; this._isViewportEnabled = (undefined !== options.isViewportEnabled) ? options.isViewportEnabled : this._isViewportEnabled; this._rootModelData = options.rootModelData ? options.rootModelData : this._rootModelData; diff --git a/src/mixins/I13nMixin.js b/src/mixins/I13nMixin.js index 87f31c72..8cda6c5c 100644 --- a/src/mixins/I13nMixin.js +++ b/src/mixins/I13nMixin.js @@ -366,8 +366,9 @@ var I13nMixin = { var self = this; var parentI13nNode = self._getParentI13nNode(); var reactI13n = self._getReactI13n(); + var I13nNodeClass = (reactI13n && reactI13n.getI13nNodeClass()) || I13nNode;; // TODO @kaesonho remove BC for model - self._i13nNode = new I13nNode( + self._i13nNode = new I13nNodeClass( parentI13nNode, self.props.i13nModel || self.props.model, self.isLeafNode(), diff --git a/src/mixins/I13nUtils.js b/src/mixins/I13nUtils.js index e1f9535b..c286429f 100644 --- a/src/mixins/I13nUtils.js +++ b/src/mixins/I13nUtils.js @@ -14,7 +14,7 @@ var I13nUtils = { executeEvent: React.PropTypes.func, getI13nNode: React.PropTypes.func, parentI13nNode: React.PropTypes.object, - reactI13nInstance: React.PropTypes.object + _reactI13nInstance: React.PropTypes.object }) }, @@ -23,7 +23,7 @@ var I13nUtils = { executeEvent: React.PropTypes.func, getI13nNode: React.PropTypes.func, parentI13nNode: React.PropTypes.object, - reactI13nInstance: React.PropTypes.object + _reactI13nInstance: React.PropTypes.object }) }, @@ -34,12 +34,12 @@ var I13nUtils = { */ getChildContext: function () { return { - i13n: Object.assign({}, this.context.i13n, { + i13n: { executeEvent: this.executeI13nEvent, getI13nNode: this.getI13nNode, parentI13nNode: this._i13nNode, - reactI13nInstance: this._getReactI13n() - }) + _reactI13nInstance: this._getReactI13n() + } }; }, @@ -53,11 +53,23 @@ var I13nUtils = { */ executeI13nEvent: function (eventName, payload, callback) { var reactI13nInstance = this._getReactI13n(); + var errorMessage = ''; payload = payload || {}; payload.i13nNode = payload.i13nNode || this.getI13nNode(); if (reactI13nInstance) { reactI13nInstance.execute(eventName, payload, callback); } else { + if ('production' !== process.env.NODE_ENV) { + errorMessage = 'ReactI13n instance is not found, ' + + 'please make sure you have setupI13n on the root component. '; + if (!IS_CLIENT) { + errorMessage += 'On server side, ' + + 'you can only execute the i13n event on the components under setupI13n, ' + + 'please make sure you are calling executeI13nEvent correctly'; + } + console && console.warn && console.warn(errorMessage); + console && console.trace && console.trace(); + } callback && callback(); } }, @@ -83,7 +95,7 @@ var I13nUtils = { globalReactI13n = window._reactI13nInstance; } return this._reactI13nInstance || - (this.context && this.context.i13n && this.context.i13n.reactI13nInstance) || + (this.context && this.context.i13n && this.context.i13n._reactI13nInstance) || globalReactI13n; }, diff --git a/src/utils/setupI13n.js b/src/utils/setupI13n.js index 21e49401..b347f4fb 100644 --- a/src/utils/setupI13n.js +++ b/src/utils/setupI13n.js @@ -30,7 +30,7 @@ module.exports = function setupI13n (Component, options, plugins) { mixins: [I13nUtils], - displayName: options.displayName || ('setupI13n(' + componentName + ')'), + displayName: options.displayName || ('RootI13n' + componentName), autobind: false, diff --git a/tests/unit/utils/setupI13n.js b/tests/unit/utils/setupI13n.js index 864c9b59..6af0f081 100644 --- a/tests/unit/utils/setupI13n.js +++ b/tests/unit/utils/setupI13n.js @@ -70,7 +70,7 @@ describe('setupI13n', function () { // check the initial state is correct after render var I13nTestApp = setupI13n(TestApp, mockData.options, [mockData.plugin]); - expect(I13nTestApp.displayName).to.eql('setupI13n(TestApp)'); + expect(I13nTestApp.displayName).to.eql('RootI13nTestApp'); var container = document.createElement('div'); var component = ReactDOM.render(React.createElement(I13nTestApp, {}), container); expect(mockData.reactI13n._options).to.eql(mockData.options);