summaryrefslogtreecommitdiff
path: root/html.lua
blob: 87ecc53d3a181a64b2c8c74b4c08f9da244fc8f4 (plain)
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
84
85
86
87
local function fmt_attrs(attrs)
	local function fmt_attr(k,v)
		if v == true then
			return k
		else
			if type(v) == "table" then v = table.concat(v," ") end
			return ('%s="%s"'):format(k,v)
		end
	end

	local o = ""
	for k,v in pairs(attrs) do
		o = o .. " " .. fmt_attr(k,v)
	end
	return o
end

local html
local function fmt_tag(tag)
	local attrs = tag.attrs and fmt_attrs(tag.attrs) or ""
	local selfclosing = (tag.body == "")
	local sameline = type(tag.body) == "string" or (type(tag.body) == "table" and tag.body.tag)
	local maybenl = sameline and "" or "\n"
	if selfclosing then
		return ("<%s%s/>"):format(tag.tname,attrs)
	else
		return ("<%s%s>%s%s</%s>"):format(tag.tname,attrs,maybenl,html(tag.body),tag.tname)
	end
end

local function tag(tname, a1, a2)
	-- tag(tname,body) or tag(tname,attrs,body)
	local body, attrs
	if a2 then attrs=a1 body=a2 else attrs=nil body=a1 end
	return setmetatable({tag=true,tname=tname,attrs=attrs,body=body},{__tostring=fmt_tag})
end

-- instead of tag('ul', {x, y, z})
-- you can do T.ul{ x, y, z}
local T = setmetatable({}, {__index=function(_,tname)
	return function (...)
		return tag(tname, ...)
	end
end})

local function safe(s)
	-- marks s as safe, doesn't escape it
	assert(type(s) == "string","can only mark string as safe")
	return setmetatable({safe=true,s=s},{__tostring=function(x)return x.s end})
end

local function escape(s)
	s=s:gsub("&","&amp;")
	s=s:gsub("<","&lt;")
	s=s:gsub(">","&gt;")
	s=s:gsub('"',"&quot;")
	return safe(s)
end


html = function (x)
	if type(x) == "string" then
		return escape(x)
	elseif type(x) == "table" then
		if x.safe then
			-- safestr. already escaped
			return x
		elseif x.tag then
			-- it's a tag
			return safe( tostring(x) )
		else
			-- just a regular list
			local o = ""
			for _,item in ipairs(x) do
				o = o .. tostring(html(item)) .. "\n"
			end
			return safe(o)
		end
	end
end

return {
	html = html,
	tag = tag,
	safe = safe,
	T = T,
}