Module:Sandbox/Was a bee/tree

local p = {}

datas = {}

-- These setdata and getdata functions are used to access (read and write) to "datas" table function p.setdata(n, key, val) if datas[n] == nil then datas[n] = {} end datas[n][key] = val end

function p.getdata(n, key, defval) if datas[n] == nil or datas[n][key] == nil then return defval else return datas[n][key] end end

function p.children(query, itemId, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) -- children function which listing all childrens that certain item has. -- Not listing grand childrens, or grand-grand childrens. Listing only childrens. -- Final returning value "childrens" is like {Q123123, Q3984198237, Q1874138746} local childrens = {} local entity = mw.wikibase.getEntity( itemId ) local claims = nil local x = 1 local tmpValue = {} ---	-- Start collecting data from the retrieved entity, and save that into the datas[] table. -- Because getEntity function is EXPENSIVE, so here, collecting all data at once. -- https://en.wikipedia.org/wiki/WP:EXPENSIVE -- https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua#mw.wikibase.getEntity local globalSiteId_1 = lang1 .. 'wiki' local globalSiteId_2 if lang2 and lang2 ~= '' then globalSiteId_2 = lang2 .. 'wiki' else globalSiteId_2 = nil end p.setdata(itemId, "sitelink_1", entity:getSitelink( globalSiteId_1 )) p.setdata(itemId, "label_1", entity:getLabel( lang1 )) if lang2 and lang2 ~= '' then p.setdata(itemId, "sitelink_2", entity:getSitelink( globalSiteId_2 )) p.setdata(itemId, "label_2", entity:getLabel( lang2 )) end -- ★★★★ Start source specific code ★★★★ -- TA98 claims = entity['claims']['P1323'] --TA98 ID	if claims then for _,claim in pairs( claims ) do			tmpValue[x] = claim.mainsnak.datavalue.value x = x + 1 end p.setdata(itemId, "TA98", tmpValue) end tmpValue = {} --initialize x = 1 --initialize claims = nil --initialize MeSH --claims = entity['claims']['P672'] --MeSH Code --if claims then --	for _,claim in pairs( claims ) do	--		tmpValue[x] = claim.mainsnak.datavalue.value --		x = x + 1 --	end --	p.setdata(itemId, "MeSH", tmpValue) --end --	--tmpValue = {} --initialize --x = 1 --initialize --claims = nil --initialize -- ★★★★ End source specific code ★★★★ -- ---			-- End collecting data ---	--mw.logObject(datas[itemId]) ---			-- Start collecting childrens ---	claims = entity['claims'][property] --local claims = wikidata.getClaims(query) if not claims then return {} end local has_source if sources then -- If input setting about "sources" exists has_source = false -- default else has_source = true -- when setting doesn't requires sources, assuming as if all cliams are sourced end for _,claim in pairs( claims ) do		if sources then -- If input setting about "sources" exists has_source = false -- reset -- ★★★★ Start source specific code ★★★★ -- if claim['references'] and claim['references'][1]['snaks']['P248'] then -- If P248 ("stated in") claim exists if claim['references'][1]['snaks']['P248'][1]['datavalue']['value']['id'] == 'Q286567' then -- If it is TA98 ('Q286567') has_source = true --If the claim is sourced by Terminologia Anatomica, then "has_source" is true p.setdata('Q' .. claim.mainsnak.datavalue.value['numeric-id'], 'sourcedBy', 'TA98')-- set datas table, like datas[Q1234]['sourceType'] = 'TA98' end end -- ★★★★ End source specific code ★★★★ -- end --Adding item only when the claim is sourced by specific literature (e.g. Terminologia Anatomica) --or adding all item if input setting doesn't need source if has_source then local value = claim.mainsnak.datavalue.value local nextitem = 'Q' .. value['numeric-id']

