diff --git a/karma.conf.continuous-test.js b/karma.conf.continuous-test.js index 8241d5cce3..ba83232e92 100644 --- a/karma.conf.continuous-test.js +++ b/karma.conf.continuous-test.js @@ -8,7 +8,8 @@ module.exports = function karmaConfig(config) { frameworks: [ 'mocha' ], files: [ - 'tests.webpack.js' + 'tests.webpack.js', + { pattern: './web/client/test-resources/**/*', included: false } ], preprocessors: { diff --git a/karma.conf.single-run.js b/karma.conf.single-run.js index af53be0119..fc3697ff91 100644 --- a/karma.conf.single-run.js +++ b/karma.conf.single-run.js @@ -8,7 +8,8 @@ module.exports = function karmaConfig(config) { frameworks: [ 'mocha' ], files: [ - 'tests.webpack.js' + 'tests.webpack.js', + { pattern: './web/client/test-resources/**/*', included: false } ], preprocessors: { diff --git a/package.json b/package.json index 2e6819175e..113045fb19 100644 --- a/package.json +++ b/package.json @@ -45,10 +45,13 @@ "react": "^0.13.3", "react-bootstrap": "^0.24.3", "react-intl": "^1.2.0", + "react-redux": "^1.0.0", + "redux": "^1.0.0", + "redux-thunk": "^0.1.0", "url": "~0.10.3" }, "scripts": { - "clean": "rm -Rf ./web/dist", + "clean": "rm -Rf ./web/client/dist", "compile": "npm run clean && mkdirp ./web/client/dist && webpack", "start": "webpack-dev-server --progress --colors --port 8081 --content-base web/client", "test": "karma start ./karma.conf.single-run.js", diff --git a/web/client/actions/I18NActions.jsx b/web/client/actions/I18NActions.jsx deleted file mode 100644 index 0ba834d59a..0000000000 --- a/web/client/actions/I18NActions.jsx +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright 2015, GeoSolutions Sas. - * 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. - */ -var assign = require('object-assign'); -var keymirror = require('keymirror'); - -var Dispatcher = require('../dispatchers/Dispatcher'); - -var I18NActions = { - launch(actionType, args) { - Dispatcher.dispatch(assign({type: actionType}, args)); - } -}; - -assign(I18NActions, keymirror({ - CHANGE_LANG: null -})); - -module.exports = I18NActions; diff --git a/web/client/actions/__tests__/I18NActions-test.jsx b/web/client/actions/__tests__/I18NActions-test.jsx deleted file mode 100644 index a957adaa7d..0000000000 --- a/web/client/actions/__tests__/I18NActions-test.jsx +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright 2015, GeoSolutions Sas. - * 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. - */ -var expect = require('expect'); -var assign = require('object-assign'); -var Dispatcher = require('../../dispatchers/Dispatcher'); - -describe('This test for I18NActions', () => { - var I18NActions; - - beforeEach((done) => { - I18NActions = require('../I18NActions'); - setTimeout(done); - }); - - afterEach((done) => { - var name = require.resolve('../I18NActions'); - delete require.cache[name]; - setTimeout(done); - }); - - it('checks launch(actionType, args)', () => { - const aType = "test"; - const aArgs = { - k0: "v0", - k1: "v1" - }; - const testArgs = assign({type: aType}, aArgs); - const spy = expect.spyOn(Dispatcher, 'dispatch'); - I18NActions.launch(aType, aArgs); - - expect(spy.calls.length).toBe(1); - expect(spy.calls[0].context).toBe(Dispatcher); - expect(spy.calls[0].arguments).toEqual([ testArgs ]); - }); -}); diff --git a/web/client/actions/__tests__/config-test.js b/web/client/actions/__tests__/config-test.js new file mode 100644 index 0000000000..0ce9ef7a39 --- /dev/null +++ b/web/client/actions/__tests__/config-test.js @@ -0,0 +1,36 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ + +var expect = require('expect'); +var loadMapConfig = require('../config').loadMapConfig; + +describe('Test configuration related actions', () => { + it('does not load a missing configuration file', (done) => { + loadMapConfig('missingConfig.json')((e) => { + try { + expect(e).toExist(); + expect(e.type).toBe('MAP_CONFIG_LOAD_ERROR'); + done(); + } catch(ex) { + done(ex); + } + }); + }); + + it('loads an existing configuration file', (done) => { + loadMapConfig('base/web/client/test-resources/testConfig.json')((e) => { + try { + expect(e).toExist(); + expect(e.type).toBe('MAP_CONFIG_LOADED'); + done(); + } catch(ex) { + done(ex); + } + }); + }); +}); diff --git a/web/client/actions/__tests__/locale-test.js b/web/client/actions/__tests__/locale-test.js new file mode 100644 index 0000000000..3c50a7ab3e --- /dev/null +++ b/web/client/actions/__tests__/locale-test.js @@ -0,0 +1,36 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ + +var expect = require('expect'); +var loadLocale = require('../locale').loadLocale; + +describe('Test locale related actions', () => { + it('does not load a missing translation file', (done) => { + loadLocale('', 'unknown')((e) => { + try { + expect(e).toExist(); + expect(e.type).toBe('LOCALE_LOAD_ERROR'); + done(); + } catch(ex) { + done(ex); + } + }); + }); + + it('loads an existing translation file', (done) => { + loadLocale('base/web/client/test-resources', 'it-IT')((e) => { + try { + expect(e).toExist(); + expect(e.type).toBe('CHANGE_LOCALE'); + done(); + } catch(ex) { + done(ex); + } + }); + }); +}); diff --git a/web/client/actions/config.js b/web/client/actions/config.js new file mode 100644 index 0000000000..ca460363fe --- /dev/null +++ b/web/client/actions/config.js @@ -0,0 +1,39 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ + +var axios = require('axios'); + +const MAP_CONFIG_LOADED = 'MAP_CONFIG_LOADED'; +const MAP_CONFIG_LOAD_ERROR = 'MAP_CONFIG_LOAD_ERROR'; + +function configureMap(conf, legacy) { + return { + type: MAP_CONFIG_LOADED, + config: conf, + legacy: legacy || false + }; +} + +function configureError(e) { + return { + type: MAP_CONFIG_LOAD_ERROR, + error: e + }; +} + +function loadMapConfig(configName, legacy) { + return (dispatch) => { + return axios.get(configName).then((response) => { + dispatch(configureMap(response.data, legacy)); + }).catch((e) => { + dispatch(configureError(e)); + }); + }; +} + +module.exports = {MAP_CONFIG_LOADED, MAP_CONFIG_LOAD_ERROR, loadMapConfig}; diff --git a/web/client/actions/locale.js b/web/client/actions/locale.js new file mode 100644 index 0000000000..5a45f79128 --- /dev/null +++ b/web/client/actions/locale.js @@ -0,0 +1,39 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ + +var axios = require('axios'); + +const CHANGE_LOCALE = 'CHANGE_LOCALE'; +const LOCALE_LOAD_ERROR = 'LOCALE_LOAD_ERROR'; + +function changeLocale(data) { + return { + type: CHANGE_LOCALE, + messages: data.messages, + locale: data.locale + }; +} + +function localeError(e) { + return { + type: LOCALE_LOAD_ERROR, + error: e + }; +} + +function loadLocale(translationFolder, language) { + return (dispatch) => { + return axios.get(translationFolder + '/data.' + language).then((response) => { + dispatch(changeLocale(response.data)); + }).catch((e) => { + dispatch(localeError(e)); + }); + }; +} + +module.exports = {CHANGE_LOCALE, LOCALE_LOAD_ERROR, loadLocale}; diff --git a/web/client/components/I18N/Localized.jsx b/web/client/components/I18N/Localized.jsx new file mode 100644 index 0000000000..87e533e49e --- /dev/null +++ b/web/client/components/I18N/Localized.jsx @@ -0,0 +1,36 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ +var React = require('react'); + +var Localized = React.createClass({ + propTypes: { + locale: React.PropTypes.string, + messages: React.PropTypes.object + }, + childContextTypes: { + locale: React.PropTypes.string, + messages: React.PropTypes.object + }, + getChildContext() { + return { + locale: this.props.locale, + messages: this.props.messages + }; + }, + render() { + let { children } = this.props; + + if (typeof children === 'function') { + children = children(); + } + + return React.Children.only(children); + } + }); + +module.exports = Localized; diff --git a/web/client/components/I18N/Message.jsx b/web/client/components/I18N/Message.jsx index 8420148a54..bcd5984192 100644 --- a/web/client/components/I18N/Message.jsx +++ b/web/client/components/I18N/Message.jsx @@ -9,40 +9,22 @@ var React = require('react'); var ReactIntl = require('react-intl'); var FormattedMessage = ReactIntl.FormattedMessage; -var I18NStore = require('../../stores/I18NStore'); - var Message = React.createClass({ propTypes: { + locale: React.PropTypes.string, + messages: React.PropTypes.object, msgId: React.PropTypes.string.isRequired, msgParams: React.PropTypes.object }, - getInitialState() { - const currentLocale = I18NStore.getCurrentLocale(); - const msg = I18NStore.getMsgById(this.props.msgId); - return { - locales: currentLocale, - msg: msg - }; - }, - // it makes this component reactive when a new language is loaded in - // language store. - componentDidMount() { - I18NStore.register(I18NStore.Event.LANG_CHANGED, this.onLangChanged); - }, - componentWillUnmount() { - I18NStore.unregister(I18NStore.Event.LANG_CHANGED, this.onLangChanged); - }, - // it updates the state of this component when the language store loads a new one. - onLangChanged() { - const currentLocale = I18NStore.getCurrentLocale(); - const msg = I18NStore.getMsgById(this.props.msgId); - this.setState({ - locales: currentLocale, - msg: msg - }); + contextTypes: { + locale: React.PropTypes.string.isRequired, + messages: React.PropTypes.object }, render() { - return ; + var locale = this.props.locale || this.context.locale; + var messages = this.props.messages || this.context.messages; + + return ; } }); diff --git a/web/client/components/I18N/__tests__/I18N.Message-test.jsx b/web/client/components/I18N/__tests__/I18N.Message-test.jsx index 3bc3cf61f5..958e1684d0 100644 --- a/web/client/components/I18N/__tests__/I18N.Message-test.jsx +++ b/web/client/components/I18N/__tests__/I18N.Message-test.jsx @@ -8,46 +8,55 @@ var expect = require('expect'); var React = require('react/addons'); -var I18NStore = require('../../../stores/I18NStore'); var I18N = require('../I18N'); -var I18NActions = require('../../../actions/I18NActions'); -var ita = require('../../../stores/data.it-IT'); -var eng = require('../../../stores/data.en-US'); +var ita = { + "locale": "it-IT", + "messages": { + "aboutLbl": "Info" + } +}; +var eng = { + "locale": "en-US", + "messages": { + "aboutLbl": "About" + } +}; describe('This test for I18N.Message', () => { + const msgId = "aboutLbl"; + const data = { + "en-US": eng, + "it-IT": ita + }; + afterEach((done) => { React.unmountComponentAtNode(document.body); document.body.innerHTML = ''; setTimeout(done); }); - it('checks if the component reacts at I18NStore edits', () => { - var testMsg; - var currentData; - const msgId = "aboutLbl"; - const data = { - "en-US": eng, - "it-IT": ita - }; - currentData = data[I18NStore.getCurrentLocale()]; - testMsg = currentData.messages[msgId]; - - const cmp = React.render(, document.body); + it('checks if the component renders english messages', () => { + var currentData = data["en-US"]; + var testMsg = currentData.messages[msgId]; + + const cmp = React.render(, document.body); expect(cmp).toExist(); const cmpDom = React.findDOMNode(cmp); expect(cmpDom).toExist(); expect(cmpDom.innerHTML).toBe(testMsg); + }); - const nextLocale = I18NStore.getCurrentLocale() === "it-It" ? "en-US" : "it-IT"; - I18NStore._emulate_dispatcher({ - locale: nextLocale, - type: I18NActions.CHANGE_LANG - }); + it('checks if the component renders italian messages', () => { + var currentData = data["it-IT"]; + var testMsg = currentData.messages[msgId]; - currentData = data[I18NStore.getCurrentLocale()]; - testMsg = currentData.messages[msgId]; + const cmp = React.render(, document.body); + expect(cmp).toExist(); + + const cmpDom = React.findDOMNode(cmp); + expect(cmpDom).toExist(); expect(cmpDom.innerHTML).toBe(testMsg); }); }); diff --git a/web/client/components/I18N/__tests__/Localized-test.jsx b/web/client/components/I18N/__tests__/Localized-test.jsx new file mode 100644 index 0000000000..6b0cbfd3fc --- /dev/null +++ b/web/client/components/I18N/__tests__/Localized-test.jsx @@ -0,0 +1,35 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ +var expect = require('expect'); + +var React = require('react/addons'); +var Localized = require('../Localized'); +var Message = require('../Message'); + +const messages = { + "testMsg": "my message" +}; + +describe('Test the localization support HOC', () => { + afterEach((done) => { + React.unmountComponentAtNode(document.body); + document.body.innerHTML = ''; + setTimeout(done); + }); + + it('localizes wrapped component', () => { + var localized = React.render( + + {() => } + + , document.body); + var dom = React.findDOMNode(localized); + expect(dom).toExist(); + expect(dom.innerHTML).toBe("my message"); + }); +}); diff --git a/web/client/components/LangSelector/LangSelector.jsx b/web/client/components/LangSelector/LangSelector.jsx index 9ef8e962e2..07bbec24ef 100644 --- a/web/client/components/LangSelector/LangSelector.jsx +++ b/web/client/components/LangSelector/LangSelector.jsx @@ -9,17 +9,18 @@ var React = require('react'); var BootstrapReact = require('react-bootstrap'); var Input = BootstrapReact.Input; - -var I18NStore = require('../../stores/I18NStore'); -var I18NActions = require('../../actions/I18NActions'); +var LocaleUtils = require('../../utils/LocaleUtils'); var LangSelector = React.createClass({ propTypes: { - locales: React.PropTypes.object + locales: React.PropTypes.object, + currentLocale: React.PropTypes.string, + onLanguageChange: React.PropTypes.func }, getDefaultProps() { return { - locales: I18NStore.getSupportedLocales() + locales: LocaleUtils.getSupportedLocales(), + currentLocale: 'en-US' }; }, render() { @@ -28,13 +29,13 @@ var LangSelector = React.createClass({ var list = []; for (let lang in this.props.locales) { if (this.props.locales.hasOwnProperty(lang)) { - val = this.props.locales[lang]; - label = lang; + val = this.props.locales[lang].code; + label = this.props.locales[lang].description; list.push({label}); } } return ( - + {list} ); @@ -42,7 +43,7 @@ var LangSelector = React.createClass({ launchNewLangAction() { var element = React.findDOMNode(this); var selectNode = element.getElementsByTagName('select').item(0); - I18NActions.launch(I18NActions.CHANGE_LANG, {locale: selectNode.value}); + this.props.onLanguageChange(selectNode.value); } }); diff --git a/web/client/components/LangSelector/__tests__/LangSelector-test.jsx b/web/client/components/LangSelector/__tests__/LangSelector-test.jsx index 1867a5787b..5772b1d72d 100644 --- a/web/client/components/LangSelector/__tests__/LangSelector-test.jsx +++ b/web/client/components/LangSelector/__tests__/LangSelector-test.jsx @@ -8,8 +8,6 @@ var expect = require('expect'); var React = require('react/addons'); -var I18NStore = require('../../../stores/I18NStore'); -var I18NActions = require('../../../actions/I18NActions'); var LangSelector = require('../LangSelector'); describe('LangSelector', () => { @@ -32,7 +30,7 @@ describe('LangSelector', () => { const select = cmpDom.getElementsByTagName("select").item(0); const opts = select.childNodes; - const langs = I18NStore.getSupportedLocales(); + const langs = {'Italiano': 'it-IT', 'English': 'en-US'}; for (let i = 0; i < opts.length; i++) { lbl = opts[i].innerHTML; @@ -42,10 +40,9 @@ describe('LangSelector', () => { } }); - it('checks if a change of the compo fires the proper action', () => { - const spy = expect.spyOn(I18NActions, 'launch'); - - const cmp = React.render(, document.body); + it('checks if a change of the combo fires the proper action', () => { + let newLang; + const cmp = React.render( {newLang = lang; }}/>, document.body); const cmpDom = React.findDOMNode(cmp); const select = cmpDom.getElementsByTagName("select").item(0); @@ -53,7 +50,6 @@ describe('LangSelector', () => { React.addons.TestUtils.Simulate.change(select, {target: {value: 'it-IT'}}); // select.children[1].click(); - expect(spy.calls.length).toBe(1); - expect(spy.calls[0].arguments).toEqual([I18NActions.CHANGE_LANG, {locale: "it-IT"}]); + expect(newLang).toBe('it-IT'); }); }); diff --git a/web/client/components/leaflet/Layer.jsx b/web/client/components/leaflet/Layer.jsx index 8c28473d08..f3544e462c 100644 --- a/web/client/components/leaflet/Layer.jsx +++ b/web/client/components/leaflet/Layer.jsx @@ -41,8 +41,8 @@ var LeafletLayer = React.createClass({ break; case "wms": this.layer = L.tileLayer.wms( - WMSUtils.getWMSURL(options.sourceOptions.url), - WMSUtils.wmsToLeafletOptions(options.sourceOptions, options) + WMSUtils.getWMSURL(options.url), + WMSUtils.wmsToLeafletOptions(options) ); break; default: diff --git a/web/client/components/leaflet/__tests__/Layer-test.jsx b/web/client/components/leaflet/__tests__/Layer-test.jsx index 85d59c4c1c..1b5b480cf6 100644 --- a/web/client/components/leaflet/__tests__/Layer-test.jsx +++ b/web/client/components/leaflet/__tests__/Layer-test.jsx @@ -52,14 +52,12 @@ describe('Leaflet layer', () => { }); it('creates a wms layer for leaflet map', () => { var options = { - "source": "demo", + "type": "wms", "visibility": true, "name": "nurc:Arc_Sample", "group": "Meteo", "format": "image/png", - "sourceOptions": { - "url": "http://demo.geo-solutions.it/geoserver/wms" - } + "url": "http://demo.geo-solutions.it/geoserver/wms" }; // create layers var layer = React.render( diff --git a/web/client/dispatchers/Dispatcher.jsx b/web/client/dispatchers/Dispatcher.jsx deleted file mode 100644 index ccdf52787c..0000000000 --- a/web/client/dispatchers/Dispatcher.jsx +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright 2015, GeoSolutions Sas. - * 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. - */ -var Dispatcher = require('flux').Dispatcher; - -module.exports = new Dispatcher(); diff --git a/web/client/examples/viewer/app.jsx b/web/client/examples/viewer/app.jsx index 28dd61f1bc..a5d3067368 100644 --- a/web/client/examples/viewer/app.jsx +++ b/web/client/examples/viewer/app.jsx @@ -6,47 +6,30 @@ * LICENSE file in the root directory of this source tree. */ var React = require('react'); -var MapViewController = require('../../components/Map/MapViewController'); -var InfoButton = require('../../components/InfoButton/InfoButton'); -var I18N = require('../../components/I18N/I18N'); -var LangSelector = require('../../components/LangSelector/LangSelector'); -var ConfigUtils = require('../../utils/ConfigUtils'); + +var Provider = require('react-redux').Provider; +var Viewer = require('./containers/Viewer'); var url = require('url'); -var Api = require('../../api/MapConfigDAO'); - -// window.geoStoreBase = "http://mapstore.geo-solutions.it/geostore/rest/" -Api.getMergedConfig("../data/mapStoreConfig.json", url.parse(window.location.href, true).query.mapId, window.geoStoreBase).then( function(legacyConfig) { - const mapId = "map"; - // convert from legacy - const conf = ConfigUtils.convertFromLegacy(legacyConfig); - React.render(, document.getElementById("mapContainer")); -}); - -React.render(} - title={} - glyphicon="info-sign" - body={ - - MapStore 2 - - OpenLayers 3 Leaflet. - - - - - - - - MapStore wiki. - - - - - - - - - }/>, document.getElementById("aboutContainer")); -React.render(, document.getElementById("langSelContainer")); +var loadMapConfig = require('../../actions/config').loadMapConfig; +var loadLocale = require('../../actions/locale').loadLocale; +var ConfigUtils = require('../../utils/ConfigUtils'); +var LocaleUtils = require('../../utils/LocaleUtils'); + +var store = require('./stores/viewerstore'); + +const urlQuery = url.parse(window.location.href, true).query; + +const { configUrl, legacy } = ConfigUtils.getConfigurationOptions(urlQuery, 'config', 'json'); + +store.dispatch(loadMapConfig(configUrl, legacy)); + +let locale = LocaleUtils.getLocale(urlQuery); +store.dispatch(loadLocale('../../translations', locale)); + +React.render( + + {() => } + , + document.getElementById('container') +); diff --git a/web/client/examples/viewer/config.json b/web/client/examples/viewer/config.json new file mode 100644 index 0000000000..5c5514f956 --- /dev/null +++ b/web/client/examples/viewer/config.json @@ -0,0 +1,39 @@ +{ + "map": { + "projection": "EPSG:900913", + "units": "m", + "center": [1250000.000000, 5370000.000000], + "zoom":5, + "maxExtent": [ + -20037508.34, -20037508.34, + 20037508.34, 20037508.34 + ], + "layers": [ + { + "type": "osm", + "title": "Open Street Map", + "name": "mapnik", + "group": "background", + "visibility": true + },{ + "type": "wms", + "url":"http://213.215.135.196/reflector/open/service", + "visibility": false, + "title": "e-Geos Ortofoto RealVista 1.0", + "name": "rv1", + "group": "background", + "format": "image/png" + }, + { + "type": "wms", + "url":"http://demo.geo-solutions.it/geoserver/wms", + "visibility": true, + "opacity": 0.5, + "title": "Weather data", + "name": "nurc:Arc_Sample", + "group": "Meteo", + "format": "image/png" + } + ] + } +} diff --git a/web/client/examples/viewer/containers/Viewer.jsx b/web/client/examples/viewer/containers/Viewer.jsx new file mode 100644 index 0000000000..9575be008e --- /dev/null +++ b/web/client/examples/viewer/containers/Viewer.jsx @@ -0,0 +1,103 @@ +/** + * Copyright 2015, GeoSolutions Sas. + * 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. + */ +var React = require('react'); +var connect = require('react-redux').connect; +var LMap = require('../../../components/leaflet/Map'); +var LLayer = require('../../../components/leaflet/Layer'); +var ConfigUtils = require('../../../utils/ConfigUtils'); +var LangSelector = require('../../../components/LangSelector/LangSelector'); +var InfoButton = require('../../../components/InfoButton/InfoButton'); +var I18N = require('../../../components/I18N/I18N'); +var Localized = require('../../../components/I18N/Localized'); +var loadLocale = require('../../../actions/locale').loadLocale; + +var Viewer = React.createClass({ + propTypes: { + mapConfig: React.PropTypes.object, + messages: React.PropTypes.object, + locale: React.PropTypes.string, + dispatch: React.PropTypes.func + }, + renderLayers(layers) { + if (layers) { + return layers.map(function(layer) { + return ; + }); + } + return null; + }, + renderPlugins(locale) { + return [ + + + , + + } + title={} + glyphicon="info-sign" + body={ + + MapStore 2 + + OpenLayers 3 Leaflet. + + + + + + + + MapStore wiki. + + + + + + + + + }/> + + ]; + }, + render() { + if (this.props.mapConfig && this.props.messages) { + let config = this.props.mapConfig; + if (config.loadingError) { + return {config.loadingError}; + } + let center = ConfigUtils.getCenter(config.center, config.projection); + return ( + + {() => + + + {this.renderLayers(config.layers)} + + {this.renderPlugins(this.props.locale)} + + } + + + ); + } + return null; + }, + switchLanguage(lang) { + this.props.dispatch(loadLocale('../../translations', lang)); + } +}); + +module.exports = connect((state) => { + return { + mapConfig: state.mapConfig, + messages: state.locale ? state.locale.messages : null, + locale: state.locale ? state.locale.current : null + }; +})(Viewer); diff --git a/web/client/examples/viewer/index.html b/web/client/examples/viewer/index.html index 9d86b29d59..1378eb6322 100644 --- a/web/client/examples/viewer/index.html +++ b/web/client/examples/viewer/index.html @@ -13,7 +13,7 @@
- OpenLayers 3 Leaflet. -
- -
+ OpenLayers 3 Leaflet. +
+ +