From 861ae55aec41fb7c87f825c9f5c198c1af603f73 Mon Sep 17 00:00:00 2001 From: mgabdev <> Date: Tue, 16 Jun 2020 19:44:30 -0400 Subject: [PATCH] Rich Text Editor (WIP) x2 --- Gemfile | 2 + Gemfile.lock | 2 + .../gabsocial/actions/importer/normalizer.js | 37 +- .../gabsocial/components/composer.js | 17 +- .../components/rich_text_editor_bar.js | 11 +- .../gabsocial/components/status_list.js | 4 +- .../features/ui/util/draft-to-markdown.js | 456 ++++++++++++++++++ app/javascript/styles/global.css | 10 + app/lib/formatter.rb | 171 ++++++- app/serializers/rest/status_serializer.rb | 3 - package.json | 3 - yarn.lock | 39 +- 12 files changed, 643 insertions(+), 112 deletions(-) create mode 100644 app/javascript/gabsocial/features/ui/util/draft-to-markdown.js diff --git a/Gemfile b/Gemfile index ec339981..387d5508 100644 --- a/Gemfile +++ b/Gemfile @@ -94,6 +94,8 @@ gem 'json-ld', '~> 3.0' gem 'json-ld-preloaded', '~> 3.0' gem 'rdf-normalize', '~> 0.3' +gem 'redcarpet', '~> 3.4' + group :development, :test do gem 'fabrication', '~> 2.20' gem 'fuubar', '~> 2.3' diff --git a/Gemfile.lock b/Gemfile.lock index e64ff643..5d095708 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -479,6 +479,7 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.3.3) rdf (>= 2.2, < 4.0) + redcarpet (3.4.0) redis (4.1.2) redis-actionpack (5.0.2) actionpack (>= 4.0, < 6) @@ -740,6 +741,7 @@ DEPENDENCIES rails-i18n (~> 5.1) rails-settings-cached (~> 0.6) rdf-normalize (~> 0.3) + redcarpet (~> 3.4) redis (~> 4.1) redis-namespace (~> 1.5) redis-rails (~> 5.0) diff --git a/app/javascript/gabsocial/actions/importer/normalizer.js b/app/javascript/gabsocial/actions/importer/normalizer.js index ac17d6b6..1de5700f 100644 --- a/app/javascript/gabsocial/actions/importer/normalizer.js +++ b/app/javascript/gabsocial/actions/importer/normalizer.js @@ -1,7 +1,4 @@ import escapeTextContentForBrowser from 'escape-html' -import { markdownToDraft } from 'markdown-draft-js' -import { Remarkable } from 'remarkable' -import * as entities from 'entities' import emojify from '../../components/emoji/emoji' import { unescapeHTML } from '../../utils/html' import { expandSpoilers } from '../../initial_state' @@ -66,40 +63,8 @@ export function normalizeStatus(status, normalOldStatus) { const spoilerText = normalStatus.spoiler_text || ''; const searchContent = [spoilerText, status.content].join('\n\n').replace(//g, '\n').replace(/<\/p>

/g, '\n\n'); const emojiMap = makeEmojiMap(normalStatus); - - let theContent - if (!!normalStatus.rich_content) { - theContent = normalStatus.rich_content - // let rawObject = markdownToDraft(theContent, { - // preserveNewlines: true, - // remarkablePreset: 'commonmark', - // remarkableOptions: { - // enable: { - // inline: ['del', 'ins'], - // } - // } - // }); + const theContent = !!normalStatus.rich_content ? normalStatus.rich_content : normalStatus.content; - const md = new Remarkable({ - html: false, - breaks: true, - }) - let html = md.render(theContent) - html = entities.decodeHTML(html) - - theContent = html - - console.log("html:", html) - console.log("theContent:", theContent) - console.log("status:", status) - console.log("normalStatus:", normalStatus) - // console.log("rawObject:", rawObject) - } else { - theContent = normalStatus.content - } - // let theContent = !!normalStatus.rich_content ? normalStatus.rich_content : normalStatus.content; - - normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; normalStatus.contentHtml = emojify(theContent, emojiMap, false, true); normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap); diff --git a/app/javascript/gabsocial/components/composer.js b/app/javascript/gabsocial/components/composer.js index 1a0d9700..7be61d27 100644 --- a/app/javascript/gabsocial/components/composer.js +++ b/app/javascript/gabsocial/components/composer.js @@ -4,10 +4,8 @@ import { CompositeDecorator, RichUtils, convertToRaw, - convertFromRaw, - ContentState, } from 'draft-js' -import { draftToMarkdown } from 'markdown-draft-js' +import draftToMarkdown from '../features/ui/util/draft-to-markdown' import { urlRegex } from '../features/ui/util/url_regex' import classNames from 'classnames/bind' import RichTextEditorBar from './rich_text_editor_bar' @@ -134,7 +132,8 @@ class Composer extends PureComponent { const rawObject = convertToRaw(content); const markdownString = draftToMarkdown(rawObject, { - preserveNewlines: true, + escapeMarkdownCharacters: false, + preserveNewlines: false, remarkablePreset: 'commonmark', remarkableOptions: { disable: { @@ -147,6 +146,7 @@ class Composer extends PureComponent { }); console.log("text:", markdownString) + // console.log("html:", html) this.props.onChange(null, text, markdownString, selectionStart) } @@ -154,11 +154,12 @@ class Composer extends PureComponent { // **bold** // *italic* // __underline__ - // ~strikethrough~ - // # title + // ~~strike~~ + // # header // > quote - // `code` - // ```code``` + // ``` + // code + // ``` focus = () => { this.textbox.editor.focus() diff --git a/app/javascript/gabsocial/components/rich_text_editor_bar.js b/app/javascript/gabsocial/components/rich_text_editor_bar.js index f8b8d9dd..f6b220e9 100644 --- a/app/javascript/gabsocial/components/rich_text_editor_bar.js +++ b/app/javascript/gabsocial/components/rich_text_editor_bar.js @@ -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' @@ -70,10 +69,6 @@ const RTE_ITEMS = [ }, ] -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 { /> )) } -