childrens[x] = nextitem x = x + 1 end end --mw.logObject(datas[itemId]) --mw.log("childrens are : ") --mw.logObject(childrens) return childrens ---			-- End collecting childrens --- end -- generator, see http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators for lua doc -- definition a function that when called several times will generate a sequence of strings -- gensymbols = create_gensymbols("ABC") -- gensymbols == "A" -- gensymbols == "B" g -- gensymbols == "C" -- gensymbols == "AA" ' -- gensymbols == "BABBA" -- ... function p.gensymbols(chars) local i = 0 local charset = chars local generator = function local symbol = "" local rest rest = i		repeat local j 			j = rest % string.len(charset) rest = math.floor(rest / string.len(charset)) symbol = symbol .. string.sub(charset, j+1, j+1) until rest <= 0 i = i + 1 return symbol end return generator end

---	-- Start definition of itemOutput function which returns text like  .. label ..  ---	function p.itemOutput(item, lang1, lang2, datas, setdata, getdata, refStyle, pencil) local globalSiteId_1 = lang1 .. 'wiki' local globalSiteId_2 = lang2 .. 'wiki' --local lang_2 = 'en' --local langWiki = '//'..lang..'.wikipedia.org' -- if lang is 'fr', then this is '//fr.wikipedia.org' used to compare with mw.site.server --local currentEntity = mw.wikibase.getEntityObject( item ) local currentLabel local currentLabel_temp local content local refTable = {} local referenceText = '' local pencilText if pencil == 'none' then pencilText = '' else --(P527 "has part" or P361 "is part of") pencilText = '' end refStyle = 'asdasdsa' --mw.log('refStyle is: ' .. refStyle) if refStyle and refStyle ~= 'none' then -- ★★★★ Start source specific code ★★★★ -- if p.getdata(item, "sourcedBy", nil ) and p.getdata(item, "sourcedBy", nil ) == 'TA98' then --mw.log('datas[] is: ') --mw.logObject(datas) mw.log(' ') mw.log(' ') mw.log('item is: ') mw.logObject(item) mw.log('datas[item] is: ') mw.logObject(datas[item]) mw.log('datas[item]["TA98"] is: ') mw.logObject(datas[item]["TA98"]) refTable = p.getdata(item, "TA98", nil ) mw.log('refTable is: ') mw.logObject(refTable) mw.log(' ') mw.log(' ') if refTable and refTable ~= '' then for i, TA98ID in pairs( refTable ) do					refTable[i] = string.sub(refTable[i], 2) --Remove first character "A" from ID refTable[i] = '[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/' .. refTable[i] .. '%20Entity%20TA98%20EN.htm' .. ' ' .. 'A' .. refTable[i] ..']' -- Creating wikitext which links to TA98 official site --mw.log('refTable is :' .. tostring(table.concat(refTable))) end -- Converting multipul IDs into one line string, separated by comma, space ", " referenceText = tostring( table.concat( refTable, ', ' ) ) referenceText = referenceText .. ' TA98, 1998' if refStyle == 'normal' then referenceText = tostring( mw.getCurrentFrame:extensionTag( 'ref', referenceText, {} ) ) else referenceText = mw.getCurrentFrame:expandTemplate{ title = 'efn', args = {referenceText} } end else referenceText = '' end else referenceText = '' end -- ★★★★ End source specific code ★★★★ -- end --mw.log('referenceText is :' .. referenceText) --Link creation priority. Followings is an example. --'ja'(Japanese) represents your own language, and 'en'(English) represents other language which is familiar with your readers. --This section would be better to customize for your own readers. --1. Sitelink(ja)          --If local sitelink data exists, use that. --2. Label(ja)(en link)       --If local sitelink data doesn't exist, but local label data exists, use that (with en link). --3. Sitelink(en) (en link) --If both local language data doesn't exist, use sitelink to English Wikipedia --4. Label(en)(en link)       --If such data doesn't exist, use English label --5. Q123456                    --If all of such kind data doesn't exist, use bare item ID	currentLabel = p.getdata(item, "sitelink_1", nil ) -- wd._references( {item, 'P361'} ) if currentLabel ~= nil then content =  .. currentLabel ..  content = content .. ' ' .. referenceText content = content .. ' ' .. pencilText return content 1. Sitelink(ja) style else currentLabel = p.getdata(item, "label_1", nil ) if currentLabel ~= nil then content =  .. currentLabel ..  currentLabel_temp = p.getdata(item, "sitelink_2", nil ) if currentLabel_temp ~= nil then content = content .. ' (' .. lang2 .. ')' adding (en) link end content = content .. ' ' .. referenceText content = content .. ' ' .. pencilText return content 2. Label(ja)(en link) style else currentLabel = p.getdata(item, "sitelink_2", nil ) if currentLabel ~= nil then content = currentLabel content = content .. ' (' .. lang2 .. ')' adding (en) link content = content .. ' ' .. referenceText content = content .. ' ' .. pencilText return content 3. Sitelink(en) (en link) style else currentLabel = p.getdata(item, "label_2", nil ) if currentLabel ~= nil then content = currentLabel content = content .. ' (' .. lang2 .. ')' adding (en) link content = content .. ' ' .. referenceText content = content .. ' ' .. pencilText return content 4. Label(en)(en link) style else content = item content = content .. ' ' .. referenceText content = content .. ' ' .. pencilText return content --5. Q123456 style end end end end end ---	-- End definition of itemOutput function which returns text like  .. label ..  ---

