Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Clade: Difference between revisions

From Summertime Saga Wiki
Casiope (talk | contribs)
mNo edit summary
Casiope (talk | contribs)
No edit summary
Line 1: Line 1:
--[[NOTE: this module contains functions for generating the table structure of the clade tree:  
--NOTE: this module contains functions for generating the table structure of the clade tree in two ways:
 
-- (1) the original method was generated by a number of function calls from the template using {{invoke}}
The main function is called by the template using the {{invoke}} instruction; the three main functions are:
--        function p.openTable(frame) - creates wikitext code to open the HTML table
        p.main(frame) - opens and closes table, loops through the children of node, main is invoked once and controls the rest, calling ...
--        function p.node(frame)  - deals with the first node (|1,|label1) and creates wikitext for top row of the table
        p.addTaxon(childNumber, nodeLeaf) - the nuts and bolts; code dealing with each child node
--        function p.nodeN(frame) - deals with a sister nodes (|2-17), adding a row each time it is called
        p.addLabel(childNumber) - adds the label text
--        function p.closeTable() - closes the HTML table
       
-- (2) the revised method is called by the template with one {{invoke}} instruction; it has three functions:
        now uses templatestyles
--        p.main(frame) - opens and closes table, loops through the children of node, main is invoked once and controls the rest, calling ...
]]
--        p.addTaxon(childNumber, nodeLeaf) - the nuts and bolts; code dealing with each child node
--        p.addLabel(childNumber) - adds the label text


local p = {}
local p = {}
Line 13: Line 14:




--[[============================== main function ===========================
--============================== main function (for Method 2) ===========================
-- main function, which will generate the table structure of the tree
-- main function, which will  
--[[Main function to generate the table structure of the tree


Test version:
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE}}} }}
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE|}}} }}
Template: User:Jts1882/sandbox/templates/CladeN
Template:CladeN
]]


Release version:
Usage: {{#invoke:Clade|main|style={{{STYLE|}}} }}
Template:Clade
]]


function p.main(frame)
function p.main(frame)
Line 30: Line 28:
local maxChildren = 20 -- currently 17 in the clade/cladex templates
local maxChildren = 20 -- currently 17 in the clade/cladex templates
local childNumber = 0
local childNumber = 0
    lastNode = 0 -- make this global for now (declaring here prevents lua error for nil value in template)
local lastNode = 0
--local nodeCount = 0 -- total leafs plus new clade branches
local nodeCount = 0 -- total leafs plus new clade branches
--local leafCount = 0 -- just the terminal leaves
local leafCount = 0 -- just the terminal leaves
--local cladeCount = 0 -- new clade calls (each with a table)
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 childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon()
local totalCount = 0
local totalCount = 0
    infoOutput = p.getCladeTreeInfo() -- get info about clade structure, e.g. lastNode (last |N= child number)
--[[Note: this preprocessing loop gets information about the whole structure (number of nodes, leaves etc)
   
it makes a redundant calls to the templates through transclusion, but doen't affect the template depths;
    --[[ add the templatestyles tag 
it would probably be better to store the transcluded nodes in a table (a job for later)
          add to every clade table >> 137 times in Passeriformes test page
]]
          cladeCount==1 >> 43 insertions
--[[ disable proprocessing loop
          nodeCount==2 >> 5 insertions (once for the style css, one link in each cladegram)
while childNumber < maxChildren do -- preprocessing loop
                            2 in Neosuchia (one for style css, one link for second cladogram)
childNumber = childNumber + 1 -- so we start with 1
                            this is because it counts "dummy" clades and outer clades with one leaf
local nodeLeaf,data = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N=
          cladeCount==1 AND nodeCount==2 >>  1 insertions
 
              but none in Neosuchia
if nodeLeaf ~= "" then
    --]]
childCount = childCount + 1 -- this counts child elements in this clade
     -- worked for wrong reasons if nodeCount==2  then
   
     if cladeCount==then
    for i in string.gmatch(nodeLeaf, "|| rowspan") do -- count number of rows started (transclusion)
     cladeString = cladeString .. p.templateStyle( frame, src ) .. '\n'
  nodeCount = nodeCount + 1
     end
    end
   
    for i in string.gmatch(nodeLeaf, "{| cellspacing") do -- count number of tables started (transclusion)
   
  cladeCount = cladeCount + 1
    end
          -- _, cladeCount = string.gsub(nodeLeaf, "{| cellspacing", "")
            --_, nodeCount = string.gsub(nodeLeaf, "|| rowspan", "")
           
            --totalCount = totalCount + nodeCount
lastNode = childNumber
-- if data ~= nil then totalCount = totalCount + tonumber(data) else totalCount = totalCount + 1 end
end
 
 
--cladeString = cladeString .. '\n' .. ' count= ' .. totalCount
 
end
]]
     nodeCount = nodeCount + childCount --(elements passed down by transduction plus current child elements)
    cladeCount = cladeCount + 1        --(elements passed down by transduction plus current clade)
    leafCount = nodeCount-cladeCount+1
     totalCount =leafCount-- cladeCount --nodeCount
 
 
 
    local testing = false
    --testing = true                  -- COMMENT OUT TO GET MODULE RUNNING WITHOUT THE TEST
    if testing then  
     local dataString = p.test(1)
    cladeString = cladeString .. dataString
    return cladeString
     end
 
local tableStyle = frame.args.style or ""
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 == '{{{style}}}' then tableStyle = "" end
if tableStyle ~= "" then
tableStyle = ' style="' .. tableStyle .. '"' -- include style= in string to suppress empty style elements
end
   
    reverseClade =frame.args.reverse or false -- a global
    --ENFORCE GLOBAL FOR DEVELOPMENT
    --reverseClade = true


local captionName =mw.getCurrentFrame():getParent().args['caption'] or ""
local captionName =mw.getCurrentFrame():getParent().args['caption'] or ""
local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or ""
local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or ""


    -- add an element to mimick nowiki WORKS BUT DISABLE FOR DEMO PURPOSES
    --cladeString = '<p class="mw-empty-elt"></p>\n'
   
