模块:HtmlBuilder:修订间差异
来自末世录
更多操作
小 导入1个版本 |
无编辑摘要 标签:已被回退 |
||
| 第1行: | 第1行: | ||
-- Module | -- Module:HtmlBuilder - 安全版本,修复 tagName 为表导致的错误 | ||
local HtmlBuilder = {} | local HtmlBuilder = {} | ||
local metatable = {} | local metatable = {} | ||
-- 辅助函数:确保值为字符串,非字符串则尝试转换 | |||
local function ensureString(v) | |||
if v == nil then return nil end | |||
if type(v) == 'string' then return v end | |||
return tostring(v) | |||
end | |||
metatable.__index = function(t, key) | metatable.__index = function(t, key) | ||
| 第28行: | 第35行: | ||
metatable._build = function(t, ret) | metatable._build = function(t, ret) | ||
if t.tagName then | if t.tagName and type(t.tagName) == 'string' then | ||
table.insert(ret, '<' .. t.tagName) | table.insert(ret, '<' .. t.tagName) | ||
for i, attr in ipairs(t.attributes) do | for i, attr in ipairs(t.attributes) do | ||
| 第36行: | 第43行: | ||
table.insert(ret, ' style="') | table.insert(ret, ' style="') | ||
for i, prop in ipairs(t.styles) do | for i, prop in ipairs(t.styles) do | ||
if type(prop) == 'string' then | if type(prop) == 'string' then | ||
table.insert(ret, prop .. ';') | table.insert(ret, prop .. ';') | ||
else | else | ||
table.insert(ret, prop.name .. ':' .. prop.val .. ';') | table.insert(ret, prop.name .. ':' .. prop.val .. ';') | ||
end | end | ||
| 第47行: | 第54行: | ||
table.insert(ret, ' /') | table.insert(ret, ' /') | ||
end | end | ||
table.insert(ret, '>') | table.insert(ret, '>') | ||
end | end | ||
for i, node in ipairs(t.nodes) do | for i, node in ipairs(t.nodes) do | ||
| 第58行: | 第65行: | ||
end | end | ||
end | end | ||
if t.tagName and not t.unclosed and not t.selfClosing then | if t.tagName and type(t.tagName) == 'string' and not t.unclosed and not t.selfClosing then | ||
table.insert(ret, '</' .. t.tagName .. '>') | table.insert(ret, '</' .. t.tagName .. '>') | ||
end | end | ||
| 第88行: | 第95行: | ||
args = args or {} | args = args or {} | ||
args.parent = t | args.parent = t | ||
local builder = HtmlBuilder.create( | local safeTagName = ensureString(tagName) | ||
if not safeTagName then | |||
error("HtmlBuilder.tag: tagName 必须是字符串,传入类型为 " .. type(tagName)) | |||
end | |||
local builder = HtmlBuilder.create(safeTagName, args) | |||
table.insert(t.nodes, builder) | table.insert(t.nodes, builder) | ||
return builder | return builder | ||
| 第102行: | 第113行: | ||
metatable.attr = function(t, name, val) | metatable.attr = function(t, name, val) | ||
if | if val ~= nil then | ||
local nameStr = ensureString(name) | |||
if | local valStr = ensureString(val) | ||
t.styles = { | if nameStr == 'style' then | ||
t.styles = {valStr} | |||
return t | return t | ||
end | end | ||
local attr = getAttr(t, | local attr = getAttr(t, nameStr) | ||
if attr then | if attr then | ||
attr.val = | attr.val = valStr | ||
else | else | ||
table.insert(t.attributes, {name = | table.insert(t.attributes, {name = nameStr, val = valStr}) | ||
end | end | ||
end | end | ||
| 第122行: | 第134行: | ||
metatable.addClass = function(t, class) | metatable.addClass = function(t, class) | ||
if class then | if class then | ||
local attr = getAttr(t, 'class') | local classStr = ensureString(class) | ||
if classStr then | |||
local attr = getAttr(t, 'class') | |||
if attr then | |||
attr.val = attr.val .. ' ' .. classStr | |||
else | |||
t.attr('class', classStr) | |||
end | |||
end | end | ||
end | end | ||
| 第134行: | 第149行: | ||
metatable.css = function(t, name, val) | metatable.css = function(t, name, val) | ||
if | if name and val then | ||
local nameStr = ensureString(name) | |||
local valStr = ensureString(val) | |||
for i, prop in ipairs(t.styles) do | for i, prop in ipairs(t.styles) do | ||
if prop.name == | if prop.name == nameStr then | ||
prop.val = | prop.val = valStr | ||
return t | return t | ||
end | end | ||
end | end | ||
table.insert(t.styles, {name = | table.insert(t.styles, {name = nameStr, val = valStr}) | ||
end | end | ||
| 第150行: | 第167行: | ||
metatable.cssText = function(t, css) | metatable.cssText = function(t, css) | ||
if css then | if css then | ||
table.insert(t.styles, css) | table.insert(t.styles, ensureString(css)) | ||
end | end | ||
return t | return t | ||
| 第168行: | 第185行: | ||
function HtmlBuilder.create(tagName, args) | function HtmlBuilder.create(tagName, args) | ||
args = args or {} | args = args or {} | ||
local safeTagName = ensureString(tagName) | |||
if not safeTagName then | |||
error("HtmlBuilder.create: tagName 必须是字符串,传入类型为 " .. type(tagName)) | |||
end | |||
local builder = {} | local builder = {} | ||
setmetatable(builder, metatable) | setmetatable(builder, metatable) | ||
| 第173行: | 第194行: | ||
builder.attributes = {} | builder.attributes = {} | ||
builder.styles = {} | builder.styles = {} | ||
builder.tagName = | builder.tagName = safeTagName | ||
builder.parent = args.parent | builder.parent = args.parent | ||
builder.unclosed = args.unclosed or false | builder.unclosed = args.unclosed or false | ||
2026年3月28日 (六) 19:50的版本
此模块的文档可以在模块:HtmlBuilder/doc创建
-- Module:HtmlBuilder - 安全版本,修复 tagName 为表导致的错误
local HtmlBuilder = {}
local metatable = {}
-- 辅助函数:确保值为字符串,非字符串则尝试转换
local function ensureString(v)
if v == nil then return nil end
if type(v) == 'string' then return v end
return tostring(v)
end
metatable.__index = function(t, key)
local ret = rawget(t, key)
if ret then
return ret
end
ret = metatable[key]
if type(ret) == 'function' then
return function(...)
return ret(t, ...)
end
else
return ret
end
end
metatable.__tostring = function(t)
local ret = {}
t._build(ret)
return table.concat(ret)
end
metatable._build = function(t, ret)
if t.tagName and type(t.tagName) == 'string' then
table.insert(ret, '<' .. t.tagName)
for i, attr in ipairs(t.attributes) do
table.insert(ret, ' ' .. attr.name .. '="' .. attr.val .. '"')
end
if #t.styles > 0 then
table.insert(ret, ' style="')
for i, prop in ipairs(t.styles) do
if type(prop) == 'string' then
table.insert(ret, prop .. ';')
else
table.insert(ret, prop.name .. ':' .. prop.val .. ';')
end
end
table.insert(ret, '"')
end
if t.selfClosing then
table.insert(ret, ' /')
end
table.insert(ret, '>')
end
for i, node in ipairs(t.nodes) do
if node then
if type(node) == 'table' then
node._build(ret)
else
table.insert(ret, tostring(node))
end
end
end
if t.tagName and type(t.tagName) == 'string' and not t.unclosed and not t.selfClosing then
table.insert(ret, '</' .. t.tagName .. '>')
end
end
metatable.node = function(t, builder)
if builder then
table.insert(t.nodes, builder)
end
return t
end
metatable.wikitext = function(t, ...)
local vals = {...}
for i = 1, #vals do
if vals[i] then
table.insert(t.nodes, vals[i])
end
end
return t
end
metatable.newline = function(t)
table.insert(t.nodes, '\n')
return t
end
metatable.tag = function(t, tagName, args)
args = args or {}
args.parent = t
local safeTagName = ensureString(tagName)
if not safeTagName then
error("HtmlBuilder.tag: tagName 必须是字符串,传入类型为 " .. type(tagName))
end
local builder = HtmlBuilder.create(safeTagName, args)
table.insert(t.nodes, builder)
return builder
end
local function getAttr(t, name)
for i, attr in ipairs(t.attributes) do
if attr.name == name then
return attr
end
end
end
metatable.attr = function(t, name, val)
if val ~= nil then
local nameStr = ensureString(name)
local valStr = ensureString(val)
if nameStr == 'style' then
t.styles = {valStr}
return t
end
local attr = getAttr(t, nameStr)
if attr then
attr.val = valStr
else
table.insert(t.attributes, {name = nameStr, val = valStr})
end
end
return t
end
metatable.addClass = function(t, class)
if class then
local classStr = ensureString(class)
if classStr then
local attr = getAttr(t, 'class')
if attr then
attr.val = attr.val .. ' ' .. classStr
else
t.attr('class', classStr)
end
end
end
return t
end
metatable.css = function(t, name, val)
if name and val then
local nameStr = ensureString(name)
local valStr = ensureString(val)
for i, prop in ipairs(t.styles) do
if prop.name == nameStr then
prop.val = valStr
return t
end
end
table.insert(t.styles, {name = nameStr, val = valStr})
end
return t
end
metatable.cssText = function(t, css)
if css then
table.insert(t.styles, ensureString(css))
end
return t
end
metatable.done = function(t)
return t.parent or t
end
metatable.allDone = function(t)
while t.parent do
t = t.parent
end
return t
end
function HtmlBuilder.create(tagName, args)
args = args or {}
local safeTagName = ensureString(tagName)
if not safeTagName then
error("HtmlBuilder.create: tagName 必须是字符串,传入类型为 " .. type(tagName))
end
local builder = {}
setmetatable(builder, metatable)
builder.nodes = {}
builder.attributes = {}
builder.styles = {}
builder.tagName = safeTagName
builder.parent = args.parent
builder.unclosed = args.unclosed or false
builder.selfClosing = args.selfClosing or false
return builder
end
return HtmlBuilder