commonmark-spec icon indicating copy to clipboard operation
commonmark-spec copied to clipboard

Precedence of link within link

Open Knagis opened this issue 10 years ago • 15 comments

Example 389 shows what happens when a link is nested within a link - the inner link is rendered. But I can't find the rule describing this - probably a statement similar to the emphasis rule (closed-first and opened last) should be added.

Knagis avatar Nov 10 '14 19:11 Knagis

Furthermore, there is an inconsistency between how links and images are handled:

Example 389: [foo [bar](/uri)](/uri) :arrow_right: <p>[foo <a href="/uri">bar</a>](/uri)</p>

Example 436: ![foo ![bar](/url)](/url2) :arrow_right: <p><img src="/url2" alt="foo bar" /></p>

My opinion is that there should be no difference between nested images and links in these cases.

Knagis avatar Nov 10 '14 19:11 Knagis

@Knagis - I don't think this is an inconsistency. There's an important difference between the two cases. Links are not allowed in the link text of a link, but they are allowed in the image description. The difference is obscured a bit by the fact that links are not rendered as links inside an alt attribute, but see the AST output:

% ./cmark -t ast
[foo [bar](/uri)](/uri)
paragraph
  text "["
  text "foo "
  link url="/uri"
    text "bar"
  text "]"
  text "(/uri)"
% ./cmark -t ast
![foo ![bar](/url)](/url2)
paragraph
  image url="/url2"
    text "foo "
    image url="/url"
      text "bar"

jgm avatar Dec 26 '14 18:12 jgm

For me it feels that these similar looking cases should act the same in terms of which - inner or outer - link/image takes precedence (but that is just a visual thing by looking at these two cases). And for links the same approach as with images would be used - the contents of the link are parsed as is in the AST but rendered without the nested link. So the output for 389 would be <a href="/uri">foo bar</a>.

The only practical benefit though for this approach (apart from the test cases looking nicer together) is that an application could walk the AST and issue a warning that the link-within-link is not a valid construct. If the parser creates text nodes, this cannot be done.

Knagis avatar Dec 26 '14 18:12 Knagis

If that lone argument did not convince you, this issue can be closed - I will then adjust my parser accordingly.

Knagis avatar Dec 26 '14 18:12 Knagis

Looking at the github commits I just realized a rather good example how links within links could be used if the renderer decides to support it:

[Fixed [#285](/issues/285) in cmark](/commits/12345)

<a href="/commits/12345">Fixed </a><a href="/issues/285">#285</a><a href="/commits/12345"> in cmark</a>

Knagis avatar Jan 17 '15 12:01 Knagis

Commit #331 clarifies this in the spec, but I'm leaving this issue open, because I think it still needs rethinking.

jgm avatar Jun 15 '15 17:06 jgm

Also note there is yet another inconsistency: While links cannot be nested in each other, an autolink on the other side is allowed to be nested in the link text.

See [<http://foo>](/url)

mity avatar Jun 07 '17 07:06 mity

There is some additional discussion in https://talk.commonmark.org/t/why-is-link-text-not-allowed-to-contain-other-links/2434.

mgeier avatar Jun 07 '17 09:06 mgeier

For reference, it looks like HTML rendering on this concept is unclear too. Browsers choose to deal with this in a different manner.

[foo [bar](/bar) foo](/foo)

would intuitively translate into:

<a href="/foo">foo <a href="/bar">bar</a> foo</a>

I expected this to give me foo bar foo in which clicking the word "bar" goes to /bar and clicking either word "foo", or the spaces around "bar", would go to /foo. However, Firefox and Chromium both terminate the first link at the beginning of the second one (the second foo is plain text).

Here's a paste from the DOM inspector's console output for console.log(document.body.innerHTML):

<a href="/foo">foo </a><a href="/bar">bar</a> foo

(I'm not going to dig through the HTML specs to see if this is explicitly defined or if it's ambiguous and Google & Mozilla merely decided to do the same as each other, especially since one goal of CommonMark is to be independent from HTML. That doesn't mean we can't learn from HTML's decisions.)

One easy solution would simply be to pass the buck: defer to the browser and offer nested <a> tags. A related (and more HTML-independent) alternative would be to terminate the first link at the start of the second link, reproducing the web browser decision.

adamhotep avatar Oct 18 '22 21:10 adamhotep

Link nesting simply does not make sense semantically, so why should it be supported syntactically?

Case in point, how often, if ever do you see

<a href="/foo">foo <a href="/bar">bar</a> foo</a>

in the wild? Firefox and Chromium behaviors are more likely 🤷🏾‍♂️ ways of dealing with tag soup than an expression of "Oh yeah, this makes sense, and here is the natural interpretation."

In other words, no "solution" is needed.

vassudanagunta avatar Oct 21 '22 05:10 vassudanagunta

@vassudanagunta: I see this as semantically reasonable. The inner link overrides the outer link. Think about it like colors:

<span style="color:red">red <span style="color:orange">orange</span> red</span>

We don't ask "where did the red go" because we know it's merely underneath the orange. This is consistent with putting an image among text in markdown:

[foo ![image of foo](foo.png) foo](foo.html)

The text is blue and underlined while the image in the middle of it is not.

adamhotep avatar Nov 01 '22 18:11 adamhotep

For what it's worth, HTML 4.01 says no.

12.2.2 Nested links are illegal

Links and anchors defined by the A element must not be nested; an A element must not contain any other A elements.

(But I agree it has an obvious semantics regardless.

masak avatar Jan 20 '23 05:01 masak

Likewise HTML5:

Content model: Transparent, but there must be no interactive content, a element descendant,...

See also Why are nested anchor tags illegal?.

vassudanagunta avatar Jan 20 '23 06:01 vassudanagunta

The stackoverflow answer makes the case that anchors were designed to be "point-like", which explains why HTML 4.01 and HTML5 both rule out nested a elements.

Intuitively, I agree with @adamhotep 's explanation above. But I must admit that HTML 4.01 and HTML5 don't seem to share that intuition, because they consider anchors to be point-like and simple.

I also liked @Knagis 's provided example:

[Fixed [#285](/issues/285) in cmark](/commits/12345)

There's no hesitation when I read that about what that "means", or how I would expect it to look rendered in a browser. I saw that example before I saw HTML 4.01's prohibition against nested a elements; it made sense to me before, and it still makes sense to me after.

The output @Knagis suggests doesn't violate a nesting:

<a href="/commits/12345">Fixed </a><a href="/issues/285">#285</a><a href="/commits/12345"> in cmark</a>

But I suppose it could be an argument for either (a) how to render nested Markdown link syntax without violating HTML's interdictions, or (b) how cumbersome/roundabout it would be to render nested Markdown links into conformant HTML, so we'd better not. :smile:

masak avatar Jan 20 '23 08:01 masak

[Fixed [#285](/issues/285) in cmark](/commits/12345)

Sure it's clear what it means upon examination but it's really bad for readers. To me it's akin to a button within a button, but worse because it's even harder to see in text unless you start making text look like buttons.

I'm not saying that a markup language should be designed to prevent writers from shooting themselves in the foot, but I am saying why bend over backwards to give them a foot gun?

vassudanagunta avatar Jan 20 '23 12:01 vassudanagunta