-- open table
-- open table
-- (border-collapse causes problems (see talk) -- cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;margin:0;' .. tableStyle .. '"'
--cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;margin:0;' .. tableStyle .. '"'
     -- (before CSS styling) -- cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"'
     cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"'
    cladeString = cladeString .. '{|class="clade"' .. tableStyle


     -- add caption
     -- add caption
Line 89: Line 104:
local moreNeeded = true
local moreNeeded = true
childNumber = 0
childNumber = 0
--lastNode = 0
lastNode = 0


--[[get child elements (add more rows for each child of node; each child is two rows)
--[[get child elements (add more rows for each child of node; each child is two rows)
Line 98: Line 113:
]]
]]
-- main loop
while childNumber < maxChildren do -- disable moreNeeded
while childNumber < lastNode do -- use the last number determined in the preprocessing
                                        -- while childNumber < 17 and moreNeeded == true do
 
childNumber = childNumber + 1 -- so we start with 1
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""  -- get data from |N=
local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""  -- get data from |N=
Line 111: Line 125:
nodeLabel = p.getNewickOuterterm(newickString) -- need to use terminal part of newick string for label
nodeLabel = p.getNewickOuterterm(newickString) -- need to use terminal part of newick string for label
end
end
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.newick(0, newickString), nodeLabel, lastNode)
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.newick(0, newickString), nodeLabel)
--lastNode=lastNode+1 -- there is a counting problem with the newickstring
lastNode = childNumber
elseif nodeLeaf ~= "" then -- if the node contains a leaf name or clade structue
elseif nodeLeaf ~= "" then -- if the node contains a leaf name or clade structue
--if reverseClade2 then
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel)
-- cladeString = cladeString .. '\n' .. p.addTaxonReverse(childNumber, nodeLeaf, nodeLabel, lastNode)
lastNode = childNumber
    --else
else
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode)
moreNeeded = false -- no |N= so don't look for more
--end
-- Note: this changes the behaviour. If there is no |2, it won't look for |3 or |4, which clade does (is this desirable?)
-- this has been disabled to allow consistent behaviour with clade/cladex (it will check to the limit set)
end
end
end
end


--[[finish last row by adding cell with no left border
        note: the row was started in addTaxon(), but the cell not added as left border yet to be determined;
            here the cell is added to the last child node with no left border as it is below the bracket
            this will be moved to addTaxon() when the number of the last child is known
  ]]
  local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(lastNode)] or ""  -- request in addLabel
--use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY)
--subLabel= '(N=' .. totalCount .. ')'
--cladeString = cladeString ..  '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> '
cladeString = cladeString ..  '\n' .. '|style="border:0;vertical-align:top;text-align:center;"|' .. p.addLabel(lastNode-1,subLabel)
    --[[ footer description (add addition row spanning two columns at bottom of table)
    this is designed to provide the description below the whole clade structure (mimicking cladogram);
    however, it can also be used to add labels and spacing to the whole clade structre
]]
local footerText  = mw.getCurrentFrame():getParent().args['footer'] or ""
local footerText  = mw.getCurrentFrame():getParent().args['footer'] or ""
local footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or ""
local footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or ""


if footerText ~= "" then
if footerText ~= "" then
  --cladeString = cladeString ..  '<tr><td>Test <br/><br/><br/><br/><br/></td></tr>'
  cladeString = cladeString ..  '\n|-style="' .. footerStyle .. '"\n|colspan="2"|<p>' .. footerText .. '</p>||'
  cladeString = cladeString ..  '\n|-style="' .. footerStyle .. '"\n|colspan="2"|<p>' .. footerText .. '</p>||'
  -- note the footer causes a problem with tr:last-child so need either
  -- (1) use <tfoot> but it is not allowed or incompatable
  --          cladeString = cladeString ..  '<tfoot><tr style="' .. footerStyle .. '"><td colspan="2"><p>' .. footerText .. '</p></td></tr></tfoot>'
  -- (2) always add footer and use nth:last-child(2) but is this backwards compatible
  -- (3) if footer= set the style inline for the last sublabel row (more a temp fix)
  -- (4) set class for first and last element (DONE. Also works well with reverse class)
end
end


Line 139: Line 166:
return cladeString
return cladeString
--return '<div style="width:auto;">\n' .. cladeString .. '</div>'
end
end


Line 149: Line 175:
    the middle elements (|2, |3 ...) use a left border to create the vertical line of the bracket
    the middle elements (|2, |3 ...) use a left border to create the vertical line of the bracket
    the first child element doesn't use a left border for the first cell in the top row (as it is above the bracket)
    the first child element doesn't use a left border for the first cell in the top row (as it is above the bracket)
    the last child doesn't use a left border for the first cell in the second row (as it is below the bracket)
    the last child doesn't use a left border for the first cell in the second row (as it is above the bracket)
    a complication is that the number of the last child node is not known;
    as a result the cells will be added to the row on the next iteration or after the main loop finishes
]]
]]
function p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode)
function p.addTaxon(childNumber, nodeLeaf, nodeLabel)


-- get border formating parameters for branch (default to global nodeParameters)
-- get leaf and labels
--local nodeLeaf  = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""    -- used passed variable to avoid redundancy
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""  -- request in addLabel
-- get formating parameters for branch (default to global nodeParameters)
--    - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
--    - the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
--    - the node parameters have no number, e.g. |color, |thickness, |state
--    - the node parameters have no number, e.g. |color, |thickness, |state
Line 163: Line 195:


     -- the left border takes node parameters, the bottom border takes branch parameters
     -- the left border takes node parameters, the bottom border takes branch parameters
    -- this has coding on the colours for green on black
   local bottomBorder =  tostring(branchThickness) ..'px ' .. branchState  .. (branchColor~="" and ' ' .. branchColor or '')
   local bottomBorder =  tostring(branchThickness) ..'px ' .. branchState  .. (branchColor~="" and ' ' .. branchColor or '')
   local leftBorder  =  tostring(nodeThickness)  ..'px ' .. nodeState  .. (nodeColor~="" and ' ' .. nodeColor or '')
   local leftBorder  =  tostring(nodeThickness)  ..'px ' .. nodeState  .. (nodeColor~="" and ' ' .. nodeColor or '')
--The default border styles are in the CSS (styles.css)
--    the inline styling is applied when thickness, color or state are change
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
-- variables for right hand bar or bracket
-- variables for right hand bar or bracket
Line 192: Line 213:
if barTop    ~= "0" then barTop    = "2px solid " .. barTop    end
if barTop    ~= "0" then barTop    = "2px solid " .. barTop    end
if barBottom ~= "0" then barBottom = "2px solid " .. barBottom end  
if barBottom ~= "0" then barBottom = "2px solid " .. barBottom end  
-- now construct wikitext  
-- now construct wikitext  
local styleString = ''
local cladeString = ''
local cladeString = ''
local styleString = ''
    local borderStyle = '' -- will be used if border color, thickness or state is to be changed
    local classString = ''
    local reverseClass = ''
   
    -- class to add if using reverse (rtl) cladogram;
    if reverseClade then reverseClass = ' reverse' end
   
    -- (1) wikitext for new row
    --cladeString = cladeString .. '\n|-'


-- (2) now add cell with label
--[[ first add cell to the spacing row (for 2-17); it completes the previous row
   
    why is this here rather than at the end of each row?
if useInlineStyle then
To allow left border (here while extending bracket) or not (end of bracket)
if childNumber == 1 then
]]
        borderStyle = 'border-left:none;border-right:none;border-bottom:' .. bottomBorder .. ';'
