forked from WikiEducationFoundation/WikiEduDashboard
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: text_area_input.jsx to functional component
- Loading branch information
1 parent
09f6a53
commit 3eeda65
Showing
1 changed file
with
120 additions
and
118 deletions.
There are no files selected for viewing
238 changes: 120 additions & 118 deletions
238
app/assets/javascripts/components/common/text_area_input.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,147 +1,149 @@ | ||
import { Editor } from '@tinymce/tinymce-react'; | ||
import React from 'react'; | ||
import React, { useState, useEffect } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import createReactClass from 'create-react-class'; | ||
import InputHOC from '../high_order/input_hoc.jsx'; | ||
import InputHOC from '../high_order/input_hoc'; | ||
import markdown_it from '../../utils/markdown_it'; | ||
|
||
const md = markdown_it({ openLinksExternally: true }); | ||
|
||
const md = require('../../utils/markdown_it.js').default({ openLinksExternally: true }); | ||
// This is a flexible text input box. It switches between edit and read mode, | ||
// and can either provide a wysiwyg editor or a plain text editor. | ||
const TextAreaInput = createReactClass({ | ||
displayName: 'TextAreaInput', | ||
|
||
propTypes: { | ||
onChange: PropTypes.func, | ||
onFocus: PropTypes.func, | ||
onBlur: PropTypes.func, | ||
value: PropTypes.string, | ||
value_key: PropTypes.string, | ||
editable: PropTypes.bool, // switch between read and edit mode | ||
id: PropTypes.string, | ||
focus: PropTypes.bool, | ||
placeholder: PropTypes.string, | ||
autoExpand: PropTypes.bool, // start with one line and expand as needed — plain text only | ||
rows: PropTypes.string, // set the number of rows — plain text only | ||
wysiwyg: PropTypes.bool, // use rich text editor instead of plain text | ||
markdown: PropTypes.bool, // render value as Markdown when in read mode | ||
className: PropTypes.string, | ||
clearOnSubmit: PropTypes.bool | ||
}, | ||
|
||
getInitialState() { | ||
return { tinymceLoaded: false }; | ||
}, | ||
const TextAreaInput = ({ | ||
onChange, | ||
onFocus, | ||
onBlur, | ||
value, | ||
editable, | ||
id, | ||
focus, | ||
placeholder, | ||
autoExpand, | ||
rows, | ||
wysiwyg, | ||
markdown, | ||
className, | ||
clearOnSubmit, | ||
invalid | ||
}) => { | ||
const [tinymceLoaded, setTinymceLoaded] = useState(false); | ||
const [activeEditor, setActiveEditor] = useState(null); | ||
|
||
componentDidMount() { | ||
if (this.props.wysiwyg) { | ||
this.loadTinyMCE(); | ||
useEffect(() => { | ||
if (wysiwyg) { | ||
loadTinyMCE(); | ||
} | ||
}, | ||
}, [wysiwyg]); | ||
|
||
loadTinyMCE() { | ||
const user_signed_in = Features.user_signed_in; | ||
const loadTinyMCE = () => { | ||
const user_signed_in = Features.user_signed_in; // Ensure Features is accessible | ||
if (user_signed_in) { | ||
import('../../tinymce').then(() => { | ||
this.setState({ | ||
tinymceLoaded: true | ||
}); | ||
setTinymceLoaded(true); | ||
}); | ||
} | ||
}, | ||
}; | ||
|
||
handleRichTextEditorChange(e) { | ||
this.props.onChange( | ||
{ target: { value: e } }, | ||
e | ||
); | ||
}, | ||
const handleRichTextEditorChange = (e) => { | ||
onChange({ target: { value: e } }, e); | ||
}; | ||
|
||
handleSubmit() { | ||
if (this.props.clearOnSubmit) { | ||
this.state.activeEditor.setContent(''); | ||
const handleSubmit = () => { | ||
if (clearOnSubmit) { | ||
activeEditor.setContent(''); | ||
} | ||
}, | ||
}; | ||
|
||
render() { | ||
let inputElement; | ||
let rawHtml; | ||
let inputElement; | ||
let rawHtml; | ||
|
||
// //////////// | ||
// Edit mode // | ||
// //////////// | ||
if (this.props.editable) { | ||
let inputClass; | ||
if (this.props.invalid) { | ||
inputClass = 'invalid'; | ||
} | ||
// //////////// | ||
// Edit mode // | ||
// //////////// | ||
if (editable) { | ||
let inputClass = ''; | ||
if (invalid) { | ||
inputClass = 'invalid'; | ||
} | ||
|
||
// Use TinyMCE if props.wysiwyg, otherwise, use a basic textarea. | ||
if (this.props.wysiwyg && this.state.tinymceLoaded) { | ||
inputElement = ( | ||
<Editor | ||
value={this.props.value} | ||
onEditorChange={this.handleRichTextEditorChange} | ||
onSubmit={this.handleSubmit} | ||
className={inputClass} | ||
init={{ | ||
setup: (editor) => { this.setState({ activeEditor: editor }); }, | ||
inline: true, | ||
convert_urls: false, | ||
plugins: 'lists link code', | ||
toolbar: [ | ||
'undo redo | styleselect | bold italic', | ||
'alignleft alignright', | ||
'bullist numlist outdent indent', | ||
'link' | ||
], | ||
}} | ||
/> | ||
); | ||
} else { | ||
inputElement = ( | ||
<textarea | ||
className={inputClass} | ||
id={this.props.id} | ||
rows={this.props.rows || '8'} | ||
value={this.props.value || ''} | ||
onChange={this.props.onChange} | ||
autoFocus={this.props.focus} | ||
onFocus={this.props.onFocus} | ||
onBlur={this.props.onBlur} | ||
maxLength="30000" | ||
placeholder={this.props.placeholder} | ||
/> | ||
); | ||
} | ||
// Use TinyMCE if props.wysiwyg, otherwise, use a basic textarea. | ||
if (wysiwyg && tinymceLoaded) { | ||
inputElement = ( | ||
<Editor | ||
value={value} | ||
onEditorChange={handleRichTextEditorChange} | ||
onSubmit={handleSubmit} | ||
className={inputClass} | ||
init={{ | ||
setup: editor => setActiveEditor(editor), | ||
inline: true, | ||
convert_urls: false, | ||
plugins: 'lists link code', | ||
toolbar: [ | ||
'undo redo | styleselect | bold italic', | ||
'alignleft alignright', | ||
'bullist numlist outdent indent', | ||
'link' | ||
], | ||
}} | ||
/> | ||
); | ||
} else { | ||
inputElement = ( | ||
<textarea | ||
className={inputClass} | ||
id={id} | ||
rows={rows || '8'} | ||
value={value || ''} | ||
onChange={onChange} | ||
autoFocus={focus} | ||
onFocus={onFocus} | ||
onBlur={onBlur} | ||
maxLength="30000" | ||
placeholder={placeholder} | ||
/> | ||
); | ||
} | ||
|
||
if (this.props.autoExpand) { | ||
return ( | ||
<div className="expandingArea active"> | ||
<pre><span>{this.props.value}</span><br /></pre> | ||
{inputElement} | ||
</div> | ||
); | ||
} | ||
if (autoExpand) { | ||
return ( | ||
<div> | ||
<div className="expandingArea active"> | ||
<pre><span>{value}</span><br /></pre> | ||
{inputElement} | ||
</div> | ||
); | ||
} | ||
return <div>{inputElement}</div>; | ||
} | ||
|
||
// //////////// | ||
// Read mode // | ||
// //////////// | ||
if (this.props.markdown) { | ||
rawHtml = md.render(this.props.value || ''); | ||
} else { | ||
rawHtml = this.props.value; | ||
} | ||
return ( | ||
<div className={this.props.className} dangerouslySetInnerHTML={{ __html: rawHtml }} /> | ||
); | ||
// //////////// | ||
// Read mode // | ||
// //////////// | ||
if (markdown) { | ||
rawHtml = md.render(value || ''); | ||
} else { | ||
rawHtml = value; | ||
} | ||
} | ||
); | ||
|
||
return <div className={className} dangerouslySetInnerHTML={{ __html: rawHtml }} />; | ||
}; | ||
|
||
TextAreaInput.propTypes = { | ||
onChange: PropTypes.func, | ||
onFocus: PropTypes.func, | ||
onBlur: PropTypes.func, | ||
value: PropTypes.string, | ||
value_key: PropTypes.string, | ||
editable: PropTypes.bool, // switch between read and edit mode | ||
id: PropTypes.string, | ||
focus: PropTypes.bool, | ||
placeholder: PropTypes.string, | ||
autoExpand: PropTypes.bool, // start with one line and expand as needed — plain text only | ||
rows: PropTypes.string, // set the number of rows — plain text only | ||
wysiwyg: PropTypes.bool, // use rich text editor instead of plain text | ||
markdown: PropTypes.bool, // render value as Markdown when in read mode | ||
className: PropTypes.string, | ||
clearOnSubmit: PropTypes.bool | ||
}; | ||
|
||
export default InputHOC(TextAreaInput); |