Module:Sandbox/Jts1882/CladeN: Difference between revisions

Content deleted Content added
updates for noglobal (note this needs to be repeated using the live version that was newer than this version)
Replace Module:No globals with require( "strict" )
 
(51 intermediate revisions by one other user not shown)
Line 8:
now uses templatestyles
]]
require('Module:No globalsstrict')
local p = {}
local pargs = {} -- parent arguments
local lastNode=0
local nodeCount=0
local cladeCount=0
local leafCount=0
local templateStylesCount=0
local infoOutput
local reverseClade = false
local nodeColor
local nodeThickness
local nodeState
 
--[[============================== main function ===========================
Line 35 ⟶ 34:
 
local cladeString = ""
local maxChildren = 20 -- currentlywas 17 in the clade/cladex templates
local childNumber = 0
lastNode = 0 -- make this global for now (declaring here prevents lua error for nil value in template)
--local nodeCount = 0 -- total leafs plus new clade branches
--local leafCount = 0 -- just the terminal leaves
--local cladeCount = 0 -- new clade calls (each with a table)
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)
--[[ add the templatestyles tag conditionally to reduce expansion size (currently diabled)
when addadded to every clade table, >> 137it timesincreases inpost‐expand Passeriformesinclude testsize pagesignificantly
e.g. the Neosuchia page (or test version) is increase by about 8% (672 bytes each)
cladeCount==1 >> 43 insertions
nodeCount==2 >> 5 insertions (onceif fortemplate thestyles styleadded css,to oneall linkpages inthere eachare 133 stripmarkers cladegram)
with cladeCount==1 2 in Neosuchia (one for style csscondition, onethis linkis forreduced secondto cladogram)34
however cladeCount==1 condition interfers with fix for additional line due to parser bug T18700
this is because it counts "dummy" clades and outer clades with one leaf
killing the strip markers also removes backlinks to references using citation templates
cladeCount==1 AND nodeCount==2 >> 1 insertions
but none in Neosuchia
--]]
--cladeString =mw.text.killMarkers( cladeString ) -- also kills off strip markers using citation templates
-- worked for wrong reasons if nodeCount==2 then
--cladeString = mw.text.unstrip(cladeString)
if cladeCount==1 then
--if cladeCount==1 then
local src = "Template:CladeN/styles.css"
cladeString = cladeString .. p.templateStyle( frame, src ) .. '\n'
--end
local tableStyle = frame.args.style or ""
 
--if tableStyle == '{{{style}}}' then tableStyle = "" end -- no longer needed as pipe added to template to suppress passing of {{{style}} when no value
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 =mw.getCurrentFrame():getParent().args pargs['caption'] or ""
local captionStyle = mw.getCurrentFrame():getParent().argspargs['captionstyle'] or ""
 
-- add an element to mimick nowiki WORKS BUT DISABLE FOR DEMO PURPOSES
Line 89 ⟶ 84:
end
-- global nodeParameters (unnumber, i.e. color, thickness, state) apply to whole node bracket,
-- but can be overrriden by branchParameters (numbered, e.g. color2, thickness2, state2)
nodeColor = mw.getCurrentFrame():getParent().args['color'] or ""
nodeThickness = tonumber(mw.getCurrentFrame():getParent().args['thickness']) or 1
nodeState = mw.getCurrentFrame():getParent().args['state'] or "solid"
local moreNeeded = true
Line 110 ⟶ 100:
 
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf = mw.getCurrentFrame():getParent().argspargs[tostring(childNumber)] or "" -- get data from |N=
local nodeLabel = mw.getCurrentFrame():getParent().argspargs['label'..tostring(childNumber)] or "" -- get data from |labelN=
local newickString = mw.getCurrentFrame():getParent().argspargs['newick'..tostring(childNumber)] or "" -- get data from |labelN=
local listString = pargs['list'..tostring(childNumber)] or ""
if newickString ~= "" then -- if using a newick string instead of a clade structure
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
nodeLabel = p.getNewickOuterterm(newickString) -- need to use terminal part of newick string for label
Line 130 ⟶ 125:
end
 
local footerText = mw.getCurrentFrame():getParent().argspargs['footer'] or ""
local footerStyle = mw.getCurrentFrame():getParent().argspargs['footerstyle'] or ""
 
if footerText ~= "" then
Line 146 ⟶ 141:
cladeString = cladeString .. '\n|}'
cladeString = p.addSubTrees(cladeString) -- add subtrees
 
return cladeString
--return '<div style="width:auto;">\n' .. cladeString .. '</div>'
end
 
end -- end p.main(0)
--[[ =============================function to add subtrees ========================================== ]]
 
function p.addSubTrees(cladeString)
--local pargs = mw.getCurrentFrame():getParent().args
--[[ local subcladeA = pargs['subcladeA']
local subcladeB = pargs['subcladeB']
local targetA = pargs['targetA'] or "SUBCLADE_A"
local targetB = pargs['targetB'] or "SUBCLADE_B"
]]
local suffix = { [1]="A", [2]="B", [3]="C", [4]="D", [5]="E"}, [6]="F", [7]="G", [8]="H", [9]="I", [10]="J",
[11]="K", [12]="L", [13]="M", [14]="N", [15]="O", [16]="P", [17]="Q", [18]="R", [19]="S", [20]="T",
for i=1, 5, 1 do
[21]="U", [22]="V", [23]="W", [24]="X", [25]="Y", [26]="Z"}
for i=1, 26, 1 do
local subclade = pargs['subclade'..suffix[i]]
local target = pargs['target'..suffix[i]] or "SUBCLADE_" .. suffix[i]
if subclade then
if string.find(cladeString, target) then
cladeString = string.gsub(cladeString,target,subclade)
-- <section begin=label /> and <section end=label />
local replacement = "<section begin="..target.." />\n"
.. subclade
.. "<section end="..target.." />"
cladeString = string.gsub(cladeString,target,mw.getCurrentFrame():preprocess(replacement))
end
end
end
--[[]
if subcladeA then
if string.find(cladeString,"SUBCLADE_A") then
cladeString = string.gsub(cladeString,"SUBCLADE_A",subcladeA)
end
--return subcladeA
end
if subcladeB then
if string.find(cladeString,"SUBCLADE_B") then
cladeString = string.gsub(cladeString,"SUBCLADE_B",subcladeB)
end
end
]]
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 204 ⟶ 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
-- - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
local branchThickness = tonumber(pargs['thickness'..tostring(childNumber)]) or nodeThickness
-- - the node parameters have no number, e.g. |color, |thickness, |state
local branchThicknessbranchState = tonumber(mw.getCurrentFrame():getParent().argspargs['thicknessstate'..tostring(childNumber)]) or nodeThicknessnodeState
if branchState == 'double' then
local branchColor = mw.getCurrentFrame():getParent().args['color'..tostring(childNumber)] or nodeColor
if branchThickness < 2 then branchThickness = 3 end -- need thick line for double
local branchStyle = mw.getCurrentFrame():getParent().args['style'..tostring(childNumber)] or ""
end
local branchState = mw.getCurrentFrame():getParent().args['state'..tostring(childNumber)] or nodeState -- "solid"
if branchState == 'double' then if branchThickness < 2 then branchThickness = 3 end end -- need thick line for double
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 223 ⟶ 209:
local useInlineStyle = false
-- use inline styling non-default color, line thickness or state have been set
if branchColor ~= "" or branchThickness ~= 1 or branchState ~= "solid" then
useInlineStyle = true
end
Line 230 ⟶ 216:
-- variables for right hand bar or bracket
--local barColor = ""
local barRight = mw.getCurrentFrame():getParent().argspargs['bar'..tostring(childNumber)] or "0"
local barBottom = mw.getCurrentFrame():getParent().argspargs['barend'..tostring(childNumber)] or "0"
local barTop = mw.getCurrentFrame():getParent().argspargs['barbegin'..tostring(childNumber)] or "0"
local barLabel = mw.getCurrentFrame():getParent().argspargs['barlabel'..tostring(childNumber)] or ""
local groupLabel = mw.getCurrentFrame():getParent().argspargs['grouplabel'..tostring(childNumber)] or ""
local groupLabelStyle = mw.getCurrentFrame():getParent().argspargs['labelstylegrouplabelstyle'..tostring(childNumber)] or ""
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 251 ⟶ 239:
local classString = ''
local reverseClass = ''
local widthClass = ''
-- class to add if using reverse (rtl) cladogram;
Line 272 ⟶ 261:
end
end
 
