2

I happened to be writing an entry and noticed that there was something odd about using the link definition name reduce. The preview updates fine until I enter the last e of reduce, then nothing changes. The editor just goes into pause mode until I remove the e again.

I'll submit this post with a test link using the link definition name reduce to see if it's just the preview that's not working properly: Test

Other, non-working names: map, filter, pop, push... yeah you get the idea? Any Array function.

2
  • The real deal works fine, it's just the preview. Click edit on my post and you'll see that the preview does not update; it's just empty.
    – Blixt
    Commented Jul 17, 2009 at 12:41
  • 1
    most of the people on here cannot click edit. we're not powerful here as we're there ;) Commented Jul 17, 2009 at 12:48

1 Answer 1

5

The link definition names are stored in an Array. Arrays have reduce as a method, which seems to be the source of the problem. You can reproduce it with concat or filter or any other Array method, too. I'm no Javascript expert, and I haven't dug far enough into the problem to figure out just why it happens -- especially because it begins working again if you include the optional title for the link -- but you can see for yourself that it affects the base WMD implementation, too, not just SO's version.

EDIT:

So the problem is that indexing any object in Javascript with a method name returns the function itself. The structure of the Markdown editor is such that it stores URLs and link titles in two arrays, both of which are indexed by the link definition name. The markdown converter craps out when attempting to escape characters on the function code returned when the index is a function name. You have to have the optional title, because if you omit it, it still thinks it has a title and attempts to escape characters on the function. It begins working when you have the URL and option text in place, because the function gets overwritten in the two arrays with the proper strings.

EDIT 2:

Here is some of the code in question from the SO branch of WMD:

    if (g_urls[link_id] != undefined) {
        url = g_urls[link_id];
        if (g_titles[link_id] != undefined) {
            title = g_titles[link_id];
        }
    }

The above code uses link_id (which would be "reduce") in order to index into g_urls and g_titles. As I mentioned before, these will not be undefined, even when they "should" be. Instead, they'll be the reduce functions themselves. Note that, because of the structure here, unless both the URL and title are defined, one or both will be set to the function.

Next is the code that actually creates the problem:

url = escapeCharacters(url,"*_");
var result = "<a href=\"" + url + "\"";

if (title != "") {
    title = title.replace(/"/g,"&quot;");
    title = escapeCharacters(title,"*_");
    result +=  " title=\"" + title + "\"";
}

The code attempts to escape characters on url and title (which, again, will not be "" even when it should be). This kills the code, because you obviously can't escape characters on a function (Wouldn't that be cool if you could, though? Like, it actually stripped the characters from the function code? Pointless? Sure. But cool.). So until both url and title have actual string values, the conversion process craps out, which is why it seems like it freezes.

So how to solve it? The simplest way would be to change the first block of code to something like this:

    if (g_urls[link_id] != undefined && typeof g_urls[link_id] != 'function') {
        url = g_urls[link_id];
        if (g_titles[link_id] != undefined && typeof g_titles[link_id] != 'function') {
            title = g_titles[link_id];
        }
    }

Maybe a Javascript ninja will know of an even better way, but that should work. I'd submit it as a patch, but my git skill is even more limited than my Javascript.

EDIT 3:

Blixt has suggested this alternate solution, which appears to work just as well, is less of a workaround, and is probably better semantically. In lieu of the above change, instead change these lines (lines 105-106):

g_urls = new Array();
g_titles = new Array();

to this:

g_urls = {};
g_titles = {};

I haven't done especially rigorous testing, but it appears to be working like a charm.

8
  • Ah okay, I didn't know WMD was an external lib. I downloaded its source and had a look at it. Apparently, the author of WMD isn't all too familiar with the workings of JavaScript since he used Array instances as dictionaries (he should have used a simple {} object.) That's why certain keys are "reserved" and cause errors.
    – Blixt
    Commented Jul 17, 2009 at 13:31
  • Does it not work if you simply change the three assignments in this.makeHtml to g_urls = {}; g_titles = {}; g_html_blocks = {}; ?
    – Blixt
    Commented Jul 17, 2009 at 13:56
  • Sorry, leave g_html_blocks alone (or change it to shorter []), that one is actually used like an Array; the others are not.
    – Blixt
    Commented Jul 17, 2009 at 13:58
  • @Blixt: I have no idea. I haven't tried it, and, like I said, I'm not fluent in Javascript. I'll go test it, though... Commented Jul 17, 2009 at 13:58
  • Sorry for the comment spam but looking through that GitHub repository it seems the variables are now called links and titles.
    – Blixt
    Commented Jul 17, 2009 at 14:00
  • @Blixt: You're right. I should've figured they'd minify the showdown.js file. I was working off a standard WMD implementation I have lying around. Still, the point remains the same. Commented Jul 17, 2009 at 14:10
  • Ah, I see. I've notified John (WMD author) by e-mail, but what should I do about the implementation being used in SO? Is this post enough?
    – Blixt
    Commented Jul 17, 2009 at 14:26
  • @Blixt: I should think so, but I supposed you could send an email to [email protected] referring them back here. Commented Jul 17, 2009 at 14:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .