diff --git a/app/assets/javascripts/discourse/app/components/fast-edit.gjs b/app/assets/javascripts/discourse/app/components/fast-edit.gjs index ff2fb75715db97..693c7d13ec672b 100644 --- a/app/assets/javascripts/discourse/app/components/fast-edit.gjs +++ b/app/assets/javascripts/discourse/app/components/fast-edit.gjs @@ -5,7 +5,6 @@ import { on } from "@ember/modifier"; import { action } from "@ember/object"; import DButton from "discourse/components/d-button"; import PluginOutlet from "discourse/components/plugin-outlet"; -import { fixQuotes } from "discourse/components/post-text-selection"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; import { translateModKey } from "discourse/lib/utilities"; @@ -52,10 +51,7 @@ export default class FastEdit extends Component { try { const result = await ajax(`/posts/${this.args.post.id}`); - const newRaw = result.raw.replace( - fixQuotes(this.args.initialValue), - fixQuotes(this.value) - ); + const newRaw = result.raw.replace(this.args.initialValue, this.value); await this.args.post.save({ raw: newRaw }); } catch (error) { diff --git a/app/assets/javascripts/discourse/app/components/post-text-selection.gjs b/app/assets/javascripts/discourse/app/components/post-text-selection.gjs index f7212834d6ac3d..e9e2b221a076ef 100644 --- a/app/assets/javascripts/discourse/app/components/post-text-selection.gjs +++ b/app/assets/javascripts/discourse/app/components/post-text-selection.gjs @@ -31,12 +31,6 @@ function getQuoteTitle(element) { return titleEl.textContent.trim().replace(/:$/, ""); } -export function fixQuotes(str) { - // u+201c, u+201d = “ ” - // u+2018, u+2019 = ‘ ’ - return str.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'"); -} - export default class PostTextSelection extends Component { @service appEvents; @service capabilities; @@ -177,14 +171,12 @@ export default class PostTextSelection extends Component { if (this.canEditPost) { const regexp = new RegExp(escapeRegExp(quoteState.buffer), "gi"); const matches = cooked.innerHTML.match(regexp); - const non_ascii_regex = /[^\x00-\x7F]/; if ( quoteState.buffer.length === 0 || quoteState.buffer.includes("|") || // tables are too complex quoteState.buffer.match(/\n/g) || // linebreaks are too complex - matches?.length > 1 || // duplicates are too complex - non_ascii_regex.test(quoteState.buffer) // non-ascii chars break fast-edit + matches?.length > 1 // duplicates are too complex ) { supportsFastEdit = false; } else if (matches?.length === 1) { diff --git a/app/assets/javascripts/discourse/tests/acceptance/fast-edit-test.js b/app/assets/javascripts/discourse/tests/acceptance/fast-edit-test.js index 2706de4534d6eb..cd8b91c2b393b3 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/fast-edit-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/fast-edit-test.js @@ -86,18 +86,39 @@ acceptance("Fast Edit", function (needs) { assert.dom(".d-editor-input").exists(); }); - test("Opens full composer when editing non-ascii characters", async function (assert) { + test("Works with diacritics", async function (assert) { await visit("/t/internationalization-localization/280"); - query("#post_2 .cooked").append( - `Je suis désolé, ”comment ça va”? A bientôt!` - ); + query("#post_2 .cooked").append(`Je suis désolé, comment ça va?`); const textNode = query("#post_2 .cooked").childNodes[2]; await selectText(textNode); await click(".quote-button .quote-edit-label"); - assert.dom("#fast-edit-input").doesNotExist(); - assert.dom(".d-editor-input").exists(); + assert.dom("#fast-edit-input").exists(); + }); + + test("Works with CJK ranges", async function (assert) { + await visit("/t/internationalization-localization/280"); + + query("#post_2 .cooked").append(`这是一个测试`); + const textNode = query("#post_2 .cooked").childNodes[2]; + + await selectText(textNode); + await click(".quote-button .quote-edit-label"); + + assert.dom("#fast-edit-input").exists(); + }); + + test("Works with emoji", async function (assert) { + await visit("/t/internationalization-localization/280"); + + query("#post_2 .cooked").append(`This is great 👍`); + const textNode = query("#post_2 .cooked").childNodes[2]; + + await selectText(textNode); + await click(".quote-button .quote-edit-label"); + + assert.dom("#fast-edit-input").exists(); }); }); diff --git a/spec/system/post_selection_fast_edit_spec.rb b/spec/system/post_selection_fast_edit_spec.rb index c4ba481372f1bb..5a89126ca6d71c 100644 --- a/spec/system/post_selection_fast_edit_spec.rb +++ b/spec/system/post_selection_fast_edit_spec.rb @@ -6,6 +6,9 @@ fab!(:topic) fab!(:post) { Fabricate(:post, topic: topic) } fab!(:post_2) { Fabricate(:post, topic: topic, raw: "It ‘twas a great’ “time”!") } + fab!(:spanish_post) { Fabricate(:post, topic: topic, raw: "Hola Juan, ¿cómo estás?") } + fab!(:chinese_post) { Fabricate(:post, topic: topic, raw: "这是一个测试") } + fab!(:post_with_emoji) { Fabricate(:post, topic: topic, raw: "Good morning :wave:!") } fab!(:current_user) { Fabricate(:admin) } before { sign_in(current_user) } @@ -52,5 +55,49 @@ text: "It ‘twas a great’ “day”!", ) end + + it "saves when text contains diacratics" do + topic_page.visit_topic(topic) + + select_text_range("#{topic_page.post_by_number_selector(3)} .cooked p", 11, 12) + + topic_page.click_fast_edit_button + + fast_editor.fill_content("¿está todo bien?") + fast_editor.save + + expect(page).to have_selector( + "#{topic_page.post_by_number_selector(3)} .cooked p", + text: "Hola Juan, ¿está todo bien?", + ) + end + + it "saves when text contains CJK ranges" do + topic_page.visit_topic(topic) + + select_text_range("#{topic_page.post_by_number_selector(4)} .cooked p", 0, 2) + topic_page.click_fast_edit_button + + fast_editor.fill_content("今天") + fast_editor.save + + expect(page).to have_selector( + "#{topic_page.post_by_number_selector(4)} .cooked p", + text: "今天一个测试", + ) + end + + it "saves when text contains emoji" do + topic_page.visit_topic(topic) + + select_text_range("#{topic_page.post_by_number_selector(5)} .cooked p", 5, 7) + topic_page.click_fast_edit_button + + fast_editor.fill_content("day") + fast_editor.save + + expect(page).to have_no_css("#fast-edit-input") + expect(post_with_emoji.raw).to eq("Good day :wave:!") + end end end