Updating composer to fix line breaks and other rich text issues

• Updating:
- composer to fix line breaks and other rich text issues
This commit is contained in:
mgabdev 2020-06-19 21:02:13 -04:00
parent a9a566e211
commit fc80955306
6 changed files with 54 additions and 36 deletions

View File

@ -264,30 +264,22 @@ export function submitCompose(group, replyToId = null, router, isStandalone) {
let status = getState().getIn(['compose', 'text'], ''); let status = getState().getIn(['compose', 'text'], '');
let markdown = getState().getIn(['compose', 'markdown'], ''); let markdown = getState().getIn(['compose', 'markdown'], '');
const media = getState().getIn(['compose', 'media_attachments']); const media = getState().getIn(['compose', 'media_attachments']);
// : hack : const replacer = (match) => {
//Prepend http:// to urls in status that don't have protocol
status = `${status}`.replace(urlRegex, (match, a, b, c) =>{
const hasProtocol = match.startsWith('https://') || match.startsWith('http://') const hasProtocol = match.startsWith('https://') || match.startsWith('http://')
//Make sure not a remote mention like @someone@somewhere.com //Make sure not a remote mention like @someone@somewhere.com
if (!hasProtocol) { if (!hasProtocol) {
if (status.indexOf(`@${match}`) > -1) return match if (status.indexOf(`@${match}`) > -1) return match
} }
return hasProtocol ? match : `http://${match}` return hasProtocol ? match : `http://${match}`
})
markdown = !!markdown ? markdown.replace(urlRegex, (match) =>{
const hasProtocol = match.startsWith('https://') || match.startsWith('http://')
if (!hasProtocol) {
if (status.indexOf(`@${match}`) > -1) return match
}
return hasProtocol ? match : `http://${match}`
}) : undefined
if (status === markdown) {
markdown = undefined
} }
// : hack :
//Prepend http:// to urls in status that don't have protocol
status = `${status}`.replace(urlRegex, replacer)
markdown = !!markdown ? `${markdown}`.replace(urlRegex, replacer) : undefined
const inReplyToId = getState().getIn(['compose', 'in_reply_to'], null) || replyToId const inReplyToId = getState().getIn(['compose', 'in_reply_to'], null) || replyToId
dispatch(submitComposeRequest()); dispatch(submitComposeRequest());

View File

