Merge branch 'feature/rich_text_editor' of https://code.gab.com/gab/social/gab-social into develop

This commit is contained in:
mgabdev
2020-06-17 16:45:45 -04:00
23 changed files with 1181 additions and 293 deletions

View File

@@ -15,6 +15,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
static propTypes = {
value: PropTypes.string,
valueMarkdown: PropTypes.string,
suggestions: ImmutablePropTypes.list,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
@@ -45,11 +46,12 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
tokenStart: 0,
}
onChange = (e, value, selectionStart, markdown) => {
onChange = (e, value, markdown, selectionStart) => {
if (!isObject(e)) {
e = {
target: {
value,
markdown,
selectionStart,
},
}
@@ -65,7 +67,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
this.props.onSuggestionsClearRequested();
}
this.props.onChange(e, markdown);
this.props.onChange(e);
}
onKeyDown = (e) => {
@@ -191,7 +193,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
}
setTextbox = (c) => {
this.textbox = c;
this.textbox = c
}
render() {
@@ -203,6 +205,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
placeholder,
onKeyUp,
children,
valueMarkdown,
id,
} = this.props
@@ -246,29 +249,14 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
<label htmlFor={id} className={_s.visiblyHidden}>
{placeholder}
</label>
<Textarea
id={id}
inputRef={this.setTextbox}
className={textareaClasses}
disabled={disabled}
placeholder={placeholder}
autoFocus={false}
value={value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp}
onFocus={this.onFocus}
onBlur={this.onBlur}
onPaste={this.onPaste}
aria-autocomplete='list'
/>
{/*<Composer
<Composer
inputRef={this.setTextbox}
disabled={disabled}
placeholder={placeholder}
autoFocus={autoFocus}
value={value}
valueMarkdown={valueMarkdown}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
onKeyUp={onKeyUp}
@@ -276,7 +264,7 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
onBlur={this.onBlur}
onPaste={this.onPaste}
small={small}
/>*/}
/>
{children}
</div>

View File

@@ -7,8 +7,8 @@ import {
convertFromRaw,
ContentState,
} from 'draft-js'
import { draftToMarkdown } from 'markdown-draft-js'
// import draftToMarkdown from 'draftjs-to-markdown'
import draftToMarkdown from '../features/ui/util/draft-to-markdown'
import markdownToDraft from '../features/ui/util/markdown-to-draft'
import { urlRegex } from '../features/ui/util/url_regex'
import classNames from 'classnames/bind'
import RichTextEditorBar from './rich_text_editor_bar'
@@ -30,11 +30,11 @@ function handleStrategy(contentBlock, callback, contentState) {
findWithRegex(HANDLE_REGEX, contentBlock, callback)
}
function hashtagStrategy (contentBlock, callback, contentState) {
function hashtagStrategy(contentBlock, callback, contentState) {
findWithRegex(HASHTAG_REGEX, contentBlock, callback)
}
function urlStrategy (contentBlock, callback, contentState) {
function urlStrategy(contentBlock, callback, contentState) {
findWithRegex(urlRegex, contentBlock, callback)
}
@@ -73,24 +73,17 @@ const compositeDecorator = new CompositeDecorator([
}
])
const HANDLE_REGEX = /\@[\w]+/g;
const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g;
const HANDLE_REGEX = /\@[\w]+/g
const HASHTAG_REGEX = /\#[\w\u0590-\u05ff]+/g
const mapDispatchToProps = (dispatch) => ({
})
export default
@connect(null, mapDispatchToProps)
class Composer extends PureComponent {
export default class Composer extends PureComponent {
static propTypes = {
inputRef: PropTypes.func,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
autoFocus: PropTypes.bool,
value: PropTypes.string,
valueMarkdown: PropTypes.string,
onChange: PropTypes.func,
onKeyDown: PropTypes.func,
onKeyUp: PropTypes.func,
@@ -101,59 +94,69 @@ class Composer extends PureComponent {
}
state = {
markdownText: '',
plainText: '',
editorState: EditorState.createEmpty(compositeDecorator),
}
static getDerivedStateFromProps(nextProps, prevState) {
// if (!nextProps.isHidden && nextProps.isIntersecting && !prevState.fetched) {
// return {
// fetched: true
// }
// }
return null
plainText: this.props.value,
}
componentDidUpdate (prevProps) {
// console.log("this.props.value:", this.props.value)
if (prevProps.value !== this.props.value) {
// const editorState = EditorState.push(this.state.editorState, ContentState.createFromText(this.props.value));
// this.setState({ editorState })
componentDidMount() {
if (this.props.valueMarkdown) {
const rawData = markdownToDraft(this.props.valueMarkdown)
const contentState = convertFromRaw(rawData)
const editorState = EditorState.createWithContent(contentState)
this.setState({
editorState,
plainText: this.props.value,
})
} else if (this.props.value) {
editorState = EditorState.push(this.state.editorState, ContentState.createFromText(this.props.value))
this.setState({
editorState,
plainText: this.props.value,
})
}
}
// EditorState.createWithContent(ContentState.createFromText('Hello'))
onChange = (editorState) => {
this.setState({ editorState })
const content = this.state.editorState.getCurrentContent();
const text = content.getPlainText('\u0001')
// const selectionState = editorState.getSelection()
// const selectionStart = selectionState.getStartOffset()
// const rawObject = convertToRaw(content);
// const markdownString = draftToMarkdown(rawObject);
// const markdownString = draftToMarkdown(rawObject, {
// trigger: '#',
// separator: ' ',
// });
// console.log("text:", text, this.props.value)
this.props.onChange(null, text, selectionStart, markdownString)
componentDidUpdate() {
if (this.state.plainText !== this.props.value) {
let editorState
if (!this.props.value) {
editorState = EditorState.createEmpty(compositeDecorator)
} else {
editorState = EditorState.push(this.state.editorState, ContentState.createFromText(this.props.value))
}
this.setState({
editorState,
plainText: this.props.value,
})
}
}
// **bold**
// *italic*
// __underline__
// ~strikethrough~
// # title
// > quote
// `code`
// ```code```
onChange = (editorState) => {
const content = editorState.getCurrentContent()
const plainText = content.getPlainText('\u0001')
this.setState({ editorState, plainText })
const selectionState = editorState.getSelection()
const selectionStart = selectionState.getStartOffset()
const rawObject = convertToRaw(content)
const markdownString = draftToMarkdown(rawObject, {
escapeMarkdownCharacters: false,
preserveNewlines: false,
remarkablePreset: 'commonmark',
remarkableOptions: {
disable: {
block: ['table']
},
enable: {
inline: ['del', 'ins'],
}
}
})
this.props.onChange(null, plainText, markdownString, selectionStart)
}
focus = () => {
this.textbox.editor.focus()
@@ -171,27 +174,24 @@ class Composer extends PureComponent {
return false
}
handleOnTogglePopoutEditor = () => {
//
}
onTab = (e) => {
const maxDepth = 4
this.onChange(RichUtils.onTab(e, this.state.editorState, maxDepth))
}
setRef = (n) => {
this.textbox = n
try {
this.textbox = n
this.props.inputRef(n)
} catch (error) {
//
}
}
render() {
const {
inputRef,
disabled,
placeholder,
autoFocus,
value,
onChange,
onKeyDown,
onKeyUp,
onFocus,
@@ -211,15 +211,13 @@ class Composer extends PureComponent {
pt15: !small,
px15: !small,
px10: small,
pt5: small,
pb5: small,
pb10: !small,
})
return (
<div className={_s.default}>
{ /** : todo : */
{
!small &&
<RichTextEditorBar
editorState={editorState}
@@ -241,6 +239,9 @@ class Composer extends PureComponent {
placeholder={placeholder}
ref={this.setRef}
readOnly={disabled}
onBlur={onBlur}
onFocus={onFocus}
stripPastedStyles
/>
</div>
</div>

View File

@@ -42,6 +42,7 @@ class ProUpgradeModal extends ImmutablePureComponent {
<Text> Larger Video and Image Uploads</Text>
<Text> Receive the PRO Badge</Text>
<Text> Remove in-feed promotions</Text>
<Text> Compose Rich Text posts (Bold, Italic, Underline and more)</Text>
</div>
<Button

View File

@@ -1,5 +1,4 @@
import { RichUtils } from 'draft-js'
import { defineMessages, injectIntl } from 'react-intl'
import classNames from 'classnames/bind'
import { me } from '../initial_state'
import { makeGetAccount } from '../selectors'
@@ -39,41 +38,37 @@ const RTE_ITEMS = [
// icon: 'circle',
// },
{
label: 'H1',
label: 'Title',
style: 'header-one',
type: 'block',
icon: 'text-size',
},
{
label: 'Blockquote',
style: 'blockquote',
type: 'block',
icon: 'blockquote',
},
{
label: 'Code Block',
style: 'code-block',
type: 'block',
icon: 'code',
},
{
label: 'UL',
style: 'unordered-list-item',
type: 'block',
icon: 'ul-list',
},
{
label: 'OL',
style: 'ordered-list-item',
type: 'block',
icon: 'ol-list',
},
// {
// label: 'Blockquote',
// style: 'blockquote',
// type: 'block',
// icon: 'blockquote',
// },
// {
// label: 'Code Block',
// style: 'code-block',
// type: 'block',
// icon: 'code',
// },
// {
// label: 'UL',
// style: 'unordered-list-item',
// type: 'block',
// icon: 'ul-list',
// },
// {
// label: 'OL',
// style: 'ordered-list-item',
// type: 'block',
// icon: 'ol-list',
// },
]
const messages = defineMessages({
follow: { id: 'follow', defaultMessage: 'Follow' },
})
const mapStateToProps = (state) => {
const getAccount = makeGetAccount()
const account = getAccount(state, me)
@@ -86,13 +81,11 @@ const mapStateToProps = (state) => {
}
export default
@injectIntl
@connect(mapStateToProps)
class RichTextEditorBar extends PureComponent {
static propTypes = {
editorState: PropTypes.object.isRequired,
intl: PropTypes.object.isRequired,
isPro: PropTypes.bool.isRequired,
rteControlsVisible: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired,
@@ -127,7 +120,7 @@ class RichTextEditorBar extends PureComponent {
/>
))
}
<Button
{/*<Button
backgroundColor='none'
color='secondary'
onClick={this.handleOnTogglePopoutEditor}
@@ -137,7 +130,7 @@ class RichTextEditorBar extends PureComponent {
iconClassName={_s.inheritFill}
iconSize='12px'
radiusSmall
/>
/>*/}
</div>
)
}

View File

@@ -46,7 +46,7 @@ class TimelineComposeBlock extends ImmutablePureComponent {
return (
<section className={_s.default}>
<div className={[_s.default, _s.flexRow].join(' ')}>
<ComposeFormContainer {...rest} />
<ComposeFormContainer {...rest} modal={modal} />
</div>
</section>
)