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

#9254 Add parametric image parsing to template viewer #9260

Merged
merged 13 commits into from
Jul 5, 2023
Merged
147 changes: 73 additions & 74 deletions web/client/components/TOC/fragments/settings/FeatureInfoEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,97 +6,96 @@
* LICENSE file in the root directory of this source tree.
*/

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import React from 'react';
import ReactQuill from '../../../../libs/quill/react-quill-suspense';

import Message from '../../../I18N/Message';
import Portal from '../../../misc/Portal';
import ResizableModal from '../../../misc/ResizableModal';
import CompactRichTextEditor from '../../../mapviews/settings/CompactRichTextEditor';
import withDebounceOnCallback from '../../../misc/enhancers/withDebounceOnCallback';
import { htmlToDraftJSEditorState, draftJSEditorStateToHtml } from '../../../../utils/EditorUtils';

const DescriptionEditor = withDebounceOnCallback('onEditorStateChange', 'editorState')(CompactRichTextEditor);
/**
* Component for rendering FeatureInfoEditor a modal editor to modify format template
* @memberof components.TOC.fragments.settings
* @name FeatureInfoEditor
* @class
* @prop {object} element data of the current selected node
* @prop {bool} showEditor show/hide modal
* @prop {funciotn} onShowEditor called when click on close buttons
* @prop {function} onChange called when text in editor has been changed
* @prop {bool} enableIFrameModule enable iframe in editor, default true
* @prop {Object} element data of the current selected node
* @prop {Boolean} showEditor show/hide modal
* @prop {Function} onShowEditor called when click on close buttons
* @prop {Function} onChange called when text in editor has been changed
* @prop {Boolean} enableIFrameModule enable iframe in editor, default true
MV88 marked this conversation as resolved.
Show resolved Hide resolved
*/

