From Wikipedia, the free encyclopedia


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 datasn == nil then

		datasn = {}

	end

	datasn][key = val

end



function p.getdata(n, key, defval)

	if  datasn == nil or datasn][key == nil then

		return defval

	else

		return datasn][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.

	-- /info/en/?search=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

			tmpValuex = 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'



			childrensx = 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 '[[' .. link .. '|' .. 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 = '[[File:Blue pencil.svg|frameless|text-top|10px|link=https://www.wikidata.org/wiki/' .. item .. '#P527]]'

	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('<br/>')

			mw.log('<br/>')

			mw.log('item is: ')

			mw.logObject(item)

			mw.log('datas[item] is: ')

			mw.logObject(datasitem])

			mw.log('datas[item]["TA98"] is: ')

			mw.logObject(datasitem]["TA98"])

				refTable = p.getdata(item, "TA98", nil )

			mw.log('refTable is: ')

			mw.logObject(refTable)

			mw.log('<br/>')

			mw.log('<br/>')

			if refTable and refTable ~=  '' then

				for  i, TA98ID in pairs( refTable ) do

					refTablei = string.sub(refTablei], 2) --Remove first character "A" from ID

					refTablei = '[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/' .. refTablei .. '%20Entity%20TA98%20EN.htm' .. ' ' .. 'A' .. refTablei ..']' -- 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 .. ' [[Terminologia Anatomica|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. [[:ja:Sitelink(ja)|Sitelink(ja)]]           --If local sitelink data exists, use that.

	--2. [[:ja:Label(ja)|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 = '[[:' .. lang1 .. ':' .. currentLabel .. '|' .. currentLabel .. ']]'

		content = content .. ' ' .. referenceText

		content = content .. ' ' .. pencilText 

		return content ----1. [[:ja:Sitelink(ja)|Sitelink(ja)]] style 

	else

		currentLabel = p.getdata(item, "label_1", nil )

		if currentLabel ~= nil then

			content = '[[:' .. lang1 .. ':' .. currentLabel .. '|' .. currentLabel .. ']]'

			currentLabel_temp = p.getdata(item, "sitelink_2", nil )

			if currentLabel_temp ~= nil then

				content = content .. ' ([[:' .. lang2 .. ':' .. currentLabel_temp .. '|' .. lang2 .. ']])' ----adding (en) link

			end

			content = content .. ' ' .. referenceText

			content = content .. ' ' .. pencilText 

			return content ----2. [[:ja:Label(ja)|Label(ja)]](en link) style

		else

			currentLabel = p.getdata(item, "sitelink_2", nil )

			if currentLabel ~= nil then

				content = currentLabel

				content = content .. ' ([[:' .. lang2 .. ':' .. currentLabel .. '|' .. 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 .. ':' .. currentLabel .. '|' .. 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 '[[' .. link .. '|' .. 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 ( /info/en/?search=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 marksn == opened then 

				p.setdata(n, "status", "loop")

				p.setdata(n, "rank", rank)

				return rank

			elseif marksn ~= closed then

				marksn = opened

 

				childrensn = p.children( query, n, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2)

				for _, node in ipairs(childrensn]) 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

					marksn = closed

				else

					p.setdata(n, "status", "incomplete")

					marksn = 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 '<span class="Unicode"><small>(' .. prefix .. ")</small></span>"

	end

	local function genAnchor(id)

		return '<span id="' .. firstItemId .. id .. '"></span>' 

	end

	local function anchorLink(id, content)

		return "[[#" .. firstItemId .. id .. "|" .. 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 datasitemId]["status" ~= nil then

			state = datasitemId]["status" 

		end

		--mw.log(itemId .. ": status is " .. state )

 

		if 	datasitemId "nparents" > 1 and datasitemId]["symbol" == nil then

			p.setdata(itemId, "symbol", gs() )

		end

		-- prevent infinite loops in non DAGs

		if state == "loop" then

			if datasitemId]["looped" == nil then

				datasitemId]["looped" = "treated"

				content =  fmtTreeLinks(" ∞") .. " " .. content .. genAnchor(itemId)

			else

				return content ..  fmtTreeLinks("∞" ..	" ↑ " .. anchorLink(itemId, formatSymbol( datasitemId]["symbol" )))

			end

		elseif state == "incomplete" or state == "unvisited" then

			content = content .. " " .. fmtTreeLinks("…")

			return content

		end

 

		-- has no chilren ? display as leaf

		if childrenitemId ~= nil and table.getn(childrenitemId]) == 0 then

			--return " " .. content .. " ? " -- would be great to use "?b, but font problem

			return " " .. content

		end

 

 

		datasitemId "nparents" = datasitemId]["nparents" - 1

 

	    local parts = {}

 

		-- sort children topologycally

		if alreadyOuteditemId == nil then

 

 			local langobj = mw.language.new(lang1)

		    local prefix = " "

		    if datasitemId "nparents" > 0 then

		    	local arrow = langobj:getArrow()

		    	prefix = fmtTreeLinks(genAnchor(itemId) .. " " .. arrow .. " " .. formatSymbol(datasitemId]["symbol"]))

	    	end

				

			order = childrenitemId

	    	table.sort(order, function (a, b) return datasa]["rank" < datasb]["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

					partsi = mw.text.tag( 'li', {}, partsi )

				end

				partsl = mw.text.tag( 'li', { class = 'lastline' }, partsl )

				alreadyOuteditemId = 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 ) )

				

				alreadyOuteditemId], matchCount = string.gsub(table.concat( parts ), "(</li></ul>)", texttmp .. "%1", 1)

				--mw.log('matchCount is:')

				--mw.log(matchCount)

				if matchCount == 0 then

					alreadyOuteditemId = prefix .. " " .. string.gsub(table.concat( parts ), "$", texttmp, 1)

				end

				alreadyOuteditemId = prefix .. " " .. alreadyOuteditemId

				--mw.log("alreadyOuted[itemId] is: ")

				--mw.logObject(alreadyOuted[itemId])

			end

			

		end

 

		if datasitemId "nparents" <= 0 or state == "loop" then

			return alreadyOuteditemId

		else 

			return content .. " " .. fmtTreeLinks(anchorLink(itemId, formatSymbol(datasitemId]["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] = "<li>[[Human body]]</li>"

	-- 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] = "<li>[[Human body]] <ul><li>[[Nervous system]]</li></ul></li>"

	-- 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.

						brothersx = 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, brothersi], property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) )

				end

				brother_content = brother_content .. mw.text.tag( 'li', {}, p.outputTree( query, brothersl], 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 '<li class=\"lastline\">...</li>') 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 <li class=\"lastline\"> from the left to the right through text. 

		while string.find(parent_content, '<li class=\"lastline\">', b) do

			mw.log(a .. ' ' .. b)

			a, b = string.find(parent_content, '<li class=\"lastline\">', b)

		end

		mw.log(a .. ' ' .. b)

		

		local c = 0

		local d = 0

		-- Finding end position of final item by searching </ul></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 {{reflist}} 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 {{reflist}} 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
