mirror of
https://github.com/discourse/discourse.git
synced 2025-01-16 05:32:41 +08:00
DEV: Fix triple click selection in WebKit derived browsers (#30628)
On WebKit-based browsers, triple clicking on the last paragraph of a post won't stop at the end of the paragraph, leaking the selection into the following nodes until it finds a non-empty node. This commit introduces a workaround to fix this behavior.
This commit is contained in:
parent
f369db5ae9
commit
e5d6ca0451
|
@ -370,6 +370,19 @@ export default class PostCooked {
|
|||
cookedDiv.innerHTML = this.attrs.cooked;
|
||||
}
|
||||
|
||||
// On WebKit-based browsers, triple clicking on the last paragraph of a post won't stop at the end of the paragraph.
|
||||
// It looks like the browser is selecting EOL characters, and that causes the selection to leak into the following
|
||||
// nodes until it finds a non-empty node. This is a workaround to prevent that from happening.
|
||||
// We insert a div after the last paragraph at the end of the cooked content, containing a <br> element.
|
||||
// The line break works as a barrier, causing the selection to stop at the correct place.
|
||||
// To prevent layout shifts this div is styled to be invisible with height 0 and overflow hidden and set aria-hidden
|
||||
// to true to prevent screen readers from reading it.
|
||||
const selectionBarrier = document.createElement("div");
|
||||
selectionBarrier.classList.add("cooked-selection-barrier");
|
||||
selectionBarrier.ariaHidden = "true";
|
||||
selectionBarrier.appendChild(document.createElement("br"));
|
||||
cookedDiv.appendChild(selectionBarrier);
|
||||
|
||||
return cookedDiv;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ acceptance("Fast Edit", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
query("#post_2 .cooked").append(`That’s what she said!`);
|
||||
const textNode = query("#post_2 .cooked").childNodes[2];
|
||||
const textNode = query("#post_2 .cooked").childNodes[3];
|
||||
|
||||
await selectText(textNode);
|
||||
await click(".quote-button .quote-edit-label");
|
||||
|
@ -101,7 +101,7 @@ acceptance("Fast Edit", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
query("#post_2 .cooked").append(`Je suis désolé, comment ça va?`);
|
||||
const textNode = query("#post_2 .cooked").childNodes[2];
|
||||
const textNode = query("#post_2 .cooked").childNodes[3];
|
||||
|
||||
await selectText(textNode);
|
||||
await click(".quote-button .quote-edit-label");
|
||||
|
@ -113,7 +113,7 @@ acceptance("Fast Edit", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
query("#post_2 .cooked").append(`这是一个测试`);
|
||||
const textNode = query("#post_2 .cooked").childNodes[2];
|
||||
const textNode = query("#post_2 .cooked").childNodes[3];
|
||||
|
||||
await selectText(textNode);
|
||||
await click(".quote-button .quote-edit-label");
|
||||
|
@ -125,7 +125,7 @@ acceptance("Fast Edit", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
query("#post_2 .cooked").append(`This is great 👍`);
|
||||
const textNode = query("#post_2 .cooked").childNodes[2];
|
||||
const textNode = query("#post_2 .cooked").childNodes[3];
|
||||
|
||||
await selectText(textNode);
|
||||
await click(".quote-button .quote-edit-label");
|
||||
|
|
|
@ -244,6 +244,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
.cooked-selection-barrier {
|
||||
height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
// add staff color
|
||||
.moderator {
|
||||
.regular > .cooked {
|
||||
|
|
|
@ -9,6 +9,7 @@ describe "Topic page", type: :system do
|
|||
<a name="toc-h2-testing" class="anchor" href="#toc-h2-testing">x</a>
|
||||
Testing
|
||||
</h2>
|
||||
<p id="test-last-cooked-paragraph">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer tempor.</p>
|
||||
HTML
|
||||
|
||||
it "allows TOC anchor navigation" do
|
||||
|
@ -98,4 +99,26 @@ describe "Topic page", type: :system do
|
|||
expect(find("#post_#{topic.highest_post_number}")).to be_visible
|
||||
end
|
||||
end
|
||||
|
||||
context "when triple clicking to select a paragraph" do
|
||||
it "select the last paragraph" do
|
||||
visit "/t/#{topic.slug}/#{topic.id}/1"
|
||||
|
||||
# select the last paragraph by triple clicking
|
||||
element = page.driver.browser.find_element(id: "test-last-cooked-paragraph")
|
||||
page.driver.browser.action.move_to(element).click.click.click.perform
|
||||
|
||||
# get the selected text in the browser
|
||||
select_content = page.evaluate_script("window.getSelection().toString()")
|
||||
|
||||
# the browser is returning control characters among the whiter space in the end of the text
|
||||
# this regex will work as a .rstrip on steroids and remove them
|
||||
select_content.gsub!(/[\s\p{Cf}]+$/, "")
|
||||
|
||||
# compare the selected text with the last paragraph
|
||||
expect(select_content).to eq(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer tempor.",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user