Module:Mw.html extension
This module is a helper module to be used by other modules; it may not be designed to be invoked directly. See Near-Reality:Lua/Helper modules for a full list and more information.
| Module | Function | Type | Use |
|---|---|---|---|
| Mw.html extension | addClassIf(cond, class) | boolean, string | If cond = true it behaves the same as the normal addClass function, otherwise it's a no-op. Ex.: mw.html.create('div'):addClassIf(true, 'align-left-1') |
attrIf(cond, name, value) | boolean, string/table, string/nil | Similar to addClassIf | |
cssIf(cond, name, value) | boolean, string/table, string/nil | Similar to addClassIf | |
doneIf(cond) | boolean | Similar to addClassIf | |
tagIf(cond, tag) | boolean, string | Similar to addClassIf | |
wikitextIf(cond, text) | boolean, string | Similar to addClassIf | |
na() | N/A | Shortcut for :tag('td'):attr('data-sort-value', 0):attr('class','table-na'):wikitext('<small>N/A</small>'):done() | |
naIf(cond) | boolean | Similar to addClassIf | |
tr([settings]) | table/nil | Shortcut for :tag('tr') but also auto closes the previous 'tr', 'th' or 'td' tag (so you don't need to add :done() before it). settings is a table with keys:
| |
th([settings]) | string/table/nil | Shortcut for :tag('th'):wikitext(settings) if settings is a string. Also auto closes the previous 'th' or 'td' tag. settings can also be a table with keys:
| |
td([settings]) | string/table/nil | Same as :th(). Example:
local tbl = mw.html.create('table')
tbl:tr{ class='sortable' }
:th{'foo', attr={'data-sort-type', 'number'}}
:th('bar')
:tr()
:td('buz')
:attr('data-sort-value', 10)
:td{'N/A', class='table-na'} | |
IF(cond) | boolean | Allows for if-blocks without breaking the chain. If the condition is true it is a no-op, if false everything inside the balanced IF-END block will be ignored. Can be nested. Ex.:
mw.html.create('div')
:IF(true)
:wikitext('Conditional text')
:END()
:...Note: This only prevents elements from being added to your html object, it does not protect against statements that throw errors. I.e mw.html.create('div')
:IF(false)
:wikitext(5 * nil) -- This will still throw an error
:END() | |
ELSEIF(cond) | boolean | Used together with IF(). | |
ELSE() | N/A | Used together with IF(). | |
END() | N/A | Used together with IF(). Make sure the IF-END tags are balanced, it wont throw an error if they are not. | |
exec(func, ...) | function, any | Call a function without breaking the chain. See module docs for more info. | |
addFunction(func, name) | function, string | Add a function to the mw.html class that can then be used on mw.html object. See module docs for more info. |
Usage
For all functions other than addFunction() all you need to do is simply require this module:
require('Module:Mw.html extension')
local p = {}
function p.main()
...
local tbl = mw.html.create('div')
:IF(true)
:wikitext('Conditional text')
:ELSE()
:wikitext('something else')
:END()
:addClassIf(true, 'wikitable')
:tag('span)'
:wikitext('normal wikitext')
:done()
...
end
return pYou can mix the normal old functions with the newly added ones.
attrIf
This accepts either a name-value pair or a table
:attrIf(true, 'data-sort-value', '0'):attrIf(true, {'data-sort-value' = '0', ...})
cssIf
This accepts either a name-value pair or a table similar to attrIf
exec
The first parameter of the function will have the current state of the mw.html object passed into it, usually we call this parameter self, the rest of the parameters can be anything you want. To not break the chaining the function must also return a mw.html object. Example:
local function repNa(self, times)
for i = 1,times do
self:na()
end
return self
endThis function can then be used as follows
mw.html.create('div'):exec(repNa, 5)addFunction
The function you want to add has to be of the same structure as in exec(). Example:
local htmlExtension = require('Module:Mw.html extension')
local p = {}
local function repNa(self, times)
for i = 1,times do
self:na()
end
return self
end
htmlExtension.addFunction(repNa, 'repNaName')
function p.main()
...
local tbl = mw.html.create('div'):repNaName(5)
...
end
return ptr, th and td
The following three tables are the same:
local tbl = mw.html.create('table')
tbl:tr{ class='sortable' }
:th{'foo', attr={['data-sort-type']='number'}} -- or attr={'data-sort-type', 'number'}
:th('bar')
:IF(expression)
:addClass('table-na')
:END()
:tr()
:td('buz')
:td{'N/A', class='table-na'}
local tbl2 = mw.html.create('table')
tbl2:tag('tr')
:addClass('sortable')
:tag('th')
:attr('data-sort-type', 'number')
:wikitext('foo')
:done()
:tag('th')
:wikitext('bar')
:IF(expression)
:addClass('table-na')
:END()
:done() -- This is needed because "tag('tr')" is used after this instead of "tr()"
:done()
:tag('tr')
:tag('td')
:wikitext('buz')
:done()
:tag('td')
:wikitext('N/A')
:addClass('table-na')
local tbl3 = mw.html.create('table')
tbl3:tag('tr')
:addClass('sortable')
:tag('th')
:attr('data-sort-type', 'number')
:wikitext('foo')
:th('bar')
:IF(expression)
:addClass('table-na')
:END()
:done()
:done()
:tag('tr')
:td('buz')
:td('N/A')
:addClass('table-na')
-- <nowiki>
local p = {}
local checkType = require( 'libraryUtil' ).checkType
local mwHtml = getmetatable( mw.html.create() ).__index -- Trick to get acces to the mw.html class
local stack = {} -- Used to keep track of nested IF-END tags
local noOp = {} -- This object is returned by IF(false) tag
function mwHtml:addClassIf( cond, class )
if cond then
return self:addClass( class )
else
return self
end
end
function mwHtml:tagIf( cond, tagname )
if cond then
return self:tag( tagname )
else
return self
end
end
function mwHtml:wikitextIf( cond, text )
if cond then
return self:wikitext( text )
else
return self
end
end
function mwHtml:doneIf( cond )
if cond then
return self:done()
else
return self
end
end
function mwHtml:attrIf( cond, name, value )
if cond then
return self:attr( name, value )
else
return self
end
end
function mwHtml:cssIf( cond, name, value )
if cond then
return self:css( name, value )
else
return self
end
end
function mwHtml:na()
return self:tag( 'td' )
:attr( 'data-sort-value', 0 )
:attr( 'class', 'table-na' )
:wikitext( '<small>N/A</small>' )
:done()
end
function mwHtml:naIf( cond )
if cond then
return self:na()
else
return self
end
end
local function addValues( self, settings )
-- wikitext and addClass are no-ops when their argument is nil
self:wikitext( settings[1] or settings.wikitext )
self:addClass( settings.class or settings.addClass )
if settings.attr then
if settings.attr[1] and settings.attr[2] then
self:attr( settings.attr[1], settings.attr[2] )
else
self:attr( settings.attr )
end
end
if settings.css then
if settings.css[1] and settings.css[2] then
self:css( settings.css[1], settings.css[2] )
else
self:css( settings.css )
end
end
if settings.cssText then
self:cssText( settings.cssText )
end
end
function mwHtml:tr( settings )
if self.tagName == 'tr' then
self = self:done():tag( 'tr' )
elseif self.tagName == 'th' or self.tagName == 'td' then
self = self:done():done():tag( 'tr' )
else
self = self:tag( 'tr' )
end
if type( settings ) == 'table' then
addValues( self, settings )
end
return self
end
function mwHtml:th( settings )
if self.tagName == 'th' or self.tagName == 'td' then
self = self:done():tag( 'th' )
else
self = self:tag( 'th' )
end
if type( settings ) == 'table' then
addValues( self, settings )
else
self = self:wikitext( settings )
end
return self
end
function mwHtml:td( settings )
if self.tagName == 'th' or self.tagName == 'td' then
self = self:done():tag( 'td' )
else
self = self:tag( 'td' )
end
if type( settings ) == 'table' then
addValues( self, settings )
else
self = self:wikitext( settings )
end
return self
end
function mwHtml:IF( cond )
if cond then
table.insert( stack, { obj=noOp, trueCaseCompleted=true } )
return self
else
table.insert( stack, { obj=self, trueCaseCompleted=false } )
return noOp
end
end
function mwHtml:ELSEIF( cond )
if #stack == 0 then error( 'Missing IF tag', 2 ) end
local last = stack[#stack]
if cond and not last.trueCaseCompleted then
last.trueCaseCompleted = true
local res = last.obj
last.obj = noOp
return res
else
if self ~= noOp then
last.obj = self
end
return noOp
end
end
function mwHtml:ELSE()
return self:ELSEIF( true )
end
function mwHtml:END()
if #stack == 0 then error( 'Missing IF tag', 2 ) end
local res = table.remove( stack ) -- Pop element from the end
if res.obj == noOp then
return self
else
return res.obj
end
end
function mwHtml:exec( func, ... )
checkType( 'exec', 1, func, 'function' )
return func( self, ... )
end
function p.addFunction( func, name )
checkType( 'addFunction', 1, func, 'function' )
checkType( 'addFunction', 2, name, 'string' )
if mwHtml[name] then
error( 'Function "' .. name .. '" already exists', 2 )
end
mwHtml[name] = func
end
noOp.IF = mwHtml.IF
noOp.ELSEIF = mwHtml.ELSEIF
noOp.ELSE = mwHtml.ELSE
noOp.END = mwHtml.END
setmetatable( noOp, {
__index = function( self )
return self
end,
__call = function( self )
return self
end,
__tostring = function()
error( 'Attempting to convert no-op object into a string. Check for unbalanced IF-END tags', 2 )
end,
__concat = function()
error( 'Attempting to concatenate a no-op object. Check for unbalanced IF-END tags', 2 )
end
} )
return p
-- </nowiki>