From 5359643a1b047f2e98acdf9863a90fc0d127d7fb Mon Sep 17 00:00:00 2001 From: Lorenzo Natali Date: Wed, 3 May 2017 12:25:32 +0200 Subject: [PATCH] First Implementation of the 3d switcher. (#1754) * First Implementation of the 3d switcher. The GlobeSwitcher plugin allow to switch to Globe view. In this pull request I also syncronize the maptype with it's reducer to keep in sync the maptype forever in the state. This is a first step to manage maptype's dependent tools (e.g. navigation tools) using react-redux system. * Fixed duplicated export and docs --- docma-config.json | 8 ++ .../actions/__tests__/globeswitcher-test.js | 31 +++++++ web/client/actions/__tests__/maptype-test.jsx | 23 +++++ web/client/actions/globeswitcher.js | 58 ++++++++++++ .../actions/home.js => actions/maptype.js} | 15 +++- .../buttons/GlobeViewSwitcherButton.jsx | 89 +++++++++++++++++++ .../GlobeViewSwitcherButton-test.jsx | 36 ++++++++ .../epics/__tests__/globeswitcher-test.js | 52 +++++++++++ web/client/epics/globeswitcher.js | 43 +++++++++ web/client/epics/maptype.js | 39 ++++++++ web/client/localConfig.json | 4 +- web/client/plugins/GlobeViewSwitcher.jsx | 49 ++++++++++ web/client/plugins/Maps.jsx | 4 +- web/client/plugins/searchbar/ToggleButton.jsx | 2 +- web/client/product/app.jsx | 2 +- web/client/product/plugins.js | 3 +- web/client/product/plugins/MapType.jsx | 19 ++-- web/client/product/reducers/home.js | 20 ----- .../reducers/__tests__/globeswitcher-test.js | 24 +++++ web/client/reducers/__tests__/maps-test.jsx | 6 +- web/client/reducers/__tests__/maptype-test.js | 17 ++++ web/client/reducers/globeswitcher.js | 35 ++++++++ web/client/reducers/maps.js | 7 -- web/client/reducers/maptype.js | 30 +++++++ 24 files changed, 568 insertions(+), 48 deletions(-) create mode 100644 web/client/actions/__tests__/globeswitcher-test.js create mode 100644 web/client/actions/__tests__/maptype-test.jsx create mode 100644 web/client/actions/globeswitcher.js rename web/client/{product/actions/home.js => actions/maptype.js} (53%) create mode 100644 web/client/components/buttons/GlobeViewSwitcherButton.jsx create mode 100644 web/client/components/buttons/__tests__/GlobeViewSwitcherButton-test.jsx create mode 100644 web/client/epics/__tests__/globeswitcher-test.js create mode 100644 web/client/epics/globeswitcher.js create mode 100644 web/client/epics/maptype.js create mode 100644 web/client/plugins/GlobeViewSwitcher.jsx delete mode 100644 web/client/product/reducers/home.js create mode 100644 web/client/reducers/__tests__/globeswitcher-test.js create mode 100644 web/client/reducers/__tests__/maptype-test.js create mode 100644 web/client/reducers/globeswitcher.js create mode 100644 web/client/reducers/maptype.js diff --git a/docma-config.json b/docma-config.json index 520037d904..551cfb114d 100644 --- a/docma-config.json +++ b/docma-config.json @@ -108,6 +108,7 @@ "framework" : [ "web/client/components/index.jsdoc", "web/client/components/buttons/FullScreenButton.jsx", + "web/client/components/buttons/GlobeViewSwitcherButton.jsx", "web/client/components/buttons/GoFullButton.jsx", "web/client/components/mapcontrols/search/SearchBar.jsx", "web/client/components/buttons/ToggleButton.jsx", @@ -116,16 +117,22 @@ "web/client/actions/index.jsdoc", "web/client/actions/controls.js", "web/client/actions/fullscreen.js", + "web/client/actions/globeswitcher.js", "web/client/actions/maps.js", + "web/client/actions/maptype.js", "web/client/actions/search.js", "web/client/reducers/index.jsdoc", "web/client/reducers/controls.js", + "web/client/reducers/globeswitcher.js", "web/client/reducers/maps.js", + "web/client/reducers/maptype.js", "web/client/reducers/search.js", "web/client/epics/index.jsdoc", "web/client/epics/fullscreen.js", + "web/client/epics/globeswitcher.js", + "web/client/epics/maptype.js", "web/client/epics/search.js", "web/client/utils/index.jsdoc", @@ -137,6 +144,7 @@ "web/client/plugins/index.jsdoc", "web/client/plugins/BackgroundSwitcher.jsx", "web/client/plugins/DrawerMenu.jsx", + "web/client/plugins/GlobeViewSwitcher.jsx", "web/client/plugins/GoFull.jsx", "web/client/plugins/Map.jsx", "web/client/plugins/FullScreen.jsx", diff --git a/web/client/actions/__tests__/globeswitcher-test.js b/web/client/actions/__tests__/globeswitcher-test.js new file mode 100644 index 0000000000..c3eaa937c8 --- /dev/null +++ b/web/client/actions/__tests__/globeswitcher-test.js @@ -0,0 +1,31 @@ +/* + * Copyright 2017, 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. + */ + +const expect = require('expect'); +const { + toggle3d, + updateLast2dMapType, + TOGGLE_3D, + UPDATE_LAST_2D_MAPTYPE +} = require('../globeswitcher'); + +describe('Test correctness of the maptype actions', () => { + + it('toggle3d', () => { + const retVal = toggle3d(true); + expect(retVal).toExist(); + expect(retVal.type).toBe(TOGGLE_3D); + expect(retVal.enable).toBe(true); + }); + it('updateLast2dMapType', () => { + const retVal = updateLast2dMapType("leaflet"); + expect(retVal).toExist(); + expect(retVal.type).toBe(UPDATE_LAST_2D_MAPTYPE); + expect(retVal.mapType).toBe('leaflet'); + }); +}); diff --git a/web/client/actions/__tests__/maptype-test.jsx b/web/client/actions/__tests__/maptype-test.jsx new file mode 100644 index 0000000000..053f44486f --- /dev/null +++ b/web/client/actions/__tests__/maptype-test.jsx @@ -0,0 +1,23 @@ +/* + * Copyright 2017, 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. + */ + +const expect = require('expect'); +const { + MAP_TYPE_CHANGED, + changeMapType +} = require('../maptype'); + +describe('Test correctness of the maptype actions', () => { + + it('changeMapType', () => { + const retVal = changeMapType('maptype'); + expect(retVal).toExist(); + expect(retVal.type).toBe(MAP_TYPE_CHANGED); + expect(retVal.mapType).toBe('maptype'); + }); +}); diff --git a/web/client/actions/globeswitcher.js b/web/client/actions/globeswitcher.js new file mode 100644 index 0000000000..4713314d8e --- /dev/null +++ b/web/client/actions/globeswitcher.js @@ -0,0 +1,58 @@ +/* + * Copyright 2017, 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. + */ + + +const TOGGLE_3D = "TOGGLE_3D"; +const UPDATE_LAST_2D_MAPTYPE = "UPDATE_LAST_2D_MAPTYPE"; +/** + * Emitted when 3d map have to be toggled + * @memberof actions.globeswitcher + * @param {boolean} enable true for enable, false for disable + * @return {action} the action of type `TOGGLE_FULLSCREEN` with enable flag and element selector. + * ``` + * { + * type: TOGGLE_3D, + * enable + * } + * ``` + */ +function toggle3d(enable, originalMapType) { + return { + type: TOGGLE_3D, + enable, + originalMapType + }; +} +/** + * Saves the last 2d map + * @memberof actions.globeswitcher + * @param {string} mapType last maptype + * @return {object} action + * ``` + * { + * type: MAPTYPE_2D_SELECTED, + * mapType + * } + * ``` + */ +function updateLast2dMapType(mapType) { + return { + type: UPDATE_LAST_2D_MAPTYPE, + mapType + }; +} +/** + * Actions for Globe Switcher Plugin. + * @name actions.globeswitcher + */ +module.exports = { + toggle3d, + updateLast2dMapType, + UPDATE_LAST_2D_MAPTYPE, + TOGGLE_3D +}; diff --git a/web/client/product/actions/home.js b/web/client/actions/maptype.js similarity index 53% rename from web/client/product/actions/home.js rename to web/client/actions/maptype.js index be79586c48..aec102bbc5 100644 --- a/web/client/product/actions/home.js +++ b/web/client/actions/maptype.js @@ -1,5 +1,5 @@ -/** - * Copyright 2016, GeoSolutions Sas. +/* + * Copyright 2017, GeoSolutions Sas. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -8,11 +8,20 @@ const MAP_TYPE_CHANGED = 'MAP_TYPE_CHANGED'; +/** + * changes the map type + * @memberof actions.maptype + * @param {string} mapType the mapType. + * @return {action} the action of type `MAP_TYPE_CHANGED` with mapType + */ function changeMapType(mapType) { return { type: MAP_TYPE_CHANGED, mapType }; } - +/** + * Actions for map type management.Allow to manage the default map type. + * @name actions.maptype + */ module.exports = {MAP_TYPE_CHANGED, changeMapType}; diff --git a/web/client/components/buttons/GlobeViewSwitcherButton.jsx b/web/client/components/buttons/GlobeViewSwitcherButton.jsx new file mode 100644 index 0000000000..4b0c6f5a4e --- /dev/null +++ b/web/client/components/buttons/GlobeViewSwitcherButton.jsx @@ -0,0 +1,89 @@ +/* + * Copyright 2017, 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. + */ + +const React = require('react'); + +const ToggleButton = require('./ToggleButton'); +const {Tooltip} = require('react-bootstrap'); +const Message = require('../I18N/Message'); +/** + * Toggle button for 3d. Wraps {@link #components.buttons.ToggleButton} with some defaults + * @memberof components.buttons + * @class + * @prop {string} [id] an id for the html component + * @prop {object} [btnConfig] the configuration to pass to the bootstrap button + * @prop {object} [options] the options to send when toggle is clicked + * @prop {string|element} [text] the text to disaplay + * @prop {string|element} [help] the help text + * @prop {string} glyphicon the icon name + * @prop {bool} active the status of the button + * @prop {function} onClick. The method to call when clicked. the method will return as parameter the toggled `pressed` prop and the `options` object + * @prop {node} [activeTooltip] the tooltip to use on mouse hover + * @prop {node} [notActiveTooltip] the tooltip to use on mouse hover when the button is active + * @prop {string} [tooltipPlace] positon of the tooltip, one of: 'top', 'right', 'bottom', 'left' + * @prop {object} css style object for the component + * @prop {btnType} [btnType] one of 'normal', 'image' + * @prop {string} image if type is 'image', the src of the image + * @prop {string} pressedStyle the bootstrap style for pressedStyle + * @prop {string} defaultStyle the bootstrap style when not pressed + * + */ +const GlobeViewSwitcherButton = React.createClass({ + propTypes: { + id: React.PropTypes.string, + btnConfig: React.PropTypes.object, + options: React.PropTypes.object, + text: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element]), + help: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.element]), + glyphicon: React.PropTypes.string, + active: React.PropTypes.bool, + onClick: React.PropTypes.func, + activeTooltip: React.PropTypes.string, + notActiveTooltip: React.PropTypes.string, + tooltipPlace: React.PropTypes.string, + style: React.PropTypes.object, + btnType: React.PropTypes.oneOf(['normal', 'image']), + image: React.PropTypes.string, + pressedStyle: React.PropTypes.string, + defaultStyle: React.PropTypes.string + }, + getDefaultProps() { + return { + id: 'globeviewswitcher-btn', + activeTooltip: 'globeswitcher.tooltipDeactivate', + notActiveTooltip: 'globeswitcher.tooltipActivate', + tooltipPlace: 'left', + defaultStyle: 'primary', + pressedStyle: 'success', + glyphicon: 'globe', + btnConfig: { + className: "square-button" + } + }; + }, + getButtonProperties() { + return ['id', + 'btnConfig', + 'options', + 'text', + 'glyphicon', + 'onClick', + 'tooltipPlace', + 'style', + 'btnType', + 'image', + 'pressedStyle', + 'defaultStyle' + ].reduce((result, key) => { result[key] = this.props[key]; return result; }, {}); + }, + render() { + return } />; + } +}); + +module.exports = GlobeViewSwitcherButton; diff --git a/web/client/components/buttons/__tests__/GlobeViewSwitcherButton-test.jsx b/web/client/components/buttons/__tests__/GlobeViewSwitcherButton-test.jsx new file mode 100644 index 0000000000..dc5294c1c2 --- /dev/null +++ b/web/client/components/buttons/__tests__/GlobeViewSwitcherButton-test.jsx @@ -0,0 +1,36 @@ +/* + * Copyright 2017, 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'); +var ReactDOM = require('react-dom'); +var GlobeViewSwitcherButton = require('../GlobeViewSwitcherButton'); + +describe("test the GlobeViewSwitcherButton", () => { + beforeEach((done) => { + document.body.innerHTML = '
'; + setTimeout(done); + }); + + afterEach((done) => { + ReactDOM.unmountComponentAtNode(document.getElementById("container")); + document.body.innerHTML = ''; + setTimeout(done); + }); + + it('test default properties', () => { + const tb = ReactDOM.render(, document.getElementById("container")); + expect(tb).toExist(); + + const tbNode = ReactDOM.findDOMNode(tb); + expect(tbNode).toExist(); + expect(tbNode.id).toBe('globeviewswitcher-btn'); + expect(tbNode).toExist(); + expect(tbNode.className.indexOf('primary') >= 0).toBe(true); + }); +}); diff --git a/web/client/epics/__tests__/globeswitcher-test.js b/web/client/epics/__tests__/globeswitcher-test.js new file mode 100644 index 0000000000..a3e441634a --- /dev/null +++ b/web/client/epics/__tests__/globeswitcher-test.js @@ -0,0 +1,52 @@ +/* + * Copyright 2017, 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'); + +const {toggle3d, UPDATE_LAST_2D_MAPTYPE} = require('../../actions/globeswitcher'); +const assign = require('object-assign'); +const Rx = require('rxjs'); +const { ActionsObservable } = require('redux-observable'); +const {updateRouteOn3dSwitch} = require('../globeswitcher'); +const epicTest = (epic, count, action, callback, state = {}) => { + const actions = new Rx.Subject(); + const actions$ = new ActionsObservable(actions); + const store = { getState: () => state }; + epic(actions$, store) + .take(count) + .toArray() + .subscribe(callback); + if (action.length) { + action.map(act => actions.next(act)); + } else { + actions.next(action); + } +}; +describe('globeswitcher Epics', () => { + it('produces the search epic', (done) => { + epicTest(updateRouteOn3dSwitch, 2, assign({hash: "/viewer/leaflet/2"}, toggle3d(true, "leaflet")), actions => { + expect(actions.length).toBe(2); + actions.map((action) => { + switch (action.type) { + case "@@router/TRANSITION": + expect(action.payload.method).toBe('push'); + expect(action.payload.args.length).toBe(1); + break; + case UPDATE_LAST_2D_MAPTYPE: + expect(action.mapType).toBe("leaflet"); + break; + default: + expect(true).toBe(false); + + } + }); + done(); + }); + + }); +}); diff --git a/web/client/epics/globeswitcher.js b/web/client/epics/globeswitcher.js new file mode 100644 index 0000000000..94a373503e --- /dev/null +++ b/web/client/epics/globeswitcher.js @@ -0,0 +1,43 @@ +/* + * Copyright 2017, 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. + */ +const {TOGGLE_3D, updateLast2dMapType} = require('../actions/globeswitcher'); + +const Rx = require('rxjs'); +const {get} = require('lodash'); +const defaultRegex = /\/(viewer)\/(\w+)\/(\d+)/; +import { push } from 'react-router-redux'; + +const replaceMapType = (path, newMapType) => { + let match = path.match(defaultRegex); + if (match) { + return `/viewer/${newMapType}/${match[3]}`; + } +}; +/** + * Gets every `TOGGLE_3D` event. + * @memberof epics.globeswitcher + * @param {external:Observable} action$ manages `TOGGLE_3D`. + * @return {external:Observable} emitting react-router-redux push action and {@link #actions.globeswitcher.updateLast2dMapType} actions + */ +const updateRouteOn3dSwitch = (action$, store) => + action$.ofType(TOGGLE_3D) + .switchMap( action => { + const newPath = replaceMapType(action.hash || location.hash, action.enable ? "cesium" : get(store.getState(), "globeswitcher.last2dMapType") || "leaflet"); + if (newPath) { + return Rx.Observable.from([push(newPath), updateLast2dMapType(action.originalMapType)]); + } + Rx.Observable.of(updateLast2dMapType(action.mapType)); + }); +/** + * Epics for 3d switcher functionality + * @name epics.globeswitcher + * @type {Object} + */ +module.exports = { + updateRouteOn3dSwitch +}; diff --git a/web/client/epics/maptype.js b/web/client/epics/maptype.js new file mode 100644 index 0000000000..5289491a4c --- /dev/null +++ b/web/client/epics/maptype.js @@ -0,0 +1,39 @@ +/* + * Copyright 2017, 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. + */ +const {changeMapType} = require('../actions/maptype'); +const Rx = require('rxjs'); +const {get} = require('lodash'); +const defaultRegex = /\/(viewer)\/(\w+)\/(\d+)/; +const findMapType = path => path.match(defaultRegex) && path.replace(defaultRegex, "$2"); +import { UPDATE_LOCATION } from 'react-router-redux'; + +/** + * keep the default mapType in sync when change the URL of the map for viewer + * @memberof epics.maptype + * @param {external:Observable} action$ the stream of actions, acts on `UPDATE_LOCATION` + * @param {object} store the store middleware API from redux `createMiddleware` + * @return {external:Observable} the stream of the actions to emit. (`changeMapType`) + */ +const syncMapType = (action$, store) => + action$.ofType(UPDATE_LOCATION) + .filter(action => + action.payload + && action.payload.pathname + && action.payload.pathname.match(defaultRegex) + && findMapType(action.payload.pathname) !== get(store.getState(), "maptype.mapType")) + .switchMap((action) => + Rx.Observable.of(changeMapType(findMapType(action.payload.pathname))) + ); +/** + * Epics for maptype switch functionalities + * @name epics.maptype + * @type {Object} + */ +module.exports = { + syncMapType +}; diff --git a/web/client/localConfig.json b/web/client/localConfig.json index 768d01cc33..ad40e9e39c 100644 --- a/web/client/localConfig.json +++ b/web/client/localConfig.json @@ -109,7 +109,7 @@ } } }, "Login", - "OmniBar", "BurgerMenu", "Expander" + "OmniBar", "BurgerMenu", "Expander", "GlobeViewSwitcher" ], "desktop": ["Map", "HelpLink", "Share", "DrawerMenu", { "name": "Identify", @@ -198,7 +198,7 @@ } } }, - "OmniBar", "Login", "Save", "SaveAs", "BurgerMenu", "Expander", "Undo", "Redo", "FullScreen" + "OmniBar", "Login", "Save", "SaveAs", "BurgerMenu", "Expander", "Undo", "Redo", "FullScreen", "GlobeViewSwitcher" ], "embedded": [{ "name": "Map", diff --git a/web/client/plugins/GlobeViewSwitcher.jsx b/web/client/plugins/GlobeViewSwitcher.jsx new file mode 100644 index 0000000000..64af87dd42 --- /dev/null +++ b/web/client/plugins/GlobeViewSwitcher.jsx @@ -0,0 +1,49 @@ +/* + * Copyright 2017, 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. + */ +const {connect} = require('react-redux'); + + +const assign = require('object-assign'); +const globeswitcher = require('../reducers/globeswitcher'); +const epics = require('../epics/globeswitcher'); +const {toggle3d} = require('../actions/globeswitcher'); +const GlobeViewSwitcherButton = require('../components/buttons/GlobeViewSwitcherButton'); + +/** + * GlobeViewSwitcher Plugin. A button that toggles to 3d mode + * @class GlobeViewSwitcher + * @memberof plugins + * @static + * + * @prop {string} cfg.id identifier of the Plugin + * + */ +const GlobeViewSwitcher = connect( ({maptype = {}} = {}) => ({ + active: maptype && maptype.mapType === "cesium", + options: { + originalMapType: maptype && maptype.mapType || "leaflet" + } +}), { + onClick: (pressed, options) => toggle3d(pressed, options.originalMapType) +})(GlobeViewSwitcherButton); + +module.exports = { + GlobeViewSwitcherPlugin: assign(GlobeViewSwitcher, { + Toolbar: { + name: '3d', + position: 5, + alwaysVisible: true, + tool: true, + priority: 1 + } + }), + reducers: { + globeswitcher + }, + epics +}; diff --git a/web/client/plugins/Maps.jsx b/web/client/plugins/Maps.jsx index bca9a3d254..0d537a67d4 100644 --- a/web/client/plugins/Maps.jsx +++ b/web/client/plugins/Maps.jsx @@ -127,12 +127,14 @@ const Maps = React.createClass({ module.exports = { MapsPlugin: connect((state) => ({ - mapType: state.home && state.home.mapType || (state.maps && state.maps.mapType) || 'leaflet' + mapType: (state.maptype && state.maptype.mapType) || 'leaflet' }), { loadMaps })(Maps), + epics: require('../epics/maptype'), reducers: { maps: require('../reducers/maps'), + maptype: require('../reducers/maptype'), currentMap: require('../reducers/currentMap') } }; diff --git a/web/client/plugins/searchbar/ToggleButton.jsx b/web/client/plugins/searchbar/ToggleButton.jsx index cc64317117..942f7976f2 100644 --- a/web/client/plugins/searchbar/ToggleButton.jsx +++ b/web/client/plugins/searchbar/ToggleButton.jsx @@ -1,4 +1,4 @@ -/** +/* * Copyright 2016, GeoSolutions Sas. * All rights reserved. * diff --git a/web/client/product/app.jsx b/web/client/product/app.jsx index 25b4ca690e..40d761ba14 100644 --- a/web/client/product/app.jsx +++ b/web/client/product/app.jsx @@ -25,7 +25,7 @@ const startApp = () => { }))(require('../components/app/StandardRouter')); const appStore = require('../stores/StandardStore').bind(null, initialState, { - home: require('./reducers/home'), + maptype: require('../reducers/maptype'), maps: require('../reducers/maps') }, {}); diff --git a/web/client/product/plugins.js b/web/client/product/plugins.js index 0ad15ac250..b7e1dd1372 100644 --- a/web/client/product/plugins.js +++ b/web/client/product/plugins.js @@ -67,7 +67,8 @@ module.exports = { TutorialPlugin: require('../plugins/Tutorial'), ThemeSwitcherPlugin: require('../plugins/ThemeSwitcher'), ScrollTopPlugin: require('../plugins/ScrollTop'), - GoFull: require('../plugins/GoFull') + GoFull: require('../plugins/GoFull'), + GlobeViewSwitcherPlugin: require('../plugins/GlobeViewSwitcher') }, requires: { ReactSwipe: require('react-swipeable-views').default, diff --git a/web/client/product/plugins/MapType.jsx b/web/client/product/plugins/MapType.jsx index 5b5daa0d6c..c36dcc17ce 100644 --- a/web/client/product/plugins/MapType.jsx +++ b/web/client/product/plugins/MapType.jsx @@ -1,4 +1,4 @@ -/** +/* * Copyright 2016, GeoSolutions Sas. * All rights reserved. * @@ -9,7 +9,7 @@ const React = require('react'); const {Label, FormControl, FormGroup} = require('react-bootstrap'); const Message = require('../../components/I18N/Message'); const {compose} = require('redux'); -const {changeMapType} = require('../actions/home'); +const {changeMapType} = require('../../actions/maptype'); const {connect} = require('react-redux'); const assign = require('object-assign'); @@ -18,12 +18,18 @@ const MapType = React.createClass({ style: React.PropTypes.object, className: React.PropTypes.object, mapType: React.PropTypes.string, + mapTypes: React.PropTypes.array, onChangeMapType: React.PropTypes.func }, getDefaultProps() { return { mapType: 'leaflet', - onChangeMapType: () => {} + onChangeMapType: () => {}, + mapTypes: [ + { key: "leaflet", label: "Leaflet"}, + { key: "openlayers", label: "OpenLayers"}, + { key: "cesium", label: "Cesium"} + ] }; }, render() { @@ -32,8 +38,7 @@ const MapType = React.createClass({ - - + {this.props.mapTypes.map(type => )} @@ -42,7 +47,7 @@ const MapType = React.createClass({ }); const MapTypePlugin = connect((state) => ({ - mapType: state.home && state.home.mapType || 'leaflet' + mapType: state.maptype && state.maptype.mapType || 'leaflet' }), { onChangeMapType: compose(changeMapType, (event) => event.target.value) })(MapType); @@ -56,5 +61,5 @@ module.exports = { priority: 1 } }), - reducers: {home: require('../reducers/home')} + reducers: {maptype: require('../../reducers/maptype')} }; diff --git a/web/client/product/reducers/home.js b/web/client/product/reducers/home.js deleted file mode 100644 index ab1c443784..0000000000 --- a/web/client/product/reducers/home.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright 2016, 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 {MAP_TYPE_CHANGED} = require('../actions/home'); - -function home(state = {mapType: "leaflet"}, action) { - switch (action.type) { - case MAP_TYPE_CHANGED: - return {mapType: action.mapType}; - default: - return state; - } -} - -module.exports = home; diff --git a/web/client/reducers/__tests__/globeswitcher-test.js b/web/client/reducers/__tests__/globeswitcher-test.js new file mode 100644 index 0000000000..d7d5c9f4cd --- /dev/null +++ b/web/client/reducers/__tests__/globeswitcher-test.js @@ -0,0 +1,24 @@ +/* + * Copyright 2017, 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. + */ +const expect = require('expect'); +const globeswitcher = require('../globeswitcher'); +const {changeMapType} = require('../../actions/maptype'); +const {updateLast2dMapType} = require('../../actions/globeswitcher'); + +describe('Test the globeswitcher reducer', () => { + it('check to store last 2d map type', () => { + const state = globeswitcher(undefined, changeMapType("leaflet")); + expect(state.last2dMapType).toBe('leaflet'); + const state2 = globeswitcher(state, changeMapType("cesium")); + expect(state2.last2dMapType).toBe('leaflet'); + const state3 = globeswitcher(state2, updateLast2dMapType("openlayers")); + expect(state3.last2dMapType).toBe('openlayers'); + const state4 = globeswitcher(state3, {type: "UNKNOWN"}); + expect(state4.last2dMapType).toBe('openlayers'); + }); +}); diff --git a/web/client/reducers/__tests__/maps-test.jsx b/web/client/reducers/__tests__/maps-test.jsx index 9e8b6b8fb7..77a7ba8d30 100644 --- a/web/client/reducers/__tests__/maps-test.jsx +++ b/web/client/reducers/__tests__/maps-test.jsx @@ -13,7 +13,6 @@ const { mapMetadataUpdated, mapDeleting, mapDeleted, attributeUpdated, thumbnailError, permissionsLoading, permissionsLoaded, saveMap, permissionsUpdated, resetUpdating, mapsSearchTextChanged} = require('../../actions/maps'); -const MAP_TYPE_CHANGED = "MAP_TYPE_CHANGED"; // NOTE: this is from home action in product. move to maps actions when finished; const sampleMap = { canDelete: false, @@ -46,10 +45,7 @@ describe('Test the maps reducer', () => { expect(state.enabled).toBe(false); expect(state.searchText).toBe(""); }); - it('on MAP_TYPE_CHANGED action', () => { - let state = maps(null, {type: MAP_TYPE_CHANGED, mapType: "cesium"}); - expect(state.mapType).toBe("cesium"); - }); + it('on mapsSearchTextChanged action', () => { let state = maps(null, mapsSearchTextChanged("TEST")); expect(state.searchText).toBe("TEST"); diff --git a/web/client/reducers/__tests__/maptype-test.js b/web/client/reducers/__tests__/maptype-test.js new file mode 100644 index 0000000000..7928e051bf --- /dev/null +++ b/web/client/reducers/__tests__/maptype-test.js @@ -0,0 +1,17 @@ +/* + * Copyright 2017, 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. + */ +const expect = require('expect'); +const maptype = require('../maptype'); +const {changeMapType} = require('../../actions/maptype'); + +describe('Test the maptype reducer', () => { + it('set a maptype', () => { + const state = maptype(undefined, changeMapType("leaflet")); + expect(state.mapType).toBe('leaflet'); + }); +}); diff --git a/web/client/reducers/globeswitcher.js b/web/client/reducers/globeswitcher.js new file mode 100644 index 0000000000..adf398fe66 --- /dev/null +++ b/web/client/reducers/globeswitcher.js @@ -0,0 +1,35 @@ +/* + * Copyright 2017, 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. + */ + +const {MAP_TYPE_CHANGED} = require('../actions/maptype'); +const {UPDATE_LAST_2D_MAPTYPE} = require('../actions/globeswitcher'); +/** + * state for globeswitcher tooltip. holds the last 2d mapType. + * @memberof reducers + * @param {Object} [state={last2dMapType: "leaflet"}] the state + * @param {action} action the actions (receives MAP_TYPE_CHANGED and UPDATE_LAST_2D_MAPTYPE) + * @return {Object} the new state + * @example + * { + * last2dMapType: "leaflet" + * } + */ +function globeswitcher(state = {last2dMapType: "leaflet"}, action) { + switch (action.type) { + case MAP_TYPE_CHANGED: + case UPDATE_LAST_2D_MAPTYPE: + if (action.mapType && action.mapType !== "cesium" && action.mapType !== state.last2dMapType) { + return {last2dMapType: action.mapType}; + } + return state; + default: + return state; + } +} + +module.exports = globeswitcher; diff --git a/web/client/reducers/maps.js b/web/client/reducers/maps.js index 725ba5b069..9b0205fce8 100644 --- a/web/client/reducers/maps.js +++ b/web/client/reducers/maps.js @@ -11,7 +11,6 @@ const { MAP_METADATA_UPDATED, MAP_DELETING, MAP_DELETED, ATTRIBUTE_UPDATED, PERMISSIONS_LIST_LOADING, PERMISSIONS_LIST_LOADED, SAVE_MAP, PERMISSIONS_UPDATED, THUMBNAIL_ERROR, RESET_UPDATING, MAPS_SEARCH_TEXT_CHANGED} = require('../actions/maps'); -const MAP_TYPE_CHANGED = "MAP_TYPE_CHANGED"; // NOTE: this is from home action in product. move to maps actions when finished; const assign = require('object-assign'); const _ = require('lodash'); /** @@ -60,16 +59,10 @@ const _ = require('lodash'); * @memberof reducers */ function maps(state = { - mapType: "leaflet", enabled: false, errors: [], searchText: ""}, action) { switch (action.type) { - case MAP_TYPE_CHANGED: { - return assign({}, state, { - mapType: action.mapType - }); - } case MAPS_SEARCH_TEXT_CHANGED: { return assign({}, state, { searchText: action.text diff --git a/web/client/reducers/maptype.js b/web/client/reducers/maptype.js new file mode 100644 index 0000000000..4719133a8c --- /dev/null +++ b/web/client/reducers/maptype.js @@ -0,0 +1,30 @@ +/* + * Copyright 2016, 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 {MAP_TYPE_CHANGED} = require('../actions/maptype'); +/** + * stores state for the mapType to use (typically one of leaflet, openlayers, cesium... ) + * @memberof reducers + * @param {Object} [state={mapType: "leaflet"}] the initial state + * @param {} action the action gets `MAP_TYPE_CHANGED` + * @return {Object} the new state + * @example + * { + * mapType: "leaflet" + * } + */ +function maptype(state = {mapType: "leaflet"}, action) { + switch (action.type) { + case MAP_TYPE_CHANGED: + return {mapType: action.mapType}; + default: + return state; + } +} + +module.exports = maptype;