Module:SimpleHTMLBuilder

From League of Legends Wiki, LoL Wiki
Revision as of 18:06, 3 February 2022 by AnataBakka (talk | contribs)
Jump to navigation Jump to search
Module:SimpleHTMLBuilder has the following documentation.

Simple HTML Builder (SHB) intends to maintain the readability provided by the mw.html interface while reducing the Lua memory usage when building large wikitext tables. It is designed as a near drop-in replacement for mw.html, the HTML library included with the Scribunto Extension.

mw.html SHB Differences
mw.html.create( tagName, args ) all tags are closed (</tagName>)
args ignored in SHB
mw.html:node( builder ) cannot be called after done() or tostring()
mw.html:wikitext( ... ) only uses first argument in SHB
cannot be called after done() or tostring()
mw.html:newline() cannot be called after done() or tostring()
mw.html:tag( tagName, args ) all tags are closed (</tagName>)
args ignored in SHB
cannot be called after done() or tostring()
mw.html:attr( name, value )
mw.html:attr( table )

cannot be called after done() or tostring()
passing nil for valueis a no-op instead of an unset operation
mw.html:getAttr( name )
mw.html:addClass( class ) cannot be called after done() or tostring()
mw.html:css( name, value )
mw.html:css( table )

cannot be called after done() or tostring()
mw.html:cssText( css ) cannot be called after done() or tostring()
mw.html:done()
mw.html:allDone()
Differences to the original mw.html
1. Attributes and tags (and thus nodes) can not be re-edited once closed.
2. Attributes and tags are closed with :done and tostring(). 
   Note: the garbage collector is kinda bugged, possible reason for why mw.html
   is expensive. The collector only collects stuff in specific undefined cases.
   The tag is locked upon using :done for this reason, because after trial and error
   i found out locking it as soon as possible greatly lowered memory consumption,
   even though it otherwise does the same thing as a late tostring().
   However, this is also inconsistent, and leaving it to a late tostring()
   may sometimes do a better job.
   Still, since doing it early seems to have a higher chance, it should be the
   prioritized method.
3. There's no second argument to p.create() and :tag()
4. :wikitext() does not allow multiple arguments (though it can be added,
   but it consumes more memory)
5. There's no :getAttr()

local concat = table.concat
local gsub = string.gsub

local p = {}
local f = {}

function f:node(node)
	node["recent_parent"] = self
	self:wikitext(node)
	
	if self.tags == nil then
		self.tags = {}
	end

	self["tags"][node] = self[11].count

	return self
end

function f:wikitext(text, text2)
	if text2 ~= nil then
		error("Wikitext does not work with multiple arguments.")
	end

	if self[11] == "" then
		self[11] = {["count"] = 0}
	end
	
	local t = self[11]
	
	t.count = t.count + 1
	t[t.count] = text
	
	return self
end

function f:newline()
	return self:wikitext("\n")
end
	
function f:tag(tag, args)
	local node = p.create(tag, args)
	self:node(node)

	return node
end

function f:attr(name, value)
	if type(name) == "table" then
		for i,v in pairs(name) do
			self:attr(i,v)
		end

		return self
	end

	if self[1] == "" then
		error("Attempting to create attribute without a tag")
	end
	
	if self[9] == "" then
		self[9] = {["count"] = 0}
	end
	
	local t = self[9]
	
	t.count = t.count + 1
	t[t.count] = ' '

	t.count = t.count + 1
	t[t.count] = gsub(name, "%<[^%>]*%>", "") --removing tags
	
	t.count = t.count + 1
	t[t.count] = '="'

	t.count = t.count + 1
	t[t.count] = gsub(value, "%<[^%>]*%>", "")
	
	t.count = t.count + 1
	t[t.count] = '"'
	
	return self
end

function f:addClass(value)
	if self[1] == "" then
		error("Attempting to create class without a tag")
	end
	
	if self[4] == "" then
		self[4] = {["count"] = 0}
	end
	
	local t = self[4]
	
	t.count = t.count + 1
	t[t.count] = gsub(value, "%<[^%>]*%>", "")
	
	t.count = t.count + 1
	t[t.count] = ' '
	
	return self
end

function f:cssText(value)
	if self[1] == "" then
		error("Attempting to create style without a tag")
	end
	
	if self[7] == "" then
		self[7] = {["count"] = 0}
	end
	
	local t = self[7]
	
	t.count = t.count + 1
	t[t.count] = gsub(value, "%<[^%>]*%>", "")
	
	t.count = t.count + 1
	t[t.count] = ';'
	
	return self
end

function f:css(name, value)
	if type(name) == "table" then
		for i,v in pairs(name) do
			self:css(i,v)
		end

		return self
	end

	if self[1] == "" then
		error("Attempting to create style without a tag")
	end
	
	if self[7] == "" then
		self[7] = {["count"] = 0}
	end
	
	local t = self[7]

	t.count = t.count + 1
	t[t.count] = gsub(name, "%<[^%>]*%>", "")
	
	t.count = t.count + 1
	t[t.count] = ':'
	
	t.count = t.count + 1
	t[t.count] = gsub(value, "%<[^%>]*%>", "")
	
	t.count = t.count + 1
	t[t.count] = ';'
	
	return self
end

function f:done()
	local parent = self.recent_parent
	tostring(self)

	return parent
end

function f:allDone()
	local node = self
	
	while node:done() ~= nil do
		node = node:done()
	end
	
	return node
end

local meta_main = {
	__index = f,
	__tostring = function(self)
		if self.result then
			return self.result
		end

		if self[4] ~= "" then
			self[3] = ' class="'
			self[4] = concat(self[4])
			self[5] = '"'
		end
		
		if self[7] ~= "" then
			self[6] = ' style="'
			self[7] = concat(self[7])
			self[8] = '"'
		end
		
		if self[9] ~= "" then
			self[9] = concat(self[9])
		end

		if self[11] ~= "" then
			if self.tags then
				for _, v in pairs(self.tags) do
					self[11][v] = tostring(self[11][v])
				end
				
				self.tags = nil
			end

			self[11] = concat(self[11])
		end

		self.result = concat(self)
		
		if self.recent_parent ~= nil then
			self.recent_parent[11][self.recent_parent.tags[self]] = self.result
			self.recent_parent.tags[self] = nil
			self.recent_parent = nil
		end

		for i = 1, 11 do
			self[i] = nil
		end

		return self.result
	end,
}

function p.create(tag, args)
	if args ~= nil then
		error("Tag creation does not accept multiple arguments.")
	end

	--struct to give to functions.
	local tag_table

	if tag == nil then
		tag_table = {"", "", "", "", "", "", "", "", "", "", ""}
	else
		-- 3 = class start, 4 = class table, 5 = class end, 6 = css start, 7 = css table, 8 = css end, 9 = attributes table, 11 = text table
		tag_table = {"<", tag, "", "", "", "", "", "", "", ">", "", "</", tag, ">"}
	end

	setmetatable(tag_table, meta_main)

	return tag_table
end

return p