function p.outputTree( query, firstItemId, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) ---	-- Start preparation of functions ---

- topological sort and meta data of the DAG ( https://en.wikipedia.org/wiki/Topological_sorting ) --This firstPass function is called only once, at first local function firstPass( query, firstItemId, item_repr ) local content = p.itemOutput(firstItemId, lang1, lang2, datas, setdata, getdata, refStyle, pencil) local opened = 1 -- This means the downstream branch of the item is under processing. -- If encountering opened item through the processing, it indicates that infinite loop exists. local closed = 2 -- This means the processing of all downstream branches of the item reached to its end. -- The downest item is showed with " ? " in tree. local incomplete = 3 -- This means the processing of all downstream branches of the item reached to its end. -- If more downstream branches exist but not processed (because of limitation from maxdepth), -- then the downest item showed with "…" in tree. local marks = {} --opened(1) or closed(2) or incomplete(3) for each QID (e.g. marks[Q12234234] -> closed) --local datas = {} --datas[QID]["nparents"], datas[QID]["symbol"], datas[QID]["looped"], datas[QID]["rank"], datas[QID]["status"] --datas[QID]["nparents"] represents "number of parents" of certain item. This is normally 1. --If this is 2 or more, it means that the exact same item appears several times in defferent branches of the tree repeatedly. local childrens = {} -- for example, childrens[Q1234] contains data like {Q123123, Q3984198237, Q1874138746}, three childrens of Q1234 --while there are unmarked nodes do		--   select an unmarked node n		--    visit(n) --function visit(node n)		--   if n has a temporary mark then stop (not a DAG) --   if n is not marked (i.e. has not been visited yet) then --       mark n temporarily --       for each node m with an edge from n to m do		--            visit(m) --       mark n permanently --       add n to head of L		-- this function -- * visits and builds the tree, DAG or graph, -- * in the same pass, computes a topological ordering for the DAG -- * annotates the nodes with informations function visit(n, depth, rank) --mw.log("depth is " .. depth .. ">=" .. "maxdepth is " .. maxdepth) --mw.log(n .. ": mark is " .. tostring(marks[n])) if marks[n] == opened then p.setdata(n, "status", "loop") p.setdata(n, "rank", rank) return rank elseif marks[n] ~= closed then marks[n] = opened childrens[n] = p.children( query, n, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2) for _, node in ipairs(childrens[n]) do					p.setdata(node, "nparents", 						p.getdata(node, "nparents", 0) + 1					) --mw.log(node .. ": nparents is " .. tostring(p.getdata(node, "nparents", "aaa"))) if depth <= maxdepth then rank = visit(node, depth + 1, rank + 1) end end if depth <= maxdepth then if p.getdata(n, "status", "complete") ~= "loop" then p.setdata(n, "status", "complete") end marks[n] = closed else p.setdata(n, "status", "incomplete") marks[n] = incomplete end p.setdata(n, "rank", rank) end return rank + 1 end p.setdata(firstItemId, "nparents", 0) visit(firstItemId, 1, 0) return datas, childrens end

local langobj = mw.language.new(lang1) -- link inside tree local function formatSymbol(prefix) return ' (' .. prefix .. ") " end local function genAnchor(id) return ' ' end local function anchorLink(id, content) return "" .. content .. "" end local function fmtTreeLinks(content) return mw.text.tag("sup", {}, content) end local function renderTree( itemId, datas, children, alreadyOuted, gs ) local content = p.itemOutput( itemId, lang1, lang2, datas, setdata, getdata, refStyle, pencil) local state if datas[itemId]["status"] ~= nil then state = datas[itemId]["status"] end --mw.log(itemId .. ": status is " .. state ) if 	datas[itemId] ["nparents"] > 1 and datas[itemId]["symbol"] == nil then p.setdata(itemId, "symbol", gs ) end -- prevent infinite loops in non DAGs if state == "loop" then if datas[itemId]["looped"] == nil then datas[itemId]["looped"] = "treated" content = fmtTreeLinks(" ∞") .. " " .. content .. genAnchor(itemId) else return content .. fmtTreeLinks("∞" ..	" ↑ " .. anchorLink(itemId, formatSymbol( datas[itemId]["symbol"] ))) end elseif state == "incomplete" or state == "unvisited" then content = content .. " " .. fmtTreeLinks("…") return content end -- has no chilren ? display as leaf if children[itemId] ~= nil and table.getn(children[itemId]) == 0 then --return " " .. content .. " ? " -- would be great to use "?b, but font problem			return " " .. content		end		datas[itemId] ["nparents"] = datas[itemId]["nparents"] - 1	   local parts = {}		-- sort children topologycally		if alreadyOuted[itemId] == nil then 			local langobj = mw.language.new(lang1)		    local prefix = " "		    if datas[itemId] ["nparents"] > 0 then		    	local arrow = langobj:getArrow		    	prefix = fmtTreeLinks(genAnchor(itemId) .. " " .. arrow .. " " .. formatSymbol(datas[itemId]["symbol"]))	    	end			order = children[itemId]	    	table.sort(order, function (a, b) return datas[a]["rank"] < datas[b]["rank"] end )		    for i, childId in ipairs(order) do		        table.insert( parts, renderTree( childId, datas, children, alreadyOuted, gs ) )		    end			if direction == "child" or direction == "brother" then 				local l = table.maxn( parts )				for i = 1,(l - 1) do					parts[i] = mw.text.tag( 'li', {}, parts[i] ) end parts[l] = mw.text.tag( 'li', { class = 'lastline' }, parts[l] ) alreadyOuted[itemId] = prefix .. " " .. content .. mw.text.tag( 'ul', {}, table.concat( parts ) ) elseif direction == "parent" then local texttmp local matchCount = 0 --mw.log("parts is: ") --mw.logObject(parts) texttmp = mw.text.tag( 'ul', {}, mw.text.tag( 'li', { class = 'lastline' }, content ) ) alreadyOuted[itemId], matchCount = string.gsub(table.concat( parts ), "()", texttmp .. "%1", 1) --mw.log('matchCount is:') --mw.log(matchCount) if matchCount == 0 then alreadyOuted[itemId] = prefix .. " " .. string.gsub(table.concat( parts ), "$", texttmp, 1) end alreadyOuted[itemId] = prefix .. " " .. alreadyOuted[itemId] --mw.log("alreadyOuted[itemId] is: ") --mw.logObject(alreadyOuted[itemId]) end end if datas[itemId] ["nparents"] <= 0 or state == "loop" then return alreadyOuted[itemId] else return content .. " " .. fmtTreeLinks(anchorLink(itemId, formatSymbol(datas[itemId]["symbol"])) .. " " .. langobj:getArrow(forward)) end end ---	-- End preparation of functions ---	- -- Start creating tree -- -	-- gen = p.gensymbols("??") -- gen = p.gensymbols("12") -- gen = p.gensymbols("★☆?") -- These symbols are used as link button for "jumping" from certain branch to other branch. -- "jumping" functionality is used when same item appears multipul times in one tree. local gen = p.gensymbols("@*#") local children datas, children = firstPass( query, firstItemId, gen) -- alreadyOuted is the table which contains html code for each QID. -- For example, like this... alreadyOuted[Q1234] = "Human body" -- Actually items which located more nearer to the root (to say, FirstItemId) contain html codes of their branchs within it. -- For example, like this... alreadyOuted[Q1234] = "Human body Nervous system" -- This is done by recursive calling of renderTree function inside the renderTree function. local alreadyOuted = {} rendering = {} -- What does this do? return renderTree( firstItemId, datas, children, alreadyOuted, gen) --- -- End creating tree -- --- end

function p.main( frame )

-- Start adjustments of arguments

local frame = frame:getParent local query = frame.args local sources local refStyle -- Option for refrence style. "none" or "normal" or other local pencil -- if pencil == "none", wikidata-linked pencil image is not shown local maxdepth local lang1 local lang2 local firstItemId = query.items if firstItemId == nil or firstItemId == '' then --If QID is not defined, using the QID of the item which is connected to the current page. firstItemId = mw.wikibase.getEntityIdForCurrentPage if not firstItemId then return 'No items passed as parameter' --If there is no connected wikidata page, abort. end end --local firstItemsId = mw.text.split( query.items, ' ' ) --if firstItemsId[1] == nil or firstItemsId[1] == '' or table.maxn( firstItemsId ) == 0 then --	--If QID is not defined, using the QID of the item which is connected to the current page. --	firstItemsId[1] = mw.wikibase.getEntityIdForCurrentPage --	if not firstItemsId[1] then --		return 'No items passed as parameter' --If there is no connected wikidata page, abort. --	end --end --for i, item in pairs( firstItemsId ) do	if tonumber(firstItemId) then --legacy format firstItemId = 'Q'.. tostring(firstItemId) end --end if tonumber(query.childProperty) then --legacy format query.childProperty = 'P'.. tostring(query.childProperty) end if tonumber(query.parentProperty) then --legacy format query.parentProperty = 'P'.. tostring(query.parentProperty) end if query.childDepth and query.childDepth ~= '' then query.childDepth = tonumber( query.childDepth ) else query.childDepth = 4 end if query.parentDepth and query.parentDepth ~= '' then query.parentDepth = tonumber( query.parentDepth ) else query.parentDepth = 2 end if query.brotherDepth and query.brotherDepth ~= '' then query.brotherDepth = tonumber( query.brotherDepth ) else query.brotherDepth = 0 end if query.sources and query.sources ~= '' then sources = mw.text.split( query.sources, ' ' ) else sources = nil end if query.refStyle and query.refStyle ~= '' then if query.refStyle == 'none' then refStyle = 'none' elseif query.refStyle == 'normal' then refStyle = 'normal' else refStyle = mw.text.split( query.sources, ' ' ) end else refStyle = 'normal' end if query.pencil and query.pencil ~= '' then pencil = tostring(query.pencil) else pencil = nil end if query.lang1 and query.lang1 ~= '' then lang1 = query.lang1 else lang1 = mw.language.getContentLanguage.code end if query.lang2 and query.lang2 ~= '' then lang2 = query.lang2 else lang2 = 'en' end -- -- End adjustments of arguments --

- -- Start creating tree -- -   local content = '' local parent_content = nil local child_content = nil local brother_content = nil local direction -- tree searching direction. "child", "parent" or "brother" local property -- property used to search items. For example "P527" (has part) or "P361" (part of) --	--Creating tree for parent side (upstream side) --	if query.parentProperty and query.parentProperty ~= '' then parent_content = '' direction = "parent" property = query.parentProperty maxdepth = query.parentDepth --for _, item in pairs( firstItemsId ) do		  parent_content = mw.text.tag( 'li', { class = 'lastline' }, p.outputTree( query, firstItemId, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) ) --end end --	--Creating tree for brother side (substream side) --	-- Brother is, as definition, "parent's child". So both query.parentProperty and query.childProperty is needed. if query.brotherDepth and query.brotherDepth >= 0 and query.parentProperty and query.parentProperty ~=  and query.parentDepth >= 1 and query.childProperty and query.childProperty ~=  then brother_content = '' direction = "brother" maxdepth = query.brotherDepth property = query.parentProperty -- Get parent QID local parents = p.children(query, firstItemId, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) --local currentEntity = mw.wikibase.getEntityObject( firstItemId ) --local claims = currentEntity['claims'][query.parentProperty] --if claims then -- If firstItemId has parent --	local x = 1 --	local parents = {} --	for _,claim in pairs( claims ) do -- Check all parent claims and get QID from there. And stored it into parents[] table. --			local value = claim.mainsnak.datavalue.value --			local nextitem = 'Q' .. value['numeric-id']

--			parents[x] = nextitem --			x = x + 1 --	end local currentEntity local claims local x = 1 local brothers, brothersPart = {} property = query.childProperty mw.log("parents is :") mw.logObject(parents) -- Get brother QID for _,parent in pairs( parents ) do				brothersPart = p.children(query, parent, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) mw.log("brothersPart is :") mw.logObject(brothersPart) --currentEntity = mw.wikibase.getEntityObject( parent ) --claims = currentEntity['claims'][query.childProperty] -- Get child property in parent entity. Parent's child is brother. for _,bro in pairs( brothersPart ) do -- Check all  child claims and get QID from there. And stored it into brothers[] table. --local value = claim.mainsnak.datavalue.value --local nextitem = 'Q' .. value['numeric-id'] if bro ~= firstItemId then -- One of parent's child is ownself. It is not brother. So exclude that. brothers[x] = bro x = x + 1 end end end mw.log("brothers is :") mw.logObject(brothers) -- Creating trees for brother local l = table.maxn( brothers ) if l >= 1 then for i = 1,(l - 1) do brother_content = brother_content .. mw.text.tag( 'li', {}, p.outputTree( query, brothers[i], property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) ) end brother_content = brother_content .. mw.text.tag( 'li', {}, p.outputTree( query, brothers[l], property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) ) end --end end --	--Creating tree for child side (downstream side) --	if query.childProperty and query.childProperty ~= '' then child_content = '' direction = "child" property = query.childProperty maxdepth = query.childDepth if brother_content and brother_content ~= '' then child_content = mw.text.tag( 'li', { class = 'lastline' }, p.outputTree( query, firstItemId, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) ) else child_content = mw.text.tag( 'li', { class = 'lastline' }, p.outputTree( query, firstItemId, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) ) end end mw.log("parent_content is: ") mw.logObject(parent_content) mw.log("") mw.log("") mw.log("child_content is: ") mw.logObject(child_content) mw.log("") mw.log("") mw.log("brother_content is: ") mw.logObject(brother_content) mw.log("") mw.log("") --	-- Combine parent and child (and brother) trees --	if parent_content and parent_content ~=  and child_content and child_content ~=  then -- Append child-tree to parent-tree. -- What is doing here is only replacing the last item (final '...') in "parent_content", by "child_content" -- But because of Lua regex function is not high functioning, bit complicated process is done here. local a = 0 local b = 0 -- Finding start position of final item by searching  from the left to the right through text. while string.find(parent_content, '', b) do mw.log(a .. ' ' .. b)			a, b = string.find(parent_content, '', b)		end mw.log(a .. ' ' .. b)		local c = 0 local d = 0 -- Finding end position of final item by searching </li>. c, d = string.find(parent_content, '</ul></li>.*$') --mw.log(c .. ' ' .. d) -- If c, d == nil, it means "parent_content" is one level, is not multipul level tree. -- In other words, it contains only one item which is correponding to "firstItemId". -- In such case, ignore "parent_content". -- Ignore "brother_content" also. Because if no parent known, no brother known. if c ~= nil and d ~= nil then -- Replacing final item of "parent_content" by "child_content". -- If "brother_content" exists, inserts it just after the "child_content". if brother_content and brother_content ~= '' then content = string.sub(parent_content, 1, a - 1) .. brother_content .. child_content .. string.sub(parent_content, c)			else content = string.sub(parent_content, 1, a - 1) .. child_content .. string.sub(parent_content, c)			end else content = child_content end end mw.log("content after is: ") mw.logObject(content) --	-- Final formatting and adding like template at the bottom --	if parent_content or child_content then res = mw.text.tag( 'div', { class = 'treeview' }, mw.text.tag( 'ul', {}, content ) ) if sources then -- if sources are shown after each items like [1], then put like template at the bottom res = res .. frame:expandTemplate{ title = 'Hidden', args = { 'Sources', frame:expandTemplate{ title = 'notelist', args = {} } } } end end --- -- End creating tree -- ---   return res end

return p