Difference between revisions of "Module:Card gallery"

From Yugipedia
Jump to: navigation, search
(I can't resist myself at using objects (or something like it).)
(Restoring revision 5001485 by User:Becasita on 2022-06-14 18:46:58. "Fix.")
 
(37 intermediate revisions by one other user not shown)
Line 1: Line 1:
 
-- <pre>
 
-- <pre>
-- NOTES:
+
-- @name Card gallery
-- input in the form of:
+
-- @description Builds a card gallery section for a single region.
-- «
+
-- @author [[User:Becasita]]
-- <card number>; <set>; <rarity>; <edition>; <alt>
+
-- @contact [[User talk:Becasita]]
-- »
 
-- 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:
 
-- Load modules:
 
----------------
 
----------------
local getArgs = require( 'Module:Arguments' ).getArgs;
+
local DATA = require( 'Module:Data' );
local DATA    = require( 'Module:Data' );
+
local UTIL = require( 'Module:Util' );
local getName = require( 'Module:Name' ).main;
+
 
 +
local InfoWrapper  = require( 'Module:InfoWrapper' );
 +
local StringBuffer = require( 'Module:StringBuffer' );
  
---------------------
+
local File = require( 'Module:Card gallery/File' );
-- 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.
+
-- Module variables:
-- If the input is only white space, returns nil.
+
--------------------
local function _trim( s )
+
-- This can be seen as the ast:
if s and not s:match( '^%s*$' ) then
+
local CardGallery = InfoWrapper( 'Card gallery' );
return mw.text.trim( s );
 
end
 
end
 
  
-- @name _count
+
-- Parser state:
-- @description Counts how many entries a table has.
+
local
local function _count( t )
+
PAGENAME,
local counter = 0;
+
NAMESPACE,
for key, value in pairs( t ) do
+
_frame,
counter = counter + 1;
+
_args,
end
+
_region,
return counter;
+
_language,
end
+
_type,
 +
_title,
 +
_debug
 +
;
 +
local _files = {};
  
-- @name _link
+
-- Methods:
-- @description TODO
+
function CardGallery:getRegion()
local function _link( ... )
+
return _region;
-- TODO
 
return;
 
 
end
 
end
  
-- @name _error
+
function CardGallery:getLanguage()
-- Generates an error and places it on the error table.
+
return _language;
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
 
end
  
--------------
+
function CardGallery:getType()
-- File class:
+
return _type;
--------------
 
-- @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
 
end
  
-- @name setNumber
+
---------------------
-- @description Sets the «number» and «setAbbr» attributes.
+
-- Utility functions:
function File:setNumber()
+
---------------------
local cardNumber = self._standard[ 1 ];
+
-- mw functions:
 +
local HTML = mw.html.create;
  
if cardNumber == '' then
+
--------------------
self.exists = false;
+
-- Module functions:
_error( ('No set abbreviation given for file input number «%d»!'):format( File.counter ) );
+
--------------------
return '';
+
local function getCardGalleryType( t )
 +
if type( t ) == 'string' then
 +
return ( {
 +
['anime']  = 'Anime',
 +
['manga']  = 'Manga',
 +
['ruhduel'] = 'Rush Duel',  ['ruh'] = 'Rush Duel', -- "s" is trimmed
 +
['game']    = 'Video games', ['vg']  = 'Video games',
 +
['other']  = 'Other',
 +
} )[
 +
mw.text.trim( t ):lower():gsub( "[%s%-s]", '' ):gsub( 'video', '' )
 +
]
 
end
 
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
 
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]]
 
  
--------------------
+
-- @name initInfo
-- Module functions:
 
--------------------
 
-- @name getInfo
 
 
-- @description Handles generic info.
 
-- @description Handles generic info.
local function getInfo()
+
local function initInfo()
 +
-- Page:
 +
local mwTitle  = mw.title.getCurrentTitle();
 +
PAGENAME  = mwTitle.text;
 +
NAMESPACE = mwTitle.nsText;
 +
 
 
-- Region and language:
 
-- Region and language:
_D.rg      = DATA.getRg( _D.args[ 'region' ] ) or _error(
+
_region = DATA.getRegion( _args[ 'region' ] ) or CardGallery:error(
('Invalid «region»: «%!'):format( _D.args[ 'region' ] or '(no region given)' ), DATA.getRg( 'en' )
+
('Invalid «region»: %s!'):format( _args[ 'region' ] or '(no region given)' ),
 +
DATA.getRegion( 'en' )
 
);
 
);
_D.region  = DATA.getRegion( _D.rg );
+
_language = DATA.getLanguage( _region.index );
_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 );
 
  
 +
