summaryrefslogtreecommitdiff
path: root/support/make4ht/domfilters/make4ht-mathmlfixes.lua
diff options
context:
space:
mode:
Diffstat (limited to 'support/make4ht/domfilters/make4ht-mathmlfixes.lua')
-rw-r--r--support/make4ht/domfilters/make4ht-mathmlfixes.lua120
1 files changed, 106 insertions, 14 deletions
diff --git a/support/make4ht/domfilters/make4ht-mathmlfixes.lua b/support/make4ht/domfilters/make4ht-mathmlfixes.lua
index 7fa74f4632..fe8384619a 100644
--- a/support/make4ht/domfilters/make4ht-mathmlfixes.lua
+++ b/support/make4ht/domfilters/make4ht-mathmlfixes.lua
@@ -35,10 +35,39 @@ local function update_element_name(el, name, prefix)
el._name = newname
end
-local function create_element(el, name, prefix)
- return el:create_element(newname)
+local function create_element(el, name, prefix, attributes)
+ local attributes = attributes or {}
+ local newname = get_new_element_name(name, prefix)
+ return el:create_element(newname, attributes)
end
+local function element_pos(el)
+ local pos, count = 0, 0
+ for _, node in ipairs(el:get_siblings()) do
+ if node:is_element() then
+ count = count + 1
+ if node == el then
+ pos = count
+ end
+ end
+ end
+ return pos, count
+end
+
+-- test if element is the first element in the current element list
+local function is_first_element(el)
+ local pos, count = element_pos(el)
+ return pos == 1
+end
+
+-- test if element is the last element in the current element list
+local function is_last_element(el)
+ local pos, count = element_pos(el)
+ return pos == count
+end
+
+
+
local function is_token_element(el)
local name, prefix = get_element_name(el)
return token_elements[name], prefix
@@ -275,6 +304,14 @@ end
local function fix_numbers(el)
-- convert <mn>1</mn><mo>.</mo><mn>3</mn> to <mn>1.3</mn>
if get_element_name(el) == "mn" then
+ -- sometimes minus sign can be outside <mn>
+ local x = el:get_sibling_node(-1)
+ if x and x:is_text()
+ and x:get_text() == "−"
+ then
+ el:add_child_node(x:copy_node(), 1)
+ x:remove_node()
+ end
local n = el:get_sibling_node(1)
-- test if next element is <mo class="MathClass-punc">.</mo>
if n and n:is_element()
@@ -357,18 +394,45 @@ local function fix_operators(x)
end
end
-local function is_last_element(el)
- local siblings = el:get_siblings()
- -- return true only if the current element is the last in the parent's children
- for i = #siblings, 1, -1 do
- local curr = siblings[i]
- if curr == el then
- return true
- elseif curr:is_element() then
- return false
- end
- end
- return false
+local function get_third_parent(el)
+ local first = el:get_parent()
+ if not first then return nil end
+ local second = first:get_parent()
+ if not second then return nil end
+ return second:get_parent()
+end
+
+local function add_space(el, pos)
+ local parent = el:get_parent()
+ local name, prefix = get_element_name(el)
+ local space = create_element(parent, "mspace", prefix)
+ space:set_attribute("width", "0.3em")
+ parent:add_child_node(space, pos)
+end
+
+local function fix_dcases(el)
+ -- we need to fix spacing in dcases* environments
+ -- when you use something like:
+ -- \begin{dcases*}
+ -- 1 & if $a=b$ then
+ -- \end{dcases*}
+ -- the spaces around $a=b$ will be missing
+ -- we detect if the <mtext> elements contains spaces that are collapsed by the browser, and add explicit <mspace>
+ -- elements when necessary
+ if el:get_element_name() == "mtext" then
+ local parent = get_third_parent(el)
+ if parent and parent:get_element_name() == "mtable" and parent:get_attribute("class") == "dcases-star" then
+ local text = el:get_text()
+ local pos = el:find_element_pos()
+ if pos == 1 and text:match("%s$") then
+ add_space(el, 2)
+ elseif text:match("^%s") and not el._used then
+ add_space(el, pos)
+ -- this is necessary to avoid infinite loop, we mark this element as processed
+ el._used = true
+ end
+ end
+ end
end
local function is_empty_row(el)
@@ -378,6 +442,9 @@ local function is_empty_row(el)
for _, child in ipairs(el:get_children()) do
if child:is_element() then count = count + 1 end
end
+ else
+ -- row is not empty if it contains any text
+ return false
end
-- if there is one or zero childrens, then it is empty row
return count < 2
@@ -398,6 +465,29 @@ local function delete_last_empty_mtr(el)
end
+local function fix_rel_mo(el)
+ -- this is necessary for LibreOffice. It has a problem with relative <mo> that are
+ -- first childs in an element list. This often happens in equations, where first
+ -- element in a table column is an operator, like non-equal-, less-than etc.
+ local el_name, prefix = get_element_name(el)
+ if el_name == "mo"
+ and not get_attribute(el, "fence") -- ignore fences
+ and not get_attribute(el, "form") -- these should be also ignored
+ and not get_attribute(el, "accent") -- and accents too
+ then
+ local parent = el:get_parent()
+ if is_first_element(el) then
+ local mrow = create_element(parent, "mrow", prefix)
+ parent:add_child_node(mrow, 1)
+ elseif is_last_element(el) then
+ local mrow = create_element(parent, "mrow", prefix)
+ parent:add_child_node(mrow)
+ end
+ end
+
+end
+
+
return function(dom)
dom:traverse_elements(function(el)
if settings.output_format ~= "odt" then
@@ -405,6 +495,7 @@ return function(dom)
fix_mfenced(el)
else
fix_mo_to_mfenced(el)
+ fix_rel_mo(el)
end
fix_radicals(el)
fix_token_elements(el)
@@ -413,6 +504,7 @@ return function(dom)
fix_numbers(el)
fix_operators(el)
fix_mathvariant(el)
+ fix_dcases(el)
top_mrow(el)
delete_last_empty_mtr(el)
end)