1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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 = mkutils.file_in_builddir(par.input .. ".css", par)
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
|