Permanently protected module

Module:DM Fusion display

From Yugipedia
Revision as of 03:55, 21 May 2024 by JustGian (talk | contribs) (Use ul and li instead of *)
Jump to: navigation, search
-- <pre>
-- @name DM Fusion display
-- @description A module used to display Fusion combinations in their respective card articles
-- @author [[User:JustGian]]
-- @contact [[User talk:JustGian]]

----------------
-- Load modules:
----------------
local DATA = require( 'Module:Data' );
local UTIL = require( 'Module:Util' );

--------------------
-- Module variables:
--------------------
-- Parser state:
local
	PAGENAME,
	NAMESPACE,
	_frame,
	_args
;

-- Stores properties for cards to avoid making a new query each time they are needed
local CARD_INFO = {}

---------------------
-- Utility functions:
---------------------
-- mw functions:
local HTML = mw.html.create;

--------------------
-- Module functions:
--------------------
--# Local functions

--[[Doc
@function U unlink
@description (From Module:Card type) If a string is passed, unlinks
and returns the page name (not the label, unless «getLabel»).
If a table is passed, unlinks every instance of it
and returns the table with the page names for each respective entry.
@parameter {*} v Any value to unlink.
@parameter {boolean} getLabel Makes the function return the label instead.
@return {*} The unlinked value.
]]
local function unlink( v, getLabel )
	local function __unlink( v, getLabel )
		return UTIL.trim( v ) and (getLabel and v:match( '%[%[:?.-|(.-)]]' ) or v:match( '%[%[:?(.-)[|%]]' )) or UTIL.trim( v );
	end
	if type( v ) == 'string' then
		return __unlink( v, getLabel );
	elseif type( v ) == 'table' then
		local t = {};
		for key, value in ipairs( v ) do
			table.insert( t, __unlink( value, getLabel ) );
		end
		return t;
	else
		return v; -- @@@ error()
	end
end

-- @name format_card_to_display
-- @description Receives a card page name and returns the expected string to be displayed
local function format_card_to_display(card)
	attr = CARD_INFO[card]
	return string.format("#%s: %s\"[[%s|%s]]\"", attr["number"], attr["level"] and ( attr["level"] .. " [[File:CG Star.svg|15px|alt=|class=noviewer]] " ) or '', card, attr["name"])
end

-- @name fill_fusion_result_table
-- @description Appends the row with the materials belonging to the current combination to a table
local function fill_fusion_result_table( cur_table, mats1, mats2, columns, mats_exceptions )
	local mats_row = cur_table:tag("tr")
	local mat1_cell = mats_row:tag("td"):tag("ul")
	local mat2_cell = mats_row:tag("td"):tag("div"):attr("style", "column-width: 13em; column-count: " .. columns):tag("ul")
	
	for _, card in pairs(mats1) do
		card = unlink(card)
		mat1_cell:tag("li"):wikitext(format_card_to_display(card))
	end
	
	-- The second cell also includes the "except with" addition
	for _, card in pairs(mats2) do
		card = unlink(card)
		mat2_cell:tag("li"):wikitext(format_card_to_display(card) .. (mats_exceptions[card] and string.format(" (except with \"[[%s|%s]]\")", mats_exceptions[card], CARD_INFO[mats_exceptions[card]]["name"]) or ''))
	end
	
	return cur_table
end

-- @name fill_fusion_material_table
-- @description Appends the row with the materials belonging to the current combination to a table
local function fill_fusion_material_table( cur_table, current_card, mats, columns, other_mat_exceptions )
	local mats_row = cur_table:tag("tr"):tag("td"):tag("div"):attr("style", "column-width: 13em; column-count: " .. columns):tag("ul")

	-- The second cell also includes the "except with" addition
	for _, card in pairs(mats) do
		if not other_mat_exceptions[card] then
			card = unlink(card)
			mats_row:tag("li"):wikitext(format_card_to_display(card) .. (other_mat_exceptions[card] and string.format(" (except with \"[[%s|%s]]\")", other_mat_exceptions[card], CARD_INFO[other_mat_exceptions[card]]["name"]) or ''))
		end
	end
	
	return cur_table
end

