Module:Clade/transclude
Appearance
From Wikipedia, the free encyclopedia
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
[edit ]{{#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)
The above documentation is transcluded from Module:Clade/transclude/doc. (edit | history)
Editors can experiment in this module's sandbox (create | mirror) and testcases (create) pages.
Subpages of this module.
Editors can experiment in this module's sandbox (create | mirror) and testcases (create) pages.
Subpages of this module.
require('strict') localDEBUG=false --DEBUG=true -- comment out or not runtime or debug localp={} localpargs={} p.main=function(frame)-- called from template pargs=frame:getParent().args localoutput localselectedTree-- subtree extracted from page content localmodifiedTree-- subtree after pruning and grafting -- (1) get page localpage=pargs['page']orframe.args['page'] ifnotpagethen returnp.errorMsg("Target page not provided") end -- (2) get content of page (move from _section(), _label, etc) localcontent localtitle=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 iftitlethen iftitle.existsthen content=title:getContent() ifnotcontentthenreturnp.errorMsg("Content of "..page.." not loaded.")end else returnp.errorMsg('Page with title "'..page..'" not found.') end end -- (3) select from content localsection=pargs['section']orpargs['section1']orpargs[1] ifsectionthen selectedTree=p._section(frame,content,section) end locallabel=pargs['label']orpargs['label1']orpargs[1] iflabelthen selectedTree=p._label(frame,content,label) end --TODO does this need to be separate from label? localsubtree=pargs['subtree']orpargs['subtree1']orpargs[1] ifsubtreethen selectedTree=p._label(frame,content,subtree) end ifnotselectedTreethen-- if none of options retrieve anything p.errorMsg("Nothing retrieved for selection option "..(labelorsubtreeorsectionor"none")) end ifDEBUGthenreturnselectedTreeend--- returns the code captured without processing --(4) modify content (excise and replace; prune and graft) localexclude=pargs['exclude']orpargs['exclude1'] ifexcludethen ifpargs['exclude']thenpargs['exclude1']=pargs['exclude']end ifpargs['replace']thenpargs['replace1']=pargs['replace']end modifiedTree=selectedTree locali=1 whilepargs['exclude'..i]do localexclude=pargs['exclude'..i] localreplace=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 ifpargs['nohidden']then modifiedTree=modifiedTree:gsub("lade hidden","lade") end ----- suppress authorities (or anything in small tags) ifpargs['noauthority']then modifiedTree=modifiedTree:gsub("<small>.-</small>","") end ----- suppress images ifpargs['noimages']then modifiedTree=modifiedTree:gsub("%[%[File:.-%]%]","") end ----- wrap in outer clade localwrap=pargs['wrap'] ifwrapand(labelorsubtree)then locallabel1=labelorstring.lower(subtree) localstyleString="" ifpargs['style']thenstyleString='|style='..pargs['style']end ifwrap~=""thenlabel1=wrapend output="{{clade "..styleString.." |label1="..p.firstToUpper(label1).."|1="..modifiedTree.." }}"-- last space before double brace important else output=modifiedTree end --(6) return final tree ifoutputthen ifpargs['raw']then returnoutput else returnframe:preprocess(output) end end returnp.errorMsg("No valid option for transclusion") end --=============================== extract LABELS or SUBTREES======================================= p.label=function(frame,page,...) localpage=frame.args[1]--"User:Jts1882/sandbox/test/Passeriformes" locallabel=frame.args[1]orframe.args['label']orframe.args['label1'] localwrap=frame.args['wrap'] localoutput=p._label(frame,page,frame.args[2],frame.args[3],frame.args[4],frame.args[5]) ifwrapthen locallabel1=string.lower(frame.args[2]) ifwrap~=""thenlabel1=wrapend output="{{clade |label1="..p.firstToUpper(label1).."|1="..output.."}}" end returnframe:preprocess(output) end p._label=function(frame,content,...) -- local page = "User:Jts1882/sandbox/test/Passeriformes" -- local label = frame.args[1] or frame.args['label'] localargs={...} localoutput="" ifnotargs[1]thenreturnp.errorMsg("Label name not provided")end localmode="label" localtargetType="label(%d)"-- standard label of form |labelN= (captures N) localcladePrefix="(%d)"-- standard node of form |N= (captures N) fork,vinpairs(args)do localsection=mw.text.trim(v) ifstring.upper(section)==sectionthen 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 = {...} ]=] localpattern=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) localindex1,index2,selectedTree=string.match(content,pattern) -- note index1 and index2 should match (X=X or N=N) ifselectedTreethen --[[ 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} ]] localpattern2="({%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 ifstring.find(selectedTree,pattern2)then-- if a subtree that hasn't been substituted. --local i,j,target = string.find(value, pattern2) -- only one subtree locali=0 forbracedMarkerinstring.gmatch(selectedTree,pattern2)do i=i+1 -- bracedMarker is either a marker in the tree or part of following -- targetX={bracedMarker} ... |subcladeX=s then localpattern3="target(%u)=[%s]*"..bracedMarker --?? if selectedTree == bracedMarker ifnotstring.find(selectedTree,pattern3)then localsubtree=p._label(frame,content,bracedMarker) ifsubtreethen --[[ 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 ]] locali,j,X=string.find(content,pattern3) ifselectedTree==bracedMarkerthen 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 ifoutput~=""then returnoutput-- 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,...) localpage=frame.args[1]--"User:Jts1882/sandbox/test/Passeriformes" locallabel=frame.args[1]orframe.args['label']orframe.args['label1'] -- page , target tree, subtrees to exclude ... -- page, include clade, multiple clades to exclude | returnp._xlabel(frame,page,frame.args[2],frame.args[3],frame.args[4],frame.args[5]) end p._xlabel=function(frame,targetTree,exclude,replace) localfullOutput=targetTree --local fullOutput = p._section(frame, page, target) localoutput=targetTree-- return unmodified tree if nothing happens localsection=exclude localtargetType="label%d" localcladePrefix="%d" ifstring.upper(section)==sectionthen targetType="target%u"-- by convention subtrees must be uppercase cladePrefix="subclade%u" end -- label = [[ name ]] |n= {...} localpattern="("..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) localvalue=string.match(fullOutput,pattern) ifvaluethen localtrimmedTree,matches=string.gsub(fullOutput,pattern,"%1"..replace)--replaces pattern with capture %1 returntrimmedTree else localmessage="" ifstring.upper(section)==sectionthen message="; subtree may have been substituted, try label" end output=output..p.warningMsg("Failed to capture subclade for exclusion with label "..section..message) end ifoutput~=""then returnoutput..'<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 returnframe: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,...) localargs={...} localoutput="" fork,vinpairs(args)do localsection=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 ]] localpattern="<section begin="..section.."[ ]*/>(.-)<section end="..section.."[ ]*/>" forvalueinstring.gmatch(content,pattern)do ifvaluethen ifframe.args.wraporframe:getParent().args.wrapthen locallabel1=frame.args.wraporframe:getParent().args.wrap iflabel1==""thenlabel1=sectionend value="{{clade |label1="..label1.."|1="..value.."}}" end output=output..value end end end ifpargs['norefs']orpargs['noref']then-- strip out references --output = mw.text.killMarkers( output ) ifoutput: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 ifoutput~=""then --return frame:preprocess(output) returnoutput-- leave preprocessing for entry function else return'<span class="error">Section not found</span>' end end p.xsection=function(frame) localpage=frame.args[1]--"User:Jts1882/sandbox/test/Passeriformes" locallabel=frame.args[1]orframe.args['label']orframe.args['label1'] -- page , target tree, sections to exclude ... returnframe:preprocess(p._xsection(frame,page,frame.args[2],frame.args[3],frame.args[4],frame.args[5])) end p._xsection=function(frame,page,target,...) localargs={...} localoutput="" localtitle=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 iftitleandtitle.existsthen localcontent=title:getContent() localfullOutput=p._section(frame,page,target) output=fullOutput fork,vinpairs(args)do localsection=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 ]] localpattern="(<section begin="..section.."[ ]*/>)(.-)(<section end="..section.."[ ]*/>)" localvalue=string.match(fullOutput,pattern) ifvaluethen localtrimmedTree,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 ifoutput~=""then --return frame:preprocess(output) returnoutput-- leave preprocessing for entry function else return'<span class="error">Section not found</span>' end end functionp.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 returnp