Module:HF/Infobox

local Infobox = {}

-- Libraries and Global functions --

-- stands for High Frequency local HF = require('Module:HF') -- Parses invocation and template parameters, trims whitespace, and removes blanks. local getArgs = require('Dev:Arguments').getArgs -- Generates lists local L = require('Dev:List') -- MediaNav Functions local MN = require('Module:HF/MediaNav')._MediaNav

-- The page title of whatever page is calling the function local pageTitle = mw.title.getCurrentTitle.text

-- Pattern Constants local stripLinkToTarget = '^%[*([^%[|]*)|?' local stripPageTitleToBase = "%s?([^(]*)" local basepattern = '^[^~]*' local extra1pattern = '^[^~]*~([^~]*)' local extra2pattern = '^[^~]*~[^~]*~([^~]*)'

-- Local functions (used only in this Module) --

local function nameCheck ( target ) local nq = mw.smw.ask{ HF.Link(target:match(stripLinkToTarget)), '?Maintenance' } if type(nq) == 'table' and (	       nq[1]['Maintenance'] == 'Name'	        or ( type(nq[1]['Maintenance']) == 'table' and table.concat(nq[1]['Maintenance']):match('Name') )           )	then return true else return nil end end

local function arrayRemove (args) local hash = {} if (args[1] == nil) then return '' end local t = mw.text.split(args[1], ",") local s = mw.text.split(args[2], ",")

for i, v in ipairs(t) do		t[i] = mw.text.trim(v) hash[t[i]] = true end

if args[3] == '' then args[3] = false end if args[3] and not hash[args[3]] then return table.concat(t, ", ") end

for i, v in ipairs(s) do		s[i] = mw.text.trim(v) end

for j = #s, 1, -1 do		for i = #t, 1, -1 do			if t[i] == s[j] then table.remove(t, i)			end end end return table.concat(t, ", ") end

local function linkCheck ( candidate ) return candidate:match('^%[%[') and candidate or HF.Link( candidate ) end

-- -- Public functions (called from a Template or article) -- -- -- Replaces and -- with a comparable tabbed gallery for inside a PI. -- Also replaces the "Missing image" Maintenance function -- Also replaces the function Infobox.imageGallery (frame) local infobox_args = getArgs(frame, { parentOnly = true }) local invoke_args = getArgs(frame, { frameOnly = true }) local image_string = infobox_args[invoke_args[1]] if image_string then local gallery = { '{{#tag:gallery|\n' } local image_items = mw.text.split( mw.text.trim(image_string), '\n') for _,item in ipairs(image_items) do			table.insert(				gallery,				tostring(string.gsub( item, ';', '|'):match('[^:]*'))..'\n'			) mw.smw.set{ ['Picture'] = 'File:' .. item:match("[^;:]*") } end table.insert( gallery, '}}') local gallery_preprocess = frame:newParserValue( table.concat( gallery, '\n' ) ) return gallery_preprocess:expand else mw.smw.set{ ['Maintenance'] = 'Missing image' } return nil end end

function Infobox.nameDistinct (frame) local infobox_args = getArgs(frame, { parentOnly = true }) local invoke_args = getArgs(frame, { frameOnly = true }) if mw.text.trim(pageTitle:match(stripPageTitleToBase)) == infobox_args[invoke_args[1]] then return nil else return infobox_args[invoke_args[1]] end end

function Infobox.namesOther ( frame ) local args = getArgs(frame) local out = {} local names = args['other'] and mw.text.split( args['other'] or '', ',' ) or '' for _,name in ipairs( names ) do		mw.smw.set{ ['Names'] = name:match("[^(]*"):gsub("'", ) }		table.insert( out, name )	end	return L.makeList( 'bulleted', out ) end

function Infobox.linkSBP ( frame ) local invoke_args = getArgs(frame, { frameOnly = true }) return HF.ExternalLink(		('%s/wiki/Special:SearchByProperty?property=%s&value=%s')			:format( mw.site.server, invoke_args['property'], mw.uri.encode( invoke_args['value'], 'QUERY' ) ),		invoke_args['link'] or ''	) end

-- Manga debut processing -- Replaces function for function Infobox.debutManga(frame) local args = getArgs(frame) local debut = args['manga debut'] or args['debut manga'] local query = mw.smw.ask { ( HF.Link('Concept:Chapter of %s Manga') ):format( args['boruto'] == 'Yes' and 'Boruto' or args['sasuke retsuden'] == 'Yes' and 'Sasuke Retsuden' or 'Naruto' ), ( HF.Link('Chapter number::%s') ):format( Infobox.base( debut ) ), '?Volume number=', 'mainlabel=-' }	mw.smw.set { ['Debut manga'] = Infobox.base( debut ), ['Debut manga type'] = args['manga type'] or 'Chapter', ['Manga'] = ( args['boruto'] == 'Yes' and 'Boruto' or args['sasuke retsuden'] == 'Yes' and 'Sasuke Retsuden' or 'Naruto' ) }	if type(query) == 'table' then local volume = query[1][1]