if useInlineStyle or (branchStyle ~= '') or branchLength ~= "" or labelStyle ~= "" then
local branchLengthStyle = ""
styleString = 'style="' .. borderStyle .. branchStyle .. '"'
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 304 ⟶ 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;"
-- wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
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
classString = 'class="clade-leaf' .. reverseClass .. '"'
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' .. nodeLeafcontent -- the new line causes <p> wrapping for plain leaf terminals
local leafCellString = '\n|rowspan=2 ' .. classString .. styleString .. ' |' .. content
--cladeString = cladeString .. leafCellString
Line 327 ⟶ 362:
if groupLabel ~= "" then
-- groupLabelStyle = groupLabelStyle .. 'border-left:5px solid red;'
barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. ' style="'.. groupLabelStyle .. '" |' .. groupLabel
else -- uncomment following line to see the cell structure
Line 345 ⟶ 379:
-- (6) add cell containing sublabel
local subLabel = mw.getCurrentFrame():getParent().argspargs['sublabel'..tostring(childNumber)] or "" -- request in addLabel
-- FOR TESTING: use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY)
Line 364 ⟶ 398:
end
end
if borderStyle ~= '' or branchStyle ~= '' or branchLength ~= '' or sublabelStyle ~= "" then
local branchLengthStyle = ""
styleString = ' style="' .. borderStyle .. branchStyle .. '"'
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 371 ⟶ 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 399 ⟶ 448:
end
 
