diff options
author | Unknwon <u@gogs.io> | 2017-02-22 19:58:08 -0500 |
---|---|---|
committer | Unknwon <u@gogs.io> | 2017-02-27 22:46:32 -0500 |
commit | d7954014a4132305a7055a3a7089efd0d579cef8 (patch) | |
tree | aac2751eed38dfd576b3ecf60ecd3170673152c9 /modules/markdown/markdown.go | |
parent | 429345b9df894465ef98d20358b1757c92b41c80 (diff) |
markdown: fix links for image nested inside a link (#2636)
Diffstat (limited to 'modules/markdown/markdown.go')
-rw-r--r-- | modules/markdown/markdown.go | 112 |
1 files changed, 68 insertions, 44 deletions
diff --git a/modules/markdown/markdown.go b/modules/markdown/markdown.go index 9e42d072..befcedc2 100644 --- a/modules/markdown/markdown.go +++ b/modules/markdown/markdown.go @@ -192,42 +192,11 @@ func (options *Renderer) ListItem(out *bytes.Buffer, text []byte, flags int) { // Note: this section is for purpose of increase performance and // reduce memory allocation at runtime since they are constant literals. var ( - svgSuffix = []byte(".svg") - svgSuffixWithMark = []byte(".svg?") - spaceBytes = []byte(" ") - spaceEncodedBytes = []byte("%20") - pound = []byte("#") - space = " " - spaceEncoded = "%20" + pound = []byte("#") + space = " " + spaceEncoded = "%20" ) -// Image defines how images should be processed to produce corresponding HTML elements. -func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { - prefix := strings.Replace(r.urlPrefix, "/src/", "/raw/", 1) - if len(link) > 0 { - if isLink(link) { - // External link with .svg suffix usually means CI status. - // TODO: define a keyword to allow non-svg images render as external link. - if bytes.HasSuffix(link, svgSuffix) || bytes.Contains(link, svgSuffixWithMark) { - r.Renderer.Image(out, link, title, alt) - return - } - } else { - if link[0] != '/' { - prefix += "/" - } - link = bytes.Replace([]byte((prefix + string(link))), spaceBytes, spaceEncodedBytes, -1) - fmt.Println(333, string(link)) - } - } - - out.WriteString(`<a href="`) - out.Write(link) - out.WriteString(`">`) - r.Renderer.Image(out, link, title, alt) - out.WriteString("</a>") -} - // cutoutVerbosePrefix cutouts URL prefix including sub-path to // return a clean unified string of request URL path. func cutoutVerbosePrefix(prefix string) string { @@ -353,14 +322,63 @@ var ( rightAngleBracket = []byte(">") ) -var noEndTags = []string{"img", "input", "br", "hr"} +var noEndTags = []string{"input", "br", "hr", "img"} + +// wrapImgWithLink warps link to standalone <img> tags. +func wrapImgWithLink(urlPrefix string, buf *bytes.Buffer, token html.Token) { + var src, alt string + // Extract "src" and "alt" attributes + for i := range token.Attr { + switch token.Attr[i].Key { + case "src": + src = token.Attr[i].Val + case "alt": + alt = token.Attr[i].Val + } + } + + // Skip in case the "src" is empty + if len(src) == 0 { + buf.WriteString(token.String()) + return + } + + buf.WriteString(`<a href="`) + buf.WriteString(src) + buf.WriteString(`">`) + + // Prepend repository base URL for internal links + if !isLink([]byte(src)) { + urlPrefix = strings.Replace(urlPrefix, "/src/", "/raw/", 1) + if src[0] != '/' { + urlPrefix += "/" + } + src = strings.Replace(urlPrefix+string(src), " ", "%20", -1) + buf.WriteString(`<img src="`) + buf.WriteString(src) + buf.WriteString(`"`) + + if len(alt) > 0 { + buf.WriteString(` alt="`) + buf.WriteString(alt) + buf.WriteString(`"`) + } + + buf.WriteString(`>`) + + } else { + buf.WriteString(token.String()) + } + + buf.WriteString(`</a>`) +} // PostProcess treats different types of HTML differently, // and only renders special links for plain text blocks. -func PostProcess(rawHtml []byte, urlPrefix string, metas map[string]string) []byte { +func PostProcess(rawHTML []byte, urlPrefix string, metas map[string]string) []byte { startTags := make([]string, 0, 5) - var buf bytes.Buffer - tokenizer := html.NewTokenizer(bytes.NewReader(rawHtml)) + buf := bytes.NewBuffer(nil) + tokenizer := html.NewTokenizer(bytes.NewReader(rawHTML)) OUTER_LOOP: for html.ErrorToken != tokenizer.Next() { @@ -370,8 +388,14 @@ OUTER_LOOP: buf.Write(RenderSpecialLink([]byte(token.String()), urlPrefix, metas)) case html.StartTagToken: - buf.WriteString(token.String()) tagName := token.Data + + if tagName == "img" { + wrapImgWithLink(urlPrefix, buf, token) + continue OUTER_LOOP + } + + buf.WriteString(token.String()) // If this is an excluded tag, we skip processing all output until a close tag is encountered. if strings.EqualFold("a", tagName) || strings.EqualFold("code", tagName) || strings.EqualFold("pre", tagName) { stackNum := 1 @@ -381,14 +405,14 @@ OUTER_LOOP: // Copy the token to the output verbatim buf.WriteString(token.String()) - if token.Type == html.StartTagToken { + // Stack number doesn't increate for tags without end tags. + if token.Type == html.StartTagToken && !com.IsSliceContainsStr(noEndTags, token.Data) { stackNum++ } // If this is the close tag to the outer-most, we are done if token.Type == html.EndTagToken { stackNum-- - if stackNum <= 0 && strings.EqualFold(tagName, token.Data) { break } @@ -397,8 +421,8 @@ OUTER_LOOP: continue OUTER_LOOP } - if !com.IsSliceContainsStr(noEndTags, token.Data) { - startTags = append(startTags, token.Data) + if !com.IsSliceContainsStr(noEndTags, tagName) { + startTags = append(startTags, tagName) } case html.EndTagToken: @@ -422,7 +446,7 @@ OUTER_LOOP: // If we are not at the end of the input, then some other parsing error has occurred, // so return the input verbatim. - return rawHtml + return rawHTML } // Render renders Markdown to HTML with special links. |