Repository: microcosm-cc/bluemonday (go)

Issue:
Can't allow `<picture>` and `<source>`
I'm trying to allow the `<picture>` and `<source>` elements in a UGCPolicy using this code:

```go
p = bluemonday.UGCPolicy()
p.AllowElements("picture", "source")
p.AllowAttrs("srcset", "src", "type", "media").OnElements("source")
p.Sanitize("<picture><source src=\"b.jpg\" media=\"(prefers-color-scheme: dark)\"></source><img src=\"a.jpg\"></picture>")
```

But no matter what I do, it seems `<picture>` element is always stripped in the output:

```
<source src="b.jpg"></source><img src="a.jpg">
```

The use case for this is allowing to provide alternative versions of an image – different resolutions or different dark/light theme version. GitHub supports this for example in their Markdown: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#specifying-the-theme-an-image-is-shown-to

Am I doing something wrong?


Pull request description:
Add picture to allowlist of elements that do not need attributes to resolve #161
`picture` was not in the list of elements that were allowed without attributes. Typically most HTML elements are not valid without an attribute except for 90 elements that have this capability, `picture` was absent from this list.

Patch:
diff --git a/policy.go b/policy.go
index 1a5e00c..c446fad 100644
--- a/policy.go
+++ b/policy.go
@@ -879,6 +879,7 @@ func (p *Policy) addDefaultElementsWithoutAttrs() {
 	p.setOfElementsAllowedWithoutAttrs["optgroup"] = struct{}{}
 	p.setOfElementsAllowedWithoutAttrs["option"] = struct{}{}
 	p.setOfElementsAllowedWithoutAttrs["p"] = struct{}{}
+	p.setOfElementsAllowedWithoutAttrs["picture"] = struct{}{}
 	p.setOfElementsAllowedWithoutAttrs["pre"] = struct{}{}
 	p.setOfElementsAllowedWithoutAttrs["q"] = struct{}{}
 	p.setOfElementsAllowedWithoutAttrs["rp"] = struct{}{}


Test patch:
diff --git a/sanitize_test.go b/sanitize_test.go
index c13a23c..ca4a94b 100644
--- a/sanitize_test.go
+++ b/sanitize_test.go
@@ -3931,3 +3931,37 @@ func TestRemovingEmptySelfClosingTag(t *testing.T) {
 			expected)
 	}
 }
+
+func TestIssue161(t *testing.T) {
+	// https://github.com/microcosm-cc/bluemonday/issues/161
+	//
+	// ```
+	// p.AllowElementsMatching(regexp.MustCompile(`^custom-`))
+	// p.AllowNoAttrs().Matching(regexp.MustCompile(`^custom-`))
+	// ```
+	// This does not work as expected. This looks like a limitation, and the
+	// question is whether the matching has to be applied in a second location
+	// to overcome the limitation.
+	//
+	// However the issue is really that the `.Matching()` returns an attribute
+	// test that has to be bound to some elements, it isn't a global test.
+	//
+	// This should work:
+	// ```
+	// p.AllowNoAttrs().Matching(regexp.MustCompile(`^custom-`)).OnElementsMatching(regexp.MustCompile(`^custom-`))
+	// ```
+	p := UGCPolicy()
+	p.AllowElements("picture", "source")
+	p.AllowAttrs("srcset", "src", "type", "media").OnElements("source")
+
+	input := `<picture><source src="b.jpg" media="(prefers-color-scheme: dark)"></source><img src="a.jpg"></picture>`
+	out := p.Sanitize(input)
+	expected := input
+	if out != expected {
+		t.Errorf(
+			"test failed;\ninput   : %s\noutput  : %s\nexpected: %s",
+			input,
+			out,
+			expected)
+	}
+}