Mô đun:Sandbox/Jts1882/CladeN

--NOTE: this module contains functions for generating the table structure of the clade tree: 
The main function is called by the template using the  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 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:
Cách sử dụng: 
Bản mẫu:CladeN
Release version:
Cách sử dụng: 
Bản mẫu:Clade
function p.main(frame)
	local cladeString = ""	
	local maxChildren = 20 -- was 17 in the clade/cladex templates
	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 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 
	local src = "Bản mẫu: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  = pargs'caption' or ""
	local captionStyle = pargs'captionstyle' or ""
-- add an element to mimick nowiki WORKS BUT DISABLE FOR DEMO PURPOSES
--cladeString = '\n'

	-- open table	
	-- (border-collapse causes problems (see talk) -- cladeString = cladeString .. 
	
	cladeString = p.addSubTrees(cladeString) -- add subtrees
	
	return cladeString
	--return '\n' .. cladeString .. 
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", 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'..suffixi
		local target = pargs'target'..suffixi or "SUBCLADE_" .. suffixi
		if subclade  then 
			if string.find(cladeString, target) then
				cladeString = string.gsub(cladeString,target,subclade)
			end
		end
end
	return cladeString
end
--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)
	--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  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, ' 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'
	-- note: the classes interfere with the node counter, so try simpler version with style
content = '\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  with vertical padding (see above)
--local leafCellString = '\n|rowspan=2 ' .. classString  .. styleString .. ' |\n' .. content -- the new line causes  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 .. '"'
	
local barLabelCellString = 
	if barRight  ~= "0"  and barLabel ~= "" then 
	   barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. barLabel
	else -- uncomment following line to see the cell structure
	   --barLabelCellString = '\n|rowspan=2 ' .. classString .. ' |' .. 'BL'
	end 
	
	if groupLabel ~= "" then 		
		barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. ' style="'.. groupLabelStyle .. '" |' .. groupLabel 
	else -- uncomment following line to see the cell structure
	    --barLabelCellString = barLabelCellString .. '\n|rowspan=2 ' .. classString .. '" |' .. 'GL' 
end 	
--cladeString = cladeString .. barLabelCellString

	-------------------------------------------------------------------------------------
	-- (5) add second row (only one cell needed for sublabel because of rowspan=2); 
	--     note: earlier versions applied branch style to row rather than cell
	--           for consistency, it is applied to the sublabel cell as with the label cell
	
	--cladeString = cladeString .. '\n
	
	-----------------------------------
	-- (6) add cell containing sublabel
	
	local subLabel = 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
--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,  --' '  -- remove space to reduce post-expand include size (the width=1.5em handles spacing)
		return  -- must return something; this is critical for clade structure 
		--return  ' --      (thin nbsp)
	else
		-- spaces can cause  wrapping and can break tree structure, hence use span with nowrap class
		--return  .. nodeLabel .. 
		
		-- a better method for template expansion size is to replace spaces with nonbreaking spaces
		-- however, there is a problem if labels have a styling element (e.g. ") then stylingElementDetected = true end 
		
		-- we know the no break is handled when using 
		if string.find(nodeLabel,  .. nodeLabel .. 
	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
	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 .. 
	--cladeString = cladeString ..  '\n|  \n
	cladeString = cladeString ..  '\n
	return cladeString
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
ti = str
i = i + 1
end
return t
end
-- =================== experimental Newick to clade parser function =========================**
--Function of convert Newick strings to clade format
Cách sử dụng: 
function p.newickConverter(frame)
	
	local newickString = frame.args'newickstring' or pargs'newick'
	
	--if newickString ==  then return newickString  end
newickString = p.processNewickString(newickString,"") -- "childNumber")


	-- 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 ..   
	local resultString = 
local option = pargs'option' or 
if option == 'tree' then
	 	--show the transcluded clade diagram
		resultString =   cladeString    	
else
	-- show the Newick string
		resultString = ..newickString..	
	    -- show the converted clade structure
	    resultString = resultString .. .. cladeString ..	
end
--resultString = frame:expandTemplate{ title = 'clade',  frame:preprocess(cladeString) }
return resultString
end
--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..'='  ..   
return cladeString
end
function p.getIndent(levelNumber)
	local indent = "\r"
	local extraIndent = pargs'indent' or mw.getCurrentFrame().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.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 '..listString..	
	    -- show the converted clade structure
	    resultString = resultString .. .. cladeString ..	
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 list = mw.text.split(listString, "\n")
local i=1
local child=1
local lastNode=0

while listi  do
		listi=listi:gsub("^@", "")               -- strip the first @
		
		if not string.match( listi, "^@", 1 ) then -- count children at this level (not beginning wiht @)
			lastNode = lastNode+1  
		end
		i=i+1
	end
i=1
	while listi  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 listi+1 and string.match( listi+1, "^@", 1 )  then
	    	
	        local label=listi
	i=i+1
	    	local recombined = listi
	    	while listi+1 and string.match( listi+1, "^@", 1 ) do
	    		recombined = recombined .. "\n" .. listi+1 
	    		i=i+1
	    	end
	    	cladeString = cladeString .. indent .. '|label' .. child ..'=' ..  label	
	    	cladeString = cladeString .. indent .. '|' .. child ..'=' ..    
	return cladeString
end
-- this must be at end
return p