Module:Clade/transclude
| This module is rated as alpha. It is ready for limited use and third-party feedback. It may be used on a small number of pages, but should be monitored closely. Suggestions for new features or adjustments to input and output are welcome. |
Module for template {{Clade transclude}} with functions for partial transclusion of cladograms made with the {{Clade}} template.
Usage
{{#invoke:Clade|main}}
Parameters described at {{Clade transclude}}.
Testcases:
- {{Clade transclude/testcases}} (examples using nested subtrees)
- {{Clade transclude/testcases2}} (examples with all trees at basal clade)
require('strict')
local DEBUG=false
--DEBUG=true -- comment out or not runtime or debug
local p ={}
local pargs ={}
p.main = function(frame) -- called from template
pargs = frame:getParent().args
local output
local selectedTree -- subtree extracted from page content
local modifiedTree -- subtree after pruning and grafting
-- (1) get page
local page = pargs['page'] or frame.args['page']
if not page then
return p.errorMsg("Target page not provided")
end
-- (2) get content of page (move from _section(), _label, etc)
local content
local title = mw.title.new( mw.text.trim(page)) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title then
if title.exists then
content = title:getContent()
if not content then return p.errorMsg("Content of " .. page .. " not loaded.") end
else
return p.errorMsg('Page with title "' .. page .. '" not found.')
end
end
-- (3) select from content
local section = pargs['section'] or pargs['section1'] or pargs[1]
if section then
selectedTree = p._section(frame, content, section)
end
local label = pargs['label'] or pargs['label1'] or pargs[1]
if label then
selectedTree = p._label(frame, content, label)
end
--TODO does this need to be separate from label?
local subtree = pargs['subtree'] or pargs['subtree1'] or pargs[1]
if subtree then
selectedTree = p._label(frame, content, subtree)
end
if not selectedTree then -- if none of options retrieve anything
p.errorMsg("Nothing retrieved for selection option " .. (label or subtree or section or "none"))
end
if DEBUG then return selectedTree end --- returns the code captured without processing
--(4) modify content (excise and replace; prune and graft)
local exclude = pargs['exclude'] or pargs['exclude1']
if exclude then
if pargs['exclude'] then pargs['exclude1'] = pargs['exclude'] end
if pargs['replace'] then pargs['replace1'] = pargs['replace'] end
modifiedTree = selectedTree
local i = 1
while pargs['exclude'..i] do
local exclude = pargs['exclude'..i]
local replace = pargs['replace'..i] or " " -- must be something
modifiedTree = p._xlabel(frame, modifiedTree, exclude, replace)
i=i+1
end
else
modifiedTree = selectedTree
end
--(5) other options
----- suppress hidden elements
if pargs['nohidden'] then
modifiedTree = modifiedTree:gsub("lade hidden", "lade")
end
----- suppress authorities (or anything in small tags)
if pargs['noauthority'] then
modifiedTree = modifiedTree:gsub("<small>.-</small>", "")
end
----- suppress images
if pargs['noimages'] then
modifiedTree = modifiedTree:gsub("%[%[File:.-%]%]", "")
end
----- wrap in outer clade
local wrap = pargs['wrap']
if wrap and (label or subtree) then
local label1 = label or string.lower(subtree)
local styleString = ""
if pargs['style'] then styleString = '|style=' .. pargs['style'] end
if wrap ~= "" then label1 = wrap end
output = "{{clade " .. styleString .. " |label1=" .. p.firstToUpper(label1) .. "|1=" .. modifiedTree .. " }}" -- last space before double brace important
else
output = modifiedTree
end
--(6) return final tree
if output then
if pargs['raw'] then
return output
else
return frame:preprocess(output)
end
end
return p.errorMsg("No valid option for transclusion")
end
--=============================== extract LABELS or SUBTREES=======================================
p.label = function (frame, page, ...)
local page = frame.args[1] --"User:Jts1882/sandbox/test/Passeriformes"
local label = frame.args[1] or frame.args['label'] or frame.args['label1']
local wrap = frame.args['wrap']
local output = p._label (frame, page, frame.args[2], frame.args[3], frame.args[4], frame.args[5] )
if wrap then
local label1 = string.lower(frame.args[2])
if wrap ~= "" then label1 = wrap end
output = "{{clade |label1=" .. p.firstToUpper(label1) .. "|1=" .. output .. "}}"
end
return frame:preprocess(output)
end
p._label = function (frame, content, ... )
-- local page = "User:Jts1882/sandbox/test/Passeriformes"
-- local label = frame.args[1] or frame.args['label']
local args = { ... }
local output = ""
if not args[1] then return p.errorMsg ("Label name not provided") end
local mode = "label"
local targetType = "label(%d)" -- standard label of form |labelN= (captures N)
local cladePrefix = "(%d)" -- standard node of form |N= (captures N)
for k,v in pairs(args) do
local section = mw.text.trim(v)
if string.upper( section) == section then
mode = "subtree"
targetType = "target(%u)" -- targets of form targetX (X=uppercase letter)
cladePrefix = "subclade(%u)" -- subclades of form subcladeX (captures X)
end
--[=[ the pattern to capture is one of two forms: labelN=Name |N={...}
targetX=NAME |subcladeX={...}
labelN = [[ name ]] |N = {...}
or targetX = [[ name ]] |subcladeX = {...}
]=]
local pattern = targetType.."=[%s%p]*"..section .. "[%s%p]+.-"..cladePrefix.."=.-(%b{})"
-- this .- skips section tags before {{clade ...}}
-- this .- skips |sublabel and styling following the label (but can return wrong clade when a subtree)
local index1, index2, selectedTree = string.match( content , pattern )
-- note index1 and index2 should match (X=X or N=N)
if selectedTree then
--[[ the tree can contain markers for subtrees like {FABIDS}
when the form is |N={FABIDS} we want to substitute the subtree
but not when the form is |targetX={FABIDS}
]]
local pattern2 = "({%u-})" -- this captures both |N={FABIDS} and |targetX={FABIDS}
-- we only want to substitute a subtree in the first kind
-- will exclude second with pattern3 test below
if string.find(selectedTree, pattern2 ) then -- if a subtree that hasn't been substituted.
--local i,j,target = string.find(value, pattern2) -- only one subtree
local i=0
for bracedMarker in string.gmatch( selectedTree , pattern2 ) do
i=i+1
-- bracedMarker is either a marker in the tree or part of following
-- targetX={bracedMarker} ... |subcladeX=s then
local pattern3 = "target(%u)=[%s]*"..bracedMarker
--?? if selectedTree == bracedMarker
if not string.find(selectedTree, pattern3 ) then
local subtree = p._label (frame, content, bracedMarker)
if subtree then
--[[ method 1: the subtree code is substituted into main tree
this substitutes the subtree within the clade structure before processing
thus there will be a problem with large trees exceeding the expansion depth
however, they can be pruned before processing
]]
--disable method 1 selectedTree = string.gsub(selectedTree, bracedMarker, subtree, 1)
--[[method 2: add the subtree code before the final double brace
substitute "|targetX={FABIDS} |subcladeX=subtree" before last double brace of selectedTree
use capture in pattern3 to find X
]]
local i,j,X = string.find(content, pattern3)
if selectedTree == bracedMarker then
selectedTree = subtree
else
selectedTree = selectedTree:sub(1,-3) -- trim final double brace
.. "\n|target" .. X .. "=" .. bracedMarker
.. "\n|subclade" .. X .. "=" .. subtree .. ""
.. "\n }}"
end
end
end --substitution of subtree
end
end
output = output .. selectedTree
else
output = output .. p.errorMsg ("Failed to capture subclade with " .. mode .. " " ..section)
end
end
if output ~= "" then
return output -- preprocess moved to entry function
else
return '<span class="error">Section for label not found</span>'
end
end
--================================== exclude LABEL ================================================
p.xlabel = function (frame, page, ...)
local page = frame.args[1] --"User:Jts1882/sandbox/test/Passeriformes"
local label = frame.args[1] or frame.args['label'] or frame.args['label1']
-- page , target tree, subtrees to exclude ...
-- page, include clade, multiple clades to exclude |
return p._xlabel (frame, page, frame.args[2], frame.args[3], frame.args[4], frame.args[5])
end
p._xlabel = function (frame, targetTree, exclude, replace)
local fullOutput = targetTree
--local fullOutput = p._section(frame, page, target)
local output=targetTree -- return unmodified tree if nothing happens
local section = exclude
local targetType = "label%d"
local cladePrefix = "%d"
if string.upper( section) == section then
targetType = "target%u" -- by convention subtrees must be uppercase
cladePrefix = "subclade%u"
end
-- label = [[ name ]] |n= {...}
local pattern = "("..targetType.."=[%s%p]*"..section .. "[%s%p]*.-"..cladePrefix.."=.-)(%b{})"
-- ^^ this .- skips section tags before clade
-- ^^this .- skips |sublabel and styling following the label (but can return wrong clade when a subtree)
local value = string.match( fullOutput , pattern )
if value then
local trimmedTree, matches = string.gsub(fullOutput, pattern, "%1"..replace)--replaces pattern with capture %1
return trimmedTree
else
local message = ""
if string.upper(section) == section then
message = "; subtree may have been substituted, try label"
end
output = output .. p.warningMsg ("Failed to capture subclade for exclusion with label "..section..message)
end
if output ~= "" then
return output .. '<span class="error">Nothing pruned</span>'
--return frame:preprocess(fullOutput)
else
return '<span class="error">Section for label not found</span>' -- shouldn't get here
end
end
--======================================== SECTION ==================================
p.section = function (frame)
-------------------------target page ---- sections
return frame:preprocess(p._section(frame, mw.text.trim(frame.args[1]),frame.args[2],frame.args[3],frame.args[4],frame.args[5]))
end
p._section = function (frame,content,...)
local args = { ... }
local output = ""
for k,v in pairs(args) do
local section = mw.text.trim(v)
--[[ note: using the non-greedy - in (.-) to allow capture of several sections
this allows internal clade structures to be closed without capturing sisters clades
e.g. see section Tyranni in User:Jts1882/sandbox/test/Passeriformes
]]
local pattern = "<section begin="..section.."[ ]*/>(.-)<section end="..section.."[ ]*/>"
for value in string.gmatch( content , pattern ) do
if value then
if frame.args.wrap or frame:getParent().args.wrap then
local label1 = frame.args.wrap or frame:getParent().args.wrap
if label1 == "" then label1 = section end
value = "{{clade |label1=" .. label1 .. "|1=" .. value .. "}}"
end
output = output .. value
end
end
end
if pargs['norefs'] or pargs['noref'] then -- strip out references
--output = mw.text.killMarkers( output )
if output:find("<ref") then
output = output:gsub('<ref[%w%p%s]-%/>', "")
output = output:gsub("<ref.-<%/ref>", "") -- %C works, %w%p%s%c doesn't
end
end
if output ~= "" then
--return frame:preprocess(output)
return output -- leave preprocessing for entry function
else
return '<span class="error">Section not found</span>'
end
end
p.xsection = function (frame)
local page = frame.args[1] --"User:Jts1882/sandbox/test/Passeriformes"
local label = frame.args[1] or frame.args['label'] or frame.args['label1']
-- page , target tree, sections to exclude ...
return frame:preprocess(p._xsection(frame, page ,frame.args[2],frame.args[3],frame.args[4],frame.args[5]))
end
p._xsection = function (frame,page, target, ...)
local args = { ... }
local output = ""
local title = mw.title.new( page) -- , ns) -- creates object if page doesn't exist (and valid page name)
--TODO: could use mw.title.makeTitle(), but that needs ns
if title and title.exists then
local content = title:getContent()
local fullOutput = p._section(frame, page, target)
output=fullOutput
for k,v in pairs(args) do
local section = mw.text.trim(v)
--[[ note: using the non-greedy - in (.-) to allow capture of several sections
this allows internal clade structures to be closed without capturing sisters clades
e.g. see section Tyranni in User:Jts1882/sandbox/test/Passeriformes
]]
local pattern = "(<section begin="..section.."[ ]*/>)(.-)(<section end="..section.."[ ]*/>)"
local value = string.match( fullOutput , pattern )
if value then
local trimmedTree, matches = string.gsub(fullOutput, pattern, "replacement string")--replaces pattern with capture %1
output = output .. trimmedTree
output = output .. "<pre>" .. trimmedTree .. "</pre>"
fullOutput = trimmedTree
else
output = output .. p.errorMsg ("Failed to capture subclade with label "..section)
end
end
else
return '<span class="error">No page title found</span>'
end
if output ~= "" then
--return frame:preprocess(output)
return output -- leave preprocessing for entry function
else
return '<span class="error">Section not found</span>'
end
end
function p.firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
p.errorMsg = function (message)
return '<span class="error">' .. message .. '</span>'
end
p.warningMsg = function (message)
return '<span class="warning" style="color:#ac6600;font-size:larger;">' .. message .. '</span>'
end
return p
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.