-- Type of gallery:
 +
_type  = getCardGalleryType( _args[ 'type' ] );
 +
_title = _args[ 'title' ];
 +
_debug = _args[ 'debug' ];
 
end
 
end
  
-- @name wrapInQuotes
+
-- @name getFiles
-- @description Wraps «name» in proper quotation marks.
+
-- @description Assembles the file entries and prepares them to be parsed.
local function wrapInQuotes( name, std )
+
local function initFiles()
if not _trim( name ) then
+
if not _args[ 1 ] then
return ''; --  Return empty string.
+
return CardGallery:error(
 +
( _frame.args[ 1 ] and 'Empty' or 'No' ) .. 'input provided for the gallery!'
 +
);
 
end
 
end
return (std or (_D.ln ~= 'ja' and _D.ln ~= 'zh'))
 
and table.concat( { '"', name, '"' } )
 
or table.concat( { '「', name, '」' } )
 
;
 
end
 
  
-- @name printErrors
+
for inputEntry in mw.text.gsplit( _args[ 1 ], '\n' ) do
-- @dascription Stringifies the errors table.
+
local entry = UTIL.trim( inputEntry ) and File.factory( CardGallery, inputEntry );
local function printErrors()
+
if entry then
local category = '[[Category:((Card gallery)) transclusion to be checked]]';
+
table.insert( _files, entry );
if not _D.errors.exists then
+
end
return '';
 
 
end
 
end
table.insert( _D.errors, category );
 
return table.concat( _D.errors, '\n' );
 
 
end
 
end
  
-- @name buildHeader
+
-- @description Builds the mediawiki section header.
-- @description builds the gallery header.
+
local function getMwSectionHeader()
local function buildHeader()
+
return (
return HTML( 'div' ):addClass( 'gallery-header' ):attr( 'id', ('%s_section'):format( _D.rg ) )
+
_type and '== %s - %s ==' or '== %s =='
:tag( 'div' )
+
):format(
:wikitext( wrapInQuotes( _D.name ) )
+
(_type or _title) or _region.full, _region.full
:done()
+
);
:tag( 'div' )
 
:wikitext( _D.region )
 
:done()
 
:allDone();
 
 
end
 
end
  
 
+
-- @description Builds the ToC skeleton.
local function _buildStandard( arg, modifier )
+
local function getToC()
local standard = {};
+
return tostring(
 
+
HTML( 'div' ):addClass( 'card-gallery__toc' )
if not _trim( arg ) then
+
:tag( 'ul' )
return standard;
+
:done()
end
+
:allDone()
+
);
for value in gsplit( arg, '%s*;%s*' ) do
 
if value then
 
table.insert( standard, _trim( value ) or '' );
 
end
 
end
 
 
 
return standard;
 
 
end
 
end
  
local function _buildOptions( arg )
+
-- @description Builds the errors' log.
local options = {};
+
local function getErrors()
 
+
return tostring(
if not _trim( arg ) then
+
HTML( 'div' )
return options;
+
:addClass( 'card-gallery__errors' )
end
+
:tag( 'ul' )
 
+
:node(
-- TODO
+
CardGallery:dumpErrors( function( err )
for option in gsplit( tempOpt, '%s*;%s*' ) do
+
return tostring(
local opt = _trim( option );
+
HTML( 'li' )
if opt then
+
:tag( 'strong' )
local optTemp = split( opt, '%s*::%s*' );
+
:wikitext( err )
local optName  = _trim( optTemp[ 1 ] );
+
:done()
local optValue = _trim( optTemp[ 2 ] );
+
:allDone()
if optName and optValue then
+
)
options[ optName ] = optValue;
+
end )
end
+
)
end
+
:done()
end
+
:allDone()
 
+
);
return options;
 
 
end
 
end
  
-- @name splitEntry
+
-- @description Builds the gallery itself.
-- @description Splits an input entry into the standard valus, the modifier and the options.
+
local function getGallery()
local function splitEntry( entry )
+
local gallery = StringBuffer()
if not _trim( entry ) then
+
:addLine( '<gallery heights="175px" position="center" captionalign="center">' )
return {}, '', {};
+
;
 +
for _, file in ipairs( _files ) do
 +