-- @name process_combination_exception_query
-- @description Gets the combinations exceptions for a query of combinatigons
local function process_combination_exception_query(combinations_query)
	local fusion_ids = {}
	for _, combination in pairs(combinations_query) do
		table.insert(fusion_ids, unlink(combination[1]))
	end
	
	local query = mw.smw.ask( string.format("[[For Fusion::%s]] |?Fusion Material exception 1 |?Fusion Material exception 2", table.concat(fusion_ids, "||")) ) or {}
	
	return query
end

-- @name process_fusion_combination_query
-- @description Gets the required attributes for a Fusion query by running the provided conditions. 
-- By running the query only once, the module saves a considerable amount of time that would be spent querying each card's name every time it is required
local function process_fusion_combination_query(conditions)
	-- The attributes that should be returned
	local required_attributes = { 
		"Fusion Material 1", "Fusion Material 2", "Fusion result", "Description", "Columns", -- Attributes about the Fusion combination
		"Fusion Material 1.English name = English name 1", "Fusion Material 1.Level = Level 1", "Fusion Material 1.Card number = Card number 1", -- Attributes about each card listed as Material 1
		"Fusion Material 2.English name = English name 2", "Fusion Material 2.Level = Level 2", "Fusion Material 2.Card number = Card number 2", -- Attributes about each card listed as Material 2
		"Fusion result.English name = English name 3",     "Fusion result.Level = Level 3",     "Fusion result.Card number = Card number 3",     -- Attributes about each card listed as Result
		"Fusion result = Fusion Material 3"
		}
	
	local query = mw.smw.ask( conditions .. "|?" .. table.concat(required_attributes, "|?"))
	
	if query then
		-- Iterates over both Fusion Material lists, and adds each card to the table
		for _, combination in pairs(query) do
			for _, combi_index in pairs({"1", "2", "3"}) do
				-- Pre-processing on the multi-value attributes
				materials = combination["Fusion Material " .. combi_index]
				materials = type(materials) == "table" and materials or { materials }
				
				en_names = combination["English name " .. combi_index]
				en_names = type(en_names) == "table" and en_names or { en_names }
				
				levels = combination["Level " .. combi_index]
				levels = type(levels) == "table" and levels or { levels }
				
				numbers = combination["Card number " .. combi_index]
				numbers = type(numbers) == "table" and numbers or { numbers }
				
		    	for i, fm_full in pairs(materials) do
		    		fm = unlink(fm_full)
		    		if not CARD_INFO[fm] then
		    			CARD_INFO[fm] = {
		    				["name"] = en_names[i],
		    				["level"] = levels[i],
		    				["number"] = numbers[i]
		    			}
	    			end
	    		end
    		end
    	end
    end

	return query
end

-- @name fusion_result
-- @description Generates the material lists for a given Fusion result. To be called through #invoke.
local function fusion_result( frame )
	_frame = frame;
	_args  = UTIL.getArgs( frame, {
		trim         = true,
		removeBlanks = true,
		parentOnly   = true
	} );

	if not mw.smw then
        return "mw.smw module not found"
    end
    
    local fusion_frame = HTML()
    
    local page_name = _args[1] or "Harpie Lady Sisters (DOR)"
    
    local query = process_fusion_combination_query( string.format("[[Fusion result::%s]]", page_name ))
    
    if query then
	    local combination_exceptions_query = process_combination_exception_query(query)
		local combination_exceptions = {}
		
		if next(combination_exceptions_query) ~= nil then
			for _, combi_ex in pairs(query) do
				combination_exceptions[unlink(combi_ex["Fusion Material exception 1"])] = unlink(combi_ex["Fusion Material exception 2"])
			end
		end
	    
	    local prev_description, cur_table
	    
	    for i, combination in pairs(query) do
	    	local mats1, mats2, description, columns = combination["Fusion Material 1"], combination["Fusion Material 2"], combination["Description"], combination["Columns"] or 1
	    	
	    	-- MW attributes don't return a table if there is only 1 value. Converting both to tables to facilitate future processing
	    	mats1 = type(mats1) ~= 'table' and { mats1 } or mats1
	    	mats2 = type(mats2) ~= 'table' and { mats2 } or mats2
	    	
	    	-- Creates a new table on the first itteration, and when a description changes
			if not cur_table or description ~= prev_description then
				cur_table = fusion_frame:tag("table"):attr("class", "wikitable")
				
				cur_table:tag("ul"):tag("li"):wikitext(description or '')
				
				local header = cur_table:tag("tr")
				
				header:tag("th"):attr("scope", "col"):wikitext("Material 1")
				header:tag("th"):attr("scope", "col"):wikitext("Material 2")
			end
	    	
	    	-- Appends materials to the table
	    	cur_table = fill_fusion_result_table(cur_table, mats1, mats2, columns, combination_exceptions)
	    	
	    	prev_description = description or prev_description
	    end
	end
	
	return tostring(fusion_frame)
