Content deleted Content added
clear out functions moved to submodules (hidden, gallery, example) and obsolete (addTaxonReverse) |
Replace Module:No globals with require( "strict" ) |
||
(44 intermediate revisions by one other user not shown) | |||
Line 8:
now uses templatestyles
]]
require('
local p = {}
local pargs = {} -- parent arguments
local lastNode=0
local nodeCount=0
Line 17 ⟶ 18:
local infoOutput
local reverseClade = false
--[[============================== main function ===========================
Line 41 ⟶ 38:
local childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon()
local totalCount = 0
pargs = frame:getParent().args -- parent arguments
infoOutput = p.getCladeTreeInfo() -- get info about clade structure, e.g. lastNode (last |N= child number)
Line 55 ⟶ 54:
--cladeString = mw.text.unstrip(cladeString)
--if cladeCount==1 then
local src = "Template:
cladeString = cladeString .. p.templateStyle( frame, src ) .. '\n'
--end
local tableStyle = frame.args.style or ""
if tableStyle ~= "" then
tableStyle = ' style="' .. tableStyle .. '"' -- include style= in string to suppress empty style elements
end
reverseClade =frame.args.reverse or pargs.reverse or false -- a global
--ENFORCE GLOBAL FOR DEVELOPMENT
--reverseClade = true
local captionName =
local captionStyle =
-- add an element to mimick nowiki WORKS BUT DISABLE FOR DEMO PURPOSES
Line 87 ⟶ 84:
end
local moreNeeded = true
Line 108 ⟶ 100:
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf =
local nodeLabel =
local newickString = pargs['newick'..tostring(childNumber)] or "" -- get data from |labelN=
local listString = pargs['list'..tostring(childNumber)] or ""
if listString ~= "" then
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.list(0, listString), nodeLabel, lastNode)
elseif newickString ~= "" then -- if using a newick string instead of a clade structure
newickString = p.processNewickString(newickString,childNumber)
if nodeLabel == "" then -- use labelN by default, otherwise use root name from Newick string
Line 129 ⟶ 125:
end
local footerText =
local footerStyle =
if footerText ~= "" then
Line 155 ⟶ 151:
function p.addSubTrees(cladeString)
--local pargs = mw.getCurrentFrame():getParent().args
local suffix = { [1]="A", [2]="B", [3]="C", [4]="D", [5]="E", [6]="F", [7]="G", [8]="H", [9]="I", [10]="J",
Line 171 ⟶ 167:
return cladeString
end
--[[ -------------------------------------- p.addTaxon() ------------------------------------------
function to add child elements
adds wikitext for two rows of the table for each child node,
the first cell in each is used for the label and sublabel; the bottom border forms the horizonal branch of the bracket
Line 182 ⟶ 179:
function p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode)
--[[ get border formating parameters (i.e. color, thickness, state)
nodeParameters for whole bracket (unnumbered, i.e. color, thickness, state) apply to whole node bracket,
branchParameters apply to individual branches
the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
the node parameters have no number, e.g. |color, |thickness, |state
]]
local nodeColor = pargs['color'] or "" -- don't set default to allow green on black gadget
local nodeThickness = tonumber(pargs['thickness']) or 1
local nodeState = pargs['state'] or "solid"
-- get border formating parameters for branch (default to global nodeParameters)
local branchColor = pargs['color'..tostring(childNumber)] or nodeColor
local branchThickness = tonumber(pargs['thickness'..tostring(childNumber)]) or nodeThickness
local
if branchState == 'double' then
if branchThickness < 2 then branchThickness = 3 end -- need thick line for double
end
local branchStyle = pargs['style'..tostring(childNumber)] or ""
local branchLength = pargs['length'] or pargs['length'..tostring(childNumber)] or ""
-- the left border takes node parameters, the bottom border takes branch parameters
Line 201 ⟶ 209:
local useInlineStyle = false
-- use inline styling non-default color, line thickness or state have been set
if branchColor ~= "" or branchThickness ~= 1 or
useInlineStyle = true
end
Line 208 ⟶ 216:
-- variables for right hand bar or bracket
--local barColor = ""
local barRight =
local barBottom =
local barTop =
local barLabel =
local groupLabel =
local groupLabelStyle
local labelStyle = pargs['labelstyle'..tostring(childNumber)] or ""
local sublabelStyle = pargs['sublabelstyle'..tostring(childNumber)] or ""
--replace colours with format string; need right bar for all three options
Line 229 ⟶ 239:
local classString = ''
local reverseClass = ''
local widthClass = ''
-- class to add if using reverse (rtl) cladogram;
Line 250 ⟶ 261:
end
end
if useInlineStyle or
local branchLengthStyle = ""
if branchLength ~= "" then
if childNumber == 1 then
branchLengthStyle = 'width:' .. branchLength .. ';' -- add width to first element
end
--if childNumber > 1 then prefix = 'max-' end
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';'
.. 'max-width:' .. branchLength ..';'
.. 'padding:0em;' -- remove padding to make calculation easier
-- following moved to styles.css
-- .. 'white-space:nowrap'
-- .. 'overflow:hidden;' -- clip labels longer than the max-width
-- .. 'text-overflow:clip;' -- ellipsis;'
--if pargs['noclip'] then
if string.find(nodeLabel, '<div style="position:absolute;') then
branchLengthStyle = branchLengthStyle .. 'overflow:visible;'
end
widthClass = " clade-fixed-width"
end
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. labelStyle .. '"'
end
if childNumber == 1 then
classString= 'class="clade-label first'.. widthClass .. '" ' -- add class "first" for top row
else
classString = 'class="clade-label' .. reverseClass .. widthClass .. '" ' -- add "reverse" class if ltr cladogram
end
Line 282 ⟶ 313:
end
end
classString = 'class="clade-leaf' .. reverseClass .. '"'
--[[note: the \n causes plain leaf elements get wrapped in <p> with style="margin:0.4em 0 0.5em 0;"
this adds spacing to rows, but is set by defaults rather than the clade template
it also means there are two newlines when it is a clade structure (which might explain some past issues)
]]
local content = '\n' .. nodeLeaf -- the newline is not necessary, but keep for backward compatibility
-- test using image parameter
local image = pargs['image'..tostring(childNumber)] or ""
if image ~= "" then
--content = content .. image -- basic version
content = '\n{| class="clade" style="width:auto;"' --defaults to width:100% because of class "clade"
.. '\n| class="clade-leaf" ' .. '|\n' .. nodeLeaf
.. '\n| class="clade-leaf" ' .. '|\n' .. image
.. '\n|}'
-- note: the classes interfere with the node counter, so try simpler version with style
content = '\n{| style="width:100%;border-spacing:0;" ' --width:auto is "tight"; 100% needed for image alignment
.. '\n| style="border:0;padding:0;" ' .. '|\n' .. nodeLeaf
.. '\n| style="border:0;padding:0;" ' .. '|\n' .. image
.. '\n|}'
end
-- wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
-- but that is no longer the case (newline is now forced)
-- the newline wraps plain leaf terminals in <P> with vertical padding (see above)
--local leafCellString = '\n|rowspan=2 ' .. classString .. styleString .. ' |\n' ..
local leafCellString = '\n|rowspan=2 ' .. classString .. styleString .. ' |' .. content
--cladeString = cladeString .. leafCellString
Line 322 ⟶ 379:
-- (6) add cell containing sublabel
local subLabel =
-- FOR TESTING: use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY)
Line 341 ⟶ 398:
end
end
if borderStyle ~= '' or branchStyle ~= '' or branchLength ~= '' or sublabelStyle ~= "" then
local branchLengthStyle = ""
if branchLength ~= "" then
if childNumber == 1 then
--only set for label branchLengthStyle = 'width:' .. branchLength .. ';' -- add width to first element
end
--if childNumber > 1 then prefix = 'max-' end
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';'
.. 'max-width:' .. branchLength ..';'
.. 'padding:0em;' -- remove padding to make calculation easier
--if pargs['noclip'] then
if string.find(subLabel, '<div style="position:absolute;') then
branchLengthStyle = branchLengthStyle .. 'overflow:visible;'
end
end
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. sublabelStyle .. '"'
--styleString = ' style="' .. borderStyle .. branchStyle .. sublabelStyle .. '"'
end
Line 348 ⟶ 420:
if childNumber == lastNode then
classString = 'class="clade-slabel last' .. widthClass .. '" '
else
classString = 'class="clade-slabel' .. reverseClass .. widthClass .. '" '
end
local sublabelCellString = '\n|' .. classString .. styleString .. '|' .. p.addLabel(childNumber,subLabel)
Line 382 ⟶ 454:
function p.addLabel(childNumber,nodeLabel)
if nodeLabel == "" then
--return '<br/>' --' <br/>' -- remove space to reduce post-expand include size (the width=1.5em handles spacing)
--return
else
-- spaces can cause wrapping and can break tree structure, hence use span with nowrap class
Line 399 ⟶ 467:
if string.find(nodeLabel, "span ") ~= nil then stylingElementDetected = true end
if string.find(nodeLabel, " style") ~= nil then stylingElementDetected = true end
--TODO test following alternative
--if nodeLabel:find( "%b<>") then stylingElementDetected = true end
-- we know the no break is handled when using {{clade label}}
if string.find(nodeLabel, '<div style="position:absolute;') then stylingElementDetected = false end
if stylingElementDetected == true then
return '<span class="nowrap">' .. nodeLabel .. '</span>'
else
--local nowrapString = string.gsub(nodeLabel," ", " ") -- replace spaces with non-breaking space
local nowrapString = nodeLabel -- spaces are now handled by CSS "white-space:nowrap;""
if not nowrapString:find("UNIQ.-QINU") then -- unless a strip marker
nowrapString = string.gsub(nowrapString,"-", "‑") -- replace hyphen with non-breaking hyphen (‑)
end
return nowrapString
end
Line 467 ⟶ 543:
end
-- emulate a standard split string function
-- why not use mw.text.split(s, sep)?
function p.strsplit(inputstr, sep)
if sep == nil then
Line 489 ⟶ 566:
function p.newickConverter(frame)
local newickString = frame.args['newickstring'] or
--if newickString == '{{{newickstring}}}' then return newickString end
Line 507 ⟶ 584:
local resultString = ''
local option =
if option == 'tree' then
--show the transcluded clade diagram
Line 575 ⟶ 652:
function p.getIndent(levelNumber)
local indent = "\r"
local extraIndent = pargs['indent'] or mw.getCurrentFrame
while tonumber(extraIndent) > 0 do
Line 597 ⟶ 674:
local maxPatterns = 5
local i = 0
local pargs =
local pattern = pargs['newick'..tostring(childNumber)..'-pattern'] -- unnumbered option for i=1
local replace = pargs['newick'..tostring(childNumber)..'-replace']
Line 645 ⟶ 722:
while childNumber < maxChildren do -- preprocessing loop
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf,data =
local newickString =
local listString = pargs['list'..tostring(childNumber)] or "" -- get data from |labelN=
if newickString ~= "" or nodeLeaf ~= "" or listString ~= "" then
--if nodeLeaf ~= "" then
childCount = childCount + 1 -- this counts child elements in this clade
Line 712 ⟶ 790:
return (str:gsub("^%l", string.upper))
end
--[[ function to generate cladogram from a wikitext-like list
- uses @ instead of * because we don't want wikitext processed and nowiki elements are passed as stripmarkers (?)
]]
function p.list(count,listString)
local cladeString = ""
--count = count+1
local list = mw.text.split(listString, "\n")
local i=1
local child=1
local lastNode=0--table.getn(list) -- number of child branches (potential)
cladeString = cladeString .. '{| class="clade" '
while list[i] do
list[i]=list[i]:gsub("^@", "") -- strip the first @
if not string.match( list[i], "^@", 1 ) then -- count children at this level (not beginning wiht @)
lastNode = lastNode+1
end
i=i+1
end
i=1
while list[i] do
--[[ pseudocode:
if next value begins with @ we have a subtree,
which must be recombined and past iteratively
else we have a simple leaf
]]
-- if the next value begins with @, we have a subtree which should be recombined
if list[i+1] and string.match( list[i+1], "^@", 1 ) then
local label=list[i]
i=i+1
local recombined = list[i]
while list[i+1] and string.match( list[i+1], "^@", 1 ) do
recombined = recombined .. "\n" .. list[i+1]
i=i+1
end
--cladeString = cladeString .. '\n' .. p.addTaxon(child, recombined, label, lastNode)
cladeString = cladeString .. '\n' .. p.addTaxon(child, p.list(count,recombined), label, lastNode)
else
cladeString = cladeString .. '\n' .. p.addTaxon(child, list[i], "", lastNode)
end
i=i+1
child=child+1
end
cladeString = cladeString .. '\n|}'
mw.addWarning("WARNING. This is a test feature only.")
return cladeString
end
-- =================== experimental Newick to clade parser function =============================
--[[Function of convert Newick strings to clade format
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|newickConverter|newickstring={{{NEWICK_STRING}}} }}
]]
function p.cladeConverter(frame)
end
function p.listConverter(frame)
local listString = frame.args['list'] or pargs['list']
-- show the list string
local cladeString = ''
local levelNumber = 1 -- for depth of iteration
local childNumber = 1 -- number of sister elements on node (always one for root)
local indent = p.getIndent(levelNumber)
-- converted the newick string to the clade structure
cladeString = cladeString .. indent .. '{{clade'
cladeString = cladeString .. p.listParseLevel(listString, levelNumber, childNumber)
--cladeString = cladeString .. '\r}}'
local resultString = ''
local option = pargs['option'] or ''
if option == 'tree' then
--show the transcluded clade diagram
resultString = cladeString
else
-- show the Newick string
resultString = '<pre>'..listString..'</pre>'
-- show the converted clade structure
resultString = resultString .. '<pre>'.. cladeString ..'</pre>'
end
--resultString = frame:expandTemplate{ title = 'clade', frame:preprocess(cladeString) }
return resultString
end
function p.listParseLevel(listString,levelNumber,childNumber)
local cladeString = ""
local indent = p.getIndent(levelNumber)
levelNumber=levelNumber+1
local list = mw.text.split(listString, "\n")
local i=1
local child=1
local lastNode=0
while list[i] do
list[i]=list[i]:gsub("^@", "") -- strip the first @
if not string.match( list[i], "^@", 1 ) then -- count children at this level (not beginning wiht @)
lastNode = lastNode+1
end
i=i+1
end
i=1
while list[i] do
--[[ pseudocode:
if next value begins with @ we have a subtree,
which must be recombined and past iteratively
else we have a simple leaf
]]
-- if the next value begins with @, we have a subtree which should be recombined
if list[i+1] and string.match( list[i+1], "^@", 1 ) then
local label=list[i]
i=i+1
local recombined = list[i]
while list[i+1] and string.match( list[i+1], "^@", 1 ) do
recombined = recombined .. "\n" .. list[i+1]
i=i+1
end
cladeString = cladeString .. indent .. '|label' .. child ..'=' .. label
cladeString = cladeString .. indent .. '|' .. child ..'=' .. '{{clade'
.. p.listParseLevel(recombined,levelNumber,i)
else
cladeString = cladeString .. indent .. '|' .. child ..'=' .. list[i]
end
i=i+1
child=child+1
end
cladeString = cladeString .. indent .. '}}'
return cladeString
end
|