if childNumber ~= 1 then
        --borderStyle = 'border-bottom:' .. bottomBorder .. ';'
  local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(childNumber-1)] or "" -- request in addLabel
else -- for 2-17
if reverseClade then
    borderStyle  = 'border-left:none;border-right:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';'
    else
    borderStyle = 'border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';'
    end
end
end


  if useInlineStyle or (branchStyle ~= '') then
--styleString = ' style="border-left:' .. leftBorder ..';border-top:0;border-right:0;border-bottom:0;vertical-align:top;text-align:center;"'
  styleString = 'style="' .. borderStyle .. branchStyle .. '"'
styleString = ' style="border:0;border-left:' .. leftBorder ..';vertical-align:top;text-align:center;"'
    end
--cladeString = cladeString .. '| ' .. styleString .. ' | <br/> ' -- for sublabel ' | y<br/> '
cladeString = cladeString .. '|' .. styleString .. '|' ..  p.addLabel(childNumber-1,subLabel)
end  
 
  -- new row
  cladeString = cladeString .. '\n|-'


-- now add cell with label
styleString = ''
if childNumber == 1 then
if childNumber == 1 then
classString= 'class="clade-label first" '   -- add class first for top row
-- the width gives minimum spacing when all labels are empty (was 1.5em)
    else
--styleString = ' style="width:1em;border-bottom:' .. bottomBorder .. ';border-left:0;border-top:0;border-right:0;padding:0 0.2em;vertical-align:bottom;text-align:center;' .. branchStyle .. '"'
     classString = 'class="clade-label' .. reverseClass .. '" ' -- add "reverse" class if ltr cladogram
styleString = ' style="width:1em;border:0;padding:0 0.2em;border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'
     end
else -- for 2-17
     styleString = ' style="border:0;padding:0 0.2em;border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'
end
     cladeString = cladeString .. '\n|' .. styleString  .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel)


    -- wikitext for cell with label
-- add cell with leaf (which may be a table with transluded content)
     local labelCellString = '\n|' .. classString .. styleString  .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel)
     --cladeString = cladeString .. '|| rowspan=2 style="border: 0; padding: 0; border-right: ' .. barRight .. ';border-bottom: ' .. barBottom .. ';border-top: ' .. barTop .. ';' .. branchStyle .. ' " | '
   
styleString = '' 
    --cladeString = cladeString .. labelCellString
 
---------------------------------------------------------------------------------
-- (3) add cell with leaf (which may be a table with transluded clade content)
   
     if barRight  ~= "0"  then  
     if barRight  ~= "0"  then  
     if reverseClade then -- we want the bar on the left
     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
    styleString = ' style="border-right:' .. barRight .. ';border-bottom:' .. barBottom .. ';border-top:' .. barTop .. ';' .. branchStyle .. '"'
    end
    else
    if (branchStyle ~= '') then
    styleString = ' style="' .. branchStyle .. '"'
        else
        styleString = '' -- use defaults in styles.css
        end
    end
 
    -- wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
 
    classString = 'class="clade-leaf' .. reverseClass .. '"'
 
    local leafCellString = '\n|rowspan=2 ' .. classString  .. styleString .. ' |\n' .. nodeLeaf
 
    --cladeString = cladeString .. leafCellString
 
   
    -------------------------------------------
    -- (4) stuff for right-hand bracket labels
 
  classString='class="clade-bar' .. reverseClass .. '"'
   
    local barLabelCellString = ''
if barRight  ~= "0"  and barLabel ~= "" then
  barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. barLabel
else -- uncomment following line to see the cell structure
  --barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. 'BL'
end
if groupLabel ~= "" then
barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. ' style="'.. groupLabelStyle .. '" |' .. groupLabel
else -- uncomment following line to see the cell structure
    --barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. '" |' .. 'GL'
  end
 
  --cladeString = cladeString .. barLabelCellString
   
-------------------------------------------------------------------------------------
-- (5) add second row (only one cell needed for sublabel because of rowspan=2);
--    note: earlier versions applied branch style to row rather than cell
--          for consistency, it is applied to the sublabel cell as with the label cell
--cladeString = cladeString .. '\n|-'
-----------------------------------
-- (6) add cell containing sublabel
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)
--if childNumber==lastNode then subLabel= infoOutput end
-- END TESTING
borderStyle = ''
styleString = ''
if useInlineStyle then
if childNumber==lastNode then -- if childNumber==lastNode we don't want left border, otherwise we do
borderStyle = 'border-right:none;border-left:none;'
    else
if reverseClade then
    borderStyle  = 'border-left:none;border-right:' .. leftBorder .. ';'
    else
    borderStyle  = 'border-right:none;border-left:' .. leftBorder .. ';' 
    end
    end
    end
    if borderStyle ~= '' or  branchStyle ~= '' then       
      styleString = ' style="' .. borderStyle .. branchStyle .. '"'
    end
 
    --local sublabel = p.addLabel(childNumber,subLabel)
 
    if childNumber == lastNode then
    classString = 'class="clade-slabel last" '  
     else
     else
        classString = 'class="clade-slabel' .. reverseClass .. '" '
    styleString = 'style="border:0;padding:0;' .. branchStyle .. '"'
     end
     end
    local sublabelCellString = '\n|' .. classString .. styleString .. '|' ..  p.addLabel(childNumber,subLabel)
   
    --cladeString = cladeString .. sublabelCellString


     -- constuct child element wikitext
     cladeString = cladeString .. '||rowspan=2 ' .. styleString .. '|'
    if reverseClade then
     -- note: this is where leading spaces can be added to labels and leaves. This was commented out in the clade template. Most trees seem to have added spaces, to would need to check for existing spaces; however, cladex uses it
    cladeString = cladeString .. '\n|-'
     -- or could use padding:0 0.2em in cell style as for labels
    cladeString = cladeString .. barLabelCellString
    cladeString = cladeString .. '\n' .. nodeLeaf
    cladeString = cladeString .. leafCellString
    cladeString = cladeString .. labelCellString
cladeString = cladeString .. '\n|-'     
cladeString = cladeString .. sublabelCellString
     else
    cladeString = cladeString .. '\n|-'
    cladeString = cladeString .. labelCellString
    cladeString = cladeString .. leafCellString
    cladeString = cladeString .. barLabelCellString
cladeString = cladeString .. '\n|-'     -- add second row (only one cell needed for sublabel because of rowspan=2);
cladeString = cladeString .. sublabelCellString
    end
      
      
return cladeString
     -- stuff for right-hand bar-bracket
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  
if barRight  ~= "0"  then  
     cladeString = cladeString .. '&nbsp;&nbsp;'            -- add spaces between leaf text and bar
     cladeString = cladeString .. '&nbsp;&nbsp;'            -- add spaces between leaf text and bar