local volume_link = MN { 'Volume', volume, ['DisplayType'] = 'Number', ['boruto'] = args['boruto'], ['sasuke retsuden'] = args['sasuke retsuden'] }

local chapter_link = MN { args['manga type'] or 'Chapter', Infobox.base( debut ), ['DisplayType'] = 'Number', ['boruto'] = args['boruto'], ['sasuke retsuden'] = args['sasuke retsuden'] }

return ( volume_link or '' ) .. (( volume_link and chapter_link ) and ', ' or '') .. ( chapter_link or '' ) .. ( Infobox.extra1( debut ) and (' (%s)'):format( Infobox.extra1( debut ) ) or '' ) else return nil end end

-- Anime debut processing -- Replaces function for function Infobox.debutAnime(frame) local args = getArgs(frame) local debut = args['anime debut'] or args['debut anime'] local Boruto = args['boruto anime'] == 'Yes' and true or nil local Shippuden = (args['shippuden'] or args['debut shippuden']) == 'Yes' and true or nil local number = tonumber( Infobox.base( debut ) ) + ( Boruto and 720 or ( Shippuden and 220 or 0 )) mw.smw.set { ['Debut anime'] = number } return MN { 'Episode', Infobox.base( debut ), ['DisplayType'] = 'Number', ['shippuden'] = args['shippuden'] or args['debut shippuden'], ['boruto'] = args['boruto anime'] } end

-- Novel debut processing -- Replaces function for function Infobox.debutNovel(frame) local args = getArgs(frame) local debut = args['novel debut'] mw.smw.set { ['Debut novel'] = mw.text.trim( Infobox.base( debut ) ):match(stripLinkToTarget) } return ("%s"):format( linkCheck( Infobox.base( debut ) ) .. ( Infobox.extra1( debut ) or '' ) ) end

-- Movie debut processing -- Replaces function for function Infobox.debutMovie(frame) local args = getArgs(frame) local debut = args['movie debut'] mw.smw.set { ['Debut movie'] = mw.text.trim( Infobox.base( debut ) ):match(stripLinkToTarget) }	return ("%s"):format( linkCheck( Infobox.base( debut ) ) .. ( Infobox.extra1( debut ) or '' ) ) end

-- Game debut processing -- Replaces function for function Infobox.debutGame(frame) local args = getArgs(frame) local debut = args['game debut'] mw.smw.set { ['Debut game'] = mw.text.trim( Infobox.base( debut ) ):match(stripLinkToTarget) }	return ("%s"):format( linkCheck( Infobox.base( debut ) ) .. ( Infobox.extra1( debut ) or '' ) ) end

-- OVA debut processing -- Replaces function for function Infobox.debutOVA(frame) local args = getArgs(frame) local debut = args['ova debut'] mw.smw.set { ['Debut ova'] = mw.text.trim( Infobox.base( debut ) ):match(stripLinkToTarget) }	return ("%s"):format( linkCheck( Infobox.base( debut ) ) .. ( Infobox.extra1( debut ) or '' ) ) end

-- Media debut processing -- Replaces function for function Infobox.debutMedia(frame) local args = getArgs(frame) local media = arrayRemove { ( args['media'] or args['jutsu media'] or args['tool media'] or '' ), 'Movie canon', 'Movie' }	for _,medium in ipairs( mw.text.split( media, ',%s*') ) do		mw.smw.set { ['Appears in'] = medium } end return Infobox.arraymap( media:gsub('Movie canon', 'Movie') or '', ',%s*', '%s', ', ' ) end

- -- Exported functions (used in this and other Modules) -- - function Infobox.base( str ) return ( type(str) == 'string' and str:match( basepattern ) ) and mw.text.trim(str:match( basepattern )) or nil end function Infobox.extra1( str ) return ( type(str) == 'string' and str:match( extra1pattern ) ) and mw.text.trim( str:match( extra1pattern ) ) or nil end function Infobox.extra2( str ) return ( type(str) == 'string' and str:match( extra2pattern ) ) and mw.text.trim( str:match( extra2pattern ) ) or nil end

function Infobox.arraymap ( str, delimiter, formula, new_delimiter ) delimiter = delimiter or ',%s*' local array = type(str) == 'string' and mw.text.split( str, delimiter ) or nil local out = {} if type(array) == 'table' then for _, v in ipairs( array ) do				table.insert( out, ( formula ):format( v ) ) end return table.concat( out, new_delimiter ) else return nil end end

function Infobox.processInput( item, options, frame ) local out = {} local exists = #item > 0 and true or nil item = options['Replace'] and tostring( item:gsub( options['Replace'][1], options['Replace'][2] )) or item local itemName, extrainfo1, extrainfo2 = item:match('^([^~\r\n]*)~?([^~\r\n]*)~?([^~\r\n]*)') extrainfo1 = #extrainfo1 > 0 and (' (%s)'):format( extrainfo1 ) or nil extrainfo2 = #extrainfo2 > 0 and (' (%s)'):format( extrainfo2 ) or nil local itemTitle = itemName:match(stripLinkToTarget) local itemLabel = itemTitle:match(stripPageTitleToBase) if options['SemanticPropertyName'] and type( options['SemanticPropertyName'] ) == 'string' then

local property = {} --[==[		if options.SemanticPattern ~= nil then for _,match in itemName:match(options.SemanticPattern) do				property = {} property[options.SemanticPropertyName] = match mw.smw.set ( property ) end else --]==]			property[ options['SemanticPropertyName'] ] = itemName mw.smw.set ( property ) --[==[		end --]==]	elseif options['SemanticPropertyName'] and type( options['SemanticPropertyName'] ) == 'table' then local properties = {} for _,property_name in ipairs( options['SemanticPropertyName'] ) do				properties[property_name] = itemName end mw.smw.set ( properties ) end if options['PrependTemplate'] and exists then local PrependTemplate = frame:newTemplateParserValue { title = options['PrependTemplate'], args = { item, options['PrependText'] or nil } }		table.insert(			out,			PrependTemplate:expand		) end if type(options['Label']) == 'table' and type(options['Item Attribute']) == 'string' then table.insert( out, options['Label'][options['Item Attribute']] ) elseif type(options['Label']) == 'string' then table.insert( out, options['Label'] ) end if options['Warning'] and options['SemanticPropertyName'] then mw.smw.set { ['Has improper value for'] = options['SemanticPropertyName'] } local warning = frame:preprocess((''):format(options['Warning'])) table.insert( out, warning:expand ) elseif options['Warning'] then local warning = frame:preprocess((''):format(options['Warning'])) table.insert( out, warning:expand ) end if options['Link'] == 'Wikipedia' and exists and options['Print'] ~= 'none' then table.insert( out, HF.Link('wikipedia:' .. itemTitle, itemLabel) ) elseif options['Link'] == 'Unnamed' and exists and options['Print'] ~= 'none' then table.insert(			out,			nameCheck(itemTitle) == true			and ("%s"):format( HF.Link( itemTitle, itemLabel ) )			or HF.Link( itemTitle, itemLabel )		) elseif options['Link'] == 'Unit' and type(options['Unit']) == 'string' and exists and options['Print'] ~= 'none' then

table.insert( out, itemName .. options['Unit'] ) elseif options['Link'] == 'default' and exists and options['Print'] ~= 'none' then table.insert( out, HF.Link( itemTitle, itemLabel ) ) elseif options['Link'] == 'none' and exists and options['Print'] ~= 'none' then table.insert( out, itemName ) end if options['AppendTemplate'] and exists then local AppendTemplate = frame:newTemplateParserValue { title = options['AppendTemplate'], args = { item, options['AppendText'] or nil } }		table.insert(			out,			AppendTemplate:expand		) end if options['SearchByProperty'] and options['SemanticPropertyName'] and exists then

local propcount = mw.smw.ask { HF.Link( options['SemanticPropertyName'] .. '::' .. itemTitle ) }		if type( propcount ) == 'table' and #propcount > 1 then local search_icon = '' local queryoptions = mw.uri.buildQueryString { property = mw.uri.encode( options['SemanticPropertyName'], 'WIKI' ), value = mw.uri.encode( itemTitle, 'WIKI' ) }			local _linkSBP = mw.html.create( 'abbr' ) :attr(					'title',					('Search the other %s pages containing the property `%s` with the value `%s`')						:format( #propcount, options['SemanticPropertyName'], itemTitle )				) :wikitext(				   HF.ExternalLink( tostring( mw.uri.fullUrl( 'Special:SearchByProperty', queryoptions) ), search_icon )			   ) :allDone table.insert( out, tostring( _linkSBP ) ) end end if options['ExtraInfo'] and options['ExtraInfo'] ~= false and type( extrainfo1 ) == 'string' then table.insert( out, extrainfo1 ) end if options['ExtraInfo'] and options['ExtraInfo'] ~= false and type( extrainfo2 ) == 'string' then table.insert( out, extrainfo2 ) end if exists then return table.concat( out ) end end

function Infobox.arrayTable ( input, delimiter, options, frame ) delimiter = delimiter or ',%s*' options = options or {} local array = type(input) == 'string' and mw.text.split( input, delimiter ) or nil local out = {} if type(array) == 'table' then for _, item in ipairs( array ) do	       local i = Infobox.processInput( item, options, frame ) table.insert( out, i ) end return out else return nil end end

function Infobox.mediaDebutList ( query ) if type( query ) == 'table' then local out = {} for _,v in ipairs( query ) do			local link = HF.Link(				v['main']:match('^%[*([^%[|]*)|?'),				v['main']:match('[^(]*'):match('^%[*:?([^%[|]*)|?') )			if v['Maintenance'] == 'Name'			   or ( type(v['Maintenance']) == 'table' and table.concat(v['Maintenance']):match('Name') ) then				table.insert( out, ("%s"):format(link) )			else				table.insert( out, link )			end		end		return L.makeList( 'bulleted', out )	else		return nil	end end - -- Output (send it back to whatever called it) -- - return Infobox