Bước tới nội dung

Mô đun:Clade/transclude

Bách khoa toàn thư mở Wikipedia
require('strict')local DEBUG=false--DEBUG=true -- comment out or not runtime or debuglocal 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"))    endif 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 "&nbsp;"  -- 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)		if wrap ~= "" then label1 = wrap end		output = "{{clade |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)endp._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>'     endend	--================================== 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, multple clades to exclude |	return p._xlabel (frame, page, frame.args[2], frame.args[3], frame.args[4], frame.args[5])endp._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     endend	--======================================== 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]))endp._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 output ~= "" then 		--return  frame:preprocess(output)		return output -- leave preprocessing for entry function	else 		return '<span class="error">Section not found</span>'     endend 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]))endp._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>'     endend function p.firstToUpper(str)    return (str:gsub("^%l", string.upper))endp.errorMsg = function (message)	return '<span class="error">' .. message .. '</span>' end	p.warningMsg = function (message)	return '<span class="warning">' .. message .. '</span>' end	return p