---------------------------------------------------------------------------------------------
--[[ reverse version;
currently duplicates the code changing order of elements (bars, leaf, label, sublabel)
variables border-right
--]]
function p.addTaxonReverse(childNumber, nodeLeaf, nodeLabel, lastNode)
 
-- (1) get formating parameters for branch (default to global nodeParameters)
-- - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
-- - the node parameters have no number, e.g. |color, |thickness, |state
local branchThickness = tonumber(mw.getCurrentFrame():getParent().args['thickness'..tostring(childNumber)]) or nodeThickness
local branchColor = mw.getCurrentFrame():getParent().args['color'..tostring(childNumber)] or nodeColor
local branchStyle = mw.getCurrentFrame():getParent().args['style'..tostring(childNumber)] or ""
local branchState = mw.getCurrentFrame():getParent().args['state'..tostring(childNumber)] or nodeState -- "solid"
if branchState == 'double' then if branchThickness < 2 then branchThickness = 3 end end -- need thick line for double
 
-- the left border takes node parameters, the bottom border takes branch parameters
local bottomBorder = tostring(branchThickness) ..'px ' .. branchState .. (branchColor~="" and ' ' .. branchColor or '')
local leftBorder = tostring(nodeThickness) ..'px ' .. nodeState .. (nodeColor~="" and ' ' .. nodeColor or '')
-- variables for right hand bar or bracket
--local barColor = ""
local barRight = mw.getCurrentFrame():getParent().args['bar'..tostring(childNumber)] or "0"
local barBottom = mw.getCurrentFrame():getParent().args['barend'..tostring(childNumber)] or "0"
local barTop = mw.getCurrentFrame():getParent().args['barbegin'..tostring(childNumber)] or "0"
local barLabel = mw.getCurrentFrame():getParent().args['barlabel'..tostring(childNumber)] or ""
local groupLabel = mw.getCurrentFrame():getParent().args['grouplabel'..tostring(childNumber)] or ""
local groupLabelStyle = mw.getCurrentFrame():getParent().args['labelstyle'..tostring(childNumber)] or ""
 
--replace colours with format string; need right bar for all three options
if barRight ~= "0" then barRight = "2px solid " .. barRight end
if barTop ~= "0" then barRight = "2px solid " .. barTop end
if barBottom ~= "0" then barRight = "2px solid " .. barBottom end
if barTop ~= "0" then barTop = "2px solid " .. barTop end
if barBottom ~= "0" then barBottom = "2px solid " .. barBottom end
-- now construct wikitext
local styleString = ''
local cladeString = ''
-- (1) wikitext for new row
cladeString = cladeString .. '\n|-'
 