if barLabel ~= "" then  
if barLabel ~= "" then  
cladeString = cladeString .. '\n|rowspan=2 style="vertical-align:middle;" |' .. barLabel  
-- cladeString = cladeString .. '\n| ' .. barLabel end  -- experiment for labeling the bar
cladeString = cladeString .. '<td style="vertical-align:middle;">' .. barLabel ..'</td>'
end
end
end  
end  
    --]]
if groupLabel ~= ""then  
 
     --cladeString = cladeString .. '&nbsp;&nbsp;'           -- add spaces between leaf text and bar (could use padding)
 
cladeString = cladeString .. '<td style="'.. groupLabelStyle .. '">' .. groupLabel ..'</td>'  
-- (3) add cell with leaf (which may be a table with transluded clade content)
end
    --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)


   
-- add row (needed because of rowspan=2);
    -- note: the cell will be added on the next iteration of addTaxon (with left border) or after the main loop (without left border)
 
-- (5) add second row (only one cell needed for sublabel because of rowspan=2)  
     local branchStyleString = 'style="' .. branchStyle .. '"  '  
     local branchStyleString = 'style="' .. branchStyle .. '"  '  
     if branchStyle == '' then branchStyleString = ''  end -- avoid empty style elements
     if branchStyle == '' then branchStyleString = ''  end -- avoid empty style elements
cladeString = cladeString .. '\n|-' .. branchStyleString
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)
-- TODO code to put whole row here instead of completing on next call to addTaxon() or after main loop
--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
return cladeString
end
end


--[[ adds text for label or sublabel to a cell
--[[ adds text for label or sublabel to a cell
Line 476: Line 290:
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""
--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?)
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 ~= "{{{label1}}}" then
if nodeLabel == "" then
if firstChars == "{{{" or nodeLabel == "" then
--return '<br/>' --'&nbsp;<br/>'  -- remove space to reduce post-expand include size (the width=1.5em handles spacing)
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
else
-- spaces can cause  wrapping and can break tree structure, hence use span with nowrap class
-- spaces can cause  wrapping and can break tree structure, hence use span with nowrap class
Line 496: Line 308:
     else
     else
     local nowrapString = string.gsub(nodeLabel," ", "&nbsp;") -- replace spaces with non-breaking space
     local nowrapString = string.gsub(nodeLabel," ", "&nbsp;") -- replace spaces with non-breaking space
                      -- could replace hyphen with non-breaking hyphen (&#8209;)
return nowrapString
return nowrapString
end
end
Line 509: Line 320:
return string.gsub(newickString, "%b()", "")  -- delete parenthetic term
return string.gsub(newickString, "%b()", "")  -- delete parenthetic term
end
end
function p.newick(count,newickString)
function p.newick(count,newickString)
local cladeString = ""
local cladeString = ""
count = count+1
count = count+1
--start table
--start table
--cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;'
cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;'
cladeString = cladeString .. '{| class="clade" '
local j,k
local j,k
Line 532: Line 340:
--cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "")
--cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "")


    -- this needs a lastNode variable
local s = strsplit(innerTerm2, ",")
local s = strsplit(innerTerm2, ",")
--oldLastNode=lastNode
local lastNode=table.getn(s) -- number of child branches
local i=1
local i=1
while s[i] do
while s[i] do
Line 543: Line 348:
if string.find(restoredString, '%(.*%)') then
if string.find(restoredString, '%(.*%)') then
--cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x")
--cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x")
cladeString = cladeString .. '\n' .. p.addTaxon(i, p.newick(count,restoredString), outerTerm, lastNode)
cladeString = cladeString .. '\n' .. p.addTaxon(i, p.newick(count,restoredString), outerTerm)
-- p.addTaxon(2, p.newick(count,newickString2), "root")
-- p.addTaxon(2, p.newick(count,newickString2), "root")
else
else
cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "", lastNode) --count)
cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "") --count)
end
end
i=i+1
i=i+1
end
end
  -- lastNode=oldLastNode
 
   
-- close table
-- close table
--cladeString = cladeString ..  '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> \n|}'
cladeString = cladeString ..  '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" | <br/> \n|}'
--cladeString = cladeString ..  '\n| <br/> \n|}' -- is this legacy for extra sublabel?
cladeString = cladeString ..  '\n|}'
return cladeString
return cladeString
end
end
Line 571: Line 374:
end
end


