モジュール:Broodkruimel

local p = {}
-- Openingstag voor alle tabellen in de broodkruimel
p.table = 
-- Curly dinges voor achter vertakkingen
p.curly = '}'
-- Wolkje voor weggelaten categorieen
p.wolkje = '(...)'
-- Maximaal aantal categorieen voor we het voor gezien houden
p.MAX = 50
-- Categorie waar we pagina's met broodkruimelproblemen in zetten
p.probleemcat = 'テンプレート呼び出しエラーのあるページ/Template:パンくず小路'
-- We houden bij of we problemen tegenkomen. Het soort probleem
-- geven we aan met een letter die als sorteersleutel in de 
-- probleemcategorie gebruiken. Als er meer problemen zijn, nemen
-- we gewoon de laatste.
--   "C": er is iets mis met de wikitekst. Mogelijk een ontbrekende
--        sluittag oid.
--   "P": parameterprobleem: er is een ongeldige waarde voor
--        een parameter opgegeven
--   "M": we hebben p.MAX bereikt, dus de boom is niet af
--   "O": de pagina (of categorie) is ongecategoriseerd
p.problemen = ""
--
broodkruimel( frame )
Maakt een broodkruimelnavigatie voor de categorieen van een pagina.
Als frame.argspagina opgegeven is, wordt die pagina gebruikt.
Zoniet, en frame.args1 is opgegeven, dan wordt die pagina gebruikt.
Als geen van beiden opgegeven is, wordt de huidige pagina gebruikt.

function p.broodkruimel( frame )
-- Voor welke pagina?
local title = frame.args1
	if ( not title or title == "" ) then
		title = mw.title.getCurrentTitle().prefixedText
	end
	
	-- Hoogte?
	local level = 8
	p.force = false
	if ( frame.args.length and frame.args.length ~= "" ) then
		n = tonumber( frame.args.length )
		if ( n ~= nil and n > 0 ) then
			level = n
			if ( frame.args.force and frame.args.force ~= "" ) then
				p.force = true
			end
		else
			p.probleem( "P" )
		end
	end
	
	-- Maximale aantal parallelle vertakkingen?
	p.max_branch = 4
	if ( frame.args.maxbranch and frame.args.maxbranch ~= "" ) then
		local n = tonumber( frame.args.maxbranch )
		if ( n ~= nil and n > 0 ) then
			p.max_branch = n
		else
			p.probleem( "P" )
		end
	end
	
	-- Text verkleinen?
	local txtsize = 20
	p.verklein = false
	if ( frame.args.startsize and frame.args.startsize ~= "" ) then
		p.verklein = true
		local n = tonumber( frame.args.startsize ) 
		if ( n ~= nil and n > 0 ) then
			txtsize = 2 * n
		else
			p.probleem( "P" )
		end
	end
	
	-- Negeerlijst?
	p.negeerlijst = {}
	if ( frame.args.ignore and frame.args.ignore ~= "" ) then
		p.negeerlijst = p.parseNegeerLijst( frame.args.ignore )
	end
		
	-- Maak boom
	local trees = p.createCategoryTree( title, level )
	
	-- Maak kruimel
	local ntitle, ntree = next( trees )
	local kruimel = ""
	if ( type( ntree ) == "table" and next( ntree ) ) then
		kruimel = p.createBreadCrumb( ntitle, ntree, txtsize )
	else
		-- Als we geen broodkruimel kunnen maken omdat de pagina
		-- in meer dan max_branch cats zit, printen we simpelweg de
		-- bovenliggende cats: i.v.m. de layout moeten we in ieder
		-- geval iets tonen.
		kruimel = p.printcats( p.hoofdcats )
		if ( p.hoofdcats == nil or next( p.hoofdcats ) == nil ) then
			-- ongecategoriseerde pagina
			p.probleem( "O" )
		end
	end
	
	return kruimel .. p.printprobleem()
	
end
--
	parseCategories( wikitext )
	Zoekt geldige categorieen in wikitext.
function p.parseCategories( txt ) 
	
	if ( txt == nil ) then return {} end
	
	local cats = {}
	
	local pattern = "%%%s*CcAaTtEeGgOoRrYy?%s*:%s*(%+)%"

	for category in mw.ustring.gmatch( txt, pattern ) do
		category = p.cleanupCatTitle( category )
		-- Sla categorieen met gekke dingen over: sjablonen e.d. 
		if ( mw.ustring.find( category, "{}%%" ) == nill) then
			-- Als de naam langer is dan 50 tekens is er waarschijnlijk
			-- iets mis 
			if ( mw.ustring.len( category )  p.max_branch ) then
			return tree
		elseif ( new_tree == nil ) then
			return tree
		end
		tree = new_tree
	end
	
	return tree
	