@ -36,6 +36,8 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
onBlur: PropTypes.func, onBlur: PropTypes.func,
textarea: PropTypes.bool, textarea: PropTypes.bool,
small: PropTypes.bool, small: PropTypes.bool,
isPro: PropTypes.bool,
isEdit: PropTypes.bool,
} }
static defaultProps = { static defaultProps = {
@ -211,6 +213,8 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
children, children,
valueMarkdown, valueMarkdown,
id, id,
isPro,
isEdit,
} = this.props } = this.props
const { suggestionsHidden } = this.state const { suggestionsHidden } = this.state
@ -284,6 +288,8 @@ export default class AutosuggestTextbox extends ImmutablePureComponent {
onBlur={this.onBlur} onBlur={this.onBlur}
onPaste={this.onPaste} onPaste={this.onPaste}
small={small} small={small}
isEdit={isEdit}
isPro={isPro}
/> />
</Responsive> </Responsive>

View File

@ -18,6 +18,21 @@ import '!style-loader!css-loader!draft-js/dist/Draft.css'
const cx = classNames.bind(_s) const cx = classNames.bind(_s)
const markdownOptions = {
escapeMarkdownCharacters: false,
preserveNewlines: true,
remarkablePreset: 'commonmark',
remarkableOptions: {
disable: {
inline: ['links'],
block: ['table', 'heading'],
},
enable: {
inline: ['del', 'ins'],
}
}
}
const getBlockStyle = (block) => { const getBlockStyle = (block) => {
switch (block.getType()) { switch (block.getType()) {
case 'blockquote': case 'blockquote':
@ -100,6 +115,8 @@ export default class Composer extends PureComponent {
onBlur: PropTypes.func, onBlur: PropTypes.func,
onPaste: PropTypes.func, onPaste: PropTypes.func,
small: PropTypes.bool, small: PropTypes.bool,
isPro: PropTypes.bool,
isEdit: PropTypes.bool,
} }
state = { state = {
@ -109,8 +126,8 @@ export default class Composer extends PureComponent {
} }
componentDidMount() { componentDidMount() {
if (this.props.valueMarkdown) { if (this.props.valueMarkdown && this.props.isPro && this.props.isEdit) {
const rawData = markdownToDraft(this.props.valueMarkdown) const rawData = markdownToDraft(this.props.valueMarkdown, markdownOptions)
const contentState = convertFromRaw(rawData) const contentState = convertFromRaw(rawData)
const editorState = EditorState.createWithContent(contentState) const editorState = EditorState.createWithContent(contentState)
@ -146,29 +163,23 @@ export default class Composer extends PureComponent {
onChange = (editorState) => { onChange = (editorState) => {
const content = editorState.getCurrentContent() const content = editorState.getCurrentContent()
const plainText = content.getPlainText('\u0001') // const plainText = content.getPlainText('\u0001')
this.setState({ editorState, plainText }) const blocks = convertToRaw(editorState.getCurrentContent()).blocks
const value = blocks.map(block => (!block.text.trim() && '') || block.text).join('\n')
this.setState({
editorState,
plainText: value,
})
const selectionState = editorState.getSelection() const selectionState = editorState.getSelection()
const selectionStart = selectionState.getStartOffset() const selectionStart = selectionState.getStartOffset()
const rawObject = convertToRaw(content) const rawObject = convertToRaw(content)
const markdownString = draftToMarkdown(rawObject, { const markdownString = this.props.isPro ? draftToMarkdown(rawObject,markdownOptions) : null
escapeMarkdownCharacters: false,
preserveNewlines: false,
remarkablePreset: 'commonmark',
remarkableOptions: {
disable: {
block: ['table']
},
enable: {
inline: ['del', 'ins'],
}
}
})
this.props.onChange(null, plainText, markdownString, selectionStart) this.props.onChange(null, value, markdownString, selectionStart)
} }
handleOnFocus = () => { handleOnFocus = () => {
@ -227,6 +238,7 @@ export default class Composer extends PureComponent {
disabled, disabled,
placeholder, placeholder,
small, small,
isPro,
} = this.props } = this.props
const { editorState } = this.state const { editorState } = this.state
@ -247,7 +259,7 @@ export default class Composer extends PureComponent {
<div className={_s.default}> <div className={_s.default}>
{ {
!small && !small && isPro &&
<RichTextEditorBar <RichTextEditorBar
editorState={editorState} editorState={editorState}
onChange={this.onChange} onChange={this.onChange}

View File

@ -88,6 +88,7 @@ class ComposeForm extends ImmutablePureComponent {
reduxReplyToId: PropTypes.string, reduxReplyToId: PropTypes.string,
hasPoll: PropTypes.bool, hasPoll: PropTypes.bool,
selectedGifSrc: PropTypes.string, selectedGifSrc: PropTypes.string,
isPro: PropTypes.bool,
}; };
static defaultProps = { static defaultProps = {
@ -244,6 +245,7 @@ class ComposeForm extends ImmutablePureComponent {
isChangingUpload, isChangingUpload,
isSubmitting, isSubmitting,
selectedGifSrc, selectedGifSrc,
isPro,
} = this.props } = this.props
const disabled = isSubmitting const disabled = isSubmitting
@ -322,6 +324,8 @@ class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste} onPaste={onPaste}
autoFocus={shouldAutoFocus} autoFocus={shouldAutoFocus}
small={shouldCondense} small={shouldCondense}
isPro={isPro}
isEdit={!!edit}
id='comment-composer' id='comment-composer'
/> />
@ -414,6 +418,8 @@ class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste} onPaste={onPaste}
autoFocus={shouldAutoFocus} autoFocus={shouldAutoFocus}
small={shouldCondense} small={shouldCondense}
isPro={isPro}
isEdit={!!edit}
id='main-composer' id='main-composer'
/> />

View File

@ -90,12 +90,13 @@ const mapStateToProps = (state, props) => {
quoteOfId: state.getIn(['compose', 'quote_of_id']), quoteOfId: state.getIn(['compose', 'quote_of_id']),
scheduledAt: state.getIn(['compose', 'scheduled_at']), scheduledAt: state.getIn(['compose', 'scheduled_at']),
account: state.getIn(['accounts', me]), account: state.getIn(['accounts', me]),
isPro: state.getIn(['accounts', me, 'is_pro']),
hasPoll: state.getIn(['compose', 'poll']), hasPoll: state.getIn(['compose', 'poll']),
selectedGifSrc: state.getIn(['tenor', 'selectedGif', 'src']), selectedGifSrc: state.getIn(['tenor', 'selectedGif', 'src']),
} }
} }
const mapDispatchToProps = (dispatch, { reduxReplyToId, replyToId, isStandalone }) => ({ const mapDispatchToProps = (dispatch, { isStandalone }) => ({
onChange(text, markdown, newReplyToId, position) { onChange(text, markdown, newReplyToId, position) {
dispatch(changeCompose(text, markdown, newReplyToId, isStandalone, position)) dispatch(changeCompose(text, markdown, newReplyToId, isStandalone, position))

View File

@ -123,7 +123,8 @@ class Formatter
def format_markdown(html) def format_markdown(html)
html = markdown_formatter.render(html) html = markdown_formatter.render(html)
html.delete("\r").delete("\n") # html.delete("\r").delete("\n")
html = html.gsub(/(?:\n\r?|\r\n?)/, '<br />')
end end
def reformat(html, outgoing = false) def reformat(html, outgoing = false)