-- Bits from Peter Coxhead's module
--    https://en.wikipedia.org/w/index.php?title=Module:Autotaxobox&action=edit
--[[
Utility function primarily intended for use in checking and debugging.
Returns number of levels in a taxonomic hierarchy, starting from
the supplied taxon as level 1.
Usage: {{#invoke:Autotaxobox|nLevels|TAXON}}
]]
function p.nLevels(frame)
local currTaxon = frame.args[1]
    local i = 1
local maxN = 2
local searching = true
while searching and i < maxN  do
--local parent = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } }
local parent = frame:expandTemplate{ title =  currTaxon, args = {['machine code'] = 'parent' } }
if parent ~= '' then
currTaxon = parent
i = i + 1
else
searching = false
end
end
if searching then return currTaxon --maxN .. '+'
else return i
end
end
--[[
Utility function primarily intended for use in checking and debugging.
Returns a comma separated list of a taxonomic hierarchy, starting from
the supplied taxon.
Usage: {{#invoke:Autotaxobox|listAll|TAXON}}
]]
function p.listAll(frame)
local currTaxon = frame.args[1]
local i = 1
local searching = true
local maxN = 100
local lst = currTaxon
while i < maxN and searching do
local currCall = 'Template:Taxonomy/' .. currTaxon
local parent = frame:expandTemplate{ title = currCall, args = {['machine code'] = 'parent' } }
if parent ~= '' then
currTaxon = parent
lst = lst .. ', ' .. currTaxon
i = i + 1
else
searching = false
end
end
if searching then lst = lst .. '...' end
return lst .. ' (' .. i .. ')'
end


-- =================== experimental Newick to clade parser function =============================
-- =================== experimental Newick to clade parser function =============================
Line 611: Line 470:
end
end


--[[ Parse one level of Newick string
--[[ Parse one level of Newick sting
     This function receives a Newick string, which has two components
     This function recieves a Newick string, which has two components
       1. the right hand term is a clade label: |labelN=labelname
       1. the right hand term is a clade label: |labelN=labelname
       2. the left hand term in parenthesis has common delimited child nodes, each of which can be
       2. the left hand term in parenthesis has common delimited child nodes, each of which can be
Line 685: Line 544:
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------


function p.test(dummy)
local dataString = ""
    dataString = "NEWCLADE:"
   
    local childNumber =0
    local lastNode = 0
while childNumber < 17 do -- disable moreNeeded
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)]  or "" -- get data from |N=
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""  -- get data from |labelN=
        if nodeLeaf ~= "" then
dataString = dataString .. tostring(childNumber)


local firstChars = string.sub(nodeLeaf, 1,2) -- get first two characters
--if nodeLabel ~= "{{{label1}}}" then
if firstChars == "{{"  then
                dataString = dataString .. 'XXX' .. nodeLeaf
end
dataString = dataString .. 'LEAF:' .. nodeLeaf
lastNode = childNumber
end
end
    local numClades=0
    local numBranches=0
    -- _, count = string.gsub(dataString, "NEWCLADE", "NEXT")
 
    for i in string.gmatch(dataString, "NEWCLADE") do
  numClades = numClades + 1
    end
    dataString =  dataString .. '<br/>(numClades=' .. numClades .. ')'
    for i in string.gmatch(dataString, "LEAF") do
  numBranches = numBranches + 1
    end
    dataString =  dataString .. '<br/>(numClades=' .. numClades .. ')'
    dataString =  dataString .. '<br/>(numBranches=' .. numBranches .. ')'
   
mw:log(numClades)
--return 'numClades=' .. numClades .. '; numBranches=' .. numBranches
return  dataString
end
function p.test2(target)
function p.test2(target)
local target ="User:Jts1882/sandbox/templates/Template:Passeroidea"
local target ="User:Jts1882/sandbox/templates/Template:Passeroidea"
Line 691: Line 592:
return result
return result
end
end
-------------------------------------------------------------------------------------------


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)
function p.hidden(frame)
      
      
Line 785: Line 657:


return cladeString
return cladeString
end
------------------------------------------------------------------------------------------
--[[function getCladeTreeInfo()
    this preprocessing loop gets information about the whole structure (number of nodes, leaves etc)
it makes a redundant calls to the templates through transclusion, but doen't affect the template depths;
it provides the global lastNode that is used to limit the main while loop
--]]
function p.getCladeTreeInfo()
    -- enable proprocessing loop
    local childNumber = 0
    local childCount =0
    local maxChildren =20
   
    --info veriables (these are global for now)
    nodeCount=0
    cladeCount=0
    leafCount=0
   
while childNumber < maxChildren do -- preprocessing loop
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf,data = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""  -- get data from |N=
        local newickString = mw.getCurrentFrame():getParent().args['newick'..tostring(childNumber)] or ""  -- get data from |labelN=
if newickString ~= "" or nodeLeaf ~= "" then
--if nodeLeaf ~= "" then
childCount = childCount + 1  -- this counts child elements in this clade
    --[[]
    for i in string.gmatch(nodeLeaf, "||rowspan") do -- count number of rows started (transclusion)
  nodeCount = nodeCount + 1
    end
    for i in string.gmatch(nodeLeaf, '{|class="clade"') do -- count number of tables started (transclusion)
  cladeCount = cladeCount + 1
    end
    ]]
    -- count occurences of clade structure using number of classes used and add to counters
            local _, nClades = string.gsub(nodeLeaf, 'class="clade"', "")
            local _, nNodes = string.gsub(nodeLeaf, 'class="clade%-leaf"', "")
            cladeCount = cladeCount + nClades
            nodeCount = nodeCount  + nNodes
           
lastNode = childNumber -- this gets the last node with a valid entry, even when missing numbers
end
end
--]]
    -- nodes can be either terminal leaves or a clade structure (table)
    --    note: should change class clade-leaf to clade-node to reflect this
    nodeCount = nodeCount            -- number of nodes (class clade-leaf) passed down by transduction
                    + childCount + 1 --  plus one for current clade and one for each of its child element
cladeCount = cladeCount + 1      -- number of clade structure tables passed down by transduction (plus one for current clade)
leafCount = nodeCount-cladeCount  -- number of terminal leaves (equals height of cladogram)
-- output for testing: number of clades / total nodes / terminal nodes (=leaves)
--                    (internal nodes)                  (cladogram height)
infoOutput = '<small>[' .. cladeCount .. '/' .. nodeCount .. '/' .. leafCount .. ']</small>'
return infoOutput
end
end


--[[ code for placing TemplateStyles from the module
    source: Anomie (CC-0)  https://phabricator.wikimedia.org/T200442
]]


function p.templateStyle( frame, src )
  return frame:extensionTag( 'templatestyles', '', { src = src } );
end


function p.showClade(frame)
-- this must be at end
--local code = frame.args.code or ""
    local code = frame:getParent().args['code2'] or ""
--return  code
--return mw.text.unstrip(code)
--local test = "<pre>Hello</pre>"
--return string.sub(test,6,-7)
local o1 =frame:getParent():getArgument('code2')
return o1:expand()
--return string.sub(code,2,-1)              -- strip marker  \127'"`UNIQ--tagname-8 hex digits-QINU`"'\127
--return frame:preprocess(string.sub(code,3))
end
function p.testTable(frame)
-- build HTML table
local galleryTable = mw.html.create('table')
galleryTable:addClass('wikitable')
galleryTable:addClass('sortable')
galleryTable:css('text-align', 'center')
    galleryTable:tag('caption'):wikitext('Table created with mw.html')
   
    local row = galleryTable:tag('tr')
row:tag('th'):wikitext('Header 1')
row:tag('th'):wikitext('Header 2')
row:tag('th'):wikitext('Header 3')
--:attr('rowspan', 2)
row = galleryTable:tag('tr')
row:tag('td'):css('text-align', 'left'):wikitext('A1')
row:tag('td'):css('text-align', 'left'):wikitext('B1')
row:tag('td'):css('text-align', 'left'):wikitext('C1')


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')
row = galleryTable:tag('tr')
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
function p.example(frame)
local params = mw.getCurrentFrame():getParent().args
-- 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 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 = firstToUpper(v) end
row:tag('th'):wikitext(headerText)
    end
    end
-- now deal with the data rows
local i=0
while i<10 do
i=i+1
local moreRows = false
for k,v in pairs(columns) do
if params[v..i] then moreRows = true end
end
if not moreRows then break end
row = exampleTable:tag('tr')
for k,v in pairs(columns) do
if params[v] then
if params[v] then
row:tag('td'):css('text-align', 'left'):wikitext(params[v..i])
else
row:tag('td')
end
end
end
    end
return tostring(exampleTable)
end
function firstToUpper(str)
    return (str:gsub("^%l", string.upper))
end
-- display a gallery of cladograms using floating div elements
function p.gallery(frame)
local params = mw.getCurrentFrame():getParent().args
    local outerBorders = false
    if params['caption'] or params['footer'] then outerBorders = true end
   
-- the gallery container
local gallery = mw.html.create('div'):addClass('clade-gallery'):css('float',params['align'])
-- main caption for gallery if there is one
if params['main-caption'] then
gallery:tag('div'):wikitext(params['main-caption']):addClass('main-caption')
end
-- a gallery of floating divs with content
    local shading = ''
