summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/make4ht/domfilters
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/make4ht/domfilters')
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua198
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua8
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua3
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua9
-rw-r--r--Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua58
7 files changed, 275 insertions, 7 deletions
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua
index 0b93c958404..4a21c893323 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-aeneas.lua
@@ -5,6 +5,7 @@
--
local cssquery = require "luaxml-cssquery"
local mkutils = require "mkutils"
+local log = logging.new "aeneas"
-- Table of CSS selectors to be skipped.
local skip_elements = { "math", "svg"}
@@ -111,7 +112,7 @@ local function aeneas(dom, par)
then
local idtitle
idtitle, id = make_id(id, id_prefix)
- print(el._name, first_child._text)
+ log:debug(el._name, first_child._text)
el:set_attribute("id", idtitle)
return el
end
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua
new file mode 100644
index 00000000000..0b77b9dbbba
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-collapsetoc.lua
@@ -0,0 +1,198 @@
+local domobject = require "luaxml-domobject"
+
+local filter = require "make4ht-filter"
+local log = logging.new "collapsetoc"
+
+
+local toc_levels = {"partToc", "chapterToc", "sectionToc", "subsectionToc", "subsubsectionToc"}
+
+local debug_print = function(...) log:debug(...) end
+
+
+-- return toc element type and it's id
+local function get_id(el)
+ local name = el:get_attribute "class"
+ local id
+ local a = el:query_selector "a" or {}
+ local first = a[1]
+ if first then
+ local href = first:get_attribute "href"
+ id = href:match("#(.+)$")
+ end
+ return name, id
+end
+
+local function remove_sections(part_elements, currentpart)
+ -- we need to remove toc entries from the previous part if the
+ -- current document isn't part of it
+ if currentpart == false then
+ for _, part in ipairs(part_elements) do
+ part:remove_node()
+ end
+ end
+end
+
+local function make_toc_selector(toc_levels)
+ local level_classes = {}
+ for _, l in ipairs(toc_levels) do
+ level_classes[#level_classes+1] = "." .. l
+ end
+ return table.concat(level_classes, ", ")
+end
+
+local function find_toc_levels(toc)
+ -- find toc levels used in the document
+ -- it ecpects that sectioning levels appears in the TOC in the descending order
+ local levels, used = {}, {}
+ local level = 1
+ -- we still expect the standard class names
+ local toc_selector = make_toc_selector(toc_levels)
+ for _, el in ipairs(toc:query_selector(toc_selector)) do
+ local class = el:get_attribute("class")
+ if not used[class] then
+ table.insert(levels, class)
+ used[class] = level
+ level = level + 1
+ end
+ end
+ return levels, used
+end
+
+local function remove_levels(toc, matched_ids)
+ -- sort the matched sections according to their levels
+ local levels, level_numbers = find_toc_levels(toc)
+ debug_print("remove levels", #levels)
+ -- for _, level in ipairs(levels) do
+ -- print(level, level_numbers[level], matched_ids[level])
+ -- end
+ local keep_branch = false
+ local matched_levels = {}
+ local toc_selector = make_toc_selector(toc_levels)
+ for _, el in ipairs(toc:query_selector(toc_selector)) do
+ local name, id = get_id(el)
+ -- get the current toc hiearchy level
+ local level = level_numbers[name]
+ -- get the matched id for the current level
+ local level_id = matched_ids[name]
+ local matched = level_id == id
+ local remove = true
+ -- we will use this for toc elements at lower hiearchy than is the top sectioning level on the page
+ if matched then keep_branch = true end
+ -- find the parent level to the current section level
+ local parent_level = toc_levels[level - 1]
+ local parent_matched = matched_levels[parent_level]
+ if matched then
+ debug_print("match",name, id, level_id, level, #levels)
+ keep_branch = true
+ remove = false
+ elseif level==1 then
+ -- don't remove the top level
+ debug_print("part",name, id, level_id, level)
+ remove = false
+ matched_levels = {}
+ if not matched then keep_branch = false end
+ elseif keep_branch then
+ -- if level >= (#levels - 1) then
+ if level > matched_ids._levels then
+ debug_print("level",name, id, level_id, level, parent_level, parent_matched)
+ remove = false
+ elseif matched_ids.ids[id] then
+ debug_print("matched id",name, id, level_id, level, parent_level, parent_matched)
+ remove = false
+ elseif parent_matched then
+ debug_print("parent_matched",name, id, level_id, level, parent_level, parent_matched)
+ keep_branch = false
+ remove = false
+ end
+ -- else
+ -- print("remove", name, id, level_id, level, #matched_ids)
+ -- end
+ elseif parent_matched then
+ debug_print("parent_matched alternative",name, id, level_id, level, parent_level, parent_matched)
+ remove = false
+ else
+ debug_print("else",name, id, level_id, level, keep_branch)
+ keep_branch = false
+ end
+ matched_levels[name] = matched
+ if remove then
+ el:remove_node()
+ --print(name,id, level_id, matched)
+ end
+ end
+
+end
+
+
+
+
+
+-- local process = filter{ function(s)
+ -- local dom = domobject.parse(s)
+local function collapse_toc(dom, par)
+ -- set options
+ local options = get_filter_settings "collapsetoc"
+ local toc_query = par.toc_query or options.toc_query or ".tableofcontents"
+ local title_query = par.title_query or options.title_query or ".partHead a, .chapterHead a, .sectionHead a, .subsectionHead a"
+ toc_levels = par.toc_levels or options.toc_levels or toc_levels
+ -- keep track of current id of each sectioning level
+ local current_ids, matched_ids = {}, {_levels = 0, ids = {}}
+ -- search sectioning elements
+ local titles = dom:query_selector(title_query)
+ local section_ids = {}
+ for _, x in ipairs(titles) do
+ -- get their id attributes and save them in a table
+ section_ids[#section_ids+1] = x:get_attribute("id")
+ end
+
+ -- we need to retrieve the first table of contents
+ local toctables = dom:query_selector(toc_query) or {}
+ -- process only when we got a TOC
+ debug_print("toc query", toc_query, #toctables)
+ if #toctables > 0 then
+ local tableofcontents = toctables[1]
+ -- all toc entries are in span elements
+ local toc = tableofcontents:query_selector("span")
+ local currentpart = false
+ local part_elements = {}
+ for _, el in ipairs(toc) do
+ -- get sectioning level and id of the current TOC entry
+ local name, id = get_id(el)
+ -- set the id of the current sectioning level
+ current_ids[name] = id
+ for _, sectid in ipairs(section_ids) do
+ -- detect if the current TOC entry match some sectioning element in the current document
+ if id == sectid then
+ currentpart = true
+ -- save the current id as a matched id
+ matched_ids.ids[id] = true
+ -- copy the TOC hiearchy for the current toc level
+ for i, level in ipairs(toc_levels) do
+ -- print("xxx",i, level, current_ids[level])
+ matched_ids[level] = current_ids[level]
+ -- set the maximum matched level
+ if i > matched_ids._levels then matched_ids._levels = i end
+ if level == name then break end
+ end
+ debug_print("match", id)
+ end
+ end
+ end
+ remove_levels(tableofcontents, matched_ids)
+
+ -- remove sections from the last part
+ -- remove_sections(part_elements,currentpart)
+ -- remove unneeded br elements
+ local br = tableofcontents:query_selector("br")
+ for _, el in ipairs(br) do el:remove_node() end
+ -- remove unneded whitespace
+ for _, el in ipairs(tableofcontents:get_children()) do
+ if el:is_text() then el:remove_node() end
+ end
+ end
+ return dom
+end
+
+return collapse_toc
+
+-- Make:match("html$", process)
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua
index 99d3058d7dd..30ed6e1382a 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincharacters.lua
@@ -1,4 +1,4 @@
-local charclases = {
+local charclasses = {
span=true,
mn = true,
}
@@ -8,7 +8,7 @@ local function join_characters(obj,par)
-- tex4ht to just one object.
local par = par or {}
local options = get_filter_settings "joincharacters"
- local charclases = options.charclases or par.charclases or charclases
+ local charclasses = options.charclasses or par.charclasses or charclasses
obj:traverse_elements(function(el)
local get_name = function(curr)
@@ -18,7 +18,7 @@ local function join_characters(obj,par)
return next_el:get_attribute("class")
end
local is_span = function(next_el)
- return charclases[get_name(next_el)]
+ return charclasses[get_name(next_el)]
end
local function get_next(curr, class)
@@ -33,7 +33,7 @@ local function join_characters(obj,par)
end
end
-- loop over all elements and test if the current element is in a list of
- -- processed elements (charclases)
+ -- processed elements (charclasses)
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
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua
index 94a3a054e61..730f66a7a0d 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-joincolors.lua
@@ -1,4 +1,5 @@
local cssfiles = {}
+local log = logging.new "joincolors"
-- keep mapping between span ids and colors
@@ -45,7 +46,7 @@ local function process_css_files(dom)
for _, el in ipairs(dom:query_selector("link")) do
local href = el:get_attribute("href") or ""
if not cssfiles[href] and href:match("css$") then
- print("Load CSS file ", href)
+ log:debug("Load CSS file ", href)
cssfiles[href] = true
process_css(href)
end
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua
index 4ce8f0d92ea..2b87372fdb1 100644
--- a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtimagesize.lua
@@ -1,3 +1,4 @@
+local log = logging.new "odtimagesize"
-- set correct dimensions to frames around images
return function(dom)
local frames = dom:query_selector("draw|frame")
@@ -9,7 +10,7 @@ return function(dom)
local height = image:get_attribute("svg:height")
if widht then frame:set_attribute("svg:width", width) end
if height then frame:set_attribute("svg:height", height) end
- print("image dimensions", width, height)
+ log:debug("image dimensions", width, height)
end
end
return dom
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua
new file mode 100644
index 00000000000..f4e84b55d96
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-odtpartable.lua
@@ -0,0 +1,9 @@
+-- find all tables inside paragraphs, replace the found paragraphs with the child table
+return function(dom)
+ for _,table in ipairs(dom:query_selector("text|p table|table")) do
+ -- replace the paragraph by its child element
+ local parent = table:get_parent()
+ parent:replace_node(table)
+ end
+ return dom
+end
diff --git a/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua
new file mode 100644
index 00000000000..155c24529ac
--- /dev/null
+++ b/Master/texmf-dist/scripts/make4ht/domfilters/make4ht-tablerows.lua
@@ -0,0 +1,58 @@
+local log = logging.new ("tablerows")
+return function(dom)
+ local is_empty_row = function(row)
+ local not_empty = false
+ local element_count = 0
+ -- ignore hline rows
+ local row_class = row:get_attribute("class")
+ if row_class == "hline" or row_class == "cline" then return false end
+ -- detect if the row contain only one empty child
+ for _,child in ipairs(row:get_children() or {}) do
+ if child:is_element() then
+ element_count = element_count + 1
+ -- empty rows contain only one element, it is not empty otherwise
+ if element_count > 1 then return false end
+ -- detect if it contains only whitespace
+ not_empty = child:get_text():gsub("%s","") ~= "" or not_empty
+ end
+ end
+ -- print("element count", element_count, not_empty)
+ return element_count == 1 and not_empty == false
+ end
+ local is_not_styled = function(row, css)
+ -- get the id attribute and escape it, so it can be used in regexp
+ local id = row:get_attribute("id")
+ if not id then return true end -- no styling without id
+ local search_term = "%#" .. id:gsub("%-", "%%-")
+ -- if the CSS file contains the row id (<td> elements can also have id
+ -- that matches this pattern, so we should keep the row if we match them too)
+ return not css:match(search_term)
+ end
+ local load_css_files = function()
+ -- the empty rows can be styled using CSS, for example configuration for
+ -- Booktabs does that. We shouldn't remove such rows.
+ local cssfiles = {}
+ for _, link in ipairs(dom:query_selector("head link")) do
+ local src = link:get_attribute("href")
+ if src then
+ local f = io.open(src, "r")
+ if f then
+ local contents = f:read("*all")
+ f:close()
+ table.insert(cssfiles, contents)
+ end
+ end
+ end
+ return table.concat(cssfiles, "\n")
+ end
+ local css = load_css_files()
+ for _, tbl in ipairs(dom:query_selector("table")) do
+ -- find the empty rows
+ for _, row in ipairs(tbl:query_selector("tr")) do
+ if is_empty_row(row) and is_not_styled(row, css) then row:remove_node() end
+ end
+
+ end
+ return dom
+end
+