-- (4) stuff for right-hand brackets (or left hand brackets in reverse version)
 
-- note: it might be useful to add rowspan=2 to allow full range of positions
if groupLabel ~= ""then
cladeString = cladeString .. '\n|rowspan=2 class="clade-bar" style="'.. groupLabelStyle .. '" |' .. groupLabel
end
--[[ don't use bar label in the reverse version (probably best to get rid altogether)
if barRight ~= "0" then
cladeString = cladeString .. '&nbsp;&nbsp;' -- add spaces between leaf text and bar
if barLabel ~= "" then
cladeString = cladeString .. '\n|rowspan=2 style="vertical-align:middle;" |' .. barLabel
end
end
--]]
 
 
-- (3) add cell with leaf (which may be a table with transluded clade content)
--cladeString = cladeString .. '|| rowspan=2 style="border: 0; padding: 0; border-right: ' .. barRight .. ';border-bottom: ' .. barBottom .. ';border-top: ' .. barTop .. ';' .. branchStyle .. ' " | '
styleString = ''
if barRight ~= "0" then
--(before CSS styling) -- styleString = 'style="border:0;padding:0;border-right:' .. barRight .. ';border-bottom:' .. barBottom .. ';border-top:' .. barTop .. ';' .. branchStyle .. '"'
styleString = ' style="border-left:' .. barRight .. ';border-bottom:' .. barBottom .. ';border-top:' .. barTop .. ';' .. branchStyle .. '"'
else
--(before CSS styling) -- styleString = 'style="border:0;padding:0;' .. branchStyle .. '"'
if (branchStyle ~= '') then
styleString = ' style="' .. branchStyle .. '"'
end
end
-- add wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
cladeString = cladeString .. '\n|rowspan=2 class="clade-leafR"' .. styleString .. '|\n' .. nodeLeaf
--cladeString = cladeString .. '\n' .. nodeLeaf -- needs to be on newline if new wikitable
 
-- (2) now add cell with label
styleString = ''
if childNumber == 1 then
-- the width gives minimum spacing when all labels are empty (was 1.5em)
--(before CSS styling) -- styleString = ' style="width:1em;border:0;padding:0 0.2em;border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'
styleString = 'style="border-bottom:' .. bottomBorder .. ';' .. branchStyle .. '"'
else -- for 2-17
--(before CSS styling) -- styleString = ' style="border:0;padding:0 0.2em;border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'
styleString = 'style="border-right:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';' .. branchStyle .. '"'
end
-- add wikitext for cell with label
cladeString = cladeString .. '\n|class="clade-label" ' .. styleString .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel)
 
 
-- (5) add second row (only one cell needed for sublabel because of rowspan=2)
local branchStyleString = 'style="' .. branchStyle .. '" '
if branchStyle == '' then branchStyleString = '' end -- avoid empty style elements
cladeString = cladeString .. '\n|-' .. branchStyleString
local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(childNumber)] or "" -- request in addLabel
-- FOR TESTING: use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY)
--subLabel= '(N=' .. infoOutput .. ')'
-- END TESTING
-- (6) add cell containing sublabel
if childNumber~=lastNode then -- if childNumber==lastNode we don't want left border, otherwise we do
styleString = ' style="border-right:' .. leftBorder ..';"'
else
--cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> '
--(before CSS styling) -- styleString = 'style="border:0;vertical-align:top;text-align:center;"'
styleString = ''
end
local sublabel = p.addLabel(childNumber,subLabel)
local classString = '' -- class only needed if there is a label to display
if sublabel ~= '<br/>' then classString = 'class="clade-slabel" ' end
cladeString = cladeString .. '\n|' .. classString .. styleString .. '|' .. sublabel
return cladeString
end
 
 
Line 526 ⟶ 454:
function p.addLabel(childNumber,nodeLabel)
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""
 
