Module:SimpleHTMLBuilder: Difference between revisions

From League of Legends Wiki, LoL Wiki
Jump to navigation Jump to search
Content added Content deleted
No edit summary
m (Protected "Module:SimpleHTMLBuilder": Fundamental module ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)))
 
(25 intermediate revisions by 2 users not shown)
Line 1: Line 1:
local concat = table.concat
--Differences to the original mw.html
local gsub = string.gsub
--1. Attributes and tags (and thus nodes) can not be re-edited once closed.
local sub = string.sub
--2. Attributes and tags are closed with :done and tostring().
local nowiki = mw.text.nowiki
-- 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 tostring() does.
-- However that's not guaranteed. Sometimes tostring does a better job.
-- Still, you should always use :done after finishing with a tag, as that
-- has a much higher chance of lowering memory.
--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()
--6. :attr() and :css() do not allow a table paramater (this could be added,
-- but i'm not sure if it's needed)
local userError = require('Dev:User error')
local concat = table.concat


local p = {}
local p = {}
local f = {}
local f = {}

local function return_table(self, index)
if self[index] == "" then
self[index] = {count = 0}
elseif self[index] == nil then
error("Tag cannot be edited once closed.")
end
return self[index]
end


function f:node(node)
function f:node(node)
node["recent_parent"] = self
self:wikitext(node)
self:wikitext(node)

if node.parents == nil then
node.parents = {count = 0}
end
node.parents.count = node.parents.count+1
node.parents[node.parents.count] = {parent = self, nodePtr = self[11].count}


return self
return self
end
end


function f:wikitext(text)
function f:wikitext(text, text2)
if self[11] == "" then
if text2 ~= nil then
error("Wikitext does not work with multiple arguments.")
self[11] = {["count"] = 0}
end
end
local t = self[11]
local t = return_table(self, 11)
t.count = t.count + 1
t.count = t.count + 1
Line 46: Line 47:
end
end
function f:tag(tag)
function f:tag(tag, args)
local node = p.create(tag)
local node = p.create(tag, args)
self:node(node)
self:node(node)


Line 53: Line 54:
end
end


function f:attr(name, value)
function attrTable(self, inputTable)
for i,v in pairs(inputTable) do
if self[1] == "" then
attrFlat(self, i,v)
error("Attempting to create attribute without a tag")
end
end
if self[9] == "" then
return self
end
self[9] = {["count"] = 0}

function attrFlat(self, name, value)
if (value == nil) then
return self
end
end

local t = self[9]
if self[1] ~= "<" then
error("Attempting to create attribute without a tag")
end

local t = return_table(self, 9)
t.count = t.count + 1
t.count = t.count + 1
Line 68: Line 77:


t.count = t.count + 1
t.count = t.count + 1
t[t.count] = name
t[t.count] = nowiki(name)
t.count = t.count + 1
t.count = t.count + 1
Line 74: Line 83:


t.count = t.count + 1
t.count = t.count + 1
t[t.count] = value
t[t.count] = nowiki(value)
t.count = t.count + 1
t.count = t.count + 1
Line 80: Line 89:
return self
return self
end

function f:attr(name, value)
if type(name) == "table" then
return attrTable(self, name)
else
return attrFlat(self, name, value)
end
end
end


function f:addClass(value)
function f:addClass(value)
if self[1] == "" then
if self[1] ~= "<" then
error("Attempting to create class without a tag")
error("Attempting to create class without a tag")
end
end
local t = return_table(self, 4)
if self[4] == "" then
self[4] = {["count"] = 0}
end
local t = self[4]
t.count = t.count + 1
t.count = t.count + 1
t[t.count] = value
t[t.count] = nowiki(value)
t.count = t.count + 1
t.count = t.count + 1
Line 103: Line 116:


function f:cssText(value)
function f:cssText(value)
if self[1] == "" then
if self[1] ~= "<" then
error("Attempting to create style without a tag")
error("Attempting to create style without a tag")
end
end
local t = return_table(self, 7)
if self[7] == "" then
self[7] = {["count"] = 0}
end
local t = self[7]
t.count = t.count + 1
t.count = t.count + 1
t[t.count] = value
t[t.count] = nowiki(value)
t.count = t.count + 1
t.count = t.count + 1
Line 123: Line 132:


function f:css(name, value)
function f:css(name, value)
if self[1] == "" then
if type(name) == "table" then
for i,v in pairs(name) do
error("Attempting to create style without a tag")
self:css(i,v)
end

return self
end
end

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


