Markdown task list improvements (#13952)
* Markdown task list improvements - Remove `.ui` class and wrappers to prevent fomantic from messing with it. - Change rendered HTML to match GitHub. - Add custom styling for the checkboxes. * fix unittest Co-authored-by: Lauris BH <lauris@nix.lv> Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
parent
287b594803
commit
41e8b834af
5 changed files with 60 additions and 16 deletions
|
@ -357,9 +357,9 @@ func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byt
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
if n.IsChecked {
|
if n.IsChecked {
|
||||||
_, err = w.WriteString(`<span class="ui checked checkbox"><input type="checkbox" checked="" readonly="readonly"` + end + `<label>`)
|
_, err = w.WriteString(`<input type="checkbox" disabled="" checked=""` + end)
|
||||||
} else {
|
} else {
|
||||||
_, err = w.WriteString(`<span class="ui checkbox"><input type="checkbox" readonly="readonly"` + end + `<label>`)
|
_, err = w.WriteString(`<input type="checkbox" disabled=""` + end)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ast.WalkStop, err
|
return ast.WalkStop, err
|
||||||
|
@ -371,7 +371,7 @@ func (r *HTMLRenderer) renderTaskCheckBoxListItem(w util.BufWriter, source []byt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, _ = w.WriteString("</label></span></li>\n")
|
_, _ = w.WriteString("</li>\n")
|
||||||
}
|
}
|
||||||
return ast.WalkContinue, nil
|
return ast.WalkContinue, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,9 +142,9 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
|
||||||
<p>(from <a href="https://www.markdownguide.org/extended-syntax/" rel="nofollow">https://www.markdownguide.org/extended-syntax/</a>)</p>
|
<p>(from <a href="https://www.markdownguide.org/extended-syntax/" rel="nofollow">https://www.markdownguide.org/extended-syntax/</a>)</p>
|
||||||
<h3 id="user-content-checkboxes">Checkboxes</h3>
|
<h3 id="user-content-checkboxes">Checkboxes</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="task-list-item"><span class="ui checkbox"><input type="checkbox" readonly="readonly"/><label>unchecked</label></span></li>
|
<li class="task-list-item"><input type="checkbox" disabled=""/>unchecked</li>
|
||||||
<li class="task-list-item"><span class="ui checked checkbox"><input type="checkbox" checked="" readonly="readonly"/><label>checked</label></span></li>
|
<li class="task-list-item"><input type="checkbox" disabled="" checked=""/>checked</li>
|
||||||
<li class="task-list-item"><span class="ui checkbox"><input type="checkbox" readonly="readonly"/><label>still unchecked</label></span></li>
|
<li class="task-list-item"><input type="checkbox" disabled=""/>still unchecked</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3 id="user-content-definition-list">Definition list</h3>
|
<h3 id="user-content-definition-list">Definition list</h3>
|
||||||
<dl>
|
<dl>
|
||||||
|
|
|
@ -43,7 +43,7 @@ func ReplaceSanitizer() {
|
||||||
|
|
||||||
// Checkboxes
|
// Checkboxes
|
||||||
sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
|
sanitizer.policy.AllowAttrs("type").Matching(regexp.MustCompile(`^checkbox$`)).OnElements("input")
|
||||||
sanitizer.policy.AllowAttrs("checked", "disabled", "readonly").OnElements("input")
|
sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input")
|
||||||
|
|
||||||
// Custom URL-Schemes
|
// Custom URL-Schemes
|
||||||
sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
|
sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
|
||||||
|
@ -66,8 +66,8 @@ func ReplaceSanitizer() {
|
||||||
// Allow classes for emojis
|
// Allow classes for emojis
|
||||||
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`emoji`)).OnElements("img")
|
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`emoji`)).OnElements("img")
|
||||||
|
|
||||||
// Allow icons, checkboxes, emojis, and chroma syntax on span
|
// Allow icons, emojis, and chroma syntax on span
|
||||||
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^((icon(\s+[\p{L}\p{N}_-]+)+)|(ui checkbox)|(ui checked checkbox)|(emoji))$|^([a-z][a-z0-9]{0,2})$`)).OnElements("span")
|
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^((icon(\s+[\p{L}\p{N}_-]+)+)|(emoji))$|^([a-z][a-z0-9]{0,2})$`)).OnElements("span")
|
||||||
|
|
||||||
// Allow generally safe attributes
|
// Allow generally safe attributes
|
||||||
generalSafeAttrs := []string{"abbr", "accept", "accept-charset",
|
generalSafeAttrs := []string{"abbr", "accept", "accept-charset",
|
||||||
|
|
|
@ -40,7 +40,7 @@ func Test_Sanitizer(t *testing.T) {
|
||||||
`<kbd>Ctrl + C</kbd>`, `<kbd>Ctrl + C</kbd>`,
|
`<kbd>Ctrl + C</kbd>`, `<kbd>Ctrl + C</kbd>`,
|
||||||
`<i class="dropdown icon">NAUGHTY</i>`, `<i>NAUGHTY</i>`,
|
`<i class="dropdown icon">NAUGHTY</i>`, `<i>NAUGHTY</i>`,
|
||||||
`<i class="icon dropdown"></i>`, `<i class="icon dropdown"></i>`,
|
`<i class="icon dropdown"></i>`, `<i class="icon dropdown"></i>`,
|
||||||
`<span class="ui checkbox"><input type="checkbox" readonly="readonly"/><label>unchecked</label></span>`, `<span class="ui checkbox"><input type="checkbox" readonly="readonly"/><label>unchecked</label></span>`,
|
`<input type="checkbox" disabled=""/>unchecked`, `<input type="checkbox" disabled=""/>unchecked`,
|
||||||
`<span class="emoji dropdown">NAUGHTY</span>`, `<span>NAUGHTY</span>`,
|
`<span class="emoji dropdown">NAUGHTY</span>`, `<span>NAUGHTY</span>`,
|
||||||
`<span class="emoji">contents</span>`, `<span class="emoji">contents</span>`,
|
`<span class="emoji">contents</span>`, `<span class="emoji">contents</span>`,
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,9 +162,57 @@
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.task-list-item {
|
.task-list-item {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin-left: calc(-2em + 2px);
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
margin: 0 6px .25em -1.6em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-list-item + .task-list-item {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
position: relative;
|
||||||
|
border: 1px solid var(--color-secondary);
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--color-input-background);
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
opacity: 1 !important; // override fomantic on edit preview
|
||||||
|
pointer-events: auto !important; // override fomantic on edit preview
|
||||||
|
vertical-align: middle !important; // override fomantic on edit preview
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:not([disabled]):hover,
|
||||||
|
input[type="checkbox"]:not([disabled]):active {
|
||||||
|
border-color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
background: var(--color-text);
|
||||||
|
mask-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked::after {
|
||||||
|
content: "";
|
||||||
|
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1 -1 18 18" width="16" height="16"><path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>');
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:indeterminate::after {
|
||||||
|
content: "";
|
||||||
|
mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2 7.75A.75.75 0 012.75 7h10a.75.75 0 010 1.5h-10A.75.75 0 012 7.75z"></path></svg>');
|
||||||
}
|
}
|
||||||
|
|
||||||
ul ul,
|
ul ul,
|
||||||
|
@ -422,10 +470,6 @@
|
||||||
box-shadow: inset 0 -1px 0 var(--color-secondary);
|
box-shadow: inset 0 -1px 0 var(--color-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
|
||||||
vertical-align: middle !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.csv-data td,
|
.csv-data td,
|
||||||
.csv-data th {
|
.csv-data th {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
|
Reference in a new issue