Content deleted Content added
updates for noglobal (note this needs to be repeated using the live version that was newer than this version) |
Replace Module:No globals with require( "strict" ) |
||
(51 intermediate revisions by one other user not shown) | |||
Line 8:
now uses templatestyles
]]
require('
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 ===========================
Line 35 ⟶ 34:
local cladeString = ""
local maxChildren = 20 --
local childNumber = 0
local childCount = 0 -- number of leaves in the clade (can use to set bottom of bracket in addTaxon()
local totalCount = 0
pargs = frame:getParent().args -- parent arguments
infoOutput = p.getCladeTreeInfo() -- get info about clade structure, e.g. lastNode (last |N= child number)
--[[ add the templatestyles tag conditionally to reduce expansion size (currently diabled)
when
e.g. the Neosuchia page (or test version) is increase by about 8% (672 bytes each)
with cladeCount==1
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
local src = "Template:CladeN/styles.css"
cladeString = cladeString .. p.templateStyle( frame, src ) .. '\n'
--end
local tableStyle = frame.args.style or ""
if tableStyle ~= "" then
tableStyle = ' style="' .. tableStyle .. '"' -- include style= in string to suppress empty style elements
end
reverseClade =frame.args.reverse or pargs.reverse or false -- a global
--ENFORCE GLOBAL FOR DEVELOPMENT
--reverseClade = true
local captionName =
local captionStyle =
-- add an element to mimick nowiki WORKS BUT DISABLE FOR DEMO PURPOSES
Line 89 ⟶ 84:
end
local moreNeeded = true
Line 110 ⟶ 100:
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf =
local nodeLabel =
local newickString =
local listString = pargs['list'..tostring(childNumber)] or ""
if listString ~= "" then
cladeString = cladeString .. '\n' .. p.addTaxon(childNumber, p.list(0, listString), nodeLabel, lastNode)
elseif newickString ~= "" then -- if using a newick string instead of a clade structure
newickString = p.processNewickString(newickString,childNumber)
if nodeLabel == "" then -- use labelN by default, otherwise use root name from Newick string
nodeLabel = p.getNewickOuterterm(newickString) -- need to use terminal part of newick string for label
Line 130 ⟶ 125:
end
local footerText =
local footerStyle =
if footerText ~= "" then
Line 146 ⟶ 141:
cladeString = cladeString .. '\n|}'
cladeString = p.addSubTrees(cladeString) -- add subtrees
return cladeString
--return '<div style="width:auto;">\n' .. cladeString .. '</div>'
end
--[[ =============================function to add subtrees ========================================== ]]
function p.addSubTrees(cladeString)
--local pargs = mw.getCurrentFrame():getParent().args
local suffix = { [1]="A", [2]="B", [3]="C", [4]="D", [5]="E"
[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() ------------------------------------------
adds wikitext for two rows of the table for each child node,
the first cell in each is used for the label and sublabel; the bottom border forms the horizonal branch of the bracket
Line 204 ⟶ 179:
function p.addTaxon(childNumber, nodeLeaf, nodeLabel, lastNode)
--[[ get border formating parameters (i.e. color, thickness, state)
nodeParameters for whole bracket (unnumbered, i.e. color, thickness, state) apply to whole node bracket,
branchParameters apply to individual branches
the branch parameters have a number, e.g. |colorN, |thicknessN, |stateN
the node parameters have no number, e.g. |color, |thickness, |state
]]
local nodeColor = pargs['color'] or "" -- don't set default to allow green on black gadget
local nodeThickness = tonumber(pargs['thickness']) or 1
local nodeState = pargs['state'] or "solid"
-- get border formating parameters for branch (default to global nodeParameters)
local branchColor = pargs['color'..tostring(childNumber)] or nodeColor
local branchThickness = tonumber(pargs['thickness'..tostring(childNumber)]) or nodeThickness
local
if branchState == 'double' then
if branchThickness < 2 then branchThickness = 3 end -- need thick line for double
end
local branchStyle = pargs['style'..tostring(childNumber)] or ""
local branchLength = pargs['length'] or pargs['length'..tostring(childNumber)] or ""
-- the left border takes node parameters, the bottom border takes branch parameters
Line 223 ⟶ 209:
local useInlineStyle = false
-- use inline styling non-default color, line thickness or state have been set
if branchColor ~= "" or branchThickness ~= 1 or
useInlineStyle = true
end
Line 230 ⟶ 216:
-- variables for right hand bar or bracket
--local barColor = ""
local barRight =
local barBottom =
local barTop =
local barLabel =
local groupLabel =
local groupLabelStyle
local labelStyle = pargs['labelstyle'..tostring(childNumber)] or ""
local sublabelStyle = pargs['sublabelstyle'..tostring(childNumber)] or ""
--replace colours with format string; need right bar for all three options
Line 251 ⟶ 239:
local classString = ''
local reverseClass = ''
local widthClass = ''
-- class to add if using reverse (rtl) cladogram;
Line 272 ⟶ 261:
end
end
if useInlineStyle or
local branchLengthStyle = ""
if branchLength ~= "" then
if childNumber == 1 then
branchLengthStyle = 'width:' .. branchLength .. ';' -- add width to first element
end
--if childNumber > 1 then prefix = 'max-' end
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';'
.. 'max-width:' .. branchLength ..';'
.. 'padding:0em;' -- remove padding to make calculation easier
-- following moved to styles.css
-- .. 'white-space:nowrap'
-- .. 'overflow:hidden;' -- clip labels longer than the max-width
-- .. 'text-overflow:clip;' -- ellipsis;'
--if pargs['noclip'] then
if string.find(nodeLabel, '<div style="position:absolute;') then
branchLengthStyle = branchLengthStyle .. 'overflow:visible;'
end
widthClass = " clade-fixed-width"
end
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. labelStyle .. '"'
end
if childNumber == 1 then
classString= 'class="clade-label first'.. widthClass .. '" ' -- add class "first" for top row
else
classString = 'class="clade-label' .. reverseClass .. widthClass .. '" ' -- add "reverse" class if ltr cladogram
end
Line 304 ⟶ 313:
end
end
classString = 'class="clade-leaf' .. reverseClass .. '"'
--[[note: the \n causes plain leaf elements get wrapped in <p> with style="margin:0.4em 0 0.5em 0;"
this adds spacing to rows, but is set by defaults rather than the clade template
it also means there are two newlines when it is a clade structure (which might explain some past issues)
]]
local content = '\n' .. nodeLeaf -- the newline is not necessary, but keep for backward compatibility
-- test using image parameter
local image = pargs['image'..tostring(childNumber)] or ""
if image ~= "" then
--content = content .. image -- basic version
content = '\n{| class="clade" style="width:auto;"' --defaults to width:100% because of class "clade"
.. '\n| class="clade-leaf" ' .. '|\n' .. nodeLeaf
.. '\n| class="clade-leaf" ' .. '|\n' .. image
.. '\n|}'
-- note: the classes interfere with the node counter, so try simpler version with style
content = '\n{| style="width:100%;border-spacing:0;" ' --width:auto is "tight"; 100% needed for image alignment
.. '\n| style="border:0;padding:0;" ' .. '|\n' .. nodeLeaf
.. '\n| style="border:0;padding:0;" ' .. '|\n' .. image
.. '\n|}'
end
-- wikitext for leaf cell (note: nodeLeaf needs to be on newline if new wikitable)
-- but that is no longer the case (newline is now forced)
-- the newline wraps plain leaf terminals in <P> with vertical padding (see above)
--local leafCellString = '\n|rowspan=2 ' .. classString .. styleString .. ' |\n' ..
local leafCellString = '\n|rowspan=2 ' .. classString .. styleString .. ' |' .. content
--cladeString = cladeString .. leafCellString
Line 327 ⟶ 362:
if groupLabel ~= "" then
barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. ' style="'.. groupLabelStyle .. '" |' .. groupLabel
else -- uncomment following line to see the cell structure
Line 345 ⟶ 379:
-- (6) add cell containing sublabel
local subLabel =
-- FOR TESTING: use subLabel for annotating the clade structues to use structure information (DEBUGGIING ONLY)
Line 364 ⟶ 398:
end
end
if borderStyle ~= '' or branchStyle ~= '' or branchLength ~= '' or sublabelStyle ~= "" then
local branchLengthStyle = ""
if branchLength ~= "" then
if childNumber == 1 then
--only set for label branchLengthStyle = 'width:' .. branchLength .. ';' -- add width to first element
end
--if childNumber > 1 then prefix = 'max-' end
branchLengthStyle = branchLengthStyle --= prefix .. 'width:' .. branchLength .. ';'
.. 'max-width:' .. branchLength ..';'
.. 'padding:0em;' -- remove padding to make calculation easier
--if pargs['noclip'] then
if string.find(subLabel, '<div style="position:absolute;') then
branchLengthStyle = branchLengthStyle .. 'overflow:visible;'
end
end
styleString = 'style="' .. borderStyle .. branchLengthStyle .. branchStyle .. sublabelStyle .. '"'
--styleString = ' style="' .. borderStyle .. branchStyle .. sublabelStyle .. '"'
end
Line 371 ⟶ 420:
if childNumber == lastNode then
classString = 'class="clade-slabel last' .. widthClass .. '" '
else
classString = 'class="clade-slabel' .. reverseClass .. widthClass .. '" '
end
local sublabelCellString = '\n|' .. classString .. styleString .. '|' .. p.addLabel(childNumber,subLabel)
Line 399 ⟶ 448:
end
Line 526 ⟶ 454:
function p.addLabel(childNumber,nodeLabel)
if nodeLabel == "" then
--return '<br/>' --' <br/>' -- remove space to reduce post-expand include size (the width=1.5em handles spacing)
--return
else
-- spaces can cause wrapping and can break tree structure, hence use span with nowrap class
Line 543 ⟶ 467:
if string.find(nodeLabel, "span ") ~= nil then stylingElementDetected = true end
if string.find(nodeLabel, " style") ~= nil then stylingElementDetected = true end
--TODO test following alternative
--if nodeLabel:find( "%b<>") then stylingElementDetected = true end
-- we know the no break is handled when using {{clade label}}
if string.find(nodeLabel, '<div style="position:absolute;') then stylingElementDetected = false end
if stylingElementDetected == true then
return '<span class="nowrap">' .. nodeLabel .. '</span>'
else
--local nowrapString = string.gsub(nodeLabel," ", " ") -- replace spaces with non-breaking space
local nowrapString = nodeLabel -- spaces are now handled by CSS "white-space:nowrap;""
if not nowrapString:find("UNIQ.-QINU") then -- unless a strip marker
nowrapString = string.gsub(nowrapString,"-", "‑") -- replace hyphen with non-breaking hyphen (‑)
end
return nowrapString
end
Line 590 ⟶ 522:
local i=1
while s[i] do
local restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas
--restoredString = s[i]
local outerTerm = string.gsub(restoredString, "%b()", "")
Line 611 ⟶ 543:
end
-- emulate a standard split string function
-- why not use mw.text.split(s, sep)?
function p.strsplit(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
local i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
Line 632 ⟶ 566:
function p.newickConverter(frame)
local newickString = frame.args['newickstring'] or pargs['newick']
--if newickString == '{{{newickstring}}}' then return newickString end
newickString = p.processNewickString(newickString,"") -- "childNumber")
-- show the Newick string
local cladeString = ''
Line 648 ⟶ 584:
local resultString = ''
local option =
if option == 'tree' then
--show the transcluded clade diagram
Line 697 ⟶ 633:
local i=1
while s[i] do
local restoredString = string.gsub(s[i],"XXX", ",") -- convert back to commas
local outerTerm = string.gsub(restoredString, "%b()", "")
Line 716 ⟶ 652:
function p.getIndent(levelNumber)
local indent = "\r"
local extraIndent = pargs['indent'] or mw.getCurrentFrame
while tonumber(extraIndent) > 0 do
Line 734 ⟶ 670:
end
function p.processNewickString(newickString,childNumber)
local maxPatterns = 5
local i = 0
local pargs = pargs
local pattern = pargs['newick'..tostring(childNumber)..'-pattern'] -- unnumbered option for i=1
local replace = pargs['newick'..tostring(childNumber)..'-replace']
while i < maxPatterns do
i=i+1
pattern = pattern or pargs['newick'..tostring(childNumber)..'-pattern'..tostring(i)]
replace = replace or pargs['newick'..tostring(childNumber)..'-replace'..tostring(i)] or ""
if pattern then
newickString = string.gsub (newickString, pattern, replace)
end
pattern = nil; replace = nil
end
newickString = string.gsub (newickString, "_", " ") -- replace underscore with space
return newickString
end
------------------------------------------------------------------------------------------
Line 745 ⟶ 701:
-------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------
--[[function getCladeTreeInfo()
Line 859 ⟶ 722:
while childNumber < maxChildren do -- preprocessing loop
childNumber = childNumber + 1 -- so we start with 1
local nodeLeaf,data =
local newickString =
local listString = pargs['list'..tostring(childNumber)] or "" -- get data from |labelN=
if newickString ~= "" or nodeLeaf ~= "" or listString ~= "" then
--if nodeLeaf ~= "" then
childCount = childCount + 1 -- this counts child elements in this clade
Line 921 ⟶ 785:
--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 list = mw.text.split(listString, "\n")
local i=1
local child=1
local lastNode=0--table.getn(list) -- number of child branches (potential)
cladeString = cladeString .. '{| class="clade" '
while list[i] do
list[i]=list[i]:gsub("^@", "") -- strip the first @
if not string.match( list[i], "^@", 1 ) then -- count children at this level (not beginning wiht @)
lastNode = lastNode+1
end
i=i+1
end
i=1
while list[i] do
--[[ pseudocode:
if next value begins with @ we have a subtree,
which must be recombined and past iteratively
else we have a simple leaf
]]
-- if the next value begins with @, we have a subtree which should be recombined
if list[i+1] and string.match( list[i+1], "^@", 1 ) then
local label=list[i]
i=i+1
local recombined = list[i]
while list[i+1] and string.match( list[i+1], "^@", 1 ) do
recombined = recombined .. "\n" .. list[i+1]
i=i+1
end
--cladeString = cladeString .. '\n' .. p.addTaxon(child, recombined, label, lastNode)
cladeString = cladeString .. '\n' .. p.addTaxon(child, p.list(count,recombined), label, lastNode)
else
cladeString = cladeString .. '\n' .. p.addTaxon(child, list[i], "", lastNode)
end
i=i+1
child=child+1
end
cladeString = cladeString .. '\n|}'
mw.addWarning("WARNING. This is a test feature only.")
return cladeString
end
-- =================== experimental Newick to clade parser function =============================
--[[Function of convert Newick strings to clade format
Usage: {{#invoke:Module:Sandbox/Jts1882/CladeN|newickConverter|newickstring={{{NEWICK_STRING}}} }}
]]
function p.cladeConverter(frame)
end
function p.listConverter(frame)
local listString = frame.args['list'] or pargs['list']
--
local
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 .. indent .. '{{clade'
cladeString = cladeString .. p.listParseLevel(listString, levelNumber, childNumber)
--cladeString = cladeString .. '\r}}'
local resultString = ''
local option = pargs['option'] or ''
--show the transcluded clade diagram
resultString = cladeString
-- show the Newick string
resultString = '<pre>'..listString..'</pre>'
-- show the converted clade structure
resultString = resultString .. '<pre>'.. cladeString ..'</pre>'
end
--resultString = frame:expandTemplate{ title = 'clade', frame:preprocess(cladeString) }
end
function p.listParseLevel(listString,levelNumber,childNumber)
local cladeString = ""
local indent = p.getIndent(levelNumber)
levelNumber=levelNumber+1
local
local i=1
local child=1
local lastNode=0
while list[i] do
list[i]=list[i]:gsub("^@", "") -- strip the first @
if not string.match( list[i], "^@", 1 ) then -- count children at this level (not beginning wiht @)
lastNode = lastNode+1
end
i=i+1
end
i=1
while list[i] do
if next value begins with @ we have a subtree,
which must be recombined and past iteratively
else we have a simple leaf
]]
-- if the next value begins with @, we have a subtree which should be recombined
if list[i+1] and string.match( list[i+1], "^@", 1 ) then
local label=list[i]
i=i+1
local recombined = list[i]
while list[i+1] and string.match( list[i+1], "^@", 1 ) do
recombined = recombined .. "\n" .. list[i+1]
i=i+1
end
cladeString = cladeString .. indent .. '|label' .. child ..'=' .. label
cladeString = cladeString .. indent .. '|' .. child ..'=' .. '{{clade'
.. p.listParseLevel(recombined,levelNumber,i)
else
cladeString = cladeString .. indent .. '|' .. child ..'=' .. list[i]
end
i=i+1
child=child+1
end
cladeString = cladeString .. indent .. '}}'
return cladeString
end
-- this must be at end
|