mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: Convert HTML to Markdown while pasting in composer
This commit is contained in:
committed by
Joffrey JAFFEUX
parent
067d454937
commit
6e054b2572
@@ -9,6 +9,8 @@ import { emojiUrlFor } from 'discourse/lib/text';
|
|||||||
import { getRegister } from 'discourse-common/lib/get-owner';
|
import { getRegister } from 'discourse-common/lib/get-owner';
|
||||||
import { findRawTemplate } from 'discourse/lib/raw-templates';
|
import { findRawTemplate } from 'discourse/lib/raw-templates';
|
||||||
import { determinePostReplaceSelection, clipboardData } from 'discourse/lib/utilities';
|
import { determinePostReplaceSelection, clipboardData } from 'discourse/lib/utilities';
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import deprecated from 'discourse-common/lib/deprecated';
|
import deprecated from 'discourse-common/lib/deprecated';
|
||||||
|
|
||||||
// Our head can be a static string or a function that returns a string
|
// Our head can be a static string or a function that returns a string
|
||||||
@@ -616,7 +618,7 @@ export default Ember.Component.extend({
|
|||||||
Ember.run.scheduleOnce("afterRender", () => $textarea.focus());
|
Ember.run.scheduleOnce("afterRender", () => $textarea.focus());
|
||||||
},
|
},
|
||||||
|
|
||||||
_detectTable(text) {
|
_extractTable(text) {
|
||||||
if (text.endsWith("\n")) {
|
if (text.endsWith("\n")) {
|
||||||
text = text.substring(0, text.length - 1);
|
text = text.substring(0, text.length - 1);
|
||||||
}
|
}
|
||||||
@@ -639,21 +641,43 @@ export default Ember.Component.extend({
|
|||||||
|
|
||||||
paste(e) {
|
paste(e) {
|
||||||
const clipboard = clipboardData(e);
|
const clipboard = clipboardData(e);
|
||||||
const types = clipboard.types;
|
const placeholder = `${ I18n.t('pasting') }`;
|
||||||
let preventDefault = false;
|
let plainText = clipboard.getData("text/plain");
|
||||||
|
const html = clipboard.getData("text/html");
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
if (types.some(t => t === "text/plain")) {
|
if (plainText) {
|
||||||
const text = clipboard.getData("text/plain");
|
plainText = plainText.trim();
|
||||||
const table = this._detectTable(text);
|
const table = this._extractTable(plainText);
|
||||||
if (table) {
|
if (table) {
|
||||||
this._addText(this._getSelected(), table);
|
this._addText(this._getSelected(), table);
|
||||||
preventDefault = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
} else if (types.some(t => t === "Files")) {
|
|
||||||
preventDefault = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preventDefault) {
|
if (html && !handled) {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
this.appEvents.trigger('composer:insert-text', placeholder);
|
||||||
|
handled = true;
|
||||||
|
|
||||||
|
ajax('/composer/parse_html', {
|
||||||
|
type: 'POST',
|
||||||
|
data: { html }
|
||||||
|
}).then(response => {
|
||||||
|
self.appEvents.trigger('composer:replace-text', placeholder, response.markdown);
|
||||||
|
}).catch(error => {
|
||||||
|
if (plainText) {
|
||||||
|
self.appEvents.trigger('composer:replace-text', placeholder, plainText);
|
||||||
|
} else {
|
||||||
|
popupAjaxError(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFiles = clipboard.types.includes("Files") && !plainText && !html;
|
||||||
|
|
||||||
|
if (handled || uploadFiles) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
12
app/controllers/composer_controller.rb
Normal file
12
app/controllers/composer_controller.rb
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
require_dependency 'html_to_markdown'
|
||||||
|
|
||||||
|
class ComposerController < ApplicationController
|
||||||
|
|
||||||
|
before_action :ensure_logged_in
|
||||||
|
|
||||||
|
def parse_html
|
||||||
|
markdown_text = HtmlToMarkdown.new(params[:html]).to_markdown
|
||||||
|
|
||||||
|
render json: { markdown: markdown_text }
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -309,6 +309,8 @@ en:
|
|||||||
uploading_filename: "Uploading {{filename}}..."
|
uploading_filename: "Uploading {{filename}}..."
|
||||||
uploaded: "Uploaded!"
|
uploaded: "Uploaded!"
|
||||||
|
|
||||||
|
pasting: "Pasting..."
|
||||||
|
|
||||||
enable: "Enable"
|
enable: "Enable"
|
||||||
disable: "Disable"
|
disable: "Disable"
|
||||||
undo: "Undo"
|
undo: "Undo"
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ Discourse::Application.routes.draw do
|
|||||||
get "session/current" => "session#current"
|
get "session/current" => "session#current"
|
||||||
get "session/csrf" => "session#csrf"
|
get "session/csrf" => "session#csrf"
|
||||||
get "composer_messages" => "composer_messages#index"
|
get "composer_messages" => "composer_messages#index"
|
||||||
|
post "composer/parse_html" => "composer#parse_html"
|
||||||
|
|
||||||
resources :static
|
resources :static
|
||||||
post "login" => "static#enter", constraints: { format: /(json|html)/ }
|
post "login" => "static#enter", constraints: { format: /(json|html)/ }
|
||||||
|
|||||||
26
spec/requests/composer_controller_spec.rb
Normal file
26
spec/requests/composer_controller_spec.rb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ComposerController do
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
describe '#parse_html' do
|
||||||
|
|
||||||
|
it "should not be able access without sign in" do
|
||||||
|
expect {
|
||||||
|
post "/composer/parse_html.json", params: {
|
||||||
|
html: "<strong>hello</strong>"
|
||||||
|
}
|
||||||
|
}.to raise_error(Discourse::NotLoggedIn)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should convert html tags to markdown text" do
|
||||||
|
sign_in(user)
|
||||||
|
|
||||||
|
post "/composer/parse_html.json", params: {
|
||||||
|
html: "<strong>hello</strong>"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.body).to eq("{\"markdown\":\"**hello**\"}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user