class FeatureInfoEditor extends React.Component {
const FeatureInfoEditor = ({
element,
showEditor,
onShowEditor,
onChange,
enableIFrameModule
}) => {

static propTypes = {
showEditor: PropTypes.bool,
element: PropTypes.object,
onChange: PropTypes.func,
onShowEditor: PropTypes.func,
enableIFrameModule: PropTypes.bool,
onReady: PropTypes.func
};

static defaultProps = {
showEditor: false,
element: {},
enableIFrameModule: false,
onChange: () => {},
onShowEditor: () => {}
};

state = {
template: ' '
const [editorState, setEditorState] = useState(htmlToDraftJSEditorState(element?.featureInfo?.template || ''));
const onClose = () => {
onShowEditor(!showEditor);
onChange('featureInfo', {
...(element && element.featureInfo || {}),
template: draftJSEditorStateToHtml(editorState)
});
};
return (
<Portal>
<ResizableModal
fade
show={showEditor}
title={<Message msgId="layerProperties.editCustomFormat"/>}
size="lg"
showFullscreen
clickOutEnabled={false}
onClose={onClose}
buttons={[
{
bsStyle: 'primary',
text: <Message msgId="close"/>,
onClick: onClose
}
]}>
<div id="ms-template-editor" className="ms-editor">
<DescriptionEditor
toolbarOptions={['fontFamily', 'blockType', 'inline', 'textAlign', 'list', 'link', 'colorPicker', 'remove', 'image'].concat(enableIFrameModule ? ['embedded'] : [])}
editorState={editorState}
onEditorStateChange={(newEditorState) => {
const previousHTML = draftJSEditorStateToHtml(editorState);
const newHTML = draftJSEditorStateToHtml(newEditorState);
if (newHTML !== previousHTML) {
onChange({ template: draftJSEditorStateToHtml(newEditorState) });
setEditorState(newEditorState);
}
}}
/>
</div>
</ResizableModal>
</Portal>
);
};

UNSAFE_componentWillMount() {
this.setState({
template: this.props.element && this.props.element.featureInfo && this.props.element.featureInfo.template || ' '
});
}
FeatureInfoEditor.propTypes = {
showEditor: PropTypes.bool,
element: PropTypes.object,
onChange: PropTypes.func,
onShowEditor: PropTypes.func,
enableIFrameModule: PropTypes.bool
};

render() {
const { showEditor, enableIFrameModule = true, onReady = () => {} } = this.props;
return (
<Portal>
<ResizableModal
fade
show={showEditor}
title={<Message msgId="layerProperties.editCustomFormat"/>}
size="lg"
showFullscreen
clickOutEnabled={false}
onClose={() => this.close()}
buttons={[
{
bsStyle: 'primary',
text: <Message msgId="close"/>,
onClick: () => this.close()
}
]}>
<div id="ms-template-editor" className="ms-editor">
<ReactQuill
bounds="#ms-template-editor"
ref={(quill) => { if (quill) { this.quill = quill; onReady(quill); } } }
modules={(toolbarConfig) => enableIFrameModule ? {
resizeModule: {},
toolbar: toolbarConfig
} : {}}
defaultValue={this.state.template}
onChange={template => this.setState({ template })}/>
</div>
</ResizableModal>
</Portal>
);
}
FeatureInfoEditor.defaultProps = {
showEditor: false,
element: {},
enableIFrameModule: false,
onChange: () => {},
onShowEditor: () => {}
};

close = () => {
this.props.onShowEditor(!this.props.showEditor);
this.props.onChange('featureInfo', {
...(this.props.element && this.props.element.featureInfo || {}),
template: this.state.template
});
};
}

export default FeatureInfoEditor;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import expect from 'expect';
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-dom/test-utils';

import FeatureInfoEditor from '../FeatureInfoEditor';

Expand All @@ -31,71 +30,4 @@ describe("test FeatureInfoEditor", () => {
expect(modalEditor.length).toBe(1);
});

it('test rendering close x', (done) => {

const template = '<p>html</p>';

ReactDOM.render(<FeatureInfoEditor
onReady={(quill) => {
try {
// edit template
const editor = quill.getEditor();
editor.clipboard.dangerouslyPasteHTML(template);
const btns = document.getElementsByClassName('ms-header-btn');
expect(btns.length).toBe(2);
TestUtils.Simulate.click(btns[1]);
} catch (e) {
done(e);
}
}}
onShowEditor={(value) => {
expect(value).toBe(false);
}}
onChange={(key, value) => {
if (value.template === template) {
expect(key).toBe('featureInfo');
expect(value).toEqual({ template });
done();
}
}}
showEditor/>, document.getElementById("container"));

const modalEditor = document.getElementsByClassName('ms-resizable-modal');
expect(modalEditor.length).toBe(1);

});

it('test rendering close button', (done) => {

const template = '<p>html</p>';

ReactDOM.render(<FeatureInfoEditor
onReady={(quill) => {
try {
// edit template
const editor = quill.getEditor();
editor.clipboard.dangerouslyPasteHTML(template);
const btns = document.getElementsByClassName('btn');
expect(btns.length).toBe(1);
TestUtils.Simulate.click(btns[0]);
} catch (e) {
done(e);
}
}}
onShowEditor={(value) => {
expect(value).toBe(false);
}}
onChange={(key, value) => {
if (value.template === template) {
expect(key).toBe('featureInfo');
expect(value).toEqual({ template });
done();
}
}}
showEditor
/>, document.getElementById("container"));
const modalEditor = document.getElementsByClassName('ms-resizable-modal');
expect(modalEditor.length).toBe(1);
});

});
13 changes: 11 additions & 2 deletions web/client/components/data/identify/viewers/TemplateViewer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
*/

import React from 'react';

import { template } from 'lodash';
import PropTypes from 'prop-types';

import { getCleanTemplate } from '../../../../utils/TemplateUtils';
import HtmlRenderer from '../../../misc/HtmlRenderer';
import Message from '../../../I18N/Message';

