Module:Sandbox/DrMeepster/C yes yes

local p = {}

-Code from other people-

TableTools = require("Module:TableTools")

--https://stackoverflow.com/a/1283608 --All stack overflow code is CC BY-SA 3.0 local function tableMerge(t1, t2) for k,v in pairs(t2) do		if type(v) == "table" then if type(t1[k] or false) == "table" then _tableMerge(t1[k] or {}, t2[k] or {}) else t1[k] = v			end else t1[k] = v		end end return t1 end

--This function is public domain. See http://lua-users.org/wiki/OrderedTable --Modified to be able to accept args local function Ordered(t) --nextkey and firstkey are used as markers; nextkey[firstkey] is --the first key in the table, and nextkey[nextkey] is the last key. --nextkey[nextkey[nextkey]] should always be nil.

local key2val, nextkey, firstkey = {}, {}, {} nextkey[nextkey] = firstkey local function onext(self, key) while key ~= nil do			key = nextkey[key] local val = self[key] if val ~= nil then return key, val end end end -- To save on tables, we use firstkey for the (customised) -- metatable; this line is just for documentation local selfmeta = firstkey -- record the nextkey table, for routines lacking the closure selfmeta.__nextkey = nextkey -- setting a new key (might) require adding the key to the chain function selfmeta:__newindex(key, val) rawset(self, key, val) if nextkey[key] == nil then -- adding a new key nextkey[nextkey[nextkey]] = key nextkey[nextkey] = key end end out = setmetatable(key2val, selfmeta) if t then tableMerge(out, t)	end return out end

p.Ordered = Ordered

--Code from me--

--metatable of mw.html p.htmlMeta = getmetatable(mw.html.create)

p.orderedMeta = getmetatable(p.Ordered)

function p.filter(tabl, typ) local typeCheck = (type(typ) == "string" and type) or (type(typ) == "table" and getmetatable) or error("Invalid type!") local out = {} for k,v in pairs(tabl) do		if typeCheck(v) == typ then out[k] = v		end end return out end

--an HTML Element local Element = {parent=nil, id = nil}

Element.__index = Element

--Create a new Element function Element.new(type) o = setmetatable({}, Element) o.type = type o.children = {} o.style = Ordered o.classes = {} return o end

--Add Element or mw.html as child function Element:add(child) if getmetatable(child) == Element then child.parent = self elseif getmetatable(child) ~= htmlMeta then error("Inavlid child!") end table.insert(self.children, child) return child end

--Add string as child function Element:wikitext(child) if type(child) ~= "string" then error("Inavlid child!") end table.insert(self.children, child) return self end

--create a new Element then add it function Element:tag(name) elem = Element.new(name) return self:add(elem) end

--add a newline (br) function Element:newline self:tag("br") return self end

--add a css property function Element:css(k, v)	if type(k) == "table" then for _,kv in ipairs(k) do			self:css(kv[1], kv[2]) end elseif type(k) == "string" and type(v) == "string" then self.style[k] = v	else error("CSS keys and values should be string!") end return self end

--add classes function Element:class(class) if type(class) == "table" then tableMerge(self.classes, class) elseif type(class) == "string" then table.insert(self.classes, class) else error("Invalid class type!") end return self end

--set the id function Element:setId(id) if type(id) ~= "string" then error("Id must be string!") end self.id = id	return self end

--returns parent. used for function chaining function Element:done return self.parent or self end

--returns the root Element function Element:allDone local parent = self.parent if parent == nil then return self end while parent.parent do		parent = parent.parent end return parent end

--turn this Element into an mw.html object function Element:bake local root = mw.html.create(self.type):css(self.style) for _,class in ipairs(self.classes) do		root:addClass(class) end for _, child in ipairs(self.children) do		if getmetatable(child) == Element then --must bake Element root:node(child:bake) elseif getmetatable(child) == htmlMeta then --do not need to bake mw.html root:node(child) elseif type(child) == "string" then --if string add as wikitext root:wikitext(child) else error("Unknown child of element!") end end return root end

--bakes the root Element function Element:bakeAll return self:allDone:bake end

--wip dont use function Element:stylesheet(css) for _,c in ipairs(css) do		for _,s in ipairs(c.selectors) do			if s:check(self) then self:css(c.properties) break end end end for _,child in pairs(p.filter(self.children, Element)) do		child:stylesheet(css) end return self end

local Selector = { yes = false, id = nil, type = nil, class = {}, directParent = nil, parent = nil, next = nil } --	selections ordered roughly by price, cheapest to most expensive	--basic selections--	yes - Makes the selector always be true (*)	id - Element must have this id (

Selector.__index = Selector

function Selector.new(s) s = s or {} if type(s.class) == "string" then s.class = {s.class} elseif type(s.class) ~= "table" then s.class = {} end return setmetatable(s, Selector) end

function Selector:check(e) if getmetatable(e) ~= Element then return false end -- all selector if self.yes then return true end -- id selector if self.id and e.id ~= self.id then return false end -- type selector if self.type and e.type ~= self.type then return false end -- class selector if #self.class > 0 then local class = true for _,v in pairs(self.class) do			if not TableTools.inArray(e.classes, v) then class = false break end end if not class then return false end end -- direct parent check if self.directParent and not self.directParent:check(e.parent) then return false end -- parent check

if self.parent then local nextParent = e.parent while true do			if nextParent == nil then return false end if self.parent:check(nextParent) then break end nextParent = nextParent.parent end end -- all selectors passed return true end

p.Element = Element p.Selector = Selector return p