Quoted replies don't keep original formatting

(Bill Ayakatubby) #1

When using the (very cool!) highlight-and-reply feature, the formatting of the original post is lost. For example, below you can see that I quoted Jeff. In his post, he italicized the word “wrong” twice, but the italicization doesn’t come through in my quote:

Quoting a link when replying doesn't include the link
Only one heading in Markdown quote?
Quoting a link when replying doesn't include the link
Quoted lists lose bullets/numbers
Markdown lists don't render correctly in quotes
(Jeff Atwood) #2

I think we should at least try to retain some of the more basic formatting in quotes, such as bold, italic, bullets. @eviltrout can you add this to your list?

It will also help with highlighting shorter replies since the formatting will match and no longer block highlight since the quote is “different”.

(Robin Ward) #3

Sure, but I should warn you that it’s very tricky, as we get the content back as HTML which would then need to be converted to markdown.

(Ben Lubar) #4

Couldn’t the quote button ask the server for the original markdown?

(Régis Hanol) #5

The issue is matching the quote (HTML) to the actual markdown code. When you’re quoting an entire post, it’s easy, but it gets complicated really fast when you’re quoting a part of it (which is most of the case anyway).

(Jeff Atwood) #6

Still, requesting the raw markdown from the server when quoting (rather than going off the cooked HTML on the client) makes sense, and gets closer to the goal.

(Kasper Peulen) #7

I noticed that when I quote mathjax content (using the mathjax plugin), I do get the orginal LaTeX source. I do get a bunch of other crap, so this is not perfect yet, but this may gives some ideas.

Here is an example. If I quote a text with this source:
We write $\sqrt {2}$ for the square root of 2.

And this output:

I get this in the quote:
`We write 2√ \sqrt {2} for the square root of 2.``

This is because mathjax stores the original source into script tags like this:

It may be an idea to the same with the markdown implementation of discourse. Making sure the original markdown is stored into the html. The html source will become a lot uglier, but it may have other adventages as well. For example something like:

<span class="markdown-output"><strong>Important</strong></span>
<span class="markdown-source">**Important**</span>

(Kasper Peulen) #8

I’ve tested this code as a plugin. This code makes sure that the quote gets the source of the original bold and italic text.

Discourse.Utilities.selectedText = function() {
    var html = '';

    if (typeof window.getSelection !== "undefined") {
      var sel = window.getSelection();
      if (sel.rangeCount) {
        var container = document.createElement("div");
        for (var i = 0, len = sel.rangeCount; i < len; ++i) {
        html = container.innerHTML;
    } else if (typeof document.selection !== "undefined") {
      if (document.selection.type === "Text") {
        html = document.selection.createRange().htmlText;

    // Strip out any .click elements from the HTML before converting it to text
    var div = document.createElement('div');
    div.innerHTML = html;
    $('.clicks', $(div)).remove();
    //+++This is what I changed+++
    $('.markdown-output', $(div)).remove();
    //+++This is what I changed+++
    var text = div.textContent || div.innerText || "";
    return String(text).trim();

var replaceMarkdown = function(match, tag) {
    between: match,
    wordBoundary: true,
    //+++This is what I changed+++
    emitter: function(contents) { return ['span',['span', {'class': 'markdown-output'},[tag].concat(contents)],['span',{'class': 'markdown-source','style' :'display:none'},match+contents+match]] }
    //+++This is what I changed+++

replaceMarkdown('**', 'strong');
replaceMarkdown('__', 'strong');
replaceMarkdown('*', 'em');
replaceMarkdown('_', 'em');

(Kane York) #9

I’d assume that the style would be applied by the CSS.

(Kasper Peulen) #10

Sure, I just wanted to show that this an option that gives the desired result. To do this for all the other dialects, is straightforward, but there may be an smarter way.

(Kasper Peulen) #11

Okay, playing around a little bit. To let this work for everything I really need to hack in better_markdown.js and dialects.js. I don’t think I can make it as a plugin this way. And I don’t know if you guys will pull something like this. The code will look like:

  inlineBetween: function(args) {
    var start = args.start || args.between,
        stop = args.stop || args.between,
        startLength = start.length;

    this.registerInline(start, function(text, match, prev) {
      if (invalidBoundary(args, prev)) { return; }

      var endPos = text.indexOf(stop, startLength);
      if (endPos === -1) { return; }
      var between = text.slice(startLength, endPos);

      // If rawcontents is set, don't process inline
      if (!args.rawContents) {
        var between = this.processInline(between);

      var contents = args.emitter.call(this, between);
     var rawMD = start+text.slice(startLength, endPos) + stop;   
     contents = ['span',['span', {'class': 'parsed-markdown'},contents],['span',{'class': 'raw-markdown'},rawMD]];
     if (contents) {
        return [endPos+stop.length, contents ];
  inlineRegexp: function(args) {
    this.registerInline(args.start, function(text, match, prev) {
      if (invalidBoundary(args, prev)) { return; }

      args.matcher.lastIndex = 0;
      var m = args.matcher.exec(text);
      if (m) {
        var result = args.emitter.call(this, m);
		var rawMD = m[0];
		result = ['span',['span', {'class': 'parsed-markdown'},result],['span',{'class': 'raw-markdown''},rawMD]];
        if (result) {
          return [m[0].length, result];

And so on, for all the dialects/patterns/blocks, it is quite straight forward. I’ve also tried headers, images,links, and it all works, but I’m not sure if I’m wasting my time here. I can imagine, that you don’t want to change markdown-js like this. Otherwise I’m happy to write a pull request.

(Sam Saffron) #12

To me this feels like a feature request as opposed to straight out bug.

System is designed to work in this way and a change is complicated full of enormous amount of edge cases. I would be afraid of making changes here cause of the wack-o-mole effect that would ensue.

Matching is tricky, going backwards from html to markdown to find the match will fail in some edge cases. (oneboxes, html comments messing stuff up … etc)

@Kasper can you include some “success” screenshots here, not against a core fix if we think it will not collapse in edge case hell. Also, images is a bit of a problem … not sure you ever really want to quote an image and include it a second time in a topic. What is the point.

(Bill Ayakatubby) #13

14 months on, I don’t disagree. :smile:

(Mik01aj) #16

Sorry to dig out this old topic, but the problem still persists. And it’s not just about formatting. Quoting this (the breaks are single-line breaks):

Results in this:

[quote="mik01aj, post:5, topic:51"]

:bug: :frowning:

(Dan Dascalescu) #17

I’ve just run into this as well, with list bullets in quotes:

Code for those who can’t edit this post:

List starts on next line and is rendered raw. But if you remove this line, the Markdown will be interpreted.

* item 1

(Mik01aj) #18

Any hopes on having this fixed?

(Avi Flax) #19

I’d love to see this addressed!

(To be clear though, I don’t consider the current behavior a bug; I understand retaining the formatting is technically challenging. I consider this a feature/enhancement request.)

(ljpp) #20

What triggers this issue? Some quotations work fine, but others lose their line breaks. Just reproduced this on 1.6 stable, using a very trivial test case. Simple three line post, which I painted and quoted using the floating button.

(Jeff Atwood) #21

That particular case is a little annoying. Anything we can do to improve that specific case @eviltrout? Without blowing this out into a ton of extra work.

(Robin Ward) #22

I have a little hack here that replaces <br> with \n and it seems to improve this case.