--if params['shading'] then shading = 'shading' end -- class for shading
if params['shading'] then shading = 'wikitable' end -- class for shading
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
    local noborder = ''
    if not params['main-borders'] then noborder = 'no-border' end
   
    -- the gallery contents
    local content = gallery:tag('div'):addClass('main-content'):addClass(noborder)
                                      :css('height',params['height']) 
  local i=0
while i<15 do
i=i+1
local caption = params['caption'..i] --or ''
local header = params['header'..i] --or ''
local footer = params['footer'..i] --or ''
-- 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(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
      break
    end
end
-- main footer
if params['main-footer'] then
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
return p
return p

Revision as of 17:22, 14 June 2019

--NOTE: this module contains functions for generating the table structure of the clade tree in two ways: -- (1) the original method was generated by a number of function calls from the template using Template:Invoke -- function p.openTable(frame) - creates wikitext code to open the HTML table -- function p.node(frame) - deals with the first node (|1,|label1) and creates wikitext for top row of the table -- function p.nodeN(frame) - deals with a sister nodes (|2-17), adding a row each time it is called -- function p.closeTable() - closes the HTML table -- (2) the revised method is called by the template with one Template:Invoke instruction; it has three functions: -- p.main(frame) - opens and closes table, loops through the children of node, main is invoked once and controls the rest, calling ... -- p.addTaxon(childNumber, nodeLeaf) - the nuts and bolts; code dealing with each child node -- p.addLabel(childNumber) - adds the label text

local p = {}


--============================== main function (for Method 2) =========================== -- main function, which will --[[Main function to generate the table structure of the tree

Usage: Script error: No such module "Module:Sandbox/Jts1882/CladeN". Template: User:Jts1882/sandbox/templates/CladeN ]]


function p.main(frame)

local cladeString = "" local maxChildren = 20 -- currently 17 in the clade/cladex templates local childNumber = 0 local lastNode = 0 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

--[[Note: this preprocessing loop gets information about the whole structure (number of nodes, leaves etc) it makes a redundant calls to the templates through transclusion, but doen't affect the template depths; it would probably be better to store the transcluded nodes in a table (a job for later) ]] --[[ disable proprocessing loop while childNumber < maxChildren do -- preprocessing loop childNumber = childNumber + 1 -- so we start with 1 local nodeLeaf,data = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N=

if nodeLeaf ~= "" then childCount = childCount + 1 -- this counts child elements in this clade

for i in string.gmatch(nodeLeaf, "|| rowspan") do -- count number of rows started (transclusion)

  				nodeCount = nodeCount + 1
    		end

for i in string.gmatch(nodeLeaf, "{| cellspacing") do -- count number of tables started (transclusion)

  				cladeCount = cladeCount + 1
    		end
          -- _, cladeCount = string.gsub(nodeLeaf, "{| cellspacing", "")
           --_, nodeCount = string.gsub(nodeLeaf, "|| rowspan", "")
           
           --totalCount = totalCount + nodeCount

lastNode = childNumber -- if data ~= nil then totalCount = totalCount + tonumber(data) else totalCount = totalCount + 1 end end


--cladeString = cladeString .. '\n' .. ' count= ' .. totalCount

end ]]

   nodeCount = nodeCount + childCount --(elements passed down by transduction plus current child elements)
   cladeCount = cladeCount + 1        --(elements passed down by transduction plus current clade)
   leafCount = nodeCount-cladeCount+1
   totalCount =leafCount-- cladeCount --nodeCount 


   local testing = false
   --testing = true                  -- COMMENT OUT TO GET MODULE RUNNING WITHOUT THE TEST
   if testing then 
   	local dataString = p.test(1)
   	cladeString = cladeString .. dataString
   	return cladeString 
   end

local tableStyle = frame.args.style or "" if tableStyle == '{{{style}}}' then tableStyle = "" end

local captionName =mw.getCurrentFrame():getParent().args['caption'] or "" local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or ""

-- open table --cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;margin:0;' .. tableStyle .. '"'

   cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"'
   -- add caption

if captionName ~= "" then cladeString = cladeString .. '\n|+ style="' .. captionStyle .. '"|' .. captionName 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 childNumber = 0 lastNode = 0

--[[get child elements (add more rows for each child of node; each child is two rows) the function addTaxon is called to add the rows for each child element; each child add two rows: the first cell of each row contains the label or sublabel (below the line label), respectively; the second cell spans both rows and contains the leaf name or a new clade structure a third cell on the top row is sometimes added to contain a group to the right ]]

while childNumber < maxChildren do -- disable moreNeeded -- while childNumber < 17 and moreNeeded == true do childNumber = childNumber + 1 -- so we start with 1 local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- get data from |labelN=


local newickString = mw.getCurrentFrame():getParent().args['newick'..tostring(childNumber)] or "" -- get data from |labelN= if newickString ~= "" then -- if using a newick string instead of a clade structure 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 end cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.newick(0, newickString), nodeLabel) lastNode = childNumber elseif nodeLeaf ~= "" then -- if the node contains a leaf name or clade structue cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel) lastNode = childNumber else moreNeeded = false -- no |N= so don't look for more -- Note: this changes the behaviour. If there is no |2, it won't look for |3 or |4, which clade does (is this desirable?) -- this has been disabled to allow consistent behaviour with clade/cladex (it will check to the limit set) end end

--[[finish last row by adding cell with no left border

       note: the row was started in addTaxon(), but the cell not added as left border yet to be determined; 
            here the cell is added to the last child node with no left border as it is below the bracket
            this will be moved to addTaxon() when the number of the last child is known 
  	]]
  local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(lastNode)] or ""  -- request in addLabel

--use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY) --subLabel= '(N=' .. totalCount .. ')'

--cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" |
' cladeString = cladeString .. '\n' .. '|style="border:0;vertical-align:top;text-align:center;"|' .. p.addLabel(lastNode-1,subLabel)

   --[[ footer description (add addition row spanning two columns at bottom of table)
   	this is designed to provide the description below the whole clade structure (mimicking cladogram);
   	however, it can also be used to add labels and spacing to the whole clade structre

]] local footerText = mw.getCurrentFrame():getParent().args['footer'] or "" local footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or ""

if footerText ~= "" then

--cladeString = cladeString .. 'Test




' cladeString = cladeString .. '\n|-style="' .. footerStyle .. '"\n|colspan="2"|

' .. footerText .. '

||'

end

-- close table (wikitext to close table) cladeString = cladeString .. '\n|}'

return cladeString end