gallery:addLine( file:render() );
 
end
 
end
 +
gallery:addLine( '</gallery>' );
  
local temp1  = split( entry, '%s*//%s*' );
+
return tostring(
local tempOpt = temp1[ 2 ] or '';
+
HTML( 'div' )
local temp2  = split( temp1[ 1 ], '%s*::%s*' );
+
:addClass( 'card-gallery__gallery' )
local tempMod = temp2[ 2 ];
+
:node(
local tempStd = temp2[ 1 ];
+
_debug and tostring(
 
+
HTML( 'pre' ):node( gallery:toString() ):done()
local modifier = _trim( tempMod );
+
) or _frame:preprocess(
local standard = _buildStandard( tempStd, modifier );
+
gallery:toString()
local options  = _buildOptions( tempOpt );
+
)
 
+
)
return standard, modifier, options;
+
:allDone()
 +
);
 
end
 
end
  
-- @name process
+
-- @description Aggregates the categories.
-- @description Processes a gallery input entry and converts it into raw wikitext markup.
+
local function getCategories()
-- TODO
+
return tostring(
local function process( entry )
+
HTML( 'div' )
local standard, modifier, options = splitEntry( entry );
+
:addClass( 'card-gallery__categories' )
local fileObject = File.new( standard, modifier, options ); -- TODO
+
:wikitext(
return table.concat( { -- TODO: TEST
+
CardGallery:dumpCategories()
table.concat( standard ),
+
)
'modifier: ' .. modifier or 'nil',
+
:allDone()
type( options ) .. _count( options )
+
);
}, '\n' );
 
 
end
 
end
  
-- @name buildInnerGallery
+
local function render()
-- TODO
+
local buffer = StringBuffer()
local function buildInnerGallery()
+
:addLine( '<div id="card-gallery--' .. _region.index .. '" class="card-gallery">' )
if (_D.args[ 1 ] or '') == '' then
+
:addLine( getMwSectionHeader() )
-- TODO: Error?
+
:addLine( getToC() )
return ''
+
:addLine( getErrors() )
end
+
:addLine( getGallery() )
-- <card number>; <set>; <rarity>; <edition>; <alt> :: <modifier> // <option1>::<value1>; <optionN>::<valueN>
+
:addLine( getCategories() )
local galleryEntries = {};
+
:add( '</div>' )
for inputEntry in gsplit( _D.args[ 1 ], '\n' ) do
+
;
local entry = _trim( inputEntry ) and process( inputEntry );
+
if entry then
+
return buffer:toString();
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
 
end
  
 
-- @name main
 
-- @name main
-- @notes exportable
 
 
-- @description To be called through #invoke.
 
-- @description To be called through #invoke.
function CardGallery.main( frame )
+
local function main( frame )
_D.errors = {};
+
_frame = frame;
_D.args  = getArgs( frame, {
+
_args  = UTIL.getArgs( frame, {
 
trim        = true,
 
trim        = true,
 
removeBlanks = true,
 
removeBlanks = true,
Line 354: Line 211:
 
} );
 
} );
  
getInfo();
+
initInfo();
 
+
initFiles();
local errors  = printErrors();
 
local header  = buildHeader();
 
local gallery = buildGallery();
 
  
return HTML( 'div' ):addClass( 'card-galleries' )
+
return render();
:node( tostring( header ) )
 
:newline()
 
:node(  errors )
 
:newline()
 
:node( frame:preprocess( gallery ) )
 
:allDone();
 
 
end
 
end
  
return CardGallery;
+
----------
 +
-- Return:
 +
----------
 +
-- @exports
 +
return {
 +
['main'] = main
 +
};
 +
-- </pre>

Latest revision as of 04:22, 15 March 2023

-- <pre>
-- @name Card gallery
-- @description Builds a card gallery section for a single region.
-- @author [[User:Becasita]]
-- @contact [[User talk:Becasita]]

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

local InfoWrapper  = require( 'Module:InfoWrapper' );
local StringBuffer = require( 'Module:StringBuffer' );

local File = require( 'Module:Card gallery/File' );

--------------------
-- Module variables:
--------------------
-- This can be seen as the ast:
local CardGallery = InfoWrapper( 'Card gallery' );

-- Parser state:
local
	PAGENAME,
	NAMESPACE,
	_frame,
	_args,
	_region,
	_language,
	_type,
	_title,
	_debug
;
local _files = {};

