From 1c0b21a1345a92a776d3969fd0c726db58dccb5f Mon Sep 17 00:00:00 2001 From: Mauro Bartolomeoli Date: Tue, 28 Mar 2017 10:34:18 +0200 Subject: [PATCH] Fixes #1645: custom connect to be used in plugins definition; properties in pluginCfg override state connected properties --- .gitignore | 1 + .../components/plugins/PluginsContainer.jsx | 2 +- web/client/plugins/ScaleBox.jsx | 2 +- web/client/utils/PluginsUtils.js | 20 ++++++++++++++ .../utils/__tests__/PluginUtils-test.js | 26 ++++++++++++++++--- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 7741507ad4..ac7a81da43 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ _site .jekyll-metadata *.lock docs/developer-guide/reference/ +web/client/mapstore/docs/ diff --git a/web/client/components/plugins/PluginsContainer.jsx b/web/client/components/plugins/PluginsContainer.jsx index 0a80fae9d0..bf691efbab 100644 --- a/web/client/components/plugins/PluginsContainer.jsx +++ b/web/client/components/plugins/PluginsContainer.jsx @@ -65,7 +65,7 @@ const PluginsContainer = React.createClass({ .filter((Plugin) => !Plugin.impl.loadPlugin) .filter(this.filterPlugins) .map((Plugin) => ); + {...this.props.params} {...Plugin.cfg} pluginCfg={Plugin.cfg} items={Plugin.items}/>); }, render() { if (this.props.pluginsConfig) { diff --git a/web/client/plugins/ScaleBox.jsx b/web/client/plugins/ScaleBox.jsx index c978e5ae94..c98b76091c 100644 --- a/web/client/plugins/ScaleBox.jsx +++ b/web/client/plugins/ScaleBox.jsx @@ -7,7 +7,7 @@ */ const React = require('react'); -const {connect} = require('react-redux'); +const {connect} = require('../utils/PluginsUtils'); const {createSelector} = require('reselect'); const {mapSelector} = require('../selectors/map'); diff --git a/web/client/utils/PluginsUtils.js b/web/client/utils/PluginsUtils.js index 5a05d2f0bd..70d0884d09 100644 --- a/web/client/utils/PluginsUtils.js +++ b/web/client/utils/PluginsUtils.js @@ -9,6 +9,8 @@ const assign = require('object-assign'); const {omit, isObject, head, isArray, isString} = require('lodash'); const {combineReducers} = require('redux'); +const {connect} = require('react-redux'); + const {combineEpics} = require('redux-observable'); const {memoize, get} = require('lodash'); @@ -122,6 +124,11 @@ const getReducers = (plugins) => Object.keys(plugins).map((name) => plugins[name const getEpics = (plugins) => Object.keys(plugins).map((name) => plugins[name].epics) .reduce((previous, current) => assign({}, previous, current), {}); +const pluginsMergeProps = (stateProps, dispatchProps, ownProps) => { + const {pluginCfg, ...otherProps} = ownProps; + return assign({}, otherProps, stateProps, dispatchProps, pluginCfg || {}); +}; + /** * Utilities to manage plugins * @class @@ -193,6 +200,19 @@ const PluginsUtils = { items: getPluginItems(state, plugins, pluginsConfig, name, id, isDefault, loadedPlugins) }; }, + /** + * Custom react-redux connect function that can override state property with plugin config. + * The plugin config properties are taken from the **pluginCfg** property. + + * @param {function} [mapStateToProps] state to properties selector + * @param {function} [mapDispatchToProps] dispatchable actions selector + * @param {function} [mergeProps] merge function, if not defined, the internal override applies + * @param {object} [options] connect options (look at react-redux docs for details) + * @returns {function} funtion to be applied to the dumb object to connect it to state / dispatchers + */ + connect: (mapStateToProps, mapDispatchToProps, mergeProps, options) => { + return connect(mapStateToProps, mapDispatchToProps, mergeProps || pluginsMergeProps, options); + }, getMorePrioritizedContainer }; module.exports = PluginsUtils; diff --git a/web/client/utils/__tests__/PluginUtils-test.js b/web/client/utils/__tests__/PluginUtils-test.js index 8686bd1245..29acafe467 100644 --- a/web/client/utils/__tests__/PluginUtils-test.js +++ b/web/client/utils/__tests__/PluginUtils-test.js @@ -5,18 +5,23 @@ * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ +const React = require('react'); +const ReactDOM = require('react-dom'); +const {Provider} = require('react-redux'); const expect = require('expect'); const PluginsUtils = require('../PluginsUtils'); const assign = require('object-assign'); const MapSearchPlugin = require('../../plugins/MapSearch'); describe('PluginsUtils', () => { - beforeEach( () => { - + beforeEach((done) => { + document.body.innerHTML = '
'; + setTimeout(done); }); + afterEach((done) => { + ReactDOM.unmountComponentAtNode(document.getElementById("container")); document.body.innerHTML = ''; - setTimeout(done); }); it('combineReducers', () => { @@ -79,5 +84,18 @@ describe('PluginsUtils', () => { const epics = PluginsUtils.combineEpics(plugins, appEpics); expect(typeof epics ).toEqual('function'); }); - + it('connect', () => { + const MyComponent = (props) =>
{props.test}
; + const Connected = PluginsUtils.connect((state) => ({test: state.test}), {})(MyComponent); + const store = { + dispatch: () => {}, + subscribe: () => {}, + getState: () => ({ + test: "statetest" + }) + }; + const app = ReactDOM.render(, document.getElementById("container")); + const domElement = ReactDOM.findDOMNode(app); + expect(domElement.innerText).toBe("plugintest"); + }); });