--[[ 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
    	the second cell is used for the leafname or a transcluded clade structure and spans both rows
    note that the first and last child nodes need to be handled differently from the middle elements

the middle elements (|2, |3 ...) use a left border to create the vertical line of the bracket the first child element doesn't use a left border for the first cell in the top row (as it is above the bracket) the last child doesn't use a left border for the first cell in the second row (as it is above the bracket) a complication is that the number of the last child node is not known; as a result the cells will be added to the row on the next iteration or after the main loop finishes ]] function p.addTaxon(childNumber, nodeLeaf, nodeLabel)

-- get leaf and labels --local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- used passed variable to avoid redundancy --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- request in addLabel

-- 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 =

--[[ first add cell to the spacing row (for 2-17); it completes the previous row why is this here rather than at the end of each row? To allow left border (here while extending bracket) or not (end of bracket) ]] if childNumber ~= 1 then

 		local subLabel = mw.getCurrentFrame():getParent().args['sublabel'..tostring(childNumber-1)] or ""  -- request in addLabel

--styleString = ' style="border-left:' .. leftBorder ..';border-top:0;border-right:0;border-bottom:0;vertical-align:top;text-align:center;"' styleString = ' style="border:0;border-left:' .. leftBorder ..';vertical-align:top;text-align:center;"' --cladeString = cladeString .. '| ' .. styleString .. ' |
' -- for sublabel ' | y
' cladeString = cladeString .. '|' .. styleString .. '|' .. p.addLabel(childNumber-1,subLabel) end

  -- new row
  cladeString = cladeString .. '\n|-'

-- now add cell with label styleString = if childNumber == 1 then -- the width gives minimum spacing when all labels are empty (was 1.5em) --styleString = ' style="width:1em;border-bottom:' .. bottomBorder .. ';border-left:0;border-top:0;border-right:0;padding:0 0.2em;vertical-align:bottom;text-align:center;' .. branchStyle .. '"' styleString = ' style="width:1em;border:0;padding:0 0.2em;border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'

	else -- for 2-17
   	styleString = ' style="border:0;padding:0 0.2em;border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'

end

   cladeString = cladeString .. '\n|' .. styleString  .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel)

-- add cell with leaf (which may be a table with transluded 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 
   	styleString = 'style="border:0;padding:0;border-right:' .. barRight .. ';border-bottom:' .. barBottom .. ';border-top:' .. barTop .. ';' .. branchStyle .. '"'
   else
   	styleString = 'style="border:0;padding:0;' .. branchStyle .. '"'
   end
   cladeString = cladeString .. '||rowspan=2 ' .. styleString .. '|'
   -- note: this is where leading spaces can be added to labels and leaves. This was commented out in the clade template. Most trees seem to have added spaces, to would need to check for existing spaces; however, cladex uses it
   -- or could use padding:0 0.2em in cell style as for labels
   cladeString = cladeString .. '\n' .. nodeLeaf
   
   -- stuff for right-hand bar-bracket

if barRight ~= "0" then

   	cladeString = cladeString .. '  '            -- add spaces between leaf text and bar

if barLabel ~= "" then -- cladeString = cladeString .. '\n| ' .. barLabel end -- experiment for labeling the bar

cladeString = cladeString .. '' .. barLabel ..''

end end if groupLabel ~= ""then

   	--cladeString = cladeString .. '  '            -- add spaces between leaf text and bar (could use padding)

cladeString = cladeString .. '' .. groupLabel ..''

end

-- add row (needed because of rowspan=2);

   -- note: the cell will be added on the next iteration of addTaxon (with left border) or after the main loop (without left border)
   local branchStyleString = 'style="' .. branchStyle .. '"  ' 
   if branchStyle ==  then branchStyleString =   end -- avoid empty style elements

cladeString = cladeString .. '\n|-' .. branchStyleString

-- TODO code to put whole row here instead of completing on next call to addTaxon() or after main loop


return cladeString end

--[[ adds text for label or sublabel to a cell ]] 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 nodeLabel ~= "{{{label1}}}" then if firstChars == "{{{" or nodeLabel == "" then return '
' --' 
' -- remove space to reduce post-expand include size (the width=1.5em handles spacing) else -- spaces can cause wrapping and can break tree structure, hence use span with nowrap class --return '' .. nodeLabel .. ''

-- a better method for template expansion size is to replace spaces with nonbreaking spaces -- however, there is a problem if labels have a styling element (e.g. <span style= ..., <span title= ...) local stylingElementDetected = false if string.find(nodeLabel, "span ") ~= nil then stylingElementDetected = true end if string.find(nodeLabel, " style") ~= nil then stylingElementDetected = true end

if stylingElementDetected == true then return '' .. nodeLabel .. ''

   	else	
   		local nowrapString = string.gsub(nodeLabel," ", " ") -- replace spaces with non-breaking space

return nowrapString end end end


--[[=================== Newick string handling function ============================= ]] function p.getNewickOuterterm(newickString) return string.gsub(newickString, "%b()", "") -- delete parenthetic term end function p.newick(count,newickString) local cladeString = "" count = count+1 --start table cladeString = cladeString .. '{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;'

local j,k j,k = string.find(newickString, '%(.*%)') -- find location of outer parenthesised term local innerTerm = string.sub(newickString, j+1, k-1) -- select content in parenthesis local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term if outerTerm == 'panthera' then outerTerm = "x" end -- how is this set in local variable for inner nodes?

outerTerm = tostring(count)

-- need to remove commas in bracket terms before split, so temporarily replace commas between brackets

   local innerTerm2 =  string.gsub(innerTerm, "%b()",  function (n)
                                        	return string.gsub(n, ",%s*", "XXX")  -- also strip spaces after commas here
                                           end)

--cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "")

local s = strsplit(innerTerm2, ",") local i=1 while s[i] do restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas --restoredString = s[i] local outerTerm = string.gsub(restoredString, "%b()", "") if string.find(restoredString, '%(.*%)') then --cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "x") cladeString = cladeString .. '\n' .. p.addTaxon(i, p.newick(count,restoredString), outerTerm) -- p.addTaxon(2, p.newick(count,newickString2), "root") else cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "") --count) end i=i+1 end

-- close table cladeString = cladeString .. '\n' .. '| style="border: 0; padding: 0; vertical-align: top;" |
\n|}'

return cladeString end -- emulate a standard split string function function strsplit(inputstr, sep)

       if sep == nil then
               sep = "%s"
       end
       local t={} ; i=1
       for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
               t[i] = str
               i = i + 1
       end
       return t

end


-- Bits from Peter Coxhead's module -- https://en.wikipedia.org/w/index.php?title=Module:Autotaxobox&action=edit

--[[ Utility function primarily intended for use in checking and debugging. Returns number of levels in a taxonomic hierarchy, starting from the supplied taxon as level 1. Usage: Script error: No such module "Autotaxobox". ]] function p.nLevels(frame) local currTaxon = frame.args[1]

   local i = 1