--local firstChars = string.sub(nodeLabel, 1,2) -- get first two characters; will be {{ if no parameter (for Old method?)
--if firstChars == "{{{" or nodeLabel == "" then
if nodeLabel == "" then
--return '<br/>' --'&nbsp;<br/>' -- remove space to reduce post-expand include size (the width=1.5em handles spacing)
--return '<br/>' -- must return something; this is critical for clade structure
--return '&#8239;' -- &nbsp; &thinsp; &#8239;(thin nbsp)
else
-- spaces can cause wrapping and can break tree structure, hence use span with nowrap class
Line 543 ⟶ 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," ", "&nbsp;") -- replace spaces with non-breaking space
local nowrapString = nodeLabel -- spaces are now handled by CSS "white-space:nowrap;""
-- could replace hyphen with non-breaking hyphen (&#8209;)
if not nowrapString:find("UNIQ.-QINU") then -- unless a strip marker
nowrapString = string.gsub(nowrapString,"-", "&#8209;") -- replace hyphen with non-breaking hyphen (&#8209;)
end
return nowrapString
end
Line 590 ⟶ 522:
local i=1
while s[i] do
local restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas
--restoredString = s[i]
local outerTerm = string.gsub(restoredString, "%b()", "")
Line 611 ⟶ 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
sep = "%s"
end
local t={} ; i=1
local i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
Line 632 ⟶ 566:
function p.newickConverter(frame)
local newickString = frame.args['newickstring'] or pargs['newick']
--if newickString == '{{{newickstring}}}' then return newickString end
if newickString == '{{{newickstring}}}' then return newickString end
 
newickString = p.processNewickString(newickString,"") -- "childNumber")
-- show the Newick string
local cladeString = ''
Line 648 ⟶ 584:
 
local resultString = ''
local option = mw.getCurrentFrame():getParent().argspargs['option'] or ''
if option == 'tree' then
--show the transcluded clade diagram
Line 697 ⟶ 633:
local i=1
while s[i] do
local restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas
local outerTerm = string.gsub(restoredString, "%b()", "")
Line 716 ⟶ 652:
function p.getIndent(levelNumber)
local indent = "\r"
local extraIndent = pargs['indent'] or mw.getCurrentFrame():getParent().args['indent'] or 0
while tonumber(extraIndent) > 0 do
Line 734 ⟶ 670:
end
function p.processNewickString(newickString,childNumber)
 
local maxPatterns = 5
local i = 0
local pargs = pargs
local pattern = pargs['newick'..tostring(childNumber)..'-pattern'] -- unnumbered option for i=1
local replace = pargs['newick'..tostring(childNumber)..'-replace']
while i < maxPatterns do
i=i+1
pattern = pattern or pargs['newick'..tostring(childNumber)..'-pattern'..tostring(i)]
replace = replace or pargs['newick'..tostring(childNumber)..'-replace'..tostring(i)] or ""
if pattern then
newickString = string.gsub (newickString, pattern, replace)
end
pattern = nil; replace = nil
end
newickString = string.gsub (newickString, "_", " ") -- replace underscore with space
return newickString
end
------------------------------------------------------------------------------------------
 
Line 745 ⟶ 701:
-------------------------------------------------------------------------------------------
 
function p.toggle(frame)
if 1==2 then return 'some text' end
--local toggleSymbol = 'toggle all'
local toggleSymbol = mw.getCurrentFrame():getParent().args['button'] or ""
 
local toggleString = '<div class="'
local i=0
while i < 20 do -- limit on number of toggle elements controlled by the trigger button
i = i + 1 -- so we start with 1
local target = mw.getCurrentFrame():getParent().args['id'..tostring(i)]
-- add classes for the three elements of each target: expand symbol, collapse symbol and contents
if target ~= nil then
toggleString = toggleString .. ' mw-customtoggle-myClade' .. target
.. ' mw-customtoggle-collapseSymbol' .. target
.. ' mw-customtoggle-expandSymbol' .. target
end
end
toggleString = toggleString .. '">' .. toggleSymbol .. '</div>'
 
return toggleString
end
-----------------------------------------------------------------------------------------------
function p.hidden(frame)
local id = mw.getCurrentFrame():getParent().args['id'] or ""
local mode = mw.getCurrentFrame():getParent().args['mode'] or "right"
local expandSymbol = mw.getCurrentFrame():getParent().args['expand-symbol'] or "&#8862;"
local collapseSymbol = mw.getCurrentFrame():getParent().args['collapse-symbol'] or "&#8863;"
local initialState = mw.getCurrentFrame():getParent().args['expanded']
-- default is content collapsed
local contentState = " mw-collapsed" -- class to collapse content at start
local collapseSymbolState = " mw-collapsed"
local expandSymbolState = ""
if initialState then
contentState = ""
collapseSymbolState = ""
expandSymbolState = " mw-collapsed"
end
-- collapsible element containing the expand sympol and/or text
local expandSymbolString = '<td style="padding:0 0 0.25em 0;">'
.. '<div class="mw-collapsible' .. expandSymbolState .. '" id="mw-customcollapsible-expandSymbol' .. id .. '">'
.. '<div class="mw-collapsible-content mw-customtoggle-expandSymbol' .. id .. '">'
.. '<span class="mw-customtoggle-myClade' .. id
.. ' mw-customtoggle-collapseSymbol' .. id
.. ' mw-customtoggle-expandSymbol' .. id
.. '" style="font-size:100%;">' .. expandSymbol .. '</span>'
.. '</div></div></td>'
-- collapsible element containing the clade content
local contentString = '<td style="padding:0;">'
.. '<div class="mw-collapsible' .. contentState .. '" id="mw-customcollapsible-myClade' .. id .. '>'
.. '<div class="mw-collapsible-content mw-customtoggle-NOT_ON_CONTENT" >' -- don't toggle on the content
.. '\n' .. p.main(frame) -- important to start wikitext tables on new line
.. '</div></div></td>'
-- collapsible element containing the collapse sympol and/or text
local collapseSymbolString = '<td style="padding:0 0 0.4em 0;">'
.. '<div class="mw-collapsible' .. collapseSymbolState .. '" id="mw-customcollapsible-collapseSymbol' .. id .. '">'
.. '<div class="mw-collapsible-content mw-customtoggle-collapseSymbol' .. id .. '" >'
.. '<span class="mw-customtoggle-expandSymbol' .. id
.. ' mw-customtoggle-myClade' .. id
.. ' mw-customtoggle-collapseSymbol' .. id
.. ' " style="font-size:100%;" >' .. collapseSymbol .. '</span>'
.. '</div></div></td>'
 
 
local tableStyle = frame.args.style or ""
if tableStyle == '{{{style}}}' then tableStyle = "" end
local cladeString = '<table style="border-spacing:0;margin:0;'..tableStyle ..'"><tr>'
cladeString = cladeString .. expandSymbolString
if mode == "left" then
cladeString = cladeString .. collapseSymbolString
end
cladeString = cladeString .. contentString
if mode == "right" then
cladeString = cladeString .. collapseSymbolString
end
-- Note: if we want collapse string left and right it needs an extra element with a different id
cladeString = cladeString .. '</tr></table>'
 
 
return cladeString
end
------------------------------------------------------------------------------------------
 
--[[function getCladeTreeInfo()
Line 859 ⟶ 722:
while childNumber < maxChildren do -- preprocessing loop
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf,data = mw.getCurrentFrame():getParent().argspargs[tostring(childNumber)] or "" -- get data from |N=
local newickString = mw.getCurrentFrame():getParent().argspargs['newick'..tostring(childNumber)] or "" -- get data from |labelN=
local listString = pargs['list'..tostring(childNumber)] or "" -- get data from |labelN=
if newickString ~= "" or nodeLeaf ~= "" then
if newickString ~= "" or nodeLeaf ~= "" or listString ~= "" then
--if nodeLeaf ~= "" then
childCount = childCount + 1 -- this counts child elements in this clade
Line 921 ⟶ 785:
--return frame:preprocess(string.sub(code,3))
end
 
function p.testTable(frame)
 
function p.firstToUpper(str)
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 = ""
-- build HTML table
--count = count+1
local galleryTable = mw.html.create('table')
local list = mw.text.split(listString, "\n")
galleryTable:addClass('wikitable')
local i=1
galleryTable:addClass('sortable')
local child=1
galleryTable:css('text-align', 'center')
local lastNode=0--table.getn(list) -- number of child branches (potential)
 
cladeString = cladeString .. '{| class="clade" '
while list[i] do
galleryTable:tag('caption'):wikitext('Table created with mw.html')
list[i]=list[i]:gsub("^@", "") -- strip the first @
local row = galleryTable:tag('tr')
if not string.match( list[i], "^@", 1 ) then -- count children at this level (not beginning wiht @)
row:tag('th'):wikitext('Header 1')
lastNode = lastNode+1
row:tag('th'):wikitext('Header 2')
end
row:tag('th'):wikitext('Header 3')
i=i+1
--:attr('rowspan', 2)
end
i=1
row = galleryTable:tag('tr')
while list[i] do
row:tag('td'):css('text-align', 'left'):wikitext('A1')
 
row:tag('td'):css('text-align', 'left'):wikitext('B1')
--[[ pseudocode:
row:tag('td'):css('text-align', 'left'):wikitext('C1')
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|}'
local row2 = mw.html.create('tr') -- create an independent row element
row2:tag('td'):css('text-align', 'left'):wikitext('A3')
row2:tag('td'):css('text-align', 'left'):wikitext('B3')
row2:tag('td'):css('text-align', 'left'):wikitext('C3')
mw.addWarning("WARNING. This is a test feature only.")
row = galleryTable:tag('tr')
return cladeString
row:tag('td'):css('text-align', 'left'):wikitext('A2')
row:tag('td'):css('text-align', 'left'):wikitext('B2')
row:tag('td'):css('text-align', 'left'):wikitext('C2')
galleryTable:node(row2) -- now add row2 as node
return tostring(galleryTable)
end
-- =================== experimental Newick to clade parser function =============================
 
--[[Function of convert Newick strings to clade format
function p.example(frame)
 
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|newickConverter|newickstring={{{NEWICK_STRING}}} }}
]]
function p.cladeConverter(frame)
end
local params = mw.getCurrentFrame():getParent().args
function p.listConverter(frame)
-- build HTML table
local exampleTable = mw.html.create('table')
exampleTable:addClass('wikitable')
local align = params['align'] or 'center'
if align == 'center' then
exampleTable:css('margin-left', 'auto')
exampleTable:css('margin-right','auto')
elseif align == 'right' then
exampleTable:css('float',align)
end
local listString = frame.args['list'] or pargs['list']
local columns = {'description','code','output','comment'}
--local headers = {'Description','Code','Output','Comment'}
-- create header row and add requested headers
local row = exampleTable:tag('tr')
local headerText
for k,v in pairs(columns) do
if params[v] then
if params[v]~='' then headerText=params[v] else headerText = p.firstToUpper(v) end
row:tag('th'):wikitext(headerText)
end
end
 
-- now deal withshow the datalist rowsstring
local icladeString =0 ''
local levelNumber = 1 -- for depth of iteration
while i<10 do
local childNumber = 1 -- number of sister elements on node (always one for root)
i=i+1
local moreRowsindent = falsep.getIndent(levelNumber)
-- converted the newick string to the clade structure
for k,v in pairs(columns) do
cladeString = cladeString .. indent .. '{{clade'
if params[v..i] then moreRows = true end
cladeString = cladeString .. p.listParseLevel(listString, levelNumber, childNumber)
end
--cladeString = cladeString .. '\r}}'
if not moreRows then break end
 
local resultString = ''
row = exampleTable:tag('tr')
local option = pargs['option'] or ''
for k,v in pairs(columns) do
if params[v]option == 'tree' then
--show the transcluded clade diagram
if params[v] then
resultString = cladeString
row:tag('td'):css('text-align', 'left'):wikitext(params[v..i])
else
-- show the Newick string
row:tag('td')
resultString = '<pre>'..listString..'</pre>'
end
-- show the converted clade structure
end
resultString = resultString .. '<pre>'.. cladeString ..'</pre>'
end
end
--resultString = frame:expandTemplate{ title = 'clade', frame:preprocess(cladeString) }
 
return tostring(exampleTable)resultString
end
function p.firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
 
function p.listParseLevel(listString,levelNumber,childNumber)
-- display a gallery of cladograms using floating div elements
 
local cladeString = ""
function p.gallery(frame)
local indent = p.getIndent(levelNumber)
levelNumber=levelNumber+1
local params = mw.getCurrentFrame():getParent().args
 
local outerBorderslist = falsemw.text.split(listString, "\n")
local i=1
if params['caption'] or params['footer'] then outerBorders = true end
local child=1
local lastNode=0
while list[i] do
-- the gallery container
list[i]=list[i]:gsub("^@", "") -- strip the first @
local gallery = mw.html.create('div'):addClass('clade-gallery'):css('float',params['align'])
 
if not string.match( list[i], "^@", 1 ) then -- count children at this level (not beginning wiht @)
-- main caption for gallery if there is one
lastNode = lastNode+1
end
if params['main-caption'] then
i=i+1
gallery:tag('div'):wikitext(params['main-caption']):addClass('main-caption')
end
i=1
 
while list[i] do
-- a gallery of floating divs with content
 
local--[[ shadingpseudocode: = ''
if next value begins with @ we have a subtree,
--if params['shading'] then shading = 'shading' end -- class for shading
which must be recombined and past iteratively
if params['shading'] then shading = 'wikitable' end -- class for shading
else we have a simple leaf
]]
local vertical = '' -- defaults to horizontal
if params['vertical'] then vertical = 'vertical' end -- class for vertical display
local sizeStyling = ''
if params['width'] then sizeStyling = sizeStyling .. 'width:' .. params['width'] .. ';' end
if params['height'] then sizeStyling = sizeStyling .. 'height:' .. params['height'] .. ';' end
 
-- if the next value begins with @, we have a subtree which should be recombined
local noborder = ''
if list[i+1] and string.match( list[i+1], "^@", 1 ) then
if not params['main-borders'] then noborder = 'no-border' end
local label=list[i]
-- the gallery contents
i=i+1
local content = gallery:tag('div'):addClass('main-content'):addClass(noborder)
local recombined = list[i]
:css('height',params['height'])
while list[i+1] and string.match( list[i+1], "^@", 1 ) do
local i=0
recombined = recombined .. "\n" .. list[i+1]
while i<15 do
i=i+1
end
local caption = params['caption'..i] --or ''
cladeString = cladeString .. indent .. '|label' .. child ..'=' .. label
local header = params['header'..i] --or ''
cladeString = cladeString .. indent .. '|' .. child ..'=' .. '{{clade'
local footer = params['footer'..i] --or ''
.. p.listParseLevel(recombined,levelNumber,i)
-- for each gallery element containing a cladogram
if params['cladogram'..i] then
local cladogramTable = content:tag('table')
:addClass(shading):addClass('gallery-element'):addClass(vertical)
:css('width',params['width'])
:css('height',params['height'])
if caption then
cladogramTable:tag('caption'):wikitext(caption):addClass('caption')
end
if header then
local row = cladogramTable:tag('tr'):addClass('header')
row:tag('th'):wikitext(header)
end
-- if params['cladogram'..i] already checked
local row = cladogramTable:tag('tr')
row:tag('td'):wikitext("\n" .. params['cladogram'..i])
:addClass('cladogram')
--:css("padding", "20px")
:css('width',params['cladogram-width'])
:css('height',params['cladogram-height'])
if footer then
local row = cladogramTable:tag('tr')
row:tag('td'):wikitext(footer):addClass('footer'):addClass(shading)
end
--[[DIV VERSION - different browsers behave differently
-- the div containing each element in the gallery
local div = content:tag('div'):addClass('gallery-element'):addClass(direction)
:css('width',params['width'])
:css('height',params['height'])
-- the caption, header, content and footer for each element
if caption then div:tag('div'):wikitext(caption):addClass('caption'):addClass(shading) end
if header then div:tag('div'):wikitext(header):addClass('header'):addClass(shading) end
div:tag('div'):wikitext(params['cladogram'..i]):addClass('cladogram'):addClass(shading)
:css('width',params['cladogram-width'])
:css('height',params['cladogram-height'])
if footer then div:tag('div'):wikitext(footer):addClass('footer'):addClass(shading) end
END DIV VERSION--]]
else
cladeString = cladeString .. indent .. '|' .. child ..'=' .. list[i]
break
end
i=i+1
child=child+1
end
 
 
-- main footer
cladeString = cladeString .. indent .. '}}'
if params['main-footer'] then
return cladeString
gallery:tag('div'):wikitext(params['main-footer']):addClass('main-footer'):addClass(noborder)
end
-- TemplateStyles file
local src = "Template:Clade gallery/styles.css"
return p.templateStyle( frame, src ) .. tostring(gallery)
end
 
 
 
-- this must be at end