t.count = t.count + 1
t.count = t.count + 1
t[t.count] = name
t[t.count] = nowiki(name)
t.count = t.count + 1
t.count = t.count + 1
Line 140: Line 153:
t.count = t.count + 1
t.count = t.count + 1
t[t.count] = value
t[t.count] = nowiki(value)
t.count = t.count + 1
t.count = t.count + 1
Line 149: Line 162:


function f:done()
function f:done()
local parent = self.recent_parent
local parent = self.parents and self.parents[self.parents.count].parent or nil
tostring(self)
if parent ~= nil then
parent[11][parent[11].count] = tostring(self)
end


return parent
return parent or self
end
end


Line 161: Line 171:
local node = self
local node = self
while node:done() ~= nil do
while node ~= node:done() do
node = node:done()
node = node:done()
end
end
Line 171: Line 181:
__index = f,
__index = f,
__tostring = function(self)
__tostring = function(self)
if self.result then
return self.result
end

if self[4] ~= "" then
if self[4] ~= "" then
self[3] = ' class="'
self[3] = ' class="'
Line 190: Line 204:
for i = 1, self[11].count do
for i = 1, self[11].count do
if type(self[11][i]) == "table" then
if type(self[11][i]) == "table" then
self[11][i] = tostring(self[11][i])
self[11][i] = tostring(self[11][i])
end
end
end
end
Line 196: Line 210:
self[11] = concat(self[11])
self[11] = concat(self[11])
end
end

self.result = concat(self)
if self.parents ~= nil then
return concat(self)
for i = 1, self.parents.count do
self.parents[i].parent[11][self.parents[i].nodePtr] = self.result
end
self.parents = nil
end

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

return self.result
end,
end,
}
}


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

--struct to give to functions.
--struct to give to functions.
local tag_table
local tag_table

Latest revision as of 04:38, 9 November 2024

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 sub		= string.sub
local nowiki	= mw.text.nowiki

local p = {}
local f = {}

local function return_table(self, index)
	if self[index] == "" then
		self[index] = {count = 0}
	elseif self[index] == nil then
		error("Tag cannot be edited once closed.")
	end
	
	return self[index]
end

function f:node(node)
	self:wikitext(node)

	if node.parents == nil then
		node.parents = {count = 0}
	end
	
	node.parents.count = node.parents.count+1
	node.parents[node.parents.count] = {parent = self, nodePtr = self[11].count}

	return self
end

function f:wikitext(text, text2)
	if text2 ~= nil then
		error("Wikitext does not work with multiple arguments.")
	end
	
	local t = return_table(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 attrTable(self, inputTable)
	for i,v in pairs(inputTable) do
		attrFlat(self, i,v)
	end
	
	return self
end

function attrFlat(self, name, value)
	if (value == nil) then
		return self
	end

	if self[1] ~= "<" then
		error("Attempting to create attribute without a tag")
	end

	local t = return_table(self, 9)
	
	t.count = t.count + 1
	t[t.count] = ' '

	t.count = t.count + 1
	t[t.count] = nowiki(name)
	
	t.count = t.count + 1
	t[t.count] = '="'

	t.count = t.count + 1
	t[t.count] = nowiki(value)
	
	t.count = t.count + 1
	t[t.count] = '"'
	
	return self
end

function f:attr(name, value)
	if type(name) == "table" then
		return attrTable(self, name)
	else
		return attrFlat(self, name, value)
	end
end

function f:addClass(value)
	if self[1] ~= "<" then
		error("Attempting to create class without a tag")
	end
	
	local t = return_table(self, 4)
	
	t.count = t.count + 1
	t[t.count] = nowiki(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
	
	local t = return_table(self, 7)
	
	t.count = t.count + 1
	t[t.count] = nowiki(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
	
	local t = return_table(self, 7)

	t.count = t.count + 1
	t[t.count] = nowiki(name)
	
	t.count = t.count + 1
	t[t.count] = ':'
	
	t.count = t.count + 1
	t[t.count] = nowiki(value)
	
	t.count = t.count + 1
	t[t.count] = ';'
	
	return self
end

function f:done()
	local parent = self.parents and self.parents[self.parents.count].parent or nil
	tostring(self)

	return parent or self
end

function f:allDone()
	local node = self
	
	while node ~= node:done() 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
			for i = 1, self[11].count do
				if type(self[11][i]) == "table" then
				   self[11][i] = tostring(self[11][i])
				end
			end

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

		self.result = concat(self)
		
		if self.parents ~= nil then
			for i = 1, self.parents.count do
				self.parents[i].parent[11][self.parents[i].nodePtr] = self.result
			end
			
			self.parents = 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