From 551201c9c41df45a85f098ebdd670129395ec5eb Mon Sep 17 00:00:00 2001 From: allyoucanmap Date: Fri, 19 May 2017 12:27:04 +0200 Subject: [PATCH] Added epic to switch tutorial --- web/client/actions/__tests__/tutorial-test.js | 4 +- web/client/actions/tutorial.js | 3 +- web/client/components/tutorial/Tutorial.jsx | 4 +- .../tutorial/__tests__/Tutorial-test.jsx | 6 +-- web/client/epics/tutorial.js | 34 +++++++++++++- web/client/localConfig.json | 2 +- web/client/plugins/Tutorial.jsx | 5 +- web/client/plugins/tutorial/preset.js | 8 ++-- ...mapMobile.js => cesium_mobile_tutorial.js} | 26 +++++----- .../preset/{map.js => cesium_tutorial.js} | 47 +++++++------------ .../preset/default_mobile_tutorial.js | 26 ++++++++++ .../tutorial/preset/default_tutorial.js | 46 ++++++++++++++++++ .../preset/{home.js => home_tutorial.js} | 6 --- web/client/reducers/tutorial.js | 23 +++++---- web/client/translations/data.de-DE | 4 ++ web/client/translations/data.en-US | 4 ++ web/client/translations/data.fr-FR | 4 ++ web/client/translations/data.it-IT | 4 ++ 18 files changed, 184 insertions(+), 72 deletions(-) rename web/client/plugins/tutorial/preset/{mapMobile.js => cesium_mobile_tutorial.js} (84%) rename web/client/plugins/tutorial/preset/{map.js => cesium_tutorial.js} (82%) create mode 100644 web/client/plugins/tutorial/preset/default_mobile_tutorial.js create mode 100644 web/client/plugins/tutorial/preset/default_tutorial.js rename web/client/plugins/tutorial/preset/{home.js => home_tutorial.js} (72%) diff --git a/web/client/actions/__tests__/tutorial-test.js b/web/client/actions/__tests__/tutorial-test.js index ce2b1b60b2..7d69a3042a 100644 --- a/web/client/actions/__tests__/tutorial-test.js +++ b/web/client/actions/__tests__/tutorial-test.js @@ -34,13 +34,15 @@ describe('Test the tutorial actions', () => { }); it('setupTutorial', () => { + const id = 'id'; const steps = 'steps'; const style = 'style'; const checkbox = 'checkbox'; const defaultStep = 'defaultStep'; - const retval = setupTutorial(steps, style, checkbox, defaultStep); + const retval = setupTutorial(id, steps, style, checkbox, defaultStep); expect(retval).toExist(); expect(retval.type).toBe(SETUP_TUTORIAL); + expect(retval.id).toBe(id); expect(retval.steps).toBe(steps); expect(retval.style).toBe(style); expect(retval.checkbox).toBe(checkbox); diff --git a/web/client/actions/tutorial.js b/web/client/actions/tutorial.js index e52cdcfec4..1217423966 100644 --- a/web/client/actions/tutorial.js +++ b/web/client/actions/tutorial.js @@ -20,9 +20,10 @@ function startTutorial() { }; } -function setupTutorial(steps, style, checkbox, defaultStep) { +function setupTutorial(id, steps, style, checkbox, defaultStep) { return { type: SETUP_TUTORIAL, + id, steps, style, checkbox, diff --git a/web/client/components/tutorial/Tutorial.jsx b/web/client/components/tutorial/Tutorial.jsx index dd5af46d7c..06f699eb44 100644 --- a/web/client/components/tutorial/Tutorial.jsx +++ b/web/client/components/tutorial/Tutorial.jsx @@ -77,7 +77,7 @@ const Tutorial = React.createClass({ return { toggle: false, status: 'run', - preset: 'map', + preset: 'default_tutorial', presetList: {}, introPosition: (window.innerHeight - 348) / 2, rawSteps: [], @@ -121,7 +121,7 @@ const Tutorial = React.createClass({ componentWillMount() { let rawSteps = this.props.rawSteps.length > 0 ? this.props.rawSteps : this.props.presetList[this.props.preset] || []; let checkbox = this.props.showCheckbox ?
:
; - this.props.actions.onSetup(rawSteps, this.props.introStyle, checkbox, this.props.defaultStep); + this.props.actions.onSetup('default', rawSteps, this.props.introStyle, checkbox, this.props.defaultStep); }, componentWillUpdate(newProps) { if (this.props.steps.length > 0) { diff --git a/web/client/components/tutorial/__tests__/Tutorial-test.jsx b/web/client/components/tutorial/__tests__/Tutorial-test.jsx index 8a8b9f4982..2e02f94ad7 100644 --- a/web/client/components/tutorial/__tests__/Tutorial-test.jsx +++ b/web/client/components/tutorial/__tests__/Tutorial-test.jsx @@ -87,7 +87,7 @@ describe("Test the Tutorial component", () => { expect(cmp).toExist(); expect(spySetup).toHaveBeenCalled(); - expect(spySetup).toHaveBeenCalledWith([], {},
, {}); + expect(spySetup).toHaveBeenCalledWith('default', [], {},
, {}); const domNode = ReactDOM.findDOMNode(cmp); expect(domNode).toExist(); @@ -120,7 +120,7 @@ describe("Test the Tutorial component", () => { expect(cmp).toExist(); expect(spySetup).toHaveBeenCalled(); - expect(spySetup).toHaveBeenCalledWith(presetList.test, {},
, {}); + expect(spySetup).toHaveBeenCalledWith('default', presetList.test, {},
, {}); const domNode = ReactDOM.findDOMNode(cmp); expect(domNode).toExist(); @@ -164,7 +164,7 @@ describe("Test the Tutorial component", () => { expect(cmp).toExist(); expect(spySetup).toHaveBeenCalled(); - expect(spySetup).toHaveBeenCalledWith(rawSteps, {},
, {}); + expect(spySetup).toHaveBeenCalledWith('default', rawSteps, {},
, {}); const domNode = ReactDOM.findDOMNode(cmp); expect(domNode).toExist(); diff --git a/web/client/epics/tutorial.js b/web/client/epics/tutorial.js index f6579ac075..57033ac614 100644 --- a/web/client/epics/tutorial.js +++ b/web/client/epics/tutorial.js @@ -7,8 +7,13 @@ */ const Rx = require('rxjs'); -const {START_TUTORIAL, closeTutorial} = require('../actions/tutorial'); +const {START_TUTORIAL, closeTutorial, setupTutorial} = require('../actions/tutorial'); +const {CHANGE_MAP_VIEW} = require('../actions/map'); const {TOGGLE_3D} = require('../actions/globeswitcher'); +const preset = require('../plugins/tutorial/preset'); +const defaultRegex = /\/(viewer)\/(\w+)\/(\d+)/; +const findMapType = path => path.match(defaultRegex) && path.replace(defaultRegex, "$2"); +import { UPDATE_LOCATION } from 'react-router-redux'; /** * Closes the tutorial if 3D button has been toggled @@ -22,6 +27,30 @@ const closeTutorialEpic = (action$) => .audit(() => action$.ofType(TOGGLE_3D)) .switchMap( () => Rx.Observable.of(closeTutorial())); +/** + * Setup new steps based on the current maptype + * @memberof epics.tutorial + * @param {external:Observable} action$ manages `UPDATE_LOCATION` + * @return {external:Observable} + */ + +const switchTutorialEpic = (action$, store) => + action$.ofType(UPDATE_LOCATION) + .audit(() => action$.ofType(CHANGE_MAP_VIEW)) + .filter(action => + action.payload + && action.payload.pathname + && action.payload.pathname.match(defaultRegex)) + .switchMap( (action) => { + const path = findMapType(action.payload.pathname); + const browser = store.getState().browser; + const mobile = browser && browser.mobile ? '_mobile' : ''; + return Rx.Observable.of(preset[path + mobile + '_tutorial'] ? + setupTutorial(path + mobile, preset[path + mobile + '_tutorial']) : + setupTutorial('default' + mobile, preset['default' + mobile + '_tutorial']) + ); + }); + /** * Epics for Tutorial * @name epics.tutorial @@ -29,5 +58,6 @@ const closeTutorialEpic = (action$) => */ module.exports = { - closeTutorialEpic + closeTutorialEpic, + switchTutorialEpic }; diff --git a/web/client/localConfig.json b/web/client/localConfig.json index 175b7a8f0e..2cb20b927e 100644 --- a/web/client/localConfig.json +++ b/web/client/localConfig.json @@ -78,7 +78,7 @@ }, "Home", "TOC", { "name": "Tutorial", "cfg": { - "preset": "mapMobile" + "preset": "default_mobile_tutorial" } }, { "name": "Settings", diff --git a/web/client/plugins/Tutorial.jsx b/web/client/plugins/Tutorial.jsx index fd7f8fb8a3..d4959ef8f4 100644 --- a/web/client/plugins/Tutorial.jsx +++ b/web/client/plugins/Tutorial.jsx @@ -16,7 +16,7 @@ const I18N = require('../components/I18N/I18N'); const {Glyphicon} = require('react-bootstrap'); const {createSelector} = require('reselect'); const {tutorialSelector} = require('../selectors/tutorial'); -const {closeTutorialEpic} = require('../epics/tutorial'); +const {closeTutorialEpic, switchTutorialEpic} = require('../epics/tutorial'); /* ////////////////////////// @@ -217,6 +217,7 @@ module.exports = { tutorial: require('../reducers/tutorial') }, epics: { - closeTutorialEpic + closeTutorialEpic, + switchTutorialEpic } }; diff --git a/web/client/plugins/tutorial/preset.js b/web/client/plugins/tutorial/preset.js index f3cec401ff..3258651116 100644 --- a/web/client/plugins/tutorial/preset.js +++ b/web/client/plugins/tutorial/preset.js @@ -7,7 +7,9 @@ */ module.exports = { - map: require('./preset/map'), - home: require('./preset/home'), - mapMobile: require('./preset/mapMobile') + default_tutorial: require('./preset/default_tutorial'), + default_mobile_tutorial: require('./preset/default_mobile_tutorial'), + home_tutorial: require('./preset/home_tutorial'), + cesium_tutorial: require('./preset/cesium_tutorial'), + cesium_mobile_tutorial: require('./preset/cesium_mobile_tutorial') }; diff --git a/web/client/plugins/tutorial/preset/mapMobile.js b/web/client/plugins/tutorial/preset/cesium_mobile_tutorial.js similarity index 84% rename from web/client/plugins/tutorial/preset/mapMobile.js rename to web/client/plugins/tutorial/preset/cesium_mobile_tutorial.js index 1f630407b6..11cd5e0903 100644 --- a/web/client/plugins/tutorial/preset/mapMobile.js +++ b/web/client/plugins/tutorial/preset/cesium_mobile_tutorial.js @@ -11,15 +11,23 @@ const I18N = require('../../../components/I18N/I18N'); const CesiumTooltip = require('../../../components/tutorial/steps/CesiumTooltip'); module.exports = [ - // remove comment to enable intro/autostart - /*{ - translation: 'intro', + { + translation: 'introCesium', selector: '#intro-tutorial' - },*/ + }, + { + title: , + text: , + selector: '#map .cesium-viewer' + }, { translation: 'drawerMenu', selector: '#drawer-menu-button' }, + { + translation: 'home', + selector: '#home-button' + }, { translation: 'searchButton', selector: '#search-help' @@ -27,15 +35,5 @@ module.exports = [ { translation: 'burgerMenu', selector: '#mapstore-burger-menu' - }, - { - title: , - text: , - selector: '#map .cesium-viewer', - position: 'bottom' - }, - { - translation: 'home', - selector: '#home-button' } ]; diff --git a/web/client/plugins/tutorial/preset/map.js b/web/client/plugins/tutorial/preset/cesium_tutorial.js similarity index 82% rename from web/client/plugins/tutorial/preset/map.js rename to web/client/plugins/tutorial/preset/cesium_tutorial.js index a4abfc6a8e..b412936b95 100644 --- a/web/client/plugins/tutorial/preset/map.js +++ b/web/client/plugins/tutorial/preset/cesium_tutorial.js @@ -11,22 +11,15 @@ const I18N = require('../../../components/I18N/I18N'); const CesiumTooltip = require('../../../components/tutorial/steps/CesiumTooltip'); module.exports = [ - // remove comment to enable intro/autostart - /*{ - translation: 'intro', - selector: '#intro-tutorial' - },*/ - { - translationHTML: 'drawerMenu', - selector: '#drawer-menu-button' - }, { - translation: 'searchBar', - selector: '#map-search-bar' + translation: 'introCesium', + selector: '#intro-tutorial' }, { - translation: 'burgerMenu', - selector: '#mapstore-burger-menu' + title: , + text: , + selector: '#map .cesium-viewer', + position: 'bottom' }, { translation: 'cesiumCompass', @@ -37,14 +30,20 @@ module.exports = [ selector: '#distanceLegendDiv .navigation-controls' }, { - translation: 'zoomInButton', - selector: '#zoomin-btn', - position: 'top' + translationHTML: 'drawerMenu', + selector: '#drawer-menu-button' }, { - translation: 'zoomOutButton', - selector: '#zoomout-btn', - position: 'top' + translation: 'searchBar', + selector: '#map-search-bar' + }, + { + translation: 'home', + selector: '#home-button' + }, + { + translation: 'burgerMenu', + selector: '#mapstore-burger-menu' }, { translation: 'fullscreen', @@ -55,15 +54,5 @@ module.exports = [ translation: 'identifyButton', selector: '#identifyBar-container', position: 'top' - }, - { - title: , - text: , - selector: '#map .cesium-viewer', - position: 'bottom' - }, - { - translation: 'home', - selector: '#home-button' } ]; diff --git a/web/client/plugins/tutorial/preset/default_mobile_tutorial.js b/web/client/plugins/tutorial/preset/default_mobile_tutorial.js new file mode 100644 index 0000000000..cb68be2dd8 --- /dev/null +++ b/web/client/plugins/tutorial/preset/default_mobile_tutorial.js @@ -0,0 +1,26 @@ +/** + * 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. + */ + +module.exports = [ + { + translation: 'drawerMenu', + selector: '#drawer-menu-button' + }, + { + translation: 'home', + selector: '#home-button' + }, + { + translation: 'searchButton', + selector: '#search-help' + }, + { + translation: 'burgerMenu', + selector: '#mapstore-burger-menu' + } +]; diff --git a/web/client/plugins/tutorial/preset/default_tutorial.js b/web/client/plugins/tutorial/preset/default_tutorial.js new file mode 100644 index 0000000000..0baea9b50b --- /dev/null +++ b/web/client/plugins/tutorial/preset/default_tutorial.js @@ -0,0 +1,46 @@ +/** + * 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. + */ + +module.exports = [ + { + translationHTML: 'drawerMenu', + selector: '#drawer-menu-button' + }, + { + translation: 'searchBar', + selector: '#map-search-bar' + }, + { + translation: 'home', + selector: '#home-button' + }, + { + translation: 'burgerMenu', + selector: '#mapstore-burger-menu' + }, + { + translation: 'zoomInButton', + selector: '#zoomin-btn', + position: 'top' + }, + { + translation: 'zoomOutButton', + selector: '#zoomout-btn', + position: 'top' + }, + { + translation: 'fullscreen', + selector: '#fullscreen-btn', + position: 'top' + }, + { + translation: 'identifyButton', + selector: '#identifyBar-container', + position: 'top' + } +]; diff --git a/web/client/plugins/tutorial/preset/home.js b/web/client/plugins/tutorial/preset/home_tutorial.js similarity index 72% rename from web/client/plugins/tutorial/preset/home.js rename to web/client/plugins/tutorial/preset/home_tutorial.js index 76a206102e..bf9abc21f5 100644 --- a/web/client/plugins/tutorial/preset/home.js +++ b/web/client/plugins/tutorial/preset/home_tutorial.js @@ -7,12 +7,6 @@ */ module.exports = [ - // add Tutorial plugin to homepage, "maps" in localConfig with cfg: {preset: "home"} - // remove comment to enable intro/autostart - /*{ - translation: 'intro', - selector: '#intro-tutorial' - },*/ { translation: 'mapType', selector: '#mapstore-maptype', diff --git a/web/client/reducers/tutorial.js b/web/client/reducers/tutorial.js index a86cb77875..fe2eafd03d 100644 --- a/web/client/reducers/tutorial.js +++ b/web/client/reducers/tutorial.js @@ -28,7 +28,8 @@ const initialState = { disabled: false, status: 'close', stepIndex: 0, - tourAction: 'next' + tourAction: 'next', + id: '' }; function tutorial(state = initialState, action) { @@ -42,6 +43,12 @@ function tutorial(state = initialState, action) { case SETUP_TUTORIAL: let setup = {}; setup.steps = [].concat(action.steps); + setup.id = action.id; + setup.checkbox = action.checkbox ? action.checkbox : assign({}, state.checkbox); + setup.style = action.style ? action.style : assign({}, state.style); + setup.defaultStep = action.defaultStep ? action.defaultStep : assign({}, state.defaultStep); + setup.disabled = false; + setup.steps = setup.steps.filter((step) => { return step.selector && step.selector.substring(0, 1) === '#' || step.selector.substring(0, 1) === '.'; }).map((step, index) => { @@ -51,11 +58,11 @@ function tutorial(state = initialState, action) { let text = step.text ? step.text : ''; text = step.translation ? : text; text = step.translationHTML ? : text; - text = (step.selector === '#intro-tutorial') ?
{text}
{action.checkbox}
: text; - let style = (step.selector === '#intro-tutorial') ? action.style : {}; + text = (step.selector === '#intro-tutorial') ?
{text}
{setup.checkbox}
: text; + let style = (step.selector === '#intro-tutorial') ? setup.style : {}; let isFixed = (step.selector === '#intro-tutorial') ? true : step.isFixed || false; assign(style, step.style); - return assign({}, action.defaultStep, step, { + return assign({}, setup.defaultStep, step, { index, title, text, @@ -64,7 +71,7 @@ function tutorial(state = initialState, action) { }); }); - const isDisabled = localStorage.getItem('mapstore.plugin.tutorial.disabled'); + const isDisabled = localStorage.getItem('mapstore.plugin.tutorial.' + action.id + '.disabled'); let hasIntro = false; setup.steps.forEach((step) => { if (step.selector === '#intro-tutorial') { @@ -80,7 +87,7 @@ function tutorial(state = initialState, action) { setup.steps = setup.steps.filter((step) => { return step.selector !== '#intro-tutorial'; }).map((step, index) => { - return assign(step, {index}); + return assign({}, step, {index}); }); setup.run = false; @@ -106,7 +113,7 @@ function tutorial(state = initialState, action) { update.steps = update.steps.filter((step) => { return step.selector !== '#intro-tutorial'; }).map((step, index) => { - return assign(step, {index}); + return assign({}, step, {index}); }); } else if (action.tour.type === 'error:target_not_found') { update.status = 'error'; @@ -118,7 +125,7 @@ function tutorial(state = initialState, action) { return assign({}, state, update); case DISABLE_TUTORIAL: let disabled = !state.disabled; - localStorage.setItem('mapstore.plugin.tutorial.disabled', disabled); + localStorage.setItem('mapstore.plugin.tutorial.' + state.id + '.disabled', disabled); return assign({}, state, { disabled }); diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE index d5ae05d007..41e9e67495 100644 --- a/web/client/translations/data.de-DE +++ b/web/client/translations/data.de-DE @@ -896,6 +896,10 @@ "title": "Custom Application", "text": "You can use components and plugins of MapStore2 to build custom applications" }, + "introCesium": { + "title": "3D map instructions", + "text": "Click on next button to start the tutorial" + }, "cesium": { "title": "Interactions with the Map", "pan": "Pan view", diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US index 4b296e542e..683f841def 100644 --- a/web/client/translations/data.en-US +++ b/web/client/translations/data.en-US @@ -896,6 +896,10 @@ "title": "Custom Application", "text": "You can use components and plugins of MapStore2 to build custom applications" }, + "introCesium": { + "title": "3D map instructions", + "text": "Click on next button to start the tutorial" + }, "cesium": { "title": "Interactions with the Map", "pan": "Pan view", diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR index efb243deec..2dc03d882e 100644 --- a/web/client/translations/data.fr-FR +++ b/web/client/translations/data.fr-FR @@ -898,6 +898,10 @@ "title": "Custom Application", "text": "You can use components and plugins of MapStore2 to build custom applications" }, + "introCesium": { + "title": "3D map instructions", + "text": "Click on next button to start the tutorial" + }, "cesium": { "title": "Interactions with the Map", "pan": "Pan view", diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT index 1578f31204..98e8f65c62 100644 --- a/web/client/translations/data.it-IT +++ b/web/client/translations/data.it-IT @@ -896,6 +896,10 @@ "title": "Applicazioni personalizzate", "text": "Puoi utilizzare componenti e plugins di MapStore2 per costruire applicazioni personalizzate" }, + "introCesium": { + "title": "Istruzioni della mappa 3D", + "text": "Premi il pulsante avanti per aprire il tutorial" + }, "cesium": { "title": "Interazioni con la mappa", "pan": "Vista Pan",