end
function p.addLevel ( tree )
	local result = {}
	
	for cat,rest in pairs( tree ) do
		
		if ( rest == "" ) then
			if ( p.seencat ) then
				if ( cat == "Category:主要カテゴリ" ) then
					resultcat = {}
				else
					resultcat = { "..." = {} }
					p.branchcount = p.branchcount + 1
				end
			else
				p.count = p.count + 1
				if ( p.count > p.MAX ) then
					p.probleem( "M" )
					return nil
				end
				page = mw.title.new( cat )
				local cats = p.parseCategories( page:getContent() )
				resultcat = cats
				p.seencat = true
			end
		else
			local temp = p.addLevel( rest )
			if ( temp == nil ) then
				return nil
			else
				resultcat = temp
			end
		end
	end
	
	return result
	
end
--
	createBreadCrumb( title, trees, txtsize )
	Maakt een breadcrumb navigatie voor trees.
	title: de titel van de pagina waarvoor de breadcrumb is
	trees: de categoriebomen zoals gemaakt door createCategoryTrees(title)
	txtsize: lettergrootte
function p.createBreadCrumb( title, tree, txtsize )
	
tree = tree or {}
	local str = ""
	
	if ( p.verklein ) then
		str = str .. 
	end
	
	str = str .. p.table .. 
	
	local count = 0
	
	for ntitle, ntree in pairs( tree ) do
		count = count + 1
		if ( ntitle == "..." ) then
			str = str .. p.wolkje
		else
			if ( type( ntree ) == "table" ) then
				str = str .. p.createBreadCrumb( ntitle, ntree, txtsize-1 ) 
			else
				str = str .. p.createBreadCrumb( ntitle, {}, txtsize-1 ) 
			end
		end
	end
	
	str = str .. ""
	
	if ( count > 1 ) then
		str = str .. p.curly .. 
	end
	if ( count > 0 ) then
		str = str .. ' → '
	end
	
	str = str .. "" .. p.removeCatNS( title ) .. ""
	str = str .. ""
	
	if ( p.verklein ) then str = str .. "" end
	return str
	
end
--
cleanupCatTitle( title )
Standaardiseert een categorienaam: overbodige spaties aan begin en
eind weg, underscores vervangen door spaties, de eerste letter een
hoofdletter, naamruimte ervoor.
function p.cleanupCatTitle( title )
	
	title = mw.text.trim( title )
	title = p.removeCatNS( title )
	title = mw.ustring.gsub( title, "_", " " )
	title = mw.language.getContentLanguage():ucfirst( title )
	title = "Category:" .. title
	
	return title
	
end
--
	removeCatNS( title )
	Verwijdert "Categorie:" of "Category:"
function p.removeCatNS( title )
	title = mw.ustring.gsub( title, "^CcAaTtEeGgOoRrYy%s*:%s*", "" )
	return title
end
-- 
	parseNegeerLijst( str )
	Parsed een door komma's gescheiden lijst van categorienamen
function p.parseNegeerLijst( str )
	local lijst = {}
	
	cats = mw.text.split( str, ',', true )
	
	for _, cat in pairs( cats ) do
		cat = p.cleanupCatTitle( cat )
		lijstcat = ""
	end
	
	return lijst
end
	
--
	printCats( cats )
	Print de categorieen in cats.
	Als we geen broodkruimel kunnen we maken gebruiken we deze functie
om simpelweg de direct bovenliggende cats te tonen.
function p.printcats( cats )
	
	local str = ""
	
	str = str .. " カテゴリ: "
	
	if ( ( type( cats ) ~= "table" ) or next( cats ) == nil ) then
		str= str .. "No"
	else
		for cat in pairs( cats ) do
			str = str ..  .. p.removeCatNS( cat ) .. 
			if ( next( cats, cat ) ~= nil ) then
				str = str .. " • "
			end
		end
	end
	
	str = str .. 
	
	return str
	
end
function p.printprobleem( )
	
	if ( p.problemen ~= nil and p.problemen ~= "" ) then
		return ""
	else
		return ""
	end
end
function p.probleem( letter )
	p.problemen = letter
end
--
	pptable( table )
	Maakt een string van een table gemaakt door createCategoryTrees().
	Alleen voor testen en debuggen.
function p.pptable( table ) 
	
	local str = ""
table = table or {}
	for k,v in pairs( table ) do
		str = str .. k .. ": "
		if ( type( v ) == "string" ) then
		else
			str = str .. "{" .. p.pptable(v) .. "}, "
		end
		
	end
	
	return str
end
return p