mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-14 15:12:15 +09:00
Backport #39708 Co-authored-by: Basavaraj S m <basavaraj@digiscrypt.com> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
106 lines
2.2 KiB
Go
106 lines
2.2 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package htmlutil
|
|
|
|
import (
|
|
"strings"
|
|
)
|
|
|
|
type SrcSetCandidate struct {
|
|
SrcLink string
|
|
SrcDesc []string
|
|
}
|
|
|
|
const (
|
|
asciiSpaces = " \t\n\r\f"
|
|
asciiSpacesAndComma = " \t\n\r\f,"
|
|
)
|
|
|
|
func ParseSrcset(srcset string) (candidates []SrcSetCandidate) {
|
|
// ref: https://html.spec.whatwg.org/multipage/images.html#parse-a-srcset-attribute
|
|
// It can't simply use "split" because comma can appear in URLs and descriptors can be parenthesized and contain commas.
|
|
extractLink := func() (string, bool) {
|
|
srcset = strings.TrimLeft(srcset, asciiSpacesAndComma)
|
|
if srcset == "" {
|
|
return "", false
|
|
}
|
|
end := strings.IndexAny(srcset, asciiSpaces)
|
|
if end == -1 {
|
|
end = len(srcset)
|
|
}
|
|
link := srcset[:end]
|
|
srcset = srcset[end:]
|
|
if strings.HasSuffix(link, ",") {
|
|
return strings.TrimRight(link, ","), false
|
|
}
|
|
return link, true
|
|
}
|
|
extractDesc := func() (string, bool) {
|
|
srcset = strings.TrimLeft(srcset, asciiSpaces)
|
|
if srcset == "" {
|
|
return "", false
|
|
}
|
|
inParentheses := false
|
|
for i := range len(srcset) {
|
|
c := srcset[i]
|
|
if inParentheses {
|
|
inParentheses = c != ')'
|
|
continue
|
|
}
|
|
if c == '(' {
|
|
inParentheses = true
|
|
continue
|
|
}
|
|
if strings.IndexByte(asciiSpacesAndComma, c) != -1 {
|
|
desc := srcset[:i]
|
|
srcset = srcset[i+1:]
|
|
return desc, c != ','
|
|
}
|
|
}
|
|
desc := srcset
|
|
srcset = ""
|
|
return desc, false
|
|
}
|
|
|
|
for {
|
|
link, hasDesc := extractLink()
|
|
if link == "" {
|
|
break
|
|
}
|
|
var descriptors []string
|
|
if hasDesc {
|
|
for {
|
|
desc, hasMoreDesc := extractDesc()
|
|
if desc != "" {
|
|
descriptors = append(descriptors, desc)
|
|
}
|
|
if !hasMoreDesc {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
candidates = append(candidates, SrcSetCandidate{SrcLink: link, SrcDesc: descriptors})
|
|
}
|
|
return candidates
|
|
}
|
|
|
|
func EncodeSrcset(candidates []SrcSetCandidate) string {
|
|
var sb strings.Builder
|
|
for i, c := range candidates {
|
|
if i != 0 {
|
|
sb.WriteString(", ")
|
|
}
|
|
link := c.SrcLink
|
|
if prefix, ok := strings.CutSuffix(link, ","); ok {
|
|
link = prefix + "%2C"
|
|
}
|
|
sb.WriteString(link)
|
|
for _, d := range c.SrcDesc {
|
|
sb.WriteByte(' ')
|
|
sb.WriteString(d)
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|