Module:Clade and Module:Clade/sandbox: Difference between pages
Appearance
(Difference between pages)
Content deleted Content added
add div to allow overflow: '<div class="clade"> ... </div>' |
Simplifications and some formatting improvements |
||
Line 2: | Line 2: | ||
The main function is called by the template using the {{invoke}} instruction; the three main functions are: |
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') |
require('strict') |
||
local getArgs = require('Module:Arguments').getArgs |
|||
local p = {} |
local p = {} |
||
local pargs = {} -- parent arguments |
local pargs = {} -- parent arguments |
||
Line 40: | Line 39: | ||
local totalCount = 0 |
local totalCount = 0 |
||
pargs = |
pargs = frame:getParent().args -- parent arguments |
||
infoOutput = p.getCladeTreeInfo() -- get info about clade structure, e.g. lastNode (last |N= child number) |
|||
--[[ add the templatestyles tag conditionally to reduce expansion size (currently diabled) |
|||
when added to every clade table, it increases post‐expand include size significantly |
|||
e.g. the Neosuchia page (or test version) is increase by about 8% (672 bytes each) |
|||
if template styles added to all pages there are 133 stripmarkers |
|||
with cladeCount==1 condition, this is reduced to 34 |
|||
however cladeCount==1 condition interfers with fix for additional line due to parser bug T18700 |
|||
killing the strip markers also removes backlinks to references using citation templates |
|||
--]] |
|||
--cladeString =mw.text.killMarkers( cladeString ) -- also kills off strip markers using citation templates |
|||
--cladeString = mw.text.unstrip(cladeString) |
|||
--if cladeCount==1 then |
|||
cladeString = cladeString .. frame:extensionTag('templatestyles', '', |
|||
{ src="Template:Clade/sandbox/styles.css" }) .. '\n' |
|||
--end |
|||
local tableStyle = frame.args |
local tableStyle = frame.args.style or "" |
||
if tableStyle ~= "" then |
if tableStyle ~= "" then |
||
tableStyle = ' style="' .. tableStyle .. '"' -- include style= in string to suppress empty style elements |
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 |
|||
--ENFORCE GLOBAL FOR DEVELOPMENT |
|||
--reverseClade = true |
|||
local captionName = pargs['caption'] or "" |
local captionName = pargs['caption'] or "" |
||
local captionStyle = pargs['captionstyle'] or "" |
local captionStyle = pargs['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 .. '"' |
-- (border-collapse causes problems (see talk) -- 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 .. '{|class="clade"' .. tableStyle |
|||
-- add caption |
|||
if captionName ~= "" then |
if captionName ~= "" then |
||
cladeString = cladeString .. '\n|+ style="' .. captionStyle .. '"|' .. captionName |
cladeString = cladeString .. '\n|+ style="' .. captionStyle .. '"|' .. captionName |
||
Line 91: | Line 90: | ||
--[[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) |
||
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 |
|||
]] |
]] |
||
Line 120: | Line 119: | ||
--if reverseClade2 then |
--if reverseClade2 then |
||
-- cladeString = cladeString .. '\n' .. p.addTaxonReverse(childNumber, nodeLeaf, nodeLabel, lastNode) |
-- cladeString = cladeString .. '\n' .. p.addTaxonReverse(childNumber, nodeLeaf, nodeLabel, lastNode) |
||
--else |
|||
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode) |
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode) |
||
--end |
--end |
||
Line 133: | Line 132: | ||
-- note the footer causes a problem with tr:last-child so need either |
-- note the footer causes a problem with tr:last-child so need either |
||
-- (1) use <tfoot> but it is not allowed or incompatable |
-- (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 |
-- (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) |
-- (3) if footer= set the style inline for the last sublabel row (more a temp fix) |
||
Line 144: | Line 143: | ||
cladeString = p.addSubTrees(cladeString) -- add subtrees |
cladeString = p.addSubTrees(cladeString) -- add subtrees |
||
return cladeString |
|||
--wrap in div to allow overflow display; new vector skin for mobile has issues (see talk page) |
|||
if pargs['overflow'] == 'yes' or 1==1 then -- force for all cases |
|||
local divCSS = ' class="clade"' -- ' style="overflow:auto;"' |
|||
if string.find(cladeString, divCSS) then |
|||
cladeString = string.gsub(cladeString, divCSS, "") -- delete CSS styling of inner clades (only want on outer) |
|||
end |
|||
return '<div' .. divCSS .. '>' .. cladeString .. '</div>' |
|||
else |
|||
return cladeString |
|||
end |
|||
--return '<div style="width:auto;">\n' .. cladeString .. '</div>' |
--return '<div style="width:auto;">\n' .. cladeString .. '</div>' |
||
end |
end |
||
Line 164: | Line 154: | ||
local suffix = { [1]="A", [2]="B", [3]="C", [4]="D", [5]="E", [6]="F", [7]="G", [8]="H", [9]="I", [10]="J", |
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 |
for i = 1, 26, 1 do |
||
local subclade = pargs['subclade'..suffix[i]] |
local subclade = pargs['subclade'..suffix[i]] |
||
local target = pargs['target'..suffix[i]] or "SUBCLADE_" .. suffix[i] |
local target = pargs['target'..suffix[i]] or "SUBCLADE_" .. suffix[i] |
||
Line 174: | Line 164: | ||
end |
end |
||
end |
end |
||
end |
|||
return cladeString |
return cladeString |
||
end |
end |
||
--[[ -------------------------------------- p.addTaxon() ------------------------------------------ |
--[[ -------------------------------------- p.addTaxon() ------------------------------------------ |
||
function to add child elements |
|||
adds wikitext for two rows of the table for each child node, |
|||
the first cell in each is used for the label and sublabel; the bottom border forms the horizonal branch of the bracket |
|||
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 below the bracket) |
|||
]] |
]] |
||
function p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode) |
function p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode) |
||
--[[ get border formating parameters (i.e. color, thickness, state) |
--[[ get border formating parameters (i.e. color, thickness, state) |
||
nodeParameters for whole bracket (unnumbered, i.e. color, thickness, state) apply to whole node bracket, |
|||
branchParameters apply to individual branches |
branchParameters apply to individual branches |
||
the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN |
|||
the node parameters have no number, e.g. |color, |thickness, |state |
|||
]] |
]] |
||
local nodeColor = pargs['color'] or "" -- don't set default to allow green on black gadget |
|||
local nodeThickness = tonumber(pargs['thickness']) or 1 |
local nodeThickness = tonumber(pargs['thickness']) or 1 |
||
local nodeState = pargs['state'] or "solid" |
local nodeState = pargs['state'] or "solid" |
||
Line 209: | Line 199: | ||
local branchLength = pargs['length'] or pargs['length'..tostring(childNumber)] or "" |
local branchLength = pargs['length'] or pargs['length'..tostring(childNumber)] or "" |
||
-- the left border takes node parameters, the bottom border takes branch parameters |
|||
-- 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 default border styles are in the CSS (styles.css) |
||
-- |
-- the inline styling is applied when thickness, color or state are change |
||
local useInlineStyle = false |
local useInlineStyle = false |
||
Line 228: | Line 218: | ||
local barRight = pargs['bar'..tostring(childNumber)] or "0" |
local barRight = pargs['bar'..tostring(childNumber)] or "0" |
||
local barBottom = pargs['barend'..tostring(childNumber)] or "0" |
local barBottom = pargs['barend'..tostring(childNumber)] or "0" |
||
local barTop |
local barTop = pargs['barbegin'..tostring(childNumber)] or "0" |
||
local barLabel = pargs['barlabel'..tostring(childNumber)] or "" |
local barLabel = pargs['barlabel'..tostring(childNumber)] or "" |
||
local groupLabel |
local groupLabel = pargs['grouplabel'..tostring(childNumber)] or "" |
||
local groupLabelStyle = pargs['grouplabelstyle'..tostring(childNumber)] or "" |
local groupLabelStyle = pargs['grouplabelstyle'..tostring(childNumber)] or "" |
||
local labelStyle |
local labelStyle = pargs['labelstyle'..tostring(childNumber)] or "" |
||
local sublabelStyle = pargs['sublabelstyle'..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 |
||
if barRight ~= "0" then barRight = "2px solid " .. barRight end |
if barRight ~= "0" then barRight = "2px solid " .. barRight end |
||
if barTop |
if barTop ~= "0" then barRight = "2px solid " .. barTop end |
||
if barBottom ~= "0" then barRight = "2px solid " .. barBottom end |
if barBottom ~= "0" then barRight = "2px solid " .. barBottom end |
||
if barTop |
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 |
||
Line 246: | Line 236: | ||
local cladeString = '' |
local cladeString = '' |
||
local styleString = '' |
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 |
-- (2) now add cell with label |
||
if useInlineStyle then |
if useInlineStyle then |
||
if childNumber == 1 then |
if childNumber == 1 then |
||
borderStyle = 'border-left:none;border-right:none;border-bottom:' .. bottomBorder .. ';' |
|||
--borderStyle = 'border-bottom:' .. bottomBorder .. ';' |
|||
else -- for 2-17 |
else -- for 2-17 |
||
if reverseClade then |
if reverseClade then |
||
borderStyle = 'border-left:none;border-right:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';' |
|||
else |
|||
borderStyle = 'border-left:' .. leftBorder .. ';border-bottom:' .. bottomBorder .. ';' |
|||
end |
|||
end |
end |
||
end |
end |
||
Line 281: | Line 271: | ||
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';' |
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';' |
||
.. 'max-width:' .. branchLength ..';' |
.. 'max-width:' .. branchLength ..';' |
||
.. 'padding:0em;' -- remove padding to make calculation easier |
|||
-- following moved to styles.css |
-- following moved to styles.css |
||
-- .. 'white-space:nowrap' |
-- .. 'white-space:nowrap' |
||
-- .. 'overflow:hidden;' |
-- .. 'overflow:hidden;' -- clip labels longer than the max-width |
||
-- .. 'text-overflow:clip;' -- ellipsis;' |
-- .. 'text-overflow:clip;' -- ellipsis;' |
||
widthClass = " clade-fixed-width" |
|||
end |
end |
||
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. labelStyle .. '"' |
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. labelStyle .. '"' |
||
end |
|||
if childNumber == 1 then |
if childNumber == 1 then |
||
classString= 'class="clade-label first'.. widthClass .. '" ' |
classString= 'class="clade-label first'.. widthClass .. '" ' -- add class "first" for top row |
||
else |
|||
classString = 'class="clade-label' .. reverseClass .. widthClass .. '" ' -- add "reverse" class if ltr cladogram |
|||
end |
|||
-- wikitext for cell with label |
|||
local labelCellString = '\n|' .. classString .. styleString .. '|' .. p.addLabel(childNumber,nodeLabel) -- p.addLabel(nodeLabel) |
|||
--cladeString = cladeString .. labelCellString |
|||
--------------------------------------------------------------------------------- |
--------------------------------------------------------------------------------- |
||
-- (3) add cell with leaf (which may be a table with transluded clade content) |
-- (3) add cell with leaf (which may be a table with transluded clade content) |
||
if barRight ~= "0" then |
|||
if reverseClade then -- we want the bar on the left |
|||
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 |
|||
elseif (branchStyle ~= '') then |
|||
else |
|||
styleString = ' style="' .. branchStyle .. '"' |
|||
else |
|||
styleString = ' style="' .. branchStyle .. '"' |
|||
styleString = '' -- use defaults in styles.css |
|||
else |
|||
end |
|||
styleString = '' -- use defaults in styles.css |
|||
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 |
|||
------------------------------------------- |
|||
-- (4) stuff for right-hand bracket labels |
|||
classString='class="clade-bar' .. reverseClass .. '"' |
classString='class="clade-bar' .. reverseClass .. '"' |
||
local barLabelCellString = '' |
|||
if barRight ~= "0" and barLabel ~= "" then |
if barRight ~= "0" and barLabel ~= "" then |
||
barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. barLabel |
barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. barLabel |
||
Line 369: | Line 357: | ||
barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. ' style="'.. groupLabelStyle .. '" |' .. groupLabel |
barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. ' style="'.. groupLabelStyle .. '" |' .. groupLabel |
||
else -- uncomment following line to see the cell structure |
else -- uncomment following line to see the cell structure |
||
--barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. '" |' .. 'GL' |
|||
end |
end |
||
--cladeString = cladeString .. barLabelCellString |
--cladeString = cladeString .. barLabelCellString |
||
------------------------------------------------------------------------------------- |
------------------------------------------------------------------------------------- |
||
-- (5) add second row (only one cell needed for sublabel because of rowspan=2); |
-- (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|-' |
--cladeString = cladeString .. '\n|-' |
||
Line 395: | Line 383: | ||
if childNumber==lastNode then -- if childNumber==lastNode we don't want left border, otherwise we do |
if childNumber==lastNode then -- if childNumber==lastNode we don't want left border, otherwise we do |
||
borderStyle = 'border-right:none;border-left:none;' |
borderStyle = 'border-right:none;border-left:none;' |
||
elseif reverseClade then |
|||
else |
|||
borderStyle = 'border-left:none;border-right:' .. leftBorder .. ';' |
|||
if reverseClade then |
|||
else |
|||
borderStyle = 'border-left:none;border-right:' .. leftBorder .. ';' |
|||
borderStyle = 'border-right:none;border-left:' .. leftBorder .. ';' |
|||
else |
|||
end |
|||
borderStyle = 'border-right:none;border-left:' .. leftBorder .. ';' |
|||
end |
|||
if borderStyle ~= '' or branchStyle ~= '' or branchLength ~= '' or sublabelStyle ~= "" then |
|||
end |
|||
end |
|||
if borderStyle ~= '' or branchStyle ~= '' or branchLength ~= '' or sublabelStyle ~= "" then |
|||
local branchLengthStyle = "" |
local branchLengthStyle = "" |
||
if branchLength ~= "" then |
if branchLength ~= "" then |
||
Line 412: | Line 398: | ||
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';' |
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';' |
||
.. 'max-width:' .. branchLength ..';' |
.. 'max-width:' .. branchLength ..';' |
||
.. 'padding:0em;' -- remove padding to make calculation easier |
|||
end |
end |
||
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. sublabelStyle .. '"' |
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 .. '\n|-' |
||
cladeString = cladeString .. sublabelCellString |
cladeString = cladeString .. sublabelCellString |
||
else |
|||
cladeString = cladeString .. '\n|-' |
|||
cladeString = cladeString .. labelCellString |
|||
cladeString = cladeString .. leafCellString |
|||
cladeString = cladeString .. barLabelCellString |
|||
cladeString = cladeString .. '\n|-' |
cladeString = cladeString .. '\n|-' -- add second row (only one cell needed for sublabel because of rowspan=2); |
||
cladeString = cladeString .. sublabelCellString |
cladeString = cladeString .. sublabelCellString |
||
end |
|||
return cladeString |
return cladeString |
||
end |
end |
||
Line 469: | Line 455: | ||
-- however, there is a problem if labels have a styling element (e.g. <span style= ..., <span title= ...) |
-- however, there is a problem if labels have a styling element (e.g. <span style= ..., <span title= ...) |
||
local stylingElementDetected = false |
local stylingElementDetected = false |
||
if |
if nodeLabel:find("span ") or nodeLabel:find(" style") then |
||
stylingElementDetected = true |
|||
end |
|||
--TODO test following alternative |
--TODO test following alternative |
||
--if nodeLabel:find( "%b<>") then stylingElementDetected = true end |
--if nodeLabel:find( "%b<>") then stylingElementDetected = true end |
||
Line 476: | Line 463: | ||
if stylingElementDetected == true then |
if stylingElementDetected == true then |
||
return '<div style=display:inline class=nowrap>' .. nodeLabel .. '</div>' |
return '<div style=display:inline class=nowrap>' .. nodeLabel .. '</div>' |
||
else |
|||
local nowrapString = string.gsub(nodeLabel, " ", " ") -- 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, "-", "‑") -- replace hyphen with non-breaking hyphen (‑) |
|||
end |
|||
end |
|||
return nowrapString |
return nowrapString |
||
end |
end |
||
Line 501: | Line 488: | ||
local j,k |
local j,k |
||
j,k = string.find(newickString, '%(.*%)') |
j,k = string.find(newickString, '%(.*%)') -- find location of outer parenthesised term |
||
local innerTerm = string.sub(newickString, j+1, k-1) |
local innerTerm = string.sub(newickString, j+1, k-1) -- select content in parenthesis |
||
local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term |
local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term |
||
if outerTerm == 'panthera' then outerTerm = "x" end |
if outerTerm == 'panthera' then outerTerm = "x" end -- how is this set in local variable for inner nodes? |
||
outerTerm = tostring(count) |
outerTerm = tostring(count) |
||
-- need to remove commas in bracket terms before split, so temporarily replace commas between brackets |
-- 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) |
|||
end) |
|||
--cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "") |
--cladeString = cladeString .. '\n' .. p.addTaxon(1, innerTerm2, "") |
||
-- this needs a lastNode variable |
|||
local s = p.strsplit(innerTerm2, ",") |
local s = p.strsplit(innerTerm2, ",") |
||
--oldLastNode=lastNode |
--oldLastNode=lastNode |
||
local lastNode=table.getn(s) -- number of child branches |
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 |
local restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas |
||
Line 530: | Line 517: | ||
cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "", lastNode) --count) |
cladeString = cladeString .. '\n' .. p.addTaxon(i, restoredString, "", lastNode) --count) |
||
end |
end |
||
i=i+1 |
i = i + 1 |
||
end |
end |
||
-- lastNode=oldLastNode |
-- 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|}' |
||
Line 543: | Line 530: | ||
-- why not use mw.text.split(s, sep)? |
-- why not use mw.text.split(s, sep)? |
||
function p.strsplit(inputstr, sep) |
function p.strsplit(inputstr, sep) |
||
if sep == nil then |
|||
sep = "%s" |
|||
end |
|||
local t={} |
|||
local i = 1 |
|||
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do |
|||
t[i] = str |
|||
i = i + 1 |
|||
end |
|||
return t |
|||
end |
end |
||
Line 568: | Line 555: | ||
--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 = '' |
||
local levelNumber = 1 |
local levelNumber = 1 -- for depth of iteration |
||
local childNumber = 1 |
local childNumber = 1 -- number of sister elements on node (always one for root) |
||
-- converted the newick string to the clade structure |
-- converted the newick string to the clade structure |
||
Line 582: | Line 569: | ||
local resultString = '' |
local resultString = '' |
||
local option = pargs['option'] or '' |
|||
if option == 'tree' then |
|||
--show the transcluded clade diagram |
--show the transcluded clade diagram |
||
resultString = cladeString |
resultString = cladeString |
||
else |
|||
-- show the Newick string |
|||
resultString = '<pre>'..newickString..'</pre>' |
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 |
end |
||
--[[ Parse one level of Newick string |
--[[ Parse one level of Newick string |
||
This function receives 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) |
function p.newickParseLevel(newickString,levelNumber,childNumber) |
||
local cladeString = "" |
local cladeString = "" |
||
local indent = p.getIndent(levelNumber) |
local indent = p.getIndent(levelNumber) |
||
Line 613: | Line 600: | ||
local j=0 |
local j=0 |
||
local k=0 |
local k=0 |
||
j,k = string.find(newickString, '%(.*%)') |
j,k = string.find(newickString, '%(.*%)') -- find location of outer parenthesised term |
||
local innerTerm = string.sub(newickString, j+1, k-1) |
local innerTerm = string.sub(newickString, j+1, k-1) -- select content in parenthesis |
||
local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term |
local outerTerm = string.gsub(newickString, "%b()", "") -- delete parenthetic term |
||
Line 624: | Line 611: | ||
-- protect commas in inner parentheses from split; temporarily replace commas between parentheses |
-- 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) |
|||
end) |
|||
local s = p.strsplit(innerTerm2, ",") |
local s = p.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 |
local restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas |
||
Line 640: | Line 627: | ||
cladeString = cladeString .. indent .. '|' .. i .. '=' .. restoredString --.. '(level=' .. levelNumber .. ')' |
cladeString = cladeString .. indent .. '|' .. i .. '=' .. restoredString --.. '(level=' .. levelNumber .. ')' |
||
end |
end |
||
i=i+1 |
i = i + 1 |
||
end |
end |
||
-- |
-- end -- end splitting of strings |
||
cladeString = cladeString .. indent .. '}}' |
cladeString = cladeString .. indent .. '}}' |
||
return cladeString |
|||
end |
end |
||
Line 652: | Line 639: | ||
local extraIndent = pargs['indent'] or mw.getCurrentFrame().args['indent'] or 0 |
local extraIndent = pargs['indent'] or mw.getCurrentFrame().args['indent'] or 0 |
||
indent = indent .. string.rep(" ", extraIndent) .. string.rep(" ", levelNumber - 1) -- extra indent to make aligning compound trees easier |
|||
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 |
return indent |
||
end |
end |
||
Line 673: | Line 653: | ||
local i = 0 |
local i = 0 |
||
local pargs = pargs |
local pargs = pargs |
||
local pattern = pargs['newick'..tostring(childNumber)..'-pattern'] -- unnumbered option for i=1 |
local pattern = pargs['newick'..tostring(childNumber)..'-pattern'] -- unnumbered option for i = 1 |
||
local replace = pargs['newick'..tostring(childNumber)..'-replace'] |
|||
while i < maxPatterns do |
while i < maxPatterns do |
||
i=i+1 |
i = i + 1 |
||
pattern = pattern or pargs['newick'..tostring(childNumber)..'-pattern'..tostring(i)] |
pattern = pattern or pargs['newick'..tostring(childNumber)..'-pattern'..tostring(i)] |
||
replace = replace or pargs['newick'..tostring(childNumber)..'-replace'..tostring(i)] or "" |
replace = replace or pargs['newick'..tostring(childNumber)..'-replace'..tostring(i)] or "" |
||
if pattern then |
if pattern then |
||
newickString = string.gsub |
newickString = string.gsub(newickString, pattern, replace) |
||
end |
end |
||
pattern = nil; replace = nil |
|||
end |
end |
||
newickString = string.gsub |
newickString = string.gsub(newickString, "_", " ") -- replace underscore with space |
||
return newickString |
return newickString |
||
end |
end |
||
Line 702: | Line 682: | ||
--[[function getCladeTreeInfo() |
--[[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 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 |
it provides the global lastNode that is used to limit the main while loop |
||
Line 708: | Line 688: | ||
function p.getCladeTreeInfo() |
function p.getCladeTreeInfo() |
||
-- enable proprocessing loop |
|||
local childNumber = 0 |
|||
local childCount = 0 |
|||
local maxChildren = 20 |
|||
--info veriables (these are global for now) |
|||
nodeCount = 0 |
|||
nodeCount=0 |
|||
cladeCount = 0 |
|||
cladeCount=0 |
|||
leafCount = 0 |
|||
leafCount=0 |
|||
while |
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,data = pargs[tostring(childNumber)] or "" -- get data from |N= |
||
local newickString = pargs['newick'..tostring(childNumber)] or "" -- get data from |labelN= |
|||
local listString = pargs['list'..tostring(childNumber)] or "" -- get data from |labelN= |
|||
if newickString ~= "" or nodeLeaf ~= "" or listString ~= "" then |
if newickString ~= "" or nodeLeaf ~= "" or listString ~= "" then |
||
--if nodeLeaf ~= "" then |
--if nodeLeaf ~= "" then |
||
childCount = childCount + 1 -- this counts child elements in this clade |
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 |
nodeCount = nodeCount + 1 |
||
end |
|||
for i in string.gmatch(nodeLeaf, '{|class="clade"') do -- count number of tables started (transclusion) |
|||
cladeCount = cladeCount + 1 |
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 |
lastNode = childNumber -- this gets the last node with a valid entry, even when missing numbers |
||
end |
end |
||
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 |
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) |
leafCount = nodeCount-cladeCount -- number of terminal leaves (equals height of cladogram) |
||
-- output for testing: number of clades / total nodes / terminal nodes (=leaves) |
-- output for testing: number of clades / total nodes / terminal nodes (=leaves) |
||
-- |
-- (internal nodes) (cladogram height) |
||
infoOutput = '<small>[' .. cladeCount .. '/' .. nodeCount .. '/' .. leafCount .. ']</small>' |
infoOutput = '<small>[' .. cladeCount .. '/' .. nodeCount .. '/' .. leafCount .. ']</small>' |
||
Line 761: | Line 741: | ||
function p.showClade(frame) |
function p.showClade(frame) |
||
--local code = frame.args.code or "" |
--local code = frame.args.code or "" |
||
local code = frame:getParent().args['code2'] or "" |
|||
--return code |
--return code |
||
Line 769: | Line 749: | ||
--return string.sub(test,6,-7) |
--return string.sub(test,6,-7) |
||
local o1 =frame:getParent() |
local o1 =frame:getParent():getArgument('code2') |
||
return o1:expand() |
return o1:expand() |
||
--return string.sub(code,2,-1) |
--return string.sub(code,2,-1) -- strip marker \127'"`UNIQ--tagname-8 hex digits-QINU`"'\127 |
||
--return frame:preprocess(string.sub(code,3)) |
--return frame:preprocess(string.sub(code,3)) |
||
end |
end |
||
Line 778: | Line 758: | ||
function p.firstToUpper(str) |
function p.firstToUpper(str) |
||
return (str:gsub("^%l", string.upper)) |
|||
end |
end |
||
--[[ function to generate cladogram from a wikitext-like list |
--[[ 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) |
function p.list(count,listString) |
||
Line 787: | Line 767: | ||
local cladeString = "" |
local cladeString = "" |
||
--count = count+1 |
--count = count+1 |
||
local i = 1 |
|||
local child = 1 |
|||
local lastNode=0--table.getn(list) -- number of child branches (potential) |
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" ' |
cladeString = cladeString .. '{| class="clade" ' |
||
while list[i] |
while list[i] do |
||
list[i]=list[i]:gsub("^"..listChar, "") |
list[i] = list[i]:gsub("^"..listChar, "") -- strip the first @ or * |
||
list[i]=mw.text.trim(list[i]) |
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 @/*) |
if not string.match( list[i], "^"..listChar, 1 ) then -- count children at this level (not beginning wiht @/*) |
||
lastNode = lastNode+1 |
lastNode = lastNode+1 |
||
end |
end |
||
i=i+1 |
i = i + 1 |
||
end |
end |
||
i=1 |
i = 1 |
||
while list[i] do |
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 |
i = i + 1 |
||
child=child+1 |
child = child + 1 |
||
end |
end |
||
Line 855: | Line 835: | ||
]] |
]] |
||
function p.cladeConverter(frame) |
function p.cladeConverter(frame) |
||
pargs = |
pargs = frame:getParent().args |
||
if |
if frame.args['list'] or pargs['list'] then |
||
return p.listConverter(frame) |
return p.listConverter(frame) |
||
elseif frame.args['newickstring'] or frame.args['newick'] or pargs['newickstring'] or pargs['newick'] then |
|||
return p.newickConverter(frame) |
|||
else |
else |
||
local message = "Conversion needs wikitext list or newick string in parameters ''list'' or ''newick'' respectively" |
local message = "Conversion needs wikitext list or newick string in parameters ''list'' or ''newick'' respectively" |
||
Line 873: | Line 853: | ||
-- show the list string |
-- show the list string |
||
local cladeString = '' |
local cladeString = '' |
||
local levelNumber = 1 |
local levelNumber = 1 -- for depth of iteration |
||
local childNumber = 1 |
local childNumber = 1 -- number of sister elements on node (always one for root) |
||
local indent = p.getIndent(levelNumber) |
local indent = p.getIndent(levelNumber) |
||
-- converted the newick string to the clade structure |
-- converted the newick string to the clade structure |
||
Line 882: | Line 862: | ||
local resultString = '' |
local resultString = '' |
||
local option = pargs['option'] or '' |
|||
if option == 'tree' then |
|||
--show the transcluded clade diagram |
--show the transcluded clade diagram |
||
resultString = cladeString |
resultString = cladeString |
||
else |
|||
-- show the wikitext list string |
|||
resultString = '<pre>'..listString..'</pre>' |
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 |
end |
||
Line 901: | Line 881: | ||
local cladeString = "" |
local cladeString = "" |
||
local indent = p.getIndent(levelNumber) |
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, "") |
list[i] = list[i]:gsub("^"..listChar, "") -- strip the first @ |
||
if not string.match( |
if not string.match(list[i], "^"..listChar, 1) then -- count children at this level (not beginning wiht @) |
||
lastNode = lastNode+1 |
lastNode = lastNode +1 |
||
end |
end |
||
i=i+1 |
i = i + 1 |
||
end |
end |
||
i = 1 |
|||
while list[i] do |
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 |
i = i + 1 |
||
child=child+1 |
child=child+1 |
||
end |
end |