From Wikipedia, the free encyclopedia


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 datasn == nil then

		datasn = {}

	end

	datasn][key = val

end



function p.getdata(n, key, defval)

	if  datasn == nil or datasn][key == nil then

		return defval

	else

		return datasn][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.

	-- /info/en/?search=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

			tmpValuex = 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'



			childrensx = 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 '[[' .. link .. '|' .. 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 = '[[File:Blue pencil.svg|frameless|text-top|10px|link=https://www.wikidata.org/wiki/' .. item .. '#P527]]'

	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('<br/>')

			mw.log('<br/>')

			mw.log('item is: ')

			mw.logObject(item)

			mw.log('datas[item] is: ')

			mw.logObject(datasitem])

			mw.log('datas[item]["TA98"] is: ')

			mw.logObject(datasitem]["TA98"])

				refTable = p.getdata(item, "TA98", nil )

			mw.log('refTable is: ')

			mw.logObject(refTable)

			mw.log('<br/>')

			mw.log('<br/>')

			if refTable and refTable ~=  '' then

				for  i, TA98ID in pairs( refTable ) do

					refTablei = string.sub(refTablei], 2) --Remove first character "A" from ID

					refTablei = '[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/' .. refTablei .. '%20Entity%20TA98%20EN.htm' .. ' ' .. 'A' .. refTablei ..']' -- 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 .. ' [[Terminologia Anatomica|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. [[:ja:Sitelink(ja)|Sitelink(ja)]]           --If local sitelink data exists, use that.

	--2. [[:ja:Label(ja)|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 = '[[:' .. lang1 .. ':' .. currentLabel .. '|' .. currentLabel .. ']]'

		content = content .. ' ' .. referenceText

		content = content .. ' ' .. pencilText 

		return content ----1. [[:ja:Sitelink(ja)|Sitelink(ja)]] style 

	else

		currentLabel = p.getdata(item, "label_1", nil )

		if currentLabel ~= nil then

			content = '[[:' .. lang1 .. ':' .. currentLabel .. '|' .. currentLabel .. ']]'

			currentLabel_temp = p.getdata(item, "sitelink_2", nil )

			if currentLabel_temp ~= nil then

				content = content .. ' ([[:' .. lang2 .. ':' .. currentLabel_temp .. '|' .. lang2 .. ']])' ----adding (en) link

			end

			content = content .. ' ' .. referenceText

			content = content .. ' ' .. pencilText 

			return content ----2. [[:ja:Label(ja)|Label(ja)]](en link) style

		else

			currentLabel = p.getdata(item, "sitelink_2", nil )

			if currentLabel ~= nil then

				content = currentLabel

				content = content .. ' ([[:' .. lang2 .. ':' .. currentLabel .. '|' .. 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 .. ':' .. currentLabel .. '|' .. 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 '[[' .. link .. '|' .. 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 ( /info/en/?search=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 marksn == opened then 

				p.setdata(n, "status", "loop")

				p.setdata(n, "rank", rank)

				return rank

			elseif marksn ~= closed then

				marksn = opened

 

				childrensn = p.children( query, n, property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2)

				for _, node in ipairs(childrensn]) 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

					marksn = closed

				else

					p.setdata(n, "status", "incomplete")

					marksn = 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 '<span class="Unicode"><small>(' .. prefix .. ")</small></span>"

	end

	local function genAnchor(id)

		return '<span id="' .. firstItemId .. id .. '"></span>' 

	end

	local function anchorLink(id, content)

		return "[[#" .. firstItemId .. id .. "|" .. 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 datasitemId]["status" ~= nil then

			state = datasitemId]["status" 

		end

		--mw.log(itemId .. ": status is " .. state )

 

		if 	datasitemId "nparents" > 1 and datasitemId]["symbol" == nil then

			p.setdata(itemId, "symbol", gs() )

		end

		-- prevent infinite loops in non DAGs

		if state == "loop" then

			if datasitemId]["looped" == nil then

				datasitemId]["looped" = "treated"

				content =  fmtTreeLinks(" ∞") .. " " .. content .. genAnchor(itemId)

			else

				return content ..  fmtTreeLinks("∞" ..	" ↑ " .. anchorLink(itemId, formatSymbol( datasitemId]["symbol" )))

			end

		elseif state == "incomplete" or state == "unvisited" then

			content = content .. " " .. fmtTreeLinks("…")

			return content

		end

 

		-- has no chilren ? display as leaf

		if childrenitemId ~= nil and table.getn(childrenitemId]) == 0 then

			--return " " .. content .. " ? " -- would be great to use "?b, but font problem

			return " " .. content

		end

 

 

		datasitemId "nparents" = datasitemId]["nparents" - 1

 

	    local parts = {}

 

		-- sort children topologycally

		if alreadyOuteditemId == nil then

 

 			local langobj = mw.language.new(lang1)

		    local prefix = " "

		    if datasitemId "nparents" > 0 then

		    	local arrow = langobj:getArrow()

		    	prefix = fmtTreeLinks(genAnchor(itemId) .. " " .. arrow .. " " .. formatSymbol(datasitemId]["symbol"]))

	    	end

				

			order = childrenitemId

	    	table.sort(order, function (a, b) return datasa]["rank" < datasb]["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

					partsi = mw.text.tag( 'li', {}, partsi )

				end

				partsl = mw.text.tag( 'li', { class = 'lastline' }, partsl )

				alreadyOuteditemId = 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 ) )

				

				alreadyOuteditemId], matchCount = string.gsub(table.concat( parts ), "(</li></ul>)", texttmp .. "%1", 1)

				--mw.log('matchCount is:')

				--mw.log(matchCount)

				if matchCount == 0 then

					alreadyOuteditemId = prefix .. " " .. string.gsub(table.concat( parts ), "$", texttmp, 1)

				end

				alreadyOuteditemId = prefix .. " " .. alreadyOuteditemId

				--mw.log("alreadyOuted[itemId] is: ")

				--mw.logObject(alreadyOuted[itemId])

			end

			

		end

 

		if datasitemId "nparents" <= 0 or state == "loop" then

			return alreadyOuteditemId

		else 

			return content .. " " .. fmtTreeLinks(anchorLink(itemId, formatSymbol(datasitemId]["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] = "<li>[[Human body]]</li>"

	-- 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] = "<li>[[Human body]] <ul><li>[[Nervous system]]</li></ul></li>"

	-- 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.

						brothersx = 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, brothersi], property, direction, maxdepth, sources, refStyle, pencil, lang1, lang2 ) )

				end

				brother_content = brother_content .. mw.text.tag( 'li', {}, p.outputTree( query, brothersl], 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 '<li class=\"lastline\">...</li>') 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 <li class=\"lastline\"> from the left to the right through text. 

		while string.find(parent_content, '<li class=\"lastline\">', b) do

			mw.log(a .. ' ' .. b)

			a, b = string.find(parent_content, '<li class=\"lastline\">', b)

		end

		mw.log(a .. ' ' .. b)

		

		local c = 0

		local d = 0

		-- Finding end position of final item by searching </ul></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 {{reflist}} 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 {{reflist}} 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

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook