diff --git a/web/client/components/TOC/fragments/settings/FeatureInfoEditor.jsx b/web/client/components/TOC/fragments/settings/FeatureInfoEditor.jsx
index 00a5005a43..832e955fcf 100644
--- a/web/client/components/TOC/fragments/settings/FeatureInfoEditor.jsx
+++ b/web/client/components/TOC/fragments/settings/FeatureInfoEditor.jsx
@@ -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 {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 {bool} enableIFrameModule enable iframe in editor, default true
+ * @prop {boolean} enableIFrameModule enable iframe in editor, default true
*/
-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 (
+
+ }
+ size="lg"
+ showFullscreen
+ clickOutEnabled={false}
+ onClose={onClose}
+ buttons={[
+ {
+ bsStyle: 'primary',
+ text: ,
+ onClick: onClose
+ }
+ ]}>
+
+ {
+ const previousHTML = draftJSEditorStateToHtml(editorState);
+ const newHTML = draftJSEditorStateToHtml(newEditorState);
+ if (newHTML !== previousHTML) {
+ onChange({ template: draftJSEditorStateToHtml(newEditorState) });
+ setEditorState(newEditorState);
+ }
+ }}
+ />
+
+
+
+ );
+};
- 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 (
-
- }
- size="lg"
- showFullscreen
- clickOutEnabled={false}
- onClose={() => this.close()}
- buttons={[
- {
- bsStyle: 'primary',
- text: ,
- onClick: () => this.close()
- }
- ]}>
-
- { if (quill) { this.quill = quill; onReady(quill); } } }
- modules={(toolbarConfig) => enableIFrameModule ? {
- resizeModule: {},
- toolbar: toolbarConfig
- } : {}}
- defaultValue={this.state.template}
- onChange={template => this.setState({ template })}/>
-
-
-
- );
- }
+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;
diff --git a/web/client/components/TOC/fragments/settings/__tests__/FeatureInfoEditor-test.jsx b/web/client/components/TOC/fragments/settings/__tests__/FeatureInfoEditor-test.jsx
index 95bdd42b4f..5f4f2ecf17 100644
--- a/web/client/components/TOC/fragments/settings/__tests__/FeatureInfoEditor-test.jsx
+++ b/web/client/components/TOC/fragments/settings/__tests__/FeatureInfoEditor-test.jsx
@@ -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';
@@ -31,71 +30,4 @@ describe("test FeatureInfoEditor", () => {
expect(modalEditor.length).toBe(1);
});
- it('test rendering close x', (done) => {
-
- const template = '
html
';
-
- ReactDOM.render( {
- 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 = 'html
';
-
- ReactDOM.render( {
- 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);
- });
-
});
diff --git a/web/client/components/data/identify/viewers/TemplateViewer.jsx b/web/client/components/data/identify/viewers/TemplateViewer.jsx
index eba8fa2db7..4aa249de90 100644
--- a/web/client/components/data/identify/viewers/TemplateViewer.jsx
+++ b/web/client/components/data/identify/viewers/TemplateViewer.jsx
@@ -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}) => (
{response.features.map((feature, i) => {
const cleanTemplate = getCleanTemplate(layer.featureInfo && layer.featureInfo.template || '', feature, /\$\{.*?\}/g, 2, 1);
@@ -33,3 +35,10 @@ export default ({layer = {}, response}) => (
)}
);
+
+export default TemplateViewer;
+
+TemplateViewer.propTypes = {
+ response: PropTypes.object,
+ layer: PropTypes.object
+};
diff --git a/web/client/components/mapviews/settings/CompactRichTextEditor.jsx b/web/client/components/mapviews/settings/CompactRichTextEditor.jsx
index c0d3ec9ab7..c862d8ea69 100644
--- a/web/client/components/mapviews/settings/CompactRichTextEditor.jsx
+++ b/web/client/components/mapviews/settings/CompactRichTextEditor.jsx
@@ -9,8 +9,8 @@
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) => {
@@ -43,6 +43,7 @@ export const resizeBase64Image = (src, options) => {
function CompactRichTextEditor({
wrapperClassName = 'ms-compact-text-editor',
+ toolbarOptions,
...props
}) {
@@ -52,7 +53,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
diff --git a/web/client/themes/default/less/map-views.less b/web/client/themes/default/less/map-views.less
index b354ba823f..364858160f 100644
--- a/web/client/themes/default/less/map-views.less
+++ b/web/client/themes/default/less/map-views.less
@@ -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]);
@@ -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;