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:
parent
a60f844e38
commit
7331d24452
7 changed files with 55 additions and 35 deletions
|
@ -10,15 +10,7 @@ Take a look at [[https://niklasfasching.github.io/go-org/][github pages]] for so
|
||||||
- see [[https://github.com/kaushalmodi/ox-hugo/blob/8472cf2d8667754c9da3728255634e8001a1da6d/ox-hugo.el#L1785-L1850][ox-hugo]] for auto generation
|
- see [[https://github.com/kaushalmodi/ox-hugo/blob/8472cf2d8667754c9da3728255634e8001a1da6d/ox-hugo.el#L1785-L1850][ox-hugo]] for auto generation
|
||||||
- improve list parsing
|
- improve list parsing
|
||||||
- handle list items with empty first line
|
- handle list items with empty first line
|
||||||
- handle checkboxes & statistic cookies
|
|
||||||
- handle ordered list overrides [@10]
|
- handle ordered list overrides [@10]
|
||||||
** TODO list checkboxes & statistics [0/2]
|
|
||||||
https://orgmode.org/manual/Checkboxes.html
|
|
||||||
1. [ ] parse checkbox of list item
|
|
||||||
- convert to html radio button unchecked, indeterminate (visual only), checked
|
|
||||||
2. [ ] parse statistic cookies of headlines & first line of list items
|
|
||||||
-convert to =[sub 1<sup>1</sup>⁄<sub>2</sub>] || [90%]=
|
|
||||||
|
|
||||||
* differences to goorgeous
|
* differences to goorgeous
|
||||||
To get a feeling take a look at goorgeous vs go-org html rendering of the examples [[https://niklasfasching.github.io/go-org/go-org-vs-goorgeous][comparison]].
|
To get a feeling take a look at goorgeous vs go-org html rendering of the examples [[https://niklasfasching.github.io/go-org/go-org-vs-goorgeous][comparison]].
|
||||||
Please note that a visual comparison is not fair to goorgeous as the stylesheet is not adapted to it.
|
Please note that a visual comparison is not fair to goorgeous as the stylesheet is not adapted to it.
|
||||||
|
|
19
org/html.go
19
org/html.go
|
@ -34,6 +34,12 @@ var listTags = map[string][]string{
|
||||||
"descriptive": []string{"<dl>", "</dl>"},
|
"descriptive": []string{"<dl>", "</dl>"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var listItemStatuses = map[string]string{
|
||||||
|
" ": "unchecked",
|
||||||
|
"-": "indeterminate",
|
||||||
|
"X": "checked",
|
||||||
|
}
|
||||||
|
|
||||||
func NewHTMLWriter() *HTMLWriter {
|
func NewHTMLWriter() *HTMLWriter {
|
||||||
return &HTMLWriter{
|
return &HTMLWriter{
|
||||||
htmlEscape: true,
|
htmlEscape: true,
|
||||||
|
@ -283,13 +289,22 @@ func (w *HTMLWriter) writeList(l List) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeListItem(li ListItem) {
|
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.writeNodes(li.Children...)
|
||||||
w.WriteString("</li>\n")
|
w.WriteString("</li>\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *HTMLWriter) writeDescriptiveListItem(di DescriptiveListItem) {
|
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 {
|
if len(di.Term) != 0 {
|
||||||
w.writeNodes(di.Term...)
|
w.writeNodes(di.Term...)
|
||||||
} else {
|
} else {
|
||||||
|
|
13
org/list.go
13
org/list.go
|
@ -14,11 +14,13 @@ type List struct {
|
||||||
|
|
||||||
type ListItem struct {
|
type ListItem struct {
|
||||||
Bullet string
|
Bullet string
|
||||||
|
Status string
|
||||||
Children []Node
|
Children []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
type DescriptiveListItem struct {
|
type DescriptiveListItem struct {
|
||||||
Bullet string
|
Bullet string
|
||||||
|
Status string
|
||||||
Term []Node
|
Term []Node
|
||||||
Details []Node
|
Details []Node
|
||||||
}
|
}
|
||||||
|
@ -26,6 +28,7 @@ type DescriptiveListItem struct {
|
||||||
var unorderedListRegexp = regexp.MustCompile(`^(\s*)([-]|[+]|[*])\s(.*)`)
|
var unorderedListRegexp = regexp.MustCompile(`^(\s*)([-]|[+]|[*])\s(.*)`)
|
||||||
var orderedListRegexp = regexp.MustCompile(`^(\s*)(([0-9]+|[a-zA-Z])[.)])\s+(.*)`)
|
var orderedListRegexp = regexp.MustCompile(`^(\s*)(([0-9]+|[a-zA-Z])[.)])\s+(.*)`)
|
||||||
var descriptiveListItemRegexp = regexp.MustCompile(`\s::(\s|$)`)
|
var descriptiveListItemRegexp = regexp.MustCompile(`\s::(\s|$)`)
|
||||||
|
var listItemStatusRegexp = regexp.MustCompile(`\[( |X|-)\]\s`)
|
||||||
|
|
||||||
func lexList(line string) (token, bool) {
|
func lexList(line string) (token, bool) {
|
||||||
if m := unorderedListRegexp.FindStringSubmatch(line); m != nil {
|
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) {
|
func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
|
||||||
start, nodes, bullet := i, []Node{}, d.tokens[i].matches[2]
|
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 l.Kind == "descriptive" {
|
||||||
if m := descriptiveListItemRegexp.FindStringIndex(content); m != nil {
|
if m := descriptiveListItemRegexp.FindStringIndex(content); m != nil {
|
||||||
dterm, content = content[:m[0]], content[m[1]:]
|
dterm, content = content[:m[0]], content[m[1]:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d.tokens[i] = tokenize(strings.Repeat(" ", minIndent) + content)
|
d.tokens[i] = tokenize(strings.Repeat(" ", minIndent) + content)
|
||||||
stop := func(d *Document, i int) bool {
|
stop := func(d *Document, i int) bool {
|
||||||
if parentStop(d, i) {
|
if parentStop(d, i) {
|
||||||
|
@ -99,7 +106,7 @@ func (d *Document) parseListItem(l List, i int, parentStop stopFn) (int, Node) {
|
||||||
nodes = append(nodes, node)
|
nodes = append(nodes, node)
|
||||||
}
|
}
|
||||||
if l.Kind == "descriptive" {
|
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}
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,6 +203,9 @@ func (w *OrgWriter) writeListItem(li ListItem) {
|
||||||
liWriter.writeNodes(li.Children...)
|
liWriter.writeNodes(li.Children...)
|
||||||
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
|
content := strings.TrimPrefix(liWriter.String(), liWriter.indent)
|
||||||
w.WriteString(w.indent + li.Bullet)
|
w.WriteString(w.indent + li.Bullet)
|
||||||
|
if li.Status != "" {
|
||||||
|
w.WriteString(fmt.Sprintf(" [%s]", li.Status))
|
||||||
|
}
|
||||||
if len(content) > 0 && content[0] == '\n' {
|
if len(content) > 0 && content[0] == '\n' {
|
||||||
w.WriteString(content)
|
w.WriteString(content)
|
||||||
} else {
|
} else {
|
||||||
|
@ -212,6 +215,9 @@ func (w *OrgWriter) writeListItem(li ListItem) {
|
||||||
|
|
||||||
func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
|
func (w *OrgWriter) writeDescriptiveListItem(di DescriptiveListItem) {
|
||||||
w.WriteString(w.indent + di.Bullet)
|
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)
|
indent := w.indent + strings.Repeat(" ", len(di.Bullet)+1)
|
||||||
if len(di.Term) != 0 {
|
if len(di.Term) != 0 {
|
||||||
term := w.nodesAsString(di.Term...)
|
term := w.nodesAsString(di.Term...)
|
||||||
|
|
8
org/testdata/headlines.html
vendored
8
org/testdata/headlines.html
vendored
|
@ -2,14 +2,14 @@
|
||||||
Simple Headline <code class="statistic">[1/2]</code>
|
Simple Headline <code class="statistic">[1/2]</code>
|
||||||
</h1>
|
</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li class="checked">
|
||||||
<p>
|
<p>
|
||||||
[X] checked
|
checked
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="unchecked">
|
||||||
<p>
|
<p>
|
||||||
[ ] unchecked
|
unchecked
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
18
org/testdata/lists.html
vendored
18
org/testdata/lists.html
vendored
|
@ -1,5 +1,5 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li class="unchecked">
|
||||||
<p>
|
<p>
|
||||||
unordered list item 1
|
unordered list item 1
|
||||||
</p>
|
</p>
|
||||||
|
@ -9,22 +9,22 @@ unordered list item 1
|
||||||
unordered list item 2 - with <code>inline</code> <em>markup</em>
|
unordered list item 2 - with <code>inline</code> <em>markup</em>
|
||||||
</p>
|
</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li class="indeterminate">
|
||||||
<p>
|
<p>
|
||||||
ordered sublist item 1
|
ordered sublist item 1
|
||||||
</p>
|
</p>
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li class="checked">
|
||||||
<p>
|
<p>
|
||||||
ordered sublist item 1
|
ordered sublist item 1
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="unchecked">
|
||||||
<p>
|
<p>
|
||||||
ordered sublist item 2
|
ordered sublist item 2
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="checked">
|
||||||
<p>
|
<p>
|
||||||
ordered sublist item 3
|
ordered sublist item 3
|
||||||
</p>
|
</p>
|
||||||
|
@ -38,7 +38,7 @@ ordered sublist item 2
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li class="checked">
|
||||||
<p>
|
<p>
|
||||||
unordered list item 3 - and a <a href="https://example.com">link</a>
|
unordered list item 3 - and a <a href="https://example.com">link</a>
|
||||||
and some lines of text
|
and some lines of text
|
||||||
|
@ -95,20 +95,20 @@ that spans multiple lines
|
||||||
descriptive lists
|
descriptive lists
|
||||||
</p>
|
</p>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>
|
<dt class="unchecked">
|
||||||
term<dd>
|
term<dd>
|
||||||
<p>
|
<p>
|
||||||
details
|
details
|
||||||
continued details
|
continued details
|
||||||
</p>
|
</p>
|
||||||
<dd>
|
<dd>
|
||||||
<dt>
|
<dt class="unchecked">
|
||||||
?<dd>
|
?<dd>
|
||||||
<p>
|
<p>
|
||||||
details without a term
|
details without a term
|
||||||
</p>
|
</p>
|
||||||
<dd>
|
<dd>
|
||||||
<dt>
|
<dt class="checked">
|
||||||
term<dd>
|
term<dd>
|
||||||
<p>
|
<p>
|
||||||
details on a new line
|
details on a new line
|
||||||
|
|
18
org/testdata/lists.org
vendored
18
org/testdata/lists.org
vendored
|
@ -1,11 +1,11 @@
|
||||||
- unordered list item 1
|
- [ ] unordered list item 1
|
||||||
- unordered list item 2 - with ~inline~ /markup/
|
- unordered list item 2 - with ~inline~ /markup/
|
||||||
1. ordered sublist item 1
|
1. [-] ordered sublist item 1
|
||||||
a) ordered sublist item 1
|
a) [X] ordered sublist item 1
|
||||||
b) ordered sublist item 2
|
b) [ ] ordered sublist item 2
|
||||||
c) ordered sublist item 3
|
c) [X] ordered sublist item 3
|
||||||
2. ordered sublist item 2
|
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
|
and some lines of text
|
||||||
1. and another subitem
|
1. and another subitem
|
||||||
#+BEGIN_SRC sh
|
#+BEGIN_SRC sh
|
||||||
|
@ -24,10 +24,10 @@
|
||||||
|
|
||||||
|
|
||||||
descriptive lists
|
descriptive lists
|
||||||
- term :: details
|
- [ ] term :: details
|
||||||
continued details
|
continued details
|
||||||
- details without a term
|
- [ ] details without a term
|
||||||
- term ::
|
- [X] term ::
|
||||||
details on a new line
|
details on a new line
|
||||||
- term ::
|
- term ::
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue