تبديل القائمة
Toggle preferences menu
تبديل القائمة الشخصية
غير مسجل للدخول
سيكون عنوان الآيبي الخاص بك مرئيًا للعامة إذا قمت بإجراء أي تعديلات.

وحدة:Clade: الفرق بين النسختين

من أرابيكا، الموسوعة العربية الحرة
المزيد من اللغات
لا ملخص تعديل
وسم: مُسترجَع
لا ملخص تعديل
وسم: استرجاع يدوي
 
سطر 1: سطر 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}}
--        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 {{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


The main function is called by the template using the {{invoke}} instruction; the three main functions are:
        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
       
        now uses templatestyles
]]
require('strict')
local getArgs = require('Module:Arguments').getArgs
local p = {}
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


--[[============================== main function  ===========================
-- main function, which will generate the table structure of the tree


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


Release version:
--============================== main function (for Method 2) ===========================
Usage: {{#invoke:Clade|main|style={{{STYLE|}}} }}
-- main function, which will
Template:Clade
--[[Main function to generate the table structure of the tree
 
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE}}} }}
Template: User:Jts1882/sandbox/templates/CladeN
]]
]]


function p.main(frame)
function p.main(frame)


local cladeString = ""
local cladeString = ""
local maxChildren = 20 -- was 17 in the clade/cladex templates
local maxChildren = 20 -- currently 17 in the clade/cladex templates
local childNumber = 0
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 childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon()
local totalCount = 0
local totalCount = 0
pargs = getArgs(frame) -- parent arguments
--[[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;
    infoOutput = p.getCladeTreeInfo() -- get info about clade structure, e.g. lastNode (last |N= child number)
it would probably be better to store the transcluded nodes in a table (a job for later)
   
]]
    --[[ add the templatestyles tag  conditionally to reduce expansion size (currently diabled)
--[[ disable proprocessing loop
        when added to every clade table, it increases post‐expand include size significantly
while childNumber < maxChildren do -- preprocessing loop
          e.g. the Neosuchia page (or test version) is increase by about 8% (672 bytes each)
childNumber = childNumber + 1 -- so we start with 1
                if template styles added to all pages there are 133 stripmarkers
local nodeLeaf,data = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""  -- get data from |N=
                with cladeCount==1 condition, this is reduced to 34
 
        however cladeCount==1 condition interfers with fix for additional line due to parser bug T18700
if nodeLeaf ~= "" then
        killing the strip markers also removes backlinks to references using citation templates
childCount = childCount + 1  -- this counts child elements in this clade
    --]]
   
    --cladeString =mw.text.killMarkers( cladeString ) -- also kills off strip markers using citation templates
    for i in string.gmatch(nodeLeaf, "|| rowspan") do -- count number of rows started (transclusion)
    --cladeString = mw.text.unstrip(cladeString)
  nodeCount = nodeCount + 1
    --if cladeCount==1 then
    end
    cladeString = cladeString .. frame:extensionTag('templatestyles', '',
    for i in string.gmatch(nodeLeaf, "{| cellspacing") do -- count number of tables started (transclusion)
    { src="Template:Clade/styles.css" }) .. '\n'
  cladeCount = cladeCount + 1
    --end
    end
   
          -- _, cladeCount = string.gsub(nodeLeaf, "{| cellspacing", "")
local tableStyle = frame.args.style or pargs.style or ""
            --_, 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


if tableStyle ~= "" then
tableStyle = ' style="' .. tableStyle .. '"' -- include style= in string to suppress empty style elements
end
end
      
]]
     reverseClade =frame.args.reverse or pargs.reverse or false -- a global
     nodeCount = nodeCount + childCount --(elements passed down by transduction plus current child elements)
     --ENFORCE GLOBAL FOR DEVELOPMENT
     cladeCount = cladeCount + 1        --(elements passed down by transduction plus current clade)
     --reverseClade = true
     leafCount = nodeCount-cladeCount+1
     totalCount =leafCount-- cladeCount --nodeCount
 
 


local captionName = pargs['caption'] or ""
    local testing = false
local captionStyle = pargs['captionstyle'] or ""
    --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 tableStyleString = ' style="' .. tableStyle .. '" '
if tableStyle == '{{{style}}}' then tableStyleString = "" end
local captionName =mw.getCurrentFrame():getParent().args['caption'] 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 .. '{| cellspacing=0 cellpadding=0 border=0 style="' .. tableStyle .. '"'
    -- (before CSS styling) -- cladeString = cladeString .. '{| style="border-spacing:0;margin:0;' .. tableStyle .. '"'
cladeString = cladeString .. '{|cellspacing=0 cellpadding=0 ' .. tableStyleString
    cladeString = cladeString .. '{|class="clade"' .. tableStyle
--cladeString = cladeString .. '{| cellspacing=0 ' .. tableStyleString  -- NOTE: cellpadding supposedly not supported in HTML5


     -- add caption
     -- add caption
if captionName ~= "" then
if captionName ~= "" then
cladeString = cladeString .. '\n|+ style="' .. captionStyle .. '"|' .. captionName
cladeString = cladeString .. '\n|+style="' .. captionStyle .. '"|' .. captionName
end
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
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)
سطر 97: سطر 115:
]]
]]
-- 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 = pargs[tostring(childNumber)] or ""  -- get data from |N=
local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""  -- get data from |N=
local nodeLabel = pargs['label'..tostring(childNumber)] or ""  -- get data from |labelN=
local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""  -- get data from |labelN=
local newickString = pargs['newick'..tostring(childNumber)] or ""  -- get data from |labelN=
local newickString = mw.getCurrentFrame():getParent().args['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
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
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


local footerText  = pargs['footer'] or ""
--[[finish last row by adding cell with no left border
local footerStyle = pargs['footerstyle'] or ""
        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 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


-- close table (wikitext to close table)
-- close table (wikitext to close table)
cladeString = cladeString ..  '\n|}'
cladeString = cladeString ..  '\n|}'
cladeString = p.addSubTrees(cladeString) -- add subtrees
return cladeString
return cladeString
--return '<div style="width:auto;">\n' .. cladeString .. '</div>'
end
end


--[[ =============================function to add subtrees ========================================== ]]
--[[ function to add child elements
 
function p.addSubTrees(cladeString)
--local pargs = mw.getCurrentFrame():getParent().args
local suffix = { [1]="A", [2]="B", [3]="C", [4]="D", [5]="E", [6]="F", [7]="G", [8]="H", [9]="I", [10]="J",
            [11]="K", [12]="L", [13]="M", [14]="N", [15]="O", [16]="P", [17]="Q", [18]="R", [19]="S", [20]="T",
            [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)
end
end
    end
return cladeString
end
--[[ -------------------------------------- p.addTaxon() ------------------------------------------
    function to add child elements
     adds wikitext for two rows of the table for each child node,  
     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 first cell in each is used for the label and sublabel; the bottom border forms the horizonal branch of the bracket
سطر 176: سطر 177:
    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 (i.e. color, thickness, state)
-- get leaf and labels
    nodeParameters for whole bracket (unnumbered, i.e. color, thickness, state) apply to whole node bracket,
--local nodeLeaf  = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or ""   -- used passed variable to avoid redundancy
branchParameters apply to individual branches
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""  -- request in addLabel
    the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
    the node parameters have no number, e.g. |color, |thickness, |state
]]
    local nodeColor = pargs['color'] or ""                -- don't set default to allow green on black gadget
local nodeThickness = tonumber(pargs['thickness']) or 1
local nodeState = pargs['state'] or "solid"
-- get border formating parameters for branch (default to global nodeParameters)
local branchColor = pargs['color'..tostring(childNumber)] or nodeColor
local branchThickness = tonumber(pargs['thickness'..tostring(childNumber)]) or nodeThickness
local branchState = pargs['state'..tostring(childNumber)] or nodeState
if branchState == 'double' then
if branchThickness < 2 then branchThickness = 3 end -- need thick line for double
end 
local branchStyle = pargs['style'..tostring(childNumber)] or ""
-- get formating parameters for branch (default to global nodeParameters)
local branchLength = pargs['length'] or pargs['length'..tostring(childNumber)] or ""
--    - 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
     -- 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
--local barColor  = ""  
--local barColor  = ""  
local barRight  = pargs['bar'..tostring(childNumber)] or "0"
local barRight  = mw.getCurrentFrame():getParent().args['bar'..tostring(childNumber)] or "0"
local barBottom = pargs['barend'..tostring(childNumber)] or "0"
local barBottom = mw.getCurrentFrame():getParent().args['barend'..tostring(childNumber)] or "0"
local barTop    = pargs['barbegin'..tostring(childNumber)] or "0"
local barTop    = mw.getCurrentFrame():getParent().args['barbegin'..tostring(childNumber)] or "0"
local barLabel  = pargs['barlabel'..tostring(childNumber)] or ""
local barLabel  = mw.getCurrentFrame():getParent().args['barlabel'..tostring(childNumber)] or ""
local groupLabel     = pargs['grouplabel'..tostring(childNumber)] or ""
local groupLabel = mw.getCurrentFrame():getParent().args['grouplabel'..tostring(childNumber)] or ""
local groupLabelStyle = pargs['grouplabelstyle'..tostring(childNumber)] or ""
local groupLabelStyle = mw.getCurrentFrame():getParent().args['labelstyle'..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
--replace colours with format string; need right bar for all three options
سطر 232: سطر 215:
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 = ''
    local widthClass = ''
   
    -- 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
--styleString = ' style="border-left:' .. leftBorder ..';border-top:0;border-right:0;border-bottom:0;vertical-align:top;text-align:center;"'
    borderStyle  = 'border-left:none;border-right:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';'
styleString = ' style="border:0;border-right:' .. leftBorder ..';vertical-align:top;text-align:center;"'
    else
--cladeString = cladeString .. '| ' .. styleString .. ' | <br/> ' -- for sublabel ' | y<br/> '
    borderStyle  = 'border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';'  
cladeString = cladeString .. '|' .. styleString .. '|' .. p.addLabel(childNumber-1,subLabel)
    end
end
end
 
end
   -- new row
  cladeString = cladeString .. '\n|-'
  if useInlineStyle or branchStyle ~= '' or branchLength ~= "" or labelStyle ~= "" then
  local branchLengthStyle = ""
  if branchLength ~= "" then
  if childNumber == 1 then
  branchLengthStyle = 'width:' .. branchLength .. ';-- add width to first element
  end
  --if childNumber > 1 then prefix = 'max-' end
  branchLengthStyle = branchLengthStyle --= prefix  .. 'width:' .. branchLength .. ';'  
  .. 'max-width:' .. branchLength ..';'
                              .. 'padding:0em;'        -- remove padding to make calculation easier
  -- following moved to styles.css
  -- .. 'white-space:nowrap'
  -- .. 'overflow:hidden;'   -- clip labels longer than the max-width
  -- .. 'text-overflow:clip;' -- ellipsis;'
      widthClass = " clade-fixed-width"
  end
  styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. labelStyle .. '"'
    end


-- now add cell with label
styleString = ''
if childNumber == 1 then
if childNumber == 1 then
classString= 'class="clade-label first'.. widthClass .. '" '                 -- 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 .. widthClass .. '" ' -- 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-right:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';vertical-align:bottom;text-align:center;' .. branchStyle .. '"'
     --  wikitext for cell with label
end
    local labelCellString = '\n|' .. classString .. styleString  .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel)
     cladeString = cladeString .. '\n|' .. styleString  .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel)
   
    --cladeString = cladeString .. labelCellString


---------------------------------------------------------------------------------
-- add cell with leaf (which may be a table with transluded content)
-- (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  
     if barRight  ~= "0"  then  
     if reverseClade then -- we want the bar on the left
     styleString = 'style="border:0;padding:0;border-left:' .. 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
     else
     if (branchStyle ~= '') then
     styleString = 'style="border:0;padding:0;' .. branchStyle .. '"'
    styleString = ' style="' .. branchStyle .. '"'
        else
        styleString = '' -- use defaults in styles.css
        end
     end
     end
 
    classString = 'class="clade-leaf' .. reverseClass .. '"'
    --[[note: the \n causes plain leaf elements get wrapped in <p> with style="margin:0.4em 0 0.5em 0;"
          this adds spacing to rows, but is set by defaults rather than the clade template
          it also means there are two newlines when it is a clade structure (which might explain some past issues)
    ]]
    local content = '\n' .. nodeLeaf  -- the newline is not necessary, but keep for backward compatibility
    -- test using image parameter
    local image = pargs['image'..tostring(childNumber)] or "" 
    if image ~= "" then                                 
    --content = content .. image -- basic version
      content = '\n{|class=clade style=width:auto'  --defaults to width:100% because of class "clade"
          .. '\n|class=clade-leaf|\n' .. nodeLeaf
          .. '\n|class=clade-leaf|\n' .. image
          .. '\n|}'
      -- note: the classes interfere with the node counter, so try simpler version with style
        content = '\n{|style=width:100%;border-spacing:0'  --width:auto is "tight"; 100% needed for image alignment
          .. '\n|style=border:0;padding:0|\n' .. nodeLeaf
          .. '\n|style=border:0;padding:0|\n' .. image
          .. '\n|}'
    end
    -- wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
    --                        but that is no longer the case (newline is now forced)
    --                        the newline wraps plain leaf terminals in <P> with vertical padding (see above)
    --local leafCellString = '\n|rowspan=2 ' .. classString  .. styleString .. ' |\n' .. content -- the new line causes <p> wrapping for plain leaf terminals
    local leafCellString = '\n|rowspan=2 ' .. classString  .. styleString .. ' |' .. content
 
    --cladeString = cladeString .. leafCellString


    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
    -- (4) stuff for right-hand bracket labels
if barRight  ~= "0"  then
    cladeString = cladeString .. '&nbsp;&nbsp;'            -- add spaces between leaf text and bar
if barLabel ~= "" then
-- cladeString = cladeString ..  '\n| ' .. barLabel end  -- experiment for labeling the bar
cladeString = cladeString .. '<td style="vertical-align:middle;">' .. barLabel ..'</td>'
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>'
end


  classString='class="clade-bar' .. reverseClass .. '"'
-- 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 barLabelCellString = ''
    local branchStyleString = 'style="' .. branchStyle .. '" '  
if barRight  ~= "0"  and barLabel ~= "" then  
     if branchStyle == '' then branchStyleString = '' end -- avoid empty style elements
  barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. barLabel
cladeString = cladeString .. '\n|-' .. branchStyleString
else -- uncomment following line to see the cell structure
  --barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. 'BL'
end
if groupLabel ~= "" then
-- TODO code to put whole row here instead of completing on next call to addTaxon() or after main loop
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 = pargs['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 ~= '' or  branchLength ~= '' or sublabelStyle ~= "" then       
  local branchLengthStyle = ""
  if branchLength ~= "" then
  if childNumber == 1 then
  branchLengthStyle = 'width:' .. branchLength .. ';'  -- add width to first element
  end
  --if childNumber > 1 then prefix = 'max-' end
  branchLengthStyle = branchLengthStyle --= prefix  .. 'width:' .. branchLength .. ';'
  .. 'max-width:' .. branchLength ..';'
                              .. 'padding:0em;'        -- remove padding to make calculation easier
  end
  styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. sublabelStyle .. '"'
        --styleString = ' style="' .. borderStyle .. branchStyle .. sublabelStyle .. '"'
    end
    --local sublabel = p.addLabel(childNumber,subLabel)
    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)
   
    --cladeString = cladeString .. sublabelCellString
    -- constuct child element wikitext
    if reverseClade then
    cladeString = cladeString .. '\n|-'
    cladeString = cladeString .. barLabelCellString
    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
return cladeString
end
end


--[[ adds text for label or sublabel to a cell
--[[ adds text for label or sublabel to a cell
سطر 448: سطر 292:
--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
-- Has to be some content for layout, but can use CSS to add it instead.
return '<br/>' --'&nbsp;<br/>'  -- remove space to reduce post-expand include size (the width=1.5em handles spacing)
return ''
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
سطر 462: سطر 305:
if string.find(nodeLabel, "span ") ~= nil  then  stylingElementDetected = true end
if string.find(nodeLabel, "span ") ~= nil  then  stylingElementDetected = true end
if string.find(nodeLabel, " style") ~= 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
if stylingElementDetected == true then  
if stylingElementDetected == true then  
return '<div style=display:inline class=nowrap>' .. nodeLabel .. '</div>'
return '<span class="nowrap">' .. nodeLabel .. '</span>'
     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
    if not nowrapString:find("UNIQ.-QINU") and not nowrapString:find("%[%[.-%]%]") then                -- unless a strip marker
    nowrapString = string.gsub(nowrapString, "-", "&#8209;") -- replace hyphen with non-breaking hyphen (&#8209;)
            end
return nowrapString
return nowrapString
end
end
سطر 484: سطر 322:
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 = ""
count = count+1
--start table
--start table
--'{| style="border-collapse:collapse;border-spacing:0;border:0;margin:0;'
cladeString = cladeString .. '{| cellspacing=0 cellpadding=0 border=0 '
local cladeString = '{|class=clade '
count = count + 1
 
local j,k
local j,k
j,k = string.find(newickString, '%(.*%)')                -- find location of outer parenthesised term
j,k = string.find(newickString, '%(.*%)')                -- find location of outer parenthesised term
سطر 505: سطر 342:
--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 = p.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
local restoredString = string.gsub(s[i],"XXX", ",")  -- convert back to commas
restoredString = string.gsub(s[i],"XXX", ",")  -- convert back to commas
--restoredString = s[i]
--restoredString = s[i]
local outerTerm = string.gsub(restoredString, "%b()", "")
local outerTerm = string.gsub(restoredString, "%b()", "")
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
-- emulate a standard split string function
-- emulate a standard split string function
-- why not use mw.text.split(s, sep)?
function strsplit(inputstr, sep)  
function p.strsplit(inputstr, sep)  
         if sep == nil then
         if sep == nil then
                 sep = "%s"
                 sep = "%s"
         end
         end
         local t={}  
         local t={} ; i=1
        local i=1
         for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
         for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
                 t[i] = str
                 t[i] = str
سطر 546: سطر 376:
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 =============================
سطر 555: سطر 441:
function p.newickConverter(frame)
function p.newickConverter(frame)
local newickString = frame.args['newickstring'] or frame.args['newick'] or pargs['newickstring'] or pargs['newick']
local newickString = frame.args['newickstring']
--if newickString == '{{{newickstring}}}' then return newickString  end
if newickString == '{{{newickstring}}}' then return newickString  end


    newickString = p.processNewickString(newickString,"") -- "childNumber")
   
   
-- show the Newick string
-- show the Newick string
local cladeString = ''
local cladeString = ''
سطر 573: سطر 457:


local resultString = ''
local resultString = ''
     local option = pargs['option'] or ''
     local option = mw.getCurrentFrame():getParent().args['option'] or ''
     if option == 'tree' then
     if option == 'tree' then
--show the transcluded clade diagram
--show the transcluded clade diagram
سطر 588: سطر 472:
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
سطر 619: سطر 503:
                                            end)
                                            end)
local s = p.strsplit(innerTerm2, ",")
local s = strsplit(innerTerm2, ",")
local i=1
local i=1
while s[i] do
while s[i] do
local restoredString = string.gsub(s[i],"XXX", ",")  -- convert back to commas
restoredString = string.gsub(s[i],"XXX", ",")  -- convert back to commas
local outerTerm = string.gsub(restoredString, "%b()", "")
local outerTerm = string.gsub(restoredString, "%b()", "")
سطر 641: سطر 525:
function p.getIndent(levelNumber)
function p.getIndent(levelNumber)
local indent = "\r"
local indent = "\r"
local extraIndent = pargs['indent'] or mw.getCurrentFrame().args['indent'] or 0
local extraIndent = mw.getCurrentFrame():getParent().args['indent'] or 0
while tonumber(extraIndent) > 0 do
while tonumber(extraIndent) > 0 do
سطر 659: سطر 543:
end
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
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------


 
function p.test(dummy)
function p.test2(target)
local dataString = ""
local target ="User:Jts1882/sandbox/templates/Template:Passeroidea"
    dataString = "NEWCLADE:"
local result = mw.getCurrentFrame():expandTemplate{ title = target, args = {['style'] = '' } }
return result
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)
     local childNumber =0
    nodeCount=0
     local lastNode = 0
     cladeCount=0
while childNumber < 17 do -- disable moreNeeded
    leafCount=0
   
while childNumber < maxChildren do -- preprocessing loop
childNumber = childNumber + 1 -- so we start with 1
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf,data = pargs[tostring(childNumber)] or "" -- get data from |N=
local nodeLeaf = mw.getCurrentFrame():getParent().args[tostring(childNumber)] or "" -- get data from |N=
        local newickString = pargs['newick'..tostring(childNumber)] or ""  -- get data from |labelN=
--local nodeLabel = mw.getCurrentFrame():getParent().args['label'..tostring(childNumber)] or ""  -- get data from |labelN=
        local listString = pargs['list'..tostring(childNumber)] or ""  -- get data from |labelN=
        if nodeLeaf ~= "" then
if newickString ~= "" or nodeLeaf ~= "" or listString ~= "" then
dataString = dataString .. tostring(childNumber)
--if nodeLeaf ~= "" then  
 
childCount = childCount + 1  -- this counts child elements in this clade
local firstChars = string.sub(nodeLeaf, 1,2) -- get first two characters
    --[[]
--if nodeLabel ~= "{{{label1}}}" then
    for i in string.gmatch(nodeLeaf, "||rowspan") do -- count number of rows started (transclusion)
if firstChars == "{{" then
  nodeCount = nodeCount + 1
                dataString = dataString .. 'XXX' .. nodeLeaf
    end
end
    for i in string.gmatch(nodeLeaf, '{|class="clade"') do -- count number of tables started (transclusion)
dataString = dataString .. 'LEAF:' .. nodeLeaf
  cladeCount = cladeCount + 1
    end
lastNode = childNumber
    ]]
    -- 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
end
end
--]]
    local numClades=0
     -- nodes can be either terminal leaves or a clade structure (table)
    local numBranches=0
    --   note: should change class clade-leaf to clade-node to reflect this
     -- _, count = string.gsub(dataString, "NEWCLADE", "NEXT")
     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
     for i in string.gmatch(dataString, "NEWCLADE") do
cladeCount = cladeCount + 1      -- number of clade structure tables passed down by transduction (plus one for current clade)
  numClades = numClades + 1
leafCount = nodeCount-cladeCount   -- number of terminal leaves (equals height of cladogram)
    end
    dataString dataString .. '<br/>(numClades=' .. numClades .. ')'
-- output for testing: number of clades / total nodes / terminal nodes (=leaves)
    for i in string.gmatch(dataString, "LEAF") do
--                    (internal nodes)                  (cladogram height)
  numBranches = numBranches + 1
infoOutput = '<small>[' .. cladeCount .. '/' .. nodeCount .. '/' .. leafCount .. ']</small>'
    end
     dataString =   dataString .. '<br/>(numClades=' .. numClades .. ')'
return infoOutput
     dataString =  dataString .. '<br/>(numBranches=' .. numBranches .. ')'
end
 
function p.showClade(frame)
--local code = frame.args.code or ""
    local code = frame:getParent().args['code2'] or frame.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') or frame: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.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 = ""
--count = count+1
    local i=1
     local child=1
local lastNode=0--table.getn(list) -- number of child branches (potential)
    local listChar = "@"
   
    if listString:find("UNIQ.-QINU") then -- if wrapped in nowiki
      mw.addWarning("Stripping content in nowiki tags")
      listString = mw.text.trim( mw.text.unstripNoWiki( listString ) )
     end
    if string.match( listString, "^*", 1 ) then
      listChar = "*"
    end   
   
    local list = mw.text.split(listString, "\n")
      
      
cladeString = cladeString .. '{| class="clade" '
mw:log(numClades)
while list[i]  do
--return 'numClades=' .. numClades .. '; numBranches=' .. numBranches
list[i]=list[i]:gsub("^"..listChar, "")              -- strip the first @ or *
return  dataString
list[i]=mw.text.trim(list[i])                -- trim
if not string.match( list[i], "^"..listChar, 1 ) then -- count children at this level (not beginning wiht @/*)
lastNode = lastNode+1 
end
i=i+1
end
i=1
while list[i]  do
 
    --[[ pseudocode:
        if next value begins with @ we have a subtree,
        which must be recombined and past iteratively
        else we have a simple leaf
    ]]
 
    -- if the next value begins with @, we have a subtree which should be recombined
    if list[i+1] and string.match( list[i+1], "^"..listChar, 1 )  then
   
        local label=list[i]
          i=i+1
    local recombined = list[i]
    while list[i+1] and string.match( list[i+1], "^"..listChar, 1 ) do
    recombined = recombined .. "\n" .. list[i+1]
    i=i+1
    end
    --cladeString = cladeString .. '\n' .. p.addTaxon(child, recombined, label, lastNode)
    cladeString = cladeString .. '\n' .. p.addTaxon(child, p.list(count,recombined), label, lastNode)
    else
    cladeString = cladeString .. '\n' .. p.addTaxon(child, list[i], "", lastNode)
    end
i=i+1
child=child+1
end
 
 
cladeString = cladeString .. '\n|}'
mw.addWarning("WARNING. This is a test feature only.")
return cladeString  
end
end
-- =================== experimental wikitext list to clade parser function =============================
function p.test2(target)
 
local target ="User:Jts1882/sandbox/templates/Template:Passeroidea"
--[[Function of convert wikitext lists to clade format
local result = mw.getCurrentFrame():expandTemplate{ title = target, args = {['style'] = '' } }
 
return result
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|listConverter|list={{{WIKITEXT_LIST}}} }}
]]
function p.cladeConverter(frame)
pargs = getArgs(frame)
if  frame.args['list'] or pargs['list'] then
return p.listConverter(frame)
    elseif frame.args['newickstring'] or frame.args['newick'] or pargs['newickstring'] or pargs['newick'] then
    return p.newickConverter(frame)
else
local message = "Conversion needs wikitext list or newick string in parameters ''list'' or ''newick'' respectively"
mw.addWarning(message)
return message
end
end
end
function p.listConverter(frame)
local listString = frame.args['list'] or pargs['list']


-- show the list string
local cladeString = ''
local levelNumber = 1          --  for depth of iteration
local childNumber = 1          --  number of sister elements on node  (always one for root)
local indent = p.getIndent(levelNumber)
--  converted the newick string to the clade structure
cladeString = cladeString .. indent .. '{{clade'
cladeString = cladeString .. p.listParseLevel(listString, levelNumber, childNumber)
--cladeString = cladeString .. '\r}}' 


local resultString = ''
-- this must be at end
    local option = pargs['option'] or ''
    if option == 'tree' then
--show the transcluded clade diagram
resultString =  cladeString   
    else
    -- show the wikitext list string
resultString = '<pre>'..listString..'</pre>'
    -- show the converted clade structure
    resultString = resultString .. '<pre>'.. cladeString ..'</pre>'
    end
    --resultString = frame:expandTemplate{ title = 'clade',  frame:preprocess(cladeString) }
 
    return resultString
end
 
function p.listParseLevel(listString,levelNumber,childNumber)


local cladeString = ""
local indent = p.getIndent(levelNumber)
    levelNumber=levelNumber+1
   
    local nowiki = false
    if listString:find("UNIQ.-QINU") then -- if wrapped in nowiki
      mw.addWarning("Stripping content in nowiki tags")
      listString = mw.text.trim( mw.text.unstripNoWiki( listString ) )
      nowiki = true
    end
    local listChar = "@"
    if string.match( listString, "^*", 1 ) then
      listChar = "*"
    end 
    local list = mw.text.split(listString, "\n")
    local i=1
    local child=1
    local lastNode=0
   
    while list[i]  do
list[i]=list[i]:gsub("^"..listChar, "")              -- strip the first @
if not string.match( list[i], "^"..listChar, 1 ) then -- count children at this level (not beginning wiht @)
lastNode = lastNode+1 
end
i=i+1
end
    i=1
while list[i]  do
    --[[ pseudocode:
        if next value begins with @ we have a subtree,
        which must be recombined and past iteratively
        else we have a simple leaf
    ]]
    -- if the next value begins with @, we have a subtree which should be recombined
    if list[i+1] and string.match( list[i+1], "^"..listChar, 1 )  then
   
        local label=list[i]
          i=i+1
    local recombined = list[i]
    while list[i+1] and string.match( list[i+1], "^"..listChar, 1 ) do
    recombined = recombined .. "\n" .. list[i+1]
    i=i+1
    end
    cladeString = cladeString .. indent .. '|label' .. child ..'=' ..  label
    cladeString = cladeString .. indent .. '|' .. child ..'=' ..  '{{clade'
                              .. p.listParseLevel(recombined,levelNumber,i) 
    else
    cladeString = cladeString .. indent .. '|' .. child ..'=' ..  list[i]
    end
i=i+1
child=child+1
end
cladeString = cladeString .. indent .. '}}' 
if nowiki then
return mw.getCurrentFrame():preprocess( '<nowiki>'.. cladeString .. '</nowiki>') --return wrapped in nowiki
else
return  cladeString
end
end
-- this must be at end
return p
return p

النسخة الحالية 10:16، 12 فبراير 2024

--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}}
--        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 {{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: {{#invoke:Module:Sandbox/Jts1882/CladeN|main|style={{{STYLE}}} }}
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 ""
	local tableStyleString = ' style="' .. tableStyle .. '" '
	if tableStyle == '{{{style}}}' then tableStyleString = "" end
	
	local captionName =mw.getCurrentFrame():getParent().args['caption'] or ""
	local captionStyle = mw.getCurrentFrame():getParent().args['captionstyle'] or ""

	-- open table	
	--cladeString = cladeString .. '{| cellspacing=0 cellpadding=0 border=0 style="' .. tableStyle .. '"'
	cladeString = cladeString .. '{|cellspacing=0 cellpadding=0 ' .. tableStyleString
	--cladeString = cladeString .. '{| cellspacing=0 ' .. tableStyleString  -- NOTE: cellpadding supposedly not supported in HTML5

    -- 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;" | <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 footerStyle = mw.getCurrentFrame():getParent().args['footerstyle'] or ""

	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>||'
	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-right:' .. leftBorder ..';vertical-align:top;text-align:center;"'
		--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
		-- 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-right:' .. 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-left:' .. 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 .. '&nbsp;&nbsp;'            -- add spaces between leaf text and bar
		if barLabel ~= "" then 
			-- cladeString = cladeString ..  '\n| ' .. barLabel end  -- experiment for labeling the bar
			cladeString = cladeString .. '<td style="vertical-align:middle;">' .. barLabel ..'</td>' 
		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>' 
	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 '<br/>' --'&nbsp;<br/>'  -- 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 '<span class="nowrap">' .. nodeLabel .. '</span>'
		
		-- 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 '<span class="nowrap">' .. nodeLabel .. '</span>'
    	else	
    		local nowrapString = string.gsub(nodeLabel," ", "&nbsp;") -- 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 .. '{| cellspacing=0 cellpadding=0 border=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;" | <br/> \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: {{#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 =============================

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

Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|newickConverter|newickstring={{{NEWICK_STRING}}} }}
]]
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 = '<pre>'..newickString..'</pre>'	
	    -- show the converted clade structure
	    resultString = resultString .. '<pre>'.. cladeString ..'</pre>'	
    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 .. '<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)
	local target ="User:Jts1882/sandbox/templates/Template:Passeroidea"
	local result = mw.getCurrentFrame():expandTemplate{ title = target, args = {['style'] = '' } }
	return result
end


-- this must be at end

return p