-
Notifications
You must be signed in to change notification settings - Fork 410
/
Copy pathStandardApp.jsx
167 lines (151 loc) · 6.34 KB
/
StandardApp.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
* 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.
*/
const React = require('react');
const {Provider} = require('react-redux');
const PropTypes = require('prop-types');
const proj4 = require('proj4').default;
const {changeBrowserProperties} = require('../../actions/browser');
const {loadLocale} = require('../../actions/locale');
const {localConfigLoaded} = require('../../actions/localConfig');
const {loadPrintCapabilities} = require('../../actions/print');
const ConfigUtils = require('../../utils/ConfigUtils');
const LocaleUtils = require('../../utils/LocaleUtils');
const PluginsUtils = require('../../utils/PluginsUtils');
const assign = require('object-assign');
const url = require('url');
const {isObject, isArray} = require('lodash');
const urlQuery = url.parse(window.location.href, true).query;
require('./appPolyfill');
/**
* Standard MapStore2 application component
*
* @name StandardApp
* @memberof components.app
* @prop {function} appStore store creator function
* @prop {object} pluginsDef plugins definition object (e.g. as loaded from plugins.js)
* @prop {object} storeOpts options for the store
* @prop {array} initialActions list of actions to be dispatched on startup
* @prop {function|object} appComponent root component for the application
* @prop {bool} printingEnabled initializes printing environment based on mapfish-print
* @prop {function} onStoreInit optional callback called just after store creation
* @prop {function} onInit optional callback called before first rendering, can delay first rendering
* to do custom initialization (e.g. force SSO login)
* @prop {string} mode current application mode (e.g. desktop/mobile) drives plugins loaded from localConfig
*/
class StandardApp extends React.Component {
static propTypes = {
appStore: PropTypes.func,
pluginsDef: PropTypes.object,
storeOpts: PropTypes.object,
initialActions: PropTypes.array,
appComponent: PropTypes.func,
printingEnabled: PropTypes.bool,
onStoreInit: PropTypes.func,
onInit: PropTypes.func,
mode: PropTypes.string
};
static defaultProps = {
pluginsDef: {plugins: {}, requires: {}},
initialActions: [],
printingEnabled: false,
appStore: () => ({dispatch: () => {}}),
appComponent: () => <span/>,
onStoreInit: () => {}
};
state = {
initialized: false
};
addProjDefinitions(config) {
if (config.projectionDefs && config.projectionDefs.length) {
config.projectionDefs.forEach((proj) => {
proj4.defs(proj.code, proj.def);
});
}
}
componentWillMount() {
const onInit = (config) => {
if (!global.Intl ) {
require.ensure(['intl', 'intl/locale-data/jsonp/en.js', 'intl/locale-data/jsonp/it.js'], (require) => {
global.Intl = require('intl');
require('intl/locale-data/jsonp/en.js');
require('intl/locale-data/jsonp/it.js');
this.init(config);
});
} else {
this.init(config);
}
};
if (urlQuery.localConfig) {
ConfigUtils.setLocalConfigurationFile(urlQuery.localConfig + '.json');
}
ConfigUtils.loadConfiguration().then((config) => {
const opts = assign({}, this.props.storeOpts, {
onPersist: onInit.bind(null, config)
}, {
initialState: this.parseInitialState(config.initialState, {
mode: this.props.mode || (ConfigUtils.getBrowserProperties().mobile ? 'mobile' : 'desktop')
}) || {defaultState: {}, mobile: {}}
});
this.store = this.props.appStore(this.props.pluginsDef.plugins, opts);
this.props.onStoreInit(this.store);
if (!opts.persist) {
onInit(config);
}
});
}
render() {
const {plugins, requires} = this.props.pluginsDef;
const {pluginsDef, appStore, initialActions, appComponent, mode, ...other} = this.props;
const App = this.props.appComponent;
return this.state.initialized ?
<Provider store={this.store}>
<App {...other} plugins={assign(PluginsUtils.getPlugins(plugins), {requires})}/>
</Provider>
: (<span><div className="_ms2_init_spinner _ms2_init_center"><div></div></div>
<div className="_ms2_init_text _ms2_init_center">Loading MapStore</div></span>);
}
afterInit = () => {
if (this.props.printingEnabled) {
this.store.dispatch(loadPrintCapabilities(ConfigUtils.getConfigProp('printUrl')));
}
this.props.initialActions.forEach((action) => {
this.store.dispatch(action());
});
this.setState({
initialized: true
});
};
init = (config) => {
this.store.dispatch(changeBrowserProperties(ConfigUtils.getBrowserProperties()));
this.store.dispatch(localConfigLoaded(config));
this.addProjDefinitions(config);
const locale = LocaleUtils.getUserLocale();
this.store.dispatch(loadLocale(null, locale));
if (this.props.onInit) {
this.props.onInit(this.store, this.afterInit.bind(this, [config]), config);
} else {
this.afterInit(config);
}
};
/**
* It returns an object of the same structure of the initialState but replacing strings like "{someExpression}" with the result of the expression between brackets.
* @param {object} state the object to parse
* @param {object} context context for expression
* @return {object} the modified object
*/
parseInitialState = (state, context) => {
return Object.keys(state || {}).reduce((previous, key) => {
return { ...previous, ...{ [key]: isObject(state[key]) ?
(isArray(state[key]) ? state[key].map(s => {
return isObject(s) ? this.parseInitialState(s, context) : s;
}) : this.parseInitialState(state[key], context)) :
PluginsUtils.handleExpression({}, context, state[key])}};
}, {});
};
}
module.exports = StandardApp;