summaryrefslogtreecommitdiff
path: root/support/make4ht/domfilters/make4ht-joincharacters.lua
diff options
context:
space:
mode:
Diffstat (limited to 'support/make4ht/domfilters/make4ht-joincharacters.lua')
-rw-r--r--support/make4ht/domfilters/make4ht-joincharacters.lua85
1 files changed, 85 insertions, 0 deletions
diff --git a/support/make4ht/domfilters/make4ht-joincharacters.lua b/support/make4ht/domfilters/make4ht-joincharacters.lua
new file mode 100644
index 0000000000..99d3058d7d
--- /dev/null
+++ b/support/make4ht/domfilters/make4ht-joincharacters.lua
@@ -0,0 +1,85 @@
+local charclases = {
+ span=true,
+ mn = true,
+}
+
+local function join_characters(obj,par)
+ -- join adjanced span and similar elements inserted by
+ -- tex4ht to just one object.
+ local par = par or {}
+ local options = get_filter_settings "joincharacters"
+ local charclases = options.charclases or par.charclases or charclases
+
+ obj:traverse_elements(function(el)
+ local get_name = function(curr)
+ return string.lower(curr:get_element_name())
+ end
+ local get_class = function(next_el)
+ return next_el:get_attribute("class")
+ end
+ local is_span = function(next_el)
+ return charclases[get_name(next_el)]
+ end
+
+ local function get_next(curr, class)
+ local next_el = curr:get_next_node()
+ if next_el and next_el:is_element() and is_span(next_el) then
+ return next_el
+ -- if the next node is space followed by a matching element, we should add this space
+ elseif next_el and next_el:is_text() and get_next(next_el, class) then
+ local text = next_el._text
+ -- match only text containing just whitespace
+ if text:match("^%s+$") then return next_el end
+ end
+ end
+ -- loop over all elements and test if the current element is in a list of
+ -- processed elements (charclases)
+ if is_span(el) then
+ local next_el = get_next(el)
+ -- loop over the following elements and test whether they are of the same type
+ -- as the current one
+ while next_el do
+ -- save the next element because we will remove it later
+ local real_next = get_next(next_el)
+ if get_name(el) == get_name(next_el) and get_class(el) == get_class(next_el) and not el:get_attribute("id") then
+ -- it the following element match, copy it's children to the current element
+ for _, child in ipairs(next_el:get_children()) do
+ el:add_child_node(child)
+ end
+ -- remove the next element
+ next_el:remove_node()
+ -- add the whitespace
+ elseif next_el:is_text() then
+ local s = next_el._text
+ -- we must create a new node
+ el:add_child_node(el:create_text_node(s))
+ next_el:remove_node()
+ real_next = nil
+ else
+ real_next = nil
+ end
+ -- use the saved element as a next object
+ next_el = real_next
+ end
+ end
+
+ end)
+ -- join text nodes in an element into one
+ obj:traverse_elements(function(el)
+ -- save the text
+ local t = {}
+ local children = el:get_children()
+ for _, x in ipairs(children) do
+ if x:is_text() then
+ t[#t+1] = x._text
+ else
+ return nil
+ end
+ end
+ el._text = table.concat(t)
+ return el
+ end)
+ return obj
+end
+
+return join_characters