-- Methods:
function CardGallery:getRegion()
	return _region;
end

function CardGallery:getLanguage()
	return _language;
end

function CardGallery:getType()
	return _type;
end

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

--------------------
-- Module functions:
--------------------
local function getCardGalleryType( t )
	if type( t ) == 'string' then
		return ( {
			['anime']   = 'Anime',
			['manga']   = 'Manga',
			['ruhduel'] = 'Rush Duel',   ['ruh'] = 'Rush Duel', -- "s" is trimmed
			['game']    = 'Video games', ['vg']  = 'Video games',
			['other']   = 'Other',
		} )[
			mw.text.trim( t ):lower():gsub( "[%s%-s]", '' ):gsub( 'video', '' )
		]
	end
end

-- @name initInfo
-- @description Handles generic info.
local function initInfo()
	-- Page:
	local mwTitle  = mw.title.getCurrentTitle();
	PAGENAME  = mwTitle.text;
	NAMESPACE = mwTitle.nsText;

	-- Region and language:
	_region = DATA.getRegion( _args[ 'region' ] ) or CardGallery:error(
		('Invalid «region»: %s!'):format( _args[ 'region' ] or '(no region given)' ),
		DATA.getRegion( 'en' )
	);
	_language = DATA.getLanguage( _region.index );

	-- Type of gallery:
	_type  = getCardGalleryType( _args[ 'type' ] );
	_title = _args[ 'title' ];
	_debug = _args[ 'debug' ];
end

-- @name getFiles
-- @description Assembles the file entries and prepares them to be parsed.
local function initFiles()
	if not _args[ 1 ] then
		return CardGallery:error(
			( _frame.args[ 1 ] and 'Empty' or 'No' ) .. 'input provided for the gallery!'
		);
	end

	for inputEntry in mw.text.gsplit( _args[ 1 ], '\n' ) do
		local entry = UTIL.trim( inputEntry ) and File.factory( CardGallery, inputEntry );
		if entry then
			table.insert( _files, entry );
		end
	end
end

-- @description Builds the mediawiki section header.
local function getMwSectionHeader()
	return (
		_type and '== %s - %s ==' or '== %s =='
	):format(
		(_type or _title) or _region.full, _region.full
	);
end

-- @description Builds the ToC skeleton.
local function getToC()
	return tostring(
		HTML( 'div' ):addClass( 'card-gallery__toc' )
			:tag( 'ul' )
			:done()
		:allDone()
	);
end

-- @description Builds the errors' log.
local function getErrors()
	return tostring(
		HTML( 'div' )
			:addClass( 'card-gallery__errors' )
			:tag( 'ul' )
				:node(
					CardGallery:dumpErrors( function( err )
						return tostring(
							HTML( 'li' )
								:tag( 'strong' )
									:wikitext( err )
								:done()
							:allDone()
						)
					end )
				)
			:done()
		:allDone()
	);
end

-- @description Builds the gallery itself.
local function getGallery()
	local gallery = StringBuffer()
		:addLine( '<gallery heights="175px" position="center" captionalign="center">' )
	;
	for _, file in ipairs( _files ) do
		gallery:addLine( file:render() );
	end
	gallery:addLine( '</gallery>' );

	return tostring(
		HTML( 'div' )
			:addClass( 'card-gallery__gallery' )
			:node(
				_debug and tostring(
					HTML( 'pre' ):node( gallery:toString() ):done()
				) or _frame:preprocess(
					gallery:toString()
				)
			)
		:allDone()
	);
end

-- @description Aggregates the categories.
local function getCategories()
	return tostring(
		HTML( 'div' )
			:addClass( 'card-gallery__categories' )
			:wikitext(
				CardGallery:dumpCategories()
			)
		:allDone()
	);
end

local function render()
	local buffer = StringBuffer()
		:addLine( '<div id="card-gallery--' .. _region.index .. '" class="card-gallery">' )
		:addLine( getMwSectionHeader() )
		:addLine( getToC() )
		:addLine( getErrors() )
		:addLine( getGallery() )
		:addLine( getCategories() )
		:add( '</div>' )
	;
	
	return buffer:toString();
end

-- @name main
-- @description To be called through #invoke.
local function main( frame )
	_frame = frame;
	_args  = UTIL.getArgs( frame, {
		trim         = true,
		removeBlanks = true,
		parentOnly   = true
	} );

	initInfo();
	initFiles();

	return render();
end

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