I need the two BulletList to be treated differently.
The one inside the Div is correctly parsed when I simply return the element in the normal BulletList.
But how to make the walk inside the div work when I change the normal Bulletlist and return RawInline?
# normal chapter
* a normal list
* with items
* or more
* to finish
::: Special
# special chapter
* at the start
* something else
* the end
:::
The expected result would be like this. The items of each list are differently treated.
<h1 class="normalHeader" id="normal-chapter">normal chapter</h1>
<ul>
<li class="normal-item">a normal list</li>
<li class="normal-item">with items</li>
<li class="normal-item">or more</li>
<li class="normal-item">to finish</li>
</ul>
<section id="special-chapter" class="Special" class="specialHeader">
<h1 class="specialHeader">special chapter</h1>
<ul >
<li class="special-item">at the start</li>
<li class="special-item">something else</li>
<li class="special-item">the end</li>
</ul>
</section>
Lua filter:
Div = function (el)
if el.classes[1] == 'Special' then
return pandoc.walk_block(el, {
Header = function(el)
el.attributes['class']='specialHeader'
return el
end,
BulletList = function(el)
print("specialltest")
local mylist ='<ul >\n'
for i, item in ipairs(el.content) do
local first = item[1]
if first then
mylist = mylist .. '<li class="special-item">' .. pandoc.utils.stringify(first) .. '</li>\n'
end
end
mylist = mylist .. '</ul>\n'
return pandoc.RawInline('html', mylist)
end,
})
end
return el
end
Header = function (el)
el.attributes['class']='normalHeader'
return el
end
BulletList = function (el)
print("normalltest")
local mylist ='<ul >\n'
for i, item in ipairs(el.content) do
local first = item[1]
if first then
mylist = mylist .. '<li class="normal-item">' .. pandoc.utils.stringify(first) .. '</li>\n'
end
end
mylist = mylist .. '</ul>\n'
return pandoc.RawInline('html', mylist)
-- works if I return el without treatment
end
Below is a possible way to solve this. It defines two filters, one for the normal environments, one for the special environments inside some divs. The kind of filter to be used is selected inside the div. The filters use a non-standard traversal order (traverse = 'topdown'
). We apply the normal filter to the whole document to make sure that it will be applied to elements not wrapped in a div.
Note that some filter functions now return false
as a second value: this signals to pandoc that the element's subtree should not be filtered any further.
local normal_filter, special_filter
special_filter = {
traverse = 'topdown',
Header = function(el)
el.classes = {'specialHeader'}
return el
end,
BulletList = function (el)
local mylist ='<ul >\n'
for i, item in ipairs(el.content) do
local first = item[1]
if first then
mylist = mylist .. '<li class="special-item">' .. pandoc.utils.stringify(first) .. '</li>\n'
end
end
mylist = mylist .. '</ul>\n'
return pandoc.RawInline('html', mylist)
end
}
normal_filter = {
traverse = 'topdown',
Header = function (el)
el.classes = {'normalHeader'}
return el
end,
BulletList = function (el)
local mylist ='<ul >\n'
for i, item in ipairs(el.content) do
local first = item[1]
if first then
mylist = mylist .. '<li class="normal-item">' .. pandoc.utils.stringify(first) .. '</li>\n'
end
end
mylist = mylist .. '</ul>\n'
return pandoc.RawInline('html', mylist)
end,
Div = function (div)
local filter
if div.classes[1] == 'Special' then
filter = special_filter
else
filter = normal_filter
end
return div:walk(filter), false
end
}
Pandoc = function (doc)
return doc:walk(normal_filter)
end
The reason for the above filter not working is that pandoc traverses the document tree bottom-up, i.e., it processes the deeply nested elements first. So it processes the nested bullet list before it processes the div. After that, the div no longer contains a bullet list but raw content; the latter is not processed by the filter.
That's also why the code did work for the heading: the Header
is modified instead of replaced, so the Div filter can modify it further.