diff --git a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx index c183a644c0..8ab5c9356a 100644 --- a/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx +++ b/frontend/src/AppBuilder/RightSideBar/Inspector/Components/DefaultComponent.jsx @@ -21,6 +21,7 @@ const SHOW_ADDITIONAL_ACTIONS = [ 'DropdownV2', 'MultiselectV2', 'Button', + 'RichTextEditor', ]; const PROPERTIES_VS_ACCORDION_TITLE = { Text: 'Data', diff --git a/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js b/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js index eacee66529..c964d53d6b 100644 --- a/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js +++ b/frontend/src/AppBuilder/WidgetManager/widgets/richtextarea.js @@ -28,6 +28,15 @@ export const richtextareaConfig = { defaultValue: 'Default text', }, }, + loadingState: { + type: 'toggle', + displayName: 'Show loading state', + validation: { + schema: { type: 'boolean' }, + defaultValue: false, + }, + section: 'additionalActions', + }, }, events: {}, styles: { @@ -55,6 +64,28 @@ export const richtextareaConfig = { exposedVariables: { value: '', }, + actions: [ + { + handle: 'setValue', + displayName: 'Set value', + params: [{ handle: 'value', displayName: 'Value', defaultValue: 'New text' }], + }, + { + handle: 'setDisable', + displayName: 'Set disable', + params: [{ handle: 'setDisable', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }], + }, + { + handle: 'setVisibility', + displayName: 'Set visibility', + params: [{ handle: 'setVisibility', displayName: 'Value', defaultValue: `{{true}}`, type: 'toggle' }], + }, + { + handle: 'setLoading', + displayName: 'Set loading', + params: [{ handle: 'setLoading', displayName: 'Value', defaultValue: `{{false}}`, type: 'toggle' }], + }, + ], definition: { others: { showOnDesktop: { value: '{{true}}' }, @@ -63,6 +94,7 @@ export const richtextareaConfig = { properties: { placeholder: { value: 'Placeholder text' }, defaultValue: { value: '' }, + loadingState: { value: `{{false}}` }, }, events: [], styles: { diff --git a/frontend/src/Editor/Components/DraftEditor.jsx b/frontend/src/Editor/Components/DraftEditor.jsx index 1df78ee1bf..b2c8b61994 100644 --- a/frontend/src/Editor/Components/DraftEditor.jsx +++ b/frontend/src/Editor/Components/DraftEditor.jsx @@ -1,8 +1,10 @@ /* eslint-disable react/no-string-refs */ import React from 'react'; -import { Editor, EditorState, RichUtils, getDefaultKeyBinding, ContentState } from 'draft-js'; +import { Editor, EditorState, RichUtils, getDefaultKeyBinding, ContentState, convertFromHTML } from 'draft-js'; import 'draft-js/dist/Draft.css'; import { stateToHTML } from 'draft-js-export-html'; +import Loader from '@/ToolJetUI/Loader/Loader'; +import DOMPurify from 'dompurify'; // Custom overrides for "code" style. const styleMap = { @@ -148,8 +150,11 @@ const InlineStyleControls = (props) => { class DraftEditor extends React.Component { constructor(props) { super(props); + const blocksFromHTML = convertFromHTML(DOMPurify.sanitize(this.props.defaultValue)); this.state = { - editorState: EditorState.createWithContent(ContentState.createFromText(this.props.defaultValue)), + editorState: EditorState.createWithContent( + ContentState.createFromBlockArray(blocksFromHTML.contentBlocks, blocksFromHTML.entityMap) + ), }; this.editorContainerRef = React.createRef(); @@ -181,6 +186,38 @@ class DraftEditor extends React.Component { if (this.controlsRef.current) { this.resizeObserver.observe(this.controlsRef.current); } + + const exposedVariables = { + value: this.props.defaultValue, + isDisabled: this.props.isDisabled, + isVisible: this.props.isVisible, + isLoading: this.props.isLoading, + setValue: async (text) => { + const blocksFromHTML = convertFromHTML(DOMPurify.sanitize(text)); + const newContentState = ContentState.createFromBlockArray( + blocksFromHTML.contentBlocks, + blocksFromHTML.entityMap + ); + const newEditorState = EditorState.createWithContent(newContentState); + const html = stateToHTML(newContentState); + this.props.handleChange(html); + this.setState({ editorState: newEditorState }); + }, + setDisable: async (value) => { + this.props.setExposedVariable('isDisabled', value); + this.props.setIsDisabled(value); + }, + setVisibility: async (value) => { + this.props.setExposedVariable('isVisible', value); + this.props.setIsVisible(value); + }, + setLoading: async (value) => { + this.props.setExposedVariable('isLoading', value); + this.props.setIsLoading(value); + }, + }; + this.props.setExposedVariables(exposedVariables); + this.props.isInitialRender.current = false; } componentWillUnmount() { @@ -191,7 +228,8 @@ class DraftEditor extends React.Component { componentDidUpdate(prevProps) { if (prevProps.defaultValue !== this.props.defaultValue) { - const newContentState = ContentState.createFromText(this.props.defaultValue); + const blocksFromHTML = convertFromHTML(DOMPurify.sanitize(this.props.defaultValue)); + const newContentState = ContentState.createFromBlockArray(blocksFromHTML.contentBlocks, blocksFromHTML.entityMap); const newEditorState = EditorState.createWithContent(newContentState); const html = stateToHTML(newContentState); @@ -242,7 +280,13 @@ class DraftEditor extends React.Component { } } - return ( + return this.props.isLoading ? ( +