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

Set optional drawer menu for share ( see #1632) #1698

Merged
merged 3 commits into from
Apr 7, 2017
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions docma-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
"web/client/components/buttons/GoFullButton.jsx",
"web/client/components/mapcontrols/search/SearchBar.jsx",
"web/client/components/buttons/ToggleButton.jsx",
"web/client/components/plugins/PluginsContainer.jsx",

"web/client/actions/index.jsdoc",
"web/client/actions/controls.js",
Expand All @@ -132,6 +133,7 @@
"plugins": [
"web/client/plugins/index.jsdoc",
"web/client/plugins/BackgroundSwitcher.jsx",
"web/client/plugins/DrawerMenu.jsx",
"web/client/plugins/GoFull.jsx",
"web/client/plugins/Map.jsx",
"web/client/plugins/FullScreen.jsx",
Expand Down
17 changes: 15 additions & 2 deletions web/client/components/plugins/PluginsContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,20 @@ const PluginsUtils = require('../../utils/PluginsUtils');
const assign = require('object-assign');

const {get} = require('lodash');

/**
* Container for plugins. Get's the plugin definitions (`plugins`) and configuration (`pluginsConfig`)
* to render the configured plugins.
* The plugins to render will come from the `mode` entry of the `pluginsConfig`
* @class
* @memberof components.plugins
* @prop {string} mode key of the pluginsConfig object to get the plugins to render
* @prop {string} defaultMode mode to use if mode is not defined
* @prop {object} params params of the current page, usually from react router. Used as state to get plugins descriptor if monitored state is not present.
* @prop {object} plugins the Plugins definitions
* @prop {object} pluginsConfig the configuration for the plugins. a map of [mode]: [{pluginCfg1}...]
* @prop {object} pluginsState a piece of state to use. usually controls.
* @prop {object} monitoredState the piece of state to monitor Used as state to get plugins descriptor.
*/
const PluginsContainer = React.createClass({
propTypes: {
mode: React.PropTypes.string,
Expand Down Expand Up @@ -60,7 +73,7 @@ const PluginsContainer = React.createClass({
},
renderPlugins(plugins) {
return plugins
.filter((Plugin) => !Plugin.hide)
.filter((Plugin) => !PluginsUtils.handleExpression(this.props.pluginsState, this.props.plugins && this.props.plugins.requires, Plugin.hide))
.map(this.getPluginDescriptor)
.filter((Plugin) => Plugin && !Plugin.impl.loadPlugin)
.filter(this.filterPlugins)
Expand Down
21 changes: 17 additions & 4 deletions web/client/components/share/ShareEmbed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
const React = require('react');
const CopyToClipboard = require('react-copy-to-clipboard');
const Message = require('../../components/I18N/Message');
const {Glyphicon, Col, Grid, Row, Tooltip, Button} = require('react-bootstrap');
const {Glyphicon, Col, Grid, Row, Tooltip, Button, Checkbox} = require('react-bootstrap');
const OverlayTrigger = require('../misc/OverlayTrigger');


const url = require('url');
// css required
require('./share.css');

Expand All @@ -27,11 +27,11 @@ const ShareEmbed = React.createClass({
shareUrl: React.PropTypes.string
},
getInitialState() {
return {copied: false};
return {copied: false, forceDrawer: false};
},
render() {

const codeEmbedded = "<iframe style=\"border: none;\" height=\"400\" width=\"600\" src=\"" + this.props.shareUrl + "\"></iframe>";
const codeEmbedded = "<iframe style=\"border: none;\" height=\"400\" width=\"600\" src=\"" + this.generateUrl(this.props.shareUrl) + "\"></iframe>";
const tooltip = (<Tooltip placement="bottom" className="in" id="tooltip-bottom" style={{zIndex: 2001}}>
{this.state.copied ? <Message msgId="share.msgCopiedUrl"/> : <Message msgId="share.msgToCopyUrl"/>}
</Tooltip>);
Expand All @@ -44,11 +44,16 @@ const ShareEmbed = React.createClass({
</OverlayTrigger>);
return (
<div className="input-link">


<Grid className="embed-box" fluid={true}>
<Row key="title">
<h4>
<Message msgId="share.embeddedLinkTitle"/>
</h4>
<Checkbox checked={this.state.forceDrawer} onChange={() => this.setState({forceDrawer: !this.state.forceDrawer})}>
<Message msgId="share.forceDrawer"/>
</Checkbox>
</Row>
<Row key="data" className="row-button">
<Col key="textarea" xs={10} sm={10} md={10}><textarea name="description" rows="6" value={codeEmbedded} enabled="false" readOnly /></Col>
Expand All @@ -59,6 +64,14 @@ const ShareEmbed = React.createClass({
</Grid>
</div>
);
},
generateUrl() {
const parsed = url.parse(this.props.shareUrl, true);
if (this.state.forceDrawer) {
parsed.query.forceDrawer = true;
}
return url.format(parsed);

}
});

Expand Down
5 changes: 4 additions & 1 deletion web/client/localConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@
"cfg": {
"tools": ["locate"]
}
}, "DrawerMenu", {
}, {
"name": "DrawerMenu",
"hide": "{!(request.query && request.query.forceDrawer)}"
}, {
"name": "Identify",
"cfg": {
"style": {
Expand Down
16 changes: 16 additions & 0 deletions web/client/plugins/DrawerMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const Section = require('./drawer/Section');

const {partialRight} = require('lodash');


const Menu = connect((state) => ({
show: state.controls.drawer && state.controls.drawer.enabled,
activeKey: state.controls.drawer && state.controls.drawer.menu || "1",
Expand All @@ -33,6 +34,21 @@ const Menu = connect((state) => ({

require('./drawer/drawer.css');

/**
* DrawerMenu plugin. Shows a left menu with some pluins rendered inside it (typically the TOC).
* @prop {string} cfg.glyph glyph icon to use for the button
* @prop {object} cfg.menuButtonStyle Css inline style for the button. Display property will be overridden by the hideButton/forceDrawer options.
* @prop {string} cfg.buttonClassName class for the toggle button
* @prop {object} cfg.menuOptions options for the drawer menu. They can be `docked`, `width.
* @memberof plugins
* @class
* @example
* {
* "name": "DrawerMenu",
* "cfg": {
* "hideButton": true
* }
*/
const DrawerMenu = React.createClass({
propTypes: {
items: React.PropTypes.array,
Expand Down
17 changes: 16 additions & 1 deletion web/client/plugins/containers/ToolsContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,22 @@ const {setControlProperty, toggleControl} = require('../../actions/controls');
const {partial} = require('lodash');

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

/**
* A container for tools.
* @memberof plugins.containers.ToolsContainer
* @class ToolsContainer
* @static
* @prop {object[]} tools An array of tools. Each tool have this shape. the first in order wins:
* ```
* {
* tool: {boolean|node} if boolean and true, renders the plugins itself, if object, renders this object as a react component,
* exclusive: if true, gets a selector to make it active or not, setting active property of the tool. tool.toggleControl | tool.name is used from controls state to retrieve the status of the tool
* toggle: same as above, but sets also bsStyle
* action: if present, this action will be binded to the context and associated to the tool as eventSelector (default onClick)
* }
* ```
*
*/
const ToolsContainer = React.createClass({
propTypes: {
id: React.PropTypes.string.isRequired,
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.de-DE
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@
"socialIntro": "In deinem bevorzugten sozialen Netzwerk",
"directLinkTitle": "Über einen direkten Link",
"embeddedLinkTitle": "Über einen eingebetteten Code",
"forceDrawer": "Inhaltsverzeichnis anzeigen",
"apiLinkTitle": "API verwenden",
"social": "Social",
"direct": "Link",
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.en-US
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@
"socialIntro": "In your favourite social network",
"directLinkTitle": "Via a direct link",
"embeddedLinkTitle": "Via the embedded code",
"forceDrawer": "Show TOC",
"apiLinkTitle": "Using APIs",
"social": "Social",
"direct": "Link",
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.fr-FR
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,7 @@
"socialIntro": "via votre réseau social favori",
"directLinkTitle": "Via un lien direct",
"embeddedLinkTitle": "Via le code intégré",
"forceDrawer": "Afficher la table des matières",
"apiLinkTitle": "Via le APIs",
"social": "Social",
"direct": "Link",
Expand Down
1 change: 1 addition & 0 deletions web/client/translations/data.it-IT
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@
"direct": "Link",
"code": "Embed",
"embeddedLinkTitle": "Con il codice embedded",
"forceDrawer": "Mostra l'indice dei livelli",
"apiLinkTitle": "Usando le API",
"QRCodeLinkTitle": "Usando il QR Code",
"msgCopiedUrl":"Copiato",
Expand Down
22 changes: 17 additions & 5 deletions web/client/utils/PluginsUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const assign = require('object-assign');
const {omit, isObject, head, isArray, isString} = require('lodash');
const {combineReducers} = require('redux');
const {connect} = require('react-redux');
const url = require('url');

const {combineEpics} = require('redux-observable');

Expand All @@ -34,20 +35,30 @@ const isPluginConfigured = (pluginsConfig, plugin) => {
};

/*eslint-disable */
const parseExpression = (state, requires, value) => {
const parseExpression = (state = {}, context = {}, value) => {
const searchExpression = /^\{(.*?)\}$/;
const context = requires || {};
const expression = searchExpression.exec(value);
const request = url.parse(location.href, true);
if (expression !== null) {
return eval(expression[1]);
}
return value;
};
/*eslint-enable */

const handleExpression = (state, requires, expression) => {
/**
* Parses a expression string "{some javascript}" and evaluate it.
* The expression will be evalueted getting as parameters the state and the context and the request.
* @memberof utils.PluginsUtils
* @param {object} state the state context
* @param {object} context the context element
* @param {string} expression the expression to parse, it's a string
* @return {object} the result of the expression
* @example "{1===0 && request.query.queryParam1=paramValue1}"
* @example "{1===0 && context.el1 === 'checked'}"
*/
const handleExpression = (state, context, expression) => {
if (isString(expression) && expression.indexOf('{') === 0) {
return parseExpression(state, requires, expression);
return parseExpression(state, context, expression);
}
return expression;
};
Expand Down Expand Up @@ -213,6 +224,7 @@ const PluginsUtils = {
connect: (mapStateToProps, mapDispatchToProps, mergeProps, options) => {
return connect(mapStateToProps, mapDispatchToProps, mergeProps || pluginsMergeProps, options);
},
handleExpression,
getMorePrioritizedContainer
};
module.exports = PluginsUtils;
3 changes: 3 additions & 0 deletions web/client/utils/__tests__/PluginUtils-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,7 @@ describe('PluginsUtils', () => {
const domElement = ReactDOM.findDOMNode(app);
expect(domElement.innerText).toBe("plugintest");
});
it('handleExpression', () => {
expect(PluginsUtils.handleExpression({state1: "test1"}, {context1: "test2"}, "{state.state1 + ' ' + context.context1}")).toBe("test1 test2");
});
});