FIX: Quoting a quote preserves the original post information (#8746)

Let's say post #2 quotes post number #1. If a user decides to quote the
quote in post #2, it should keep the information of post #1
("user_1, post: 1, topic: X"), instead of replacing with current post
info ("user_2, post: 2, topic: X").
This commit is contained in:
Bianca Nenciu
2020-01-22 16:10:23 +02:00
committed by GitHub
parent 8a89b7e108
commit 7b7e1717f2
11 changed files with 86 additions and 32 deletions

View File

@@ -1,7 +1,7 @@
import { scheduleOnce } from "@ember/runloop";
import Component from "@ember/component";
import discourseDebounce from "discourse/lib/debounce";
import { selectedText } from "discourse/lib/utilities";
import { selectedText, selectedElement } from "discourse/lib/utilities";
export default Component.extend({
classNames: ["quote-button"],
@@ -48,8 +48,28 @@ export default Component.extend({
}
}
let opts;
for (
let element = selectedElement();
element && element.tagName !== "ARTICLE";
element = element.parentElement
) {
if (element.tagName === "ASIDE" && element.classList.contains("quote")) {
opts = {
username:
element.dataset.username ||
element
.querySelector(".title")
.textContent.trim()
.replace(/:$/, ""),
post: element.dataset.post,
topic: element.dataset.topic
};
}
}
const _selectedText = selectedText();
quoteState.selected(postId, _selectedText);
quoteState.selected(postId, _selectedText, opts);
this.set("visible", quoteState.buffer.length > 0);
// avoid hard loops in quote selection unconditionally
@@ -165,8 +185,8 @@ export default Component.extend({
},
click() {
const { postId, buffer } = this.quoteState;
this.attrs.selectText(postId, buffer).then(() => this._hideButton());
const { postId, buffer, opts } = this.quoteState;
this.attrs.selectText(postId, buffer, opts).then(() => this._hideButton());
return false;
}
});

View File

@@ -266,7 +266,7 @@ export default Controller.extend(bufferedProperty("model"), {
this.send("showFeatureTopic");
},
selectText(postId, buffer) {
selectText(postId, buffer, opts) {
const loadedPost = this.get("model.postStream").findLoadedPost(postId);
const promise = loadedPost
? Promise.resolve(loadedPost)
@@ -275,7 +275,7 @@ export default Controller.extend(bufferedProperty("model"), {
return promise.then(post => {
const composer = this.composer;
const viewOpen = composer.get("model.viewOpen");
const quotedText = Quote.build(post, buffer);
const quotedText = Quote.build(post, buffer, opts);
// If we can't create a post, delegate to reply as new topic
if (!viewOpen && !this.get("model.details.can_create_post")) {

View File

@@ -3,13 +3,15 @@ export default class QuoteState {
this.clear();
}
selected(postId, buffer) {
selected(postId, buffer, opts) {
this.postId = postId;
this.buffer = buffer;
this.opts = opts;
}
clear() {
this.buffer = "";
this.postId = null;
this.opts = null;
}
}

View File

@@ -8,6 +8,7 @@ export default {
}
if (!contents) contents = "";
if (!opts) opts = {};
const sansQuotes = contents.replace(this.REGEXP, "").trim();
if (sansQuotes.length === 0) {
@@ -26,9 +27,9 @@ export default {
stripped.replace(/\W/g, "") === contents.replace(/\W/g, "");
const params = [
post.get("username"),
`post:${post.get("post_number")}`,
`topic:${post.get("topic_id")}`
opts.username || post.username,
`post:${opts.post || post.post_number}`,
`topic:${opts.topic || post.topic_id}`
];
opts = opts || {};

View File

@@ -143,6 +143,13 @@ export function selectedText() {
return toMarkdown($div.html());
}
export function selectedElement() {
const selection = window.getSelection();
if (selection.rangeCount > 0) {
return selection.getRangeAt(0).startContainer.parentElement;
}
}
// Determine the row and col of the caret in an element
export function caretRowCol(el) {
var cp = caretPosition(el);

View File

@@ -73,6 +73,10 @@ const rule = {
token.attrs.push(["class", "quote no-group"]);
}
if (username) {
token.attrs.push(["data-username", username]);
}
if (postNumber) {
token.attrs.push(["data-post", postNumber]);
}