local maxN = 2 local searching = true while searching and i < maxN do --local parent = frame:expandTemplate{ title = 'Template:Taxonomy/' .. currTaxon, args = {['machine code'] = 'parent' } } local parent = frame:expandTemplate{ title = currTaxon, args = {['machine code'] = 'parent' } } if parent ~= then currTaxon = parent i = i + 1 else searching = false end end if searching then return currTaxon --maxN .. '+' else return i end end

--[[ Utility function primarily intended for use in checking and debugging. Returns a comma separated list of a taxonomic hierarchy, starting from the supplied taxon. Usage: Script error: No such module "Autotaxobox". ]] function p.listAll(frame) local currTaxon = frame.args[1] local i = 1 local searching = true local maxN = 100 local lst = currTaxon while i < maxN and searching do local currCall = 'Template:Taxonomy/' .. currTaxon local parent = frame:expandTemplate{ title = currCall, args = {['machine code'] = 'parent' } } if parent ~= then currTaxon = parent lst = lst .. ', ' .. currTaxon i = i + 1 else searching = false end end if searching then lst = lst .. '...' end return lst .. ' (' .. i .. ')' end

-- =================== experimental Newick to clade parser function =============================

--[[Function of convert Newick strings to clade format

Usage: Script error: No such module "Module:Sandbox/Jts1882/CladeN". ]] function p.newickConverter(frame)

local newickString = frame.args['newickstring']


if newickString == '{{{newickstring}}}' then return newickString end

-- show the Newick string local cladeString = local levelNumber = 1 -- for depth of iteration local childNumber = 1 -- number of sister elements on node (always one for root)

-- converted the newick string to the clade structure cladeString = cladeString .. '{{clade' cladeString = cladeString .. p.newickParseLevel(newickString, levelNumber, childNumber) cladeString = cladeString .. '\r}}'

local resultString =

   local option = mw.getCurrentFrame():getParent().args['option'] or 
   if option == 'tree' then

--show the transcluded clade diagram resultString = cladeString

   else
   	-- show the Newick string

resultString = '

'..newickString..'

'

-- show the converted clade structure

resultString = resultString .. '

'.. cladeString ..'

'

   end
   --resultString = frame:expandTemplate{ title = 'clade',  frame:preprocess(cladeString) }
   return resultString

end

--[[ Parse one level of Newick sting

    This function recieves a Newick string, which has two components
     1. the right hand term is a clade label: |labelN=labelname
     2. the left hand term in parenthesis has common delimited child nodes, each of which can be
          i.  a taxon name which just needs:  |N=leafname 
          ii. a Newick string which needs further processing through reiteration

]] function p.newickParseLevel(newickString,levelNumber,childNumber)


local cladeString = "" local indent = p.getIndent(levelNumber) --levelNumber=levelNumber+1

local j=0 local k=0 j,k = string.find(newickString, '%(.*%)') -- find location of outer parenthesised term local innerTerm = string.sub(newickString, j+1, k-1) -- select content in parenthesis local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term

cladeString = cladeString .. indent .. '|label'..childNumber..'=' .. outerTerm cladeString = cladeString .. indent .. '|' .. childNumber..'=' .. '{{clade'

levelNumber=levelNumber+1 indent = p.getIndent(levelNumber)

-- protect commas in inner parentheses from split; temporarily replace commas between parentheses local innerTerm2 = string.gsub(innerTerm, "%b()", function (n) return string.gsub(n, ",%s*", "XXX") -- also strip spaces after commas here end)

local s = strsplit(innerTerm2, ",") local i=1 while s[i] do restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas

local outerTerm = string.gsub(restoredString, "%b()", "") if string.find(restoredString, '%(.*%)') then --cladeString = cladeString .. indent .. '|y' .. i .. '=' .. p.newickParseLevel(restoredString,levelNumber+1,i) cladeString = cladeString .. p.newickParseLevel(restoredString,levelNumber,i) else cladeString = cladeString .. indent .. '|' .. i .. '=' .. restoredString --.. '(level=' .. levelNumber .. ')' end i=i+1 end -- end -- end splitting of strings

cladeString = cladeString .. indent .. '}}'

   return cladeString

end

function p.getIndent(levelNumber) local indent = "\r" local extraIndent = mw.getCurrentFrame():getParent().args['indent'] or 0

while tonumber(extraIndent) > 0 do indent = indent .. " " -- an extra indent to make aligining compound trees easier extraIndent = extraIndent - 1 end

while levelNumber > 1 do indent = indent .. " " levelNumber = levelNumber-1 end return indent end

function p.newickstuff(newickString)


end


function p.test(dummy) local dataString = ""

   dataString =	"NEWCLADE:"
   
   local childNumber =0
   local lastNode = 0

while childNumber < 17 do -- disable moreNeeded

childNumber = childNumber + 1 -- so we start with 1 local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N= --local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or "" -- get data from |labelN=

       if nodeLeaf ~= "" then

dataString = dataString .. tostring(childNumber)

local firstChars = string.sub(nodeLeaf, 1,2) -- get first two characters --if nodeLabel ~= "{{{label1}}}" then if firstChars == "{{" then

               dataString = dataString .. 'XXX' .. nodeLeaf

end dataString = dataString .. 'LEAF:' .. nodeLeaf

lastNode = childNumber end end

   local numClades=0
   local numBranches=0
   -- _, count = string.gsub(dataString, "NEWCLADE", "NEXT")
  
   for i in string.gmatch(dataString, "NEWCLADE") do
  		numClades = numClades + 1
    end
   dataString =   dataString .. '
(numClades=' .. numClades .. ')' for i in string.gmatch(dataString, "LEAF") do numBranches = numBranches + 1 end dataString = dataString .. '
(numClades=' .. numClades .. ')' dataString = dataString .. '
(numBranches=' .. numBranches .. ')'

mw:log(numClades)

--return 'numClades=' .. numClades .. '; numBranches=' .. numBranches return dataString end function p.test2(target) local target ="User:Jts1882/sandbox/templates/Template:Passeroidea" local result = mw.getCurrentFrame():expandTemplate{ title = target, args = {['style'] = } } return result 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 "⊞"
   local collapseSymbol = mw.getCurrentFrame():getParent().args['collapse-symbol'] or "⊟"
   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 = '' .. '

' .. '
'
               .. '' .. expandSymbol .. ''
.. '

'

   -- collapsible element containing the clade content 

local contentString = '' .. '

' .. '
' -- don't toggle on the content
               .. '\n' .. p.main(frame)  -- important to start wikitext tables on new line
.. '

'

   -- collapsible element containing the collapse sympol and/or text

local collapseSymbolString = '' .. '

' .. '
'
               .. '' .. collapseSymbol .. ''
.. '

'


local tableStyle = frame.args.style or "" if tableStyle == '{{{style}}}' then tableStyle = "" end

local cladeString = '

' 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 .. '

'


return cladeString end


-- this must be at end

return p