Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1619, Fixes #1549, Fixes #1103: notification system and docume… #1620

Merged
merged 4 commits into from
Mar 22, 2017
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions docma-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
"items": [
{ "label": "Framework", "href": "api/framework"},

{ "separator": true },
{ "label": "JavaScript API", "href": "api/jsapi" },
{ "separator": true },
{ "label": "Plugins", "href": "api/plugins" }

Expand Down Expand Up @@ -120,6 +122,7 @@
"web/client/utils/index.jsdoc",
"web/client/utils/PluginsUtils.js"
],
"jsapi": "web/client/jsapi/MapStore2.js",
"plugins": [
"web/client/plugins/index.jsdoc",
"web/client/plugins/Search.jsx",
Expand All @@ -131,12 +134,7 @@
"./docs/**/*md",
{
"readme": "./README.md",
"site": "./docs/index.md",
"developer-guide": "./docs/developer-guide/index.md",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

developer's guide should be produced, is referred by the top menu.

"plugins-architecture": "./docs/developer-guide/plugins-architecture.md",
"building-and-developing": "./docs/developer-guide/plugins-architecture.md",
"plugins-documentation": "./docs/developer-guide/plugins-documentation.md",
"project-creation-script": "./docs/developer-guide/project-creation-script.md"
"site": "./docs/index.md"
}
]
}
8 changes: 2 additions & 6 deletions docs/developer-guide/plugins-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Inside the **plugins** section, several modes can be configured (e.g. desktop or
}
```

Each plugin can be simply listed (and the default configuration is used):
Each plugin can be simply listed (and the default configuration is used):

```js
"plugins": {
Expand All @@ -33,15 +33,11 @@ or fully configured:
...
"desktop": [{
"name": "Map",
"cfg": {
...
}
},
...
]
}
```
Look at each plugin documentation page for a list of available configuration properties.

# Plugins List:
* [Map](map-plugin)
Look at the [plugin reference page](./api/plugins) for a list of available configuration properties.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
},
"//": "replace react-sortable-items with official on npm when 0.0.10 with remove_deprecated PR in included",
"dependencies": {
"@carnesen/redux-add-action-listener-enhancer": "0.0.1",
"ag-grid": "3.3.3",
"ag-grid-react": "3.3.1",
"axios": "0.11.1",
Expand Down
6 changes: 5 additions & 1 deletion web/client/components/app/StandardRouter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ const {Router, Route, hashHistory} = require('react-router');

const Localized = require('../I18N/Localized');

const assign = require('object-assign');

const Theme = connect((state) => ({
theme: state.theme && state.theme.selectedTheme && state.theme.selectedTheme.id
}))(require('../theme/Theme'));
}), {}, (stateProps, dispatchProps, ownProps) => {
return assign({}, stateProps, dispatchProps, ownProps);
})(require('../theme/Theme'));

const StandardRouter = React.createClass({
propTypes: {
Expand Down
2 changes: 1 addition & 1 deletion web/client/containers/Page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const Page = React.createClass({
desktop: [...this.props.pagePluginsConfig.desktop, ...this.props.pluginsConfig.desktop],
mobile: [...this.props.pagePluginsConfig.mobile, ...this.props.pluginsConfig.mobile]
};
return (<PluginsContainer key="{this.props.id}" id={"page-" + this.props.id} className={"page page-" + this.props.id}
return (<PluginsContainer key={this.props.id} id={"page-" + this.props.id} className={"page page-" + this.props.id}
pluginsConfig={pluginsConfig}
plugins={this.props.plugins}
params={this.props.params}
Expand Down
18 changes: 16 additions & 2 deletions web/client/examples/api/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
function init() {
/*eslint-enable */
var cfg;
var cfgUrl;
var theme;
var embeddedPlugins;
var pluginsCfg;

/*eslint-disable */
cfg = MapStore2.loadConfigFromStorage('mapstore.example.plugins.' + MapStore2.getMapNameFromRequest());
cfg = MapStore2.loadConfigFromStorage('mapstore.example.plugins.' + MapStore2.getParamFromRequest('map'));
cfgUrl = MapStore2.getParamFromRequest('config');
theme = MapStore2.getParamFromRequest('theme');
/*eslint-enable */
embeddedPlugins = {
"desktop": [
Expand All @@ -28,14 +32,24 @@ function init() {
/*eslint-disable */
pluginsCfg = cfg && MapStore2.buildPluginsCfg(cfg.pluginsCfg.standard, cfg.userCfg) || embeddedPlugins;
MapStore2.create('container', {
/*eslint-enable */
plugins: pluginsCfg,
configUrl: cfgUrl,
initialState: cfg && cfg.state && {
defaultState: cfg.state
} || null,
style: cfg && cfg.customStyle,
theme: {
theme,
path: '../../dist/themes'
}
});
MapStore2.onAction('CHANGE_MAP_VIEW', function(action) {
console.log('ZOOM: ' + action.zoom);
});
MapStore2.onStateChange(function(map) {
console.log('STATE ZOOM: ' + map.zoom);
}, function(state) {
return (state.map && state.map.present) || state.map || {}
});
/*eslint-enable */
}
156 changes: 148 additions & 8 deletions web/client/jsapi/MapStore2.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright 2016, GeoSolutions Sas.
* All rights reserved.
*
Expand All @@ -12,7 +12,7 @@ const StandardApp = require('../components/app/StandardApp');
const LocaleUtils = require('../utils/LocaleUtils');
const {connect} = require('react-redux');

const {configureMap} = require('../actions/config');
const {configureMap, loadMapConfig} = require('../actions/config');

const url = require('url');

Expand Down Expand Up @@ -169,7 +169,7 @@ function loadConfigFromStorage(name = 'mapstore.embedded') {
return null;
}

function getMapNameFromRequest(paramName = 'map') {
function getParamFromRequest(paramName) {
const urlQuery = url.parse(window.location.href, true).query;
return urlQuery[paramName] || null;
}
Expand All @@ -196,7 +196,74 @@ function buildPluginsCfg(plugins, cfg) {
};
}

const actionListeners = {};
let stateChangeListeners = [];
let app;

const getInitialActions = (options) => {
if (!options.initialState) {
if (options.configUrl) {
return [loadMapConfig.bind(null, options.configUrl || defaultConfig)];
}
return [configureMap.bind(null, options.config || defaultConfig)];
}
return [];
};


/**
* MapStore2 JavaScript API. Allows embedding MapStore2 functionalities into
* a standard HTML page.
* @class
*/
const MapStore2 = {
/**
* Instantiates an embedded MapStore2 application in the given container.
* @memberof MapStore2
* @static
* @param {string} container id of the DOM element that should contain the embedded MapStore2
* @param {object} options set of options of the embedded app
*
* The options object can contain the following properties, to configure the app UI and state:
* * **plugins**: list of plugins (and the related configuration) to be included in the app
* look at [Plugins documentation](./plugins-documentation) for further details
* * **config**: map configuration object for the application (look at [Map Configuration](./maps-configuration) for details)
* * **configUrl**: map configuration url for the application (look at [Map Configuration](./maps-configuration) for details)
* * **initialState**: allows setting the initial application state (look at [State Configuration](./app-state-configuration) for details)
*
* Styling can be configured either using a **theme**, or a complete custom **less stylesheet**, using the
* following options properties:
* * **style**: less style to be applied
* * **theme**: theme configuration options:
* * path: path/url of the themes folder related to the current page
* * theme: theme name to be used
*
* ```javascript
* {
* plugins: ['Map', 'ZoomIn', 'ZoomOut'],
* config: {
* map: {
* ...
* }
* },
* configUrl: '...',
* initialState: {
* defaultState: {
* ...
* }
* },
* style: '<custom style>',
* theme: {
* theme: 'mytheme',
* path: 'dist/themes'
* }
* }
* ```
* @example
* MapStore2.create('container', {
* plugins: ['Map']
* });
*/
create(container, options) {
const embedded = require('../containers/Embedded');

Expand All @@ -218,9 +285,9 @@ const MapStore2 = {
}))(require('../components/app/StandardRouter'));

const appStore = require('../stores/StandardStore').bind(null, initialState || {}, {});
const initialActions = options.initialState ? [] : [configureMap.bind(null, options.config || defaultConfig)];
const initialActions = getInitialActions(options);
const appConfig = {
storeOpts,
storeOpts: assign({}, storeOpts, {notify: true}),
appStore,
pluginsDef,
initialActions,
Expand All @@ -242,11 +309,84 @@ const MapStore2 = {
};

const themeCfg = options.theme && assign({}, defaultThemeCfg, options.theme) || defaultThemeCfg;
ReactDOM.render(<StandardApp themeCfg={themeCfg} className="fill" {...appConfig}/>, document.getElementById(container));
app = ReactDOM.render(<StandardApp themeCfg={themeCfg} className="fill" {...appConfig}/>, document.getElementById(container));
app.store.addActionListener((action) => {
(actionListeners[action.type] || []).concat(actionListeners['*'] || []).forEach((listener) => {
listener.call(null, action);
});
});
app.store.subscribe(() => {
stateChangeListeners.forEach(({listener, selector}) => {
listener.call(null, selector(app.store.getState()));
});
});
},
buildPluginsCfg,
getMapNameFromRequest,
loadConfigFromStorage
getParamFromRequest,
loadConfigFromStorage,
/**
* Adds a listener that will be notified of all the MapStore2 events (**actions**), or only some of them.
*
* @memberof MapStore2
* @static
* @param {string} type type of actions to be captured (* for all)
* @param {function} listener function to be called for each launched action; it will receive
* the action as the only argument
* @example
* MapStore2.onAction('CHANGE_MAP_VIEW', function(action) {
* console.log(action.zoom);
* });
*/
onAction: (type, listener) => {
const listeners = actionListeners[type] || [];
listeners.push(listener);
actionListeners[type] = listeners;
},
/**
* Removes an action listener.
*
* @memberof MapStore2
* @static
* @param {string} type type of actions that is captured by the listener (* for all)
* @param {function} listener listener to be removed
* @example
* MapStore2.offAction('CHANGE_MAP_VIEW', listener);
*/
offAction: (type, listener) => {
const listeners = (actionListeners[type] || []).filter((l) => l !== listener);
actionListeners[type] = listeners;
},
/**
* Adds a listener that will be notified of each state update.
*
* @memberof MapStore2
* @static
* @param {function} listener function to be called for each state udpate; it will receive
* the new state as the only argument
* @param {function} [selector] optional function that will produce a partial/derived state
* from the global state before calling the listeners
* @example
* MapStore2.onStateChange(function(map) {
* console.log(map.zoom);
* }, function(state) {
* return (state.map && state.map.present) || state.map || {};
* });
*/
onStateChange: (listener, selector = (state) => state) => {
stateChangeListeners.push({listener, selector});
},
/**
* Removes a state listener.
*
* @memberof MapStore2
* @static
* @param {function} listener listener to be removed
* @example
* MapStore2.offStateChange(listener);
*/
offStateChange: (listener) => {
stateChangeListeners = stateChangeListeners.filter((l) => l !== listener);
}
};

if (!global.Intl ) {
Expand Down
Loading