export default ({layer = {}, response}) => (

const TemplateViewer = ({layer = {}, response}) => (
<div className="ms-template-viewer">
{response.features.map((feature, i) => {
const cleanTemplate = getCleanTemplate(layer.featureInfo && layer.featureInfo.template || '', feature, /\$\{.*?\}/g, 2, 1);
Expand All @@ -33,3 +35,10 @@ export default ({layer = {}, response}) => (
)}
</div>
);

export default TemplateViewer;

TemplateViewer.propTypes = {
response: PropTypes.object,
layer: PropTypes.object
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@
* LICENSE file in the root directory of this source tree.
*/

import PropTypes from 'prop-types';
MV88 marked this conversation as resolved.
Show resolved Hide resolved
import React from 'react';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import { Editor } from 'react-draft-wysiwyg';
import { DEFAULT_FONT_FAMILIES } from '../../../utils/GeoStoryUtils';
import embed from 'embed-video';
import { DEFAULT_FONT_FAMILIES } from '../../../utils/GeoStoryUtils';

export const resizeBase64Image = (src, options) => {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -43,6 +44,7 @@ export const resizeBase64Image = (src, options) => {

function CompactRichTextEditor({
wrapperClassName = 'ms-compact-text-editor',
toolbarOptions,
...props
}) {

Expand All @@ -52,7 +54,7 @@ function CompactRichTextEditor({
editorStyle={{ minHeight: 200 }}
wrapperClassName={wrapperClassName}
toolbar={{
options: ['fontFamily', 'blockType', 'inline', 'textAlign', 'list', 'link', 'colorPicker', 'remove', 'image', 'embedded'],
options: toolbarOptions || ['fontFamily', 'blockType', 'inline', 'textAlign', 'list', 'link', 'colorPicker', 'remove', 'image', 'embedded'],
image: {
urlEnabled: true,
// disable the upload at the moment
Expand Down Expand Up @@ -123,3 +125,8 @@ function CompactRichTextEditor({
}

export default CompactRichTextEditor;

CompactRichTextEditor.propTypes = {
toolbarOptions: PropTypes.array,
wrapperClassName: PropTypes.string
};
MV88 marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions web/client/themes/default/less/map-views.less
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
.border-color-var(@theme-vars[main-border-color]);
}
}

.ms-map-views {
.ms-map-views-wrapper {
.background-color-var(@theme-vars[main-bg]);
Expand Down Expand Up @@ -90,9 +90,9 @@
.rdw-editor-toolbar {
position: sticky;
z-index: 20;
top: 30px;
}
.rdw-editor-main {
height: auto;
padding: 0 4px;
iframe {
aspect-ratio: 16 / 9;
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@
"bottom": "Unten",
"top": "Oben",
"editLayerName": "Ebenennamen bearbeiten",
"confirmLayerName": "Bestätigen Sie die Änderung des Ebenennamens"
"confirmLayerName": "Bestätigen Sie die Änderung des Ebenennamens",
"markDownImage": "Ausgewählten Text in Markdown-URL umwandeln ![]()"
MV88 marked this conversation as resolved.
Show resolved Hide resolved
},
"legendOptions": {
"title": "Legende",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@
"bottom": "Bottom",
"top": "Top",
"editLayerName": "Edit layer name",
"confirmLayerName": "Confirm layer name change"
"confirmLayerName": "Confirm layer name change",
"markDownImage": "Transform selected text into Markdown Url ![]()"
MV88 marked this conversation as resolved.
Show resolved Hide resolved
},
"legendOptions": {
"title": "Legend",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@
"bottom": "Bottom",
"top": "Cima",
"editLayerName": "Editar el nombre de la capa",
"confirmLayerName": "Confirmar cambio de nombre de capa"
"confirmLayerName": "Confirmar cambio de nombre de capa",
"markDownImage": "Transformar texto seleccionado en Markdown Url ![]()"
MV88 marked this conversation as resolved.
Show resolved Hide resolved
},
"legendOptions": {
"title": "Leyenda",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@
"bottom": "Bas",
"top": "Haut",
"editLayerName": "Modifier le nom du calque",
"confirmLayerName": "Confirmer le changement de nom du calque"
"confirmLayerName": "Confirmer le changement de nom du calque",
"markDownImage": "Transformer le texte sélectionné en URL Markdown ![]()"
MV88 marked this conversation as resolved.
Show resolved Hide resolved
},
"legendOptions": {
"title": "Légende",
Expand Down
3 changes: 2 additions & 1 deletion web/client/translations/data.it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@
"bottom": "Sotto",
"top": "Sopra",
"editLayerName": "Modifica il nome del livello",
"confirmLayerName": "Conferma la modifica del nome del livello"
"confirmLayerName": "Conferma la modifica del nome del livello",
"markDownImage": "Trasforma il testo seleziona in un MarkDown Url ![]()"
MV88 marked this conversation as resolved.
Show resolved Hide resolved
},
"legendOptions": {
"title": "Legenda",
Expand Down