summaryrefslogtreecommitdiff
path: root/support/make4ht/domfilters/make4ht-inlinecss.lua
diff options
context:
space:
mode:
Diffstat (limited to 'support/make4ht/domfilters/make4ht-inlinecss.lua')
-rw-r--r--support/make4ht/domfilters/make4ht-inlinecss.lua83
1 files changed, 83 insertions, 0 deletions
diff --git a/support/make4ht/domfilters/make4ht-inlinecss.lua b/support/make4ht/domfilters/make4ht-inlinecss.lua
new file mode 100644
index 0000000000..b086a2fc42
--- /dev/null
+++ b/support/make4ht/domfilters/make4ht-inlinecss.lua
@@ -0,0 +1,83 @@
+local cssquery = require "luaxml-cssquery"
+
+local log = logging.new("inlinecss")
+
+local cssrules = {}
+local cssobj = cssquery()
+
+local function parse_rule(line)
+ -- parse CSS selector and attributes
+ -- they are always on one line in the CSS file produced by TeX4ht
+ local selector, values = line:match("%s*(.-)%s*(%b{})")
+ if values then
+ values = values:sub(2,-2)
+ end
+ return selector, values
+end
+
+local function join_values(old, new)
+ -- correctly joins two attribute lists, depending on the ending
+ local separator = ";"
+ if not old then return new end
+ -- if old already ends with ;, then don't use semicolon as a separator
+ if old:match(";%s*$") then separator = "" end
+ return old .. separator .. new
+end
+
+local function parse_css(filename)
+ local css_file = io.open(filename, "r")
+ if not css_file then return nil, "cannot load css file: " .. (filename or "") end
+ local newlines = {}
+ for line in css_file:lines() do
+ -- match lines that contain # or =, as these can be id or attribute selectors
+ if line:match("[%#%=].-{") then
+ -- update attributes for the current selector
+ local selector, value = parse_rule(line)
+ local oldvalue = cssrules[selector]
+ cssrules[selector] = join_values(oldvalue, value)
+ else
+ newlines[#newlines+1] = line
+ end
+ end
+ -- we need to add css rules
+ for selector, value in pairs(cssrules) do
+ cssobj:add_selector(selector, function(dom) end, {value=value})
+ end
+ css_file:close()
+ -- write new version of the CSS file, without rules for ids and attributes
+ local css_file = io.open(filename, "w")
+ css_file:write(table.concat(newlines, "\n"))
+ css_file:close()
+ return true
+end
+
+local processed = false
+
+-- process the HTML file and insert inline CSS for id and attribute selectors
+return function(dom, par)
+ if not processed then
+ -- process the CSS file before everything else, but only once
+ processed = true
+ local css_file = par.input .. ".css"
+ local status, msg = parse_css(css_file)
+ if not status then log:warning(msg) end
+ end
+ -- loop over all elements in the current page
+ dom:traverse_elements(function(curr)
+ -- use CSS object to match if the current element
+ -- is matched by id attribute selector
+ local matched = cssobj:match_querylist(curr)
+ if #matched > 0 then
+ -- join possible already existing style attribute with values from the CSS file
+ local values = curr:get_attribute("style")
+ -- join values of all matched rules
+ for _,rule in ipairs(matched) do
+ values = join_values(values, rule.params.value)
+ end
+ curr:set_attribute("style", values)
+ end
+
+ end)
+ return dom
+end
+