Difference between revisions of "Module:Card gallery"

From Yugipedia
Jump to: navigation, search
m (Adapt for debug. Fix for empty input.)
(I can't resist myself at using objects (or something like it).)
Line 14: Line 14:
 
-- TLM-EN012; The Lost Millennium; UtR; UE
 
-- TLM-EN012; The Lost Millennium; UtR; UE
 
-- SDJ-035; Starter Deck: Joey; C; UE; Reprint // description::Spell
 
-- SDJ-035; Starter Deck: Joey; C; UE; Reprint // description::Spell
 +
-- S1; Yu-Gi-Oh! True Duel Monsters: Sealed Memories promotional cards; UR
 
-- »
 
-- »
  
Line 67: Line 68:
 
end
 
end
 
return counter;
 
return counter;
 +
end
 +
 +
-- @name _link
 +
-- @description TODO
 +
local function _link( ... )
 +
-- TODO
 +
return;
 
end
 
end
  
Line 86: Line 94:
 
return default or '';
 
return default or '';
 
end
 
end
 +
 +
--------------
 +
-- File class:
 +
--------------
 +
-- @name File
 +
-- @classAttr counter -> [static] Counts the number of File instances.
 +
local File  = {};
 +
File.__index = File;
 +
File.counter = 0;
 +
 +
-- @name new          -> File constructor.
 +
-- @attr exists      -> Control attribute; denotes if a file is to be printed.
 +
-- @attr number      -> The card number (linked).
 +
-- @attr region      -> The region.
 +
-- @attr setEn        -> The English name for the set.
 +
-- @attr setLn        -> The localized name for the set.
 +
-- @attr setAbbr      -> The set abbreviation.
 +
-- @attr rarity      -> The rarity name.
 +
-- @attr r            -> The rarity abbreviation.
 +
-- @attr edition      -> The full edition.
 +
-- @attr ed          -> The edition abbreviation.
 +
-- @attr modifier    -> The card modifier.
 +
-- @attr modifierAbbr -> The card modifier abbreviation (OP|GC|CT).
 +
-- @attr alt          -> The alt value.
 +
-- @attr extension    -> The file extension.
 +
function File.new( std, mod, opt )
 +
-- @attr _standard -> Contains the trimmed input args for the standard input {enum-like}.
 +
-- @attr _modifier -> Contains the trimmed input arg for the modifier (OP|GC|CT).
 +
-- @attr _options  -> Contains the trimmed input args for the options {map-like}.
 +
File.counter = File.counter + 1;
 +
local fileData = {};
 +
fileData.exists  = true;
 +
fileData._standard = std or {};
 +
fileData._modifier = mod or '';
 +
fileData._options  = opt or {};
 +
 +
return setmetatable( fileData, File );
 +
end
 +
 +
-- @name setNumber
 +
-- @description Sets the «number» and «setAbbr» attributes.
 +
function File:setNumber()
 +
local cardNumber = self._standard[ 1 ];
 +
 +
if cardNumber == '' then
 +
self.exists = false;
 +
_error( ('No set abbreviation given for file input number «%d»!'):format( File.counter ) );
 +
return '';
 +
end
 +
 +
if cardNumber and cardNumber:match( '^%w%w%w%w?%-%w%w%w%w?%w?$' ) then
 +
-- Input like «TLM-EN012».
 +
self.number  = _link( cardNumber );
 +
self.setAbbr = cardNumber:match( '^(%w%w%w%w?)%-%w%w%w%w?%w?$' );
 +
else
 +
-- Input like «S1».
 +
self.number  = nil;
 +
self.setAbbr = cardNumber;
 +
end
 +
 +
return self;
 +
end
 +
--[[function File:setSet()
 +
self.
 +
end
 +
function File:setRarity()
 +
self.
 +
end
 +
function File:setEdition()
 +
self.
 +
end
 +
function File:setModifier()
 +
self.
 +
end
 +
function File:setAlt()
 +
self.
 +
end
 +
function File:setExtension()
 +
self.
 +
end]]
  
 
--------------------
 
--------------------
Line 152: Line 240:
 
end
 
end
  
-- @name splitEntry
 
-- @description
 
-- TODO: Make standard» an associative array.
 
local function splitEntry( entry )
 
local temp1  = split( entry, '%s*//%s*' );
 
local tempOpt = temp1[ 2 ] or '';
 
local temp2  = split( temp1[ 1 ], '%s*::%s*' );
 
local tempMod = temp2[ 2 ];
 
local tempStd = temp2[ 1 ];
 
  
 +
local function _buildStandard( arg, modifier )
 
local standard = {};
 
local standard = {};
local modifier = _trim( tempMod );
 
local options  = {};
 
  
-- Grab standard values:
+
if not _trim( arg ) then
for value in gsplit( tempStd, '%s*;%s*' ) do
+
return standard;
local v = _trim( value );
+
end
if v then
+
table.insert( standard, v );
+
for value in gsplit( arg, '%s*;%s*' ) do
 +
if value then
 +
table.insert( standard, _trim( value ) or '' );
 
end
 
end
 
end
 
end
  
-- Grab options:
+
return standard;
 +
end
 +
 
 +
local function _buildOptions( arg )
 +
local options = {};
 +
 
 +
if not _trim( arg ) then
 +
return options;
 +
end
 +
 
 +
-- TODO
 
for option in gsplit( tempOpt, '%s*;%s*' ) do
 
for option in gsplit( tempOpt, '%s*;%s*' ) do
 
local opt = _trim( option );
 
local opt = _trim( option );
Line 186: Line 276:
 
end
 
end
 
end
 
end
 +
 +
return options;
 +
end
 +
 +
-- @name splitEntry
 +
-- @description Splits an input entry into the standard valus, the modifier and the options.
 +
local function splitEntry( entry )
 +
if not _trim( entry ) then
 +
return {}, '', {};
 +
end
 +
 +
local temp1  = split( entry, '%s*//%s*' );
 +
local tempOpt = temp1[ 2 ] or '';
 +
local temp2  = split( temp1[ 1 ], '%s*::%s*' );
 +
local tempMod = temp2[ 2 ];
 +
local tempStd = temp2[ 1 ];
 +
 +
local modifier = _trim( tempMod );
 +
local standard = _buildStandard( tempStd, modifier );
 +
local options  = _buildOptions( tempOpt );
  
 
return standard, modifier, options;
 
return standard, modifier, options;
Line 195: Line 305:
 
local function process( entry )
 
local function process( entry )
 
local standard, modifier, options = splitEntry( entry );
 
local standard, modifier, options = splitEntry( entry );
return table.concat( {
+
local fileObject = File.new( standard, modifier, options ); -- TODO
 +
return table.concat( { -- TODO: TEST
 
table.concat( standard ),
 
table.concat( standard ),
'modifier: ' .. modifier,
+
'modifier: ' .. modifier or 'nil',
 
type( options ) .. _count( options )
 
type( options ) .. _count( options )
}, '\n' ); -- TEST
+
}, '\n' );
 
end
 
end
  

Revision as of 23:30, 2 May 2018

-- <pre>
-- NOTES:
-- input in the form of:
-- «
-- <card number>; <set>; <rarity>; <edition>; <alt>
-- »
-- Where "rarity" and "edition" can either be in full form or abbreviated.
-- Example:
-- «
-- {{Card gallery|region=EN|
-- TLM-EN012; The Lost Millennium; SR;  1E // extension::jpg
-- TLM-EN012; The Lost Millennium; UtR; 1E // extension::jpg
-- TLM-EN012; The Lost Millennium; SR;  UE
-- TLM-EN012; The Lost Millennium; UtR; UE
-- SDJ-035; Starter Deck: Joey; C; UE; Reprint // description::Spell
-- S1; Yu-Gi-Oh! True Duel Monsters: Sealed Memories promotional cards; UR
-- »

-- Ideas:
-- * propagate:
-- «
-- TLM-EN012; The Lost Millennium; SR;  1E
--         *;                   *; UtR;  *
--         *;                   *; SR;  UE
--         *;                   *; UtR;  *
-- »
-- Avoids repitition. Harder with a file replace script.

-- TODO:
-- support for OP / GC / CT / etc. (<card number>; <set>; <rarity>; <edition>; <alt> :: GC|CT)

--------------------
-- Global vairables:
--------------------
local CardGallery = {};
local _D          = {}; -- Global data object.

----------------
-- Load modules:
----------------
local getArgs = require( 'Module:Arguments' ).getArgs;
local DATA    = require( 'Module:Data' );
local getName = require( 'Module:Name' ).main;

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

-- @name _trim
-- Trims white space from front and tail of string.
-- If the input is only white space, returns nil.
local function _trim( s )
	if s and not s:match( '^%s*$' ) then
		return mw.text.trim( s );
	end
end

-- @name _count
-- @description Counts how many entries a table has.
local function _count( t )
	local counter = 0;
	for key, value in pairs( t ) do
		counter = counter + 1;
	end
	return counter;
end

-- @name _link
-- @description TODO
local function _link( ... )
	-- TODO
	return;
end

-- @name _error
-- Generates an error and places it on the error table.
local function _error( message, default, category )
	_D.errors.exists = true;
	local err = HTML( 'div' ):css( 'padding-left', '1.6em' )
		:tag( 'strong' ):addClass( 'error' )
			:wikitext( ('Error: %s'):format( message ) )
		:done()
	:allDone();
	local cat = category and ('[[Category:%s]]'):format( category ) or '';
	table.insert(
		_D.errors, table.concat( {
			tostring( err ), cat
		} )
	);
	return default or '';
end

--------------
-- File class:
--------------
-- @name File
-- @classAttr counter -> [static] Counts the number of File instances.
local File   = {};
File.__index = File;
File.counter = 0;

-- @name new          -> File constructor.
-- @attr exists       -> Control attribute; denotes if a file is to be printed.
-- @attr number       -> The card number (linked).
-- @attr region       -> The region.
-- @attr setEn        -> The English name for the set.
-- @attr setLn        -> The localized name for the set.
-- @attr setAbbr      -> The set abbreviation.
-- @attr rarity       -> The rarity name.
-- @attr r            -> The rarity abbreviation.
-- @attr edition      -> The full edition.
-- @attr ed           -> The edition abbreviation.
-- @attr modifier     -> The card modifier.
-- @attr modifierAbbr -> The card modifier abbreviation (OP|GC|CT).
-- @attr alt          -> The alt value.
-- @attr extension    -> The file extension.
function File.new( std, mod, opt )
	-- @attr _standard -> Contains the trimmed input args for the standard input {enum-like}.
	-- @attr _modifier -> Contains the trimmed input arg for the modifier (OP|GC|CT).
	-- @attr _options  -> Contains the trimmed input args for the options {map-like}.
	File.counter = File.counter + 1;
	local fileData = {};
	fileData.exists   = true;
	fileData._standard = std or {};
	fileData._modifier = mod or '';
	fileData._options  = opt or {};

	return setmetatable( fileData, File );
end

-- @name setNumber
-- @description Sets the «number» and «setAbbr» attributes.
function File:setNumber()
	local cardNumber = self._standard[ 1 ];

	if cardNumber == '' then
		self.exists = false;
		_error( ('No set abbreviation given for file input number «%d»!'):format( File.counter ) );
		return '';
	end

	if cardNumber and cardNumber:match( '^%w%w%w%w?%-%w%w%w%w?%w?$' ) then
		-- Input like «TLM-EN012».
		self.number  = _link( cardNumber );
		self.setAbbr = cardNumber:match( '^(%w%w%w%w?)%-%w%w%w%w?%w?$' );
	else
		-- Input like «S1».
		self.number  = nil;
		self.setAbbr = cardNumber;
	end

	return self;
end
--[[function File:setSet()
	self.
end
function File:setRarity()
	self.
end
function File:setEdition()
	self.
end
function File:setModifier()
	self.
end
function File:setAlt()
	self.
end
function File:setExtension()
	self.
end]]

--------------------
-- Module functions:
--------------------
-- @name getInfo
-- @description Handles generic info.
local function getInfo()
	-- Region and language:
	_D.rg       = DATA.getRg( _D.args[ 'region' ] ) or _error(
		('Invalid «region»: «%s»!'):format( _D.args[ 'region' ] or '(no region given)' ), DATA.getRg( 'en' )
	);
	_D.region   = DATA.getRegion( _D.rg );
	_D.ln       = DATA.getLn( _D.rg );
	_D.language = DATA.getLanguage( _D.rg );
	
	-- Flags:
	_D.flags            = {};
	_D.flags.notEnglish = _D.ln ~= 'en'; -- TODO may not be needed!
	_D.flags.italics    = not ((_D.ln == 'ja') or (_D.ln == 'zh') or (_D.ln == 'ko')) --[[and 'normal' or 'italic']];
	
	-- Medium:
	_D.cg = _D.flags.italics and 'TCG' or 'OCG'; -- TODO Probably not gonna use that.
	
	-- Card and page:
	_D.PAGENAME  = mw.title.getCurrentTitle().text;
	_D.NAMESPACE = mw.title.getCurrentTitle().nsText;
	_D.name      = getName( _D.PAGENAME, _D.language );

end

-- @name wrapInQuotes
-- @description Wraps «name» in proper quotation marks.
local function wrapInQuotes( name, std )
	if not _trim( name ) then
		return '';  --  Return empty string.
	end
	return (std or (_D.ln ~= 'ja' and _D.ln ~= 'zh'))
		and table.concat( { '"', name, '"' } )
		or table.concat( { '「', name, '」' } )
	;
end

-- @name printErrors
-- @dascription Stringifies the errors table.
local function printErrors()
	local category = '[[Category:((Card gallery)) transclusion to be checked]]';
	if not _D.errors.exists then
		return '';
	end
	table.insert( _D.errors, category );
	return table.concat( _D.errors, '\n' );
end

-- @name buildHeader
-- @description builds the gallery header.
local function buildHeader()
	return HTML( 'div' ):addClass( 'gallery-header' ):attr( 'id', ('%s_section'):format( _D.rg ) )
		:tag( 'div' )
			:wikitext( wrapInQuotes( _D.name ) )
		:done()
		:tag( 'div' )
			:wikitext( _D.region )
		:done()
	:allDone();
end


local function _buildStandard( arg, modifier )
	local standard = {};

	if not _trim( arg ) then
		return standard;
	end
	
	for value in gsplit( arg, '%s*;%s*' ) do
		if value then
			table.insert( standard, _trim( value ) or '' );
		end
	end

	return standard;
end

local function _buildOptions( arg )
	local options = {};

	if not _trim( arg ) then
		return options;
	end

	-- TODO
	for option in gsplit( tempOpt, '%s*;%s*' ) do
		local opt = _trim( option );
		if opt then
			local optTemp = split( opt, '%s*::%s*' );
			local optName  = _trim( optTemp[ 1 ] );
			local optValue = _trim( optTemp[ 2 ] );
			if optName and optValue then
				options[ optName ] = optValue;
			end
		end
	end

	return options;
end

-- @name splitEntry
-- @description Splits an input entry into the standard valus, the modifier and the options.
local function splitEntry( entry )
	if not _trim( entry ) then
		return {}, '', {};
	end

	local temp1   = split( entry, '%s*//%s*' );
	local tempOpt = temp1[ 2 ] or '';
	local temp2   = split( temp1[ 1 ], '%s*::%s*' );
	local tempMod = temp2[ 2 ];
	local tempStd = temp2[ 1 ];

	local modifier = _trim( tempMod );
	local standard = _buildStandard( tempStd, modifier );
	local options  = _buildOptions( tempOpt );

	return standard, modifier, options;
end

-- @name process
-- @description Processes a gallery input entry and converts it into raw wikitext markup.
-- TODO
local function process( entry )
	local standard, modifier, options = splitEntry( entry );
	local fileObject = File.new( standard, modifier, options ); -- TODO
	return table.concat( { -- TODO: TEST
		table.concat( standard ),
		'modifier: ' .. modifier or 'nil',
		type( options ) .. _count( options )
	}, '\n' );
end

-- @name buildInnerGallery
-- TODO
local function buildInnerGallery()
	if (_D.args[ 1 ] or '') == '' then
		-- TODO: Error?
		return ''
	end
	-- <card number>; <set>; <rarity>; <edition>; <alt> :: <modifier> // <option1>::<value1>; <optionN>::<valueN>
	local galleryEntries = {};
	for inputEntry in gsplit( _D.args[ 1 ], '\n' ) do
		local entry = _trim( inputEntry ) and process( inputEntry );
		if entry then
			table.insert( galleryEntries, entry );
		end
	end

	return table.concat( galleryEntries, '\n' );
end

-- @name buildGallery
-- TODO
local function buildGallery()
	local inner = buildInnerGallery();
	return table.concat( {
		'<gallery heights="175px" position="center" captionalign="center">',
		inner,
		'</gallery>'
	}, '\n' );
end

-- @name main
-- @notes exportable 
-- @description To be called through #invoke.
function CardGallery.main( frame )
	_D.errors = {};
	_D.args   = getArgs( frame, {
		trim         = true,
		removeBlanks = true,
		parentOnly   = true
	} );

	getInfo();

	local errors  = printErrors();
	local header  = buildHeader();
	local gallery = buildGallery();

	return HTML( 'div' ):addClass( 'card-galleries' )
		:node( tostring( header ) )
		:newline()
		:node(  errors )
		:newline()
		:node( frame:preprocess( gallery ) )
	:allDone();
end

return CardGallery;