end

-- @name fusion_material
-- @description Generates the list of other materials and Fusion result for a given material. To be called through #invoke.
local function fusion_material( frame )
	_frame = frame;
	_args  = UTIL.getArgs( frame, {
		trim         = true,
		removeBlanks = true,
		parentOnly   = true
	} );

	if not mw.smw then
        return "mw.smw module not found"
    end
    
    local fusion_frame = HTML()
    
    local page_name = _args[1] or "Thunder Nyan Nyan (DOR)"
    
    local query = process_fusion_combination_query( string.format("<q>[[Fusion Material 1::%s]] OR [[Fusion Material 2::%s]]</q>|sort = Fusion result.Card number", page_name, page_name ))
    
    if query then
	    local combination_exceptions_query = process_combination_exception_query(query)
	    
	    local prev_description, cur_table
	    
	    for i, combination in pairs(query) do
	    	local combi_id, mats1, mats2, result, description, columns = 
	    		combination[1], combination["Fusion Material 1"], combination["Fusion Material 2"], combination["Fusion result"], combination["Description"], combination["Columns"] or 1
	    	local material_index, mats
	    	local cur_combi_exceptions = {}
	    	
	    	-- MW attributes don't return a table if there is only 1 value. Converting both to tables to facilitate future processing
	    	mats1 = type(mats1) ~= 'table' and { mats1 } or mats1
	    	mats2 = type(mats2) ~= 'table' and { mats2 } or mats2
	    	
	    	-- Checks to which of the two lists should be displayed (if a card belongs to Materials 2, display Materials 1)
	    	for _, mat in pairs(mats1) do
	    		if unlink(mat) == page_name then
	    			material_index = 2
	    			break
	    		end
			end
			material_index = material_index or 1
			
			-- Assigns correct material and exception list, based on the index found
			if material_index == 1 then
				mats = mats1
				if next(combination_exceptions_query) ~= nil then
					for _, combi_ex in pairs(combination_exceptions_query) do
						if unlink(combi_ex["Fusion Material exception 1"]) == page_name then
							cur_combi_exceptions[combi_ex["Fusion Material exception 2"]] = true
						end
					end
				end
			else
				mats = mats2
				if next(combination_exceptions_query) ~= nil then
					for _, combi_ex in pairs(combination_exceptions_query) do
						if unlink(combi_ex["Fusion Material exception 2"]) == page_name then
							cur_combi_exceptions[combi_ex["Fusion Material exception 1"]] = true
						end
					end
				end
			end
	    	
	    	-- Creates a new table on the first itteration, and when a description changes
			if not cur_table or description ~= prev_description then
				cur_table = fusion_frame:tag("table"):attr("class", "wikitable")
				
				cur_table:tag("ul"):tag("li"):wikitext(format_card_to_display(unlink(result)) .. (description and (" (" .. description .. ')') or ''))
				
				local header = cur_table:tag("tr")
				
				header:tag("th"):attr("scope", "col"):wikitext("Materials")
			end
	    	
	    	-- Appends materials to the table
	    	cur_table = fill_fusion_material_table(cur_table, page_name, mats, columns, cur_combi_exceptions)
	    	
	    	prev_description = description or prev_description
	    end
	end

	return tostring(fusion_frame)
end

----------
-- Return:
----------
-- @exports 
return {
	['fusion_result'] = fusion_result,
	['fusion_material'] = fusion_material
};
-- </pre>