Add support for list item checkboxes (e.g. [X])

see https://orgmode.org/manual/Checkboxes.html
We're deviating from Org mode regarding the assigned css classes but the chosen
classes feel better than (on, off, trans) and it's not like the export matches
1:1 otherwise.
This commit is contained in:
Niklas Fasching 2018-12-18 14:15:35 +01:00
parent a60f844e38
commit 7331d24452
7 changed files with 55 additions and 35 deletions

View file

@ -34,6 +34,12 @@ var listTags = map[string][]string{
"descriptive": []string{"<dl>", "</dl>"},
}
var listItemStatuses = map[string]string{
" ": "unchecked",
"-": "indeterminate",
"X": "checked",
}
func NewHTMLWriter() *HTMLWriter {
return &HTMLWriter{
htmlEscape: true,
@ -283,13 +289,22 @@ func (w *HTMLWriter) writeList(l List) {
}
func (w *HTMLWriter) writeListItem(li ListItem) {
w.WriteString("<li>\n")
if li.Status != "" {
w.WriteString(fmt.Sprintf("<li class=\"%s\">\n", listItemStatuses[li.Status]))
} else {
w.WriteString("<li>\n")
}
w.writeNodes(li.Children...)
w.WriteString("</li>\n")
}
func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
w.WriteString("<dt>\n")
if di.Status != "" {
w.WriteString(fmt.Sprintf("<dt class=\"%s\">\n", listItemStatuses[di.Status]))
} else {
w.WriteString("<dt>\n")
}
if len(di.Term) != 0 {
w.writeNodes(di.Term...)
} else {

View file

@ -14,11 +14,13 @@ type List struct {
type ListItem struct {
Bullet string
Status string
Children []Node
}
type DescriptiveListItem struct {
Bullet string
Status string
Term []Node
Details []Node
}
@ -26,6 +28,7 @@ type DescriptiveListItem struct {
var unorderedListRegexp = regexp.MustCompile(`^(\s*)([-]|[+]|[*])\s(.*)`)
var orderedListRegexp = regexp.MustCompile(`^(\s*)(([0-9]+|[a-zA-Z])[.)])\s+(.*)`)
var descriptiveListItemRegexp = regexp.MustCompile(`\s::(\s|$)`)
var listItemStatusRegexp = regexp.MustCompile(`\[( |X|-)\]\s`)
func lexList(line string) (token, bool) {
if m := unorderedListRegexp.FindStringSubmatch(line); m != nil {
@ -79,12 +82,16 @@ func (d *Document) parseList(i int, parentStop stopFn) (int, Node) {
func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
start, nodes, bullet := i, []Node{}, d.tokens[i].matches[2]
minIndent, dterm, content := d.tokens[i].lvl+len(bullet), "", d.tokens[i].content
minIndent, dterm, content, status := d.tokens[i].lvl+len(bullet), "", d.tokens[i].content, ""
if m := listItemStatusRegexp.FindStringSubmatch(content); m != nil {
status, content = m[1], content[len("[ ] "):]
}
if l.Kind == "descriptive" {
if m := descriptiveListItemRegexp.FindStringIndex(content); m != nil {
dterm, content = content[:m[0]], content[m[1]:]
}
}
d.tokens[i] = tokenize(strings.Repeat(" ", minIndent) + content)
stop := func(d *Document, i int) bool {
if parentStop(d, i) {
@ -99,7 +106,7 @@ func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
nodes = append(nodes, node)
}
if l.Kind == "descriptive" {
return i - start, DescriptiveListItem{bullet, d.parseInline(dterm), nodes}
return i - start, DescriptiveListItem{bullet, status, d.parseInline(dterm), nodes}
}
return i - start, ListItem{bullet, nodes}
return i - start, ListItem{bullet, status, nodes}
}

View file

@ -203,6 +203,9 @@ func (w *OrgWriter) writeListItem(li ListItem) {
liWriter.writeNodes(li.Children...)
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
w.WriteString(w.indent + li.Bullet)
if li.Status != "" {
w.WriteString(fmt.Sprintf(" [%s]", li.Status))
}
if len(content) > 0 && content[0] == '\n' {
w.WriteString(content)
} else {
@ -212,6 +215,9 @@ func (w *OrgWriter) writeListItem(li ListItem) {
func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
w.WriteString(w.indent + di.Bullet)
if di.Status != "" {
w.WriteString(fmt.Sprintf(" [%s]", di.Status))
}
indent := w.indent + strings.Repeat(" ", len(di.Bullet)+1)
if len(di.Term) != 0 {
term := w.nodesAsString(di.Term...)

View file

@ -2,14 +2,14 @@
Simple Headline <code class="statistic">[1/2]</code>
</h1>
<ul>
<li>
<li class="checked">
<p>
[X] checked
checked
</p>
</li>
<li>
<li class="unchecked">
<p>
[ ] unchecked
unchecked
</p>
</li>
<li>

View file

@ -1,5 +1,5 @@
<ul>
<li>
<li class="unchecked">
<p>
unordered list item 1
</p>
@ -9,22 +9,22 @@ unordered list item 1
unordered list item 2 - with <code>inline</code> <em>markup</em>
</p>
<ol>
<li>
<li class="indeterminate">
<p>
ordered sublist item 1
</p>
<ol>
<li>
<li class="checked">
<p>
ordered sublist item 1
</p>
</li>
<li>
<li class="unchecked">
<p>
ordered sublist item 2
</p>
</li>
<li>
<li class="checked">
<p>
ordered sublist item 3
</p>
@ -38,7 +38,7 @@ ordered sublist item 2
</li>
</ol>
</li>
<li>
<li class="checked">
<p>
unordered list item 3 - and a <a href="https://example.com">link</a>
and some lines of text
@ -95,20 +95,20 @@ that spans multiple lines
descriptive lists
</p>
<dl>
<dt>
<dt class="unchecked">
term<dd>
<p>
details
continued details
</p>
<dd>
<dt>
<dt class="unchecked">
?<dd>
<p>
details without a term
</p>
<dd>
<dt>
<dt class="checked">
term<dd>
<p>
details on a new line

View file

@ -1,11 +1,11 @@
- unordered list item 1
- [ ] unordered list item 1
- unordered list item 2 - with ~inline~ /markup/
1. ordered sublist item 1
a) ordered sublist item 1
b) ordered sublist item 2
c) ordered sublist item 3
1. [-] ordered sublist item 1
a) [X] ordered sublist item 1
b) [ ] ordered sublist item 2
c) [X] ordered sublist item 3
2. ordered sublist item 2
- unordered list item 3 - and a [[https://example.com][link]]
- [X] unordered list item 3 - and a [[https://example.com][link]]
and some lines of text
1. and another subitem
#+BEGIN_SRC sh
@ -24,10 +24,10 @@
descriptive lists
- term :: details
- [ ] term :: details
continued details
- details without a term
- term ::
- [ ] details without a term
- [X] term ::
details on a new line
- term ::