Module:Character Gallery: Difference between revisions

From BlazBlue Wiki
(add additional template parameter "Header" and fix Gallery Sections not showing up)
(fixed bug where Gallery Section didn't pick up category2)
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
local p = {}
local cargo = mw.ext.cargo
local cargo = mw.ext.cargo


local galleryData = mw.loadData('Module:Character Gallery/data')
-------------------------------------
local ordering = galleryData.ordering
-- Gallery Section Class
local sections = galleryData.sections
-------------------------------------
 
local GalleryTemplate = {}
GalleryTemplate.__index = GalleryTemplate
 
GalleryTemplate.fields = {
character = true,
source = true,
section = true,
limit = true,
widths = true,
header = true,
title = true,
sort = true,
see_all = true,
see_cameos = true,
--Gallery Section (BBRadio)
season = true,
episode = true,
widths = true,
--Gallery Section
cat = true,
cat2 = true,
--Misc/Shared
count_all = true,
count_cameos = true,
images_in_section = true,
}
 
GalleryTemplate.templateMethods = {
['Gallery Section (Cargo)'] = 'makeGallerySectionCargo',
['Gallery Section (BBRadio)'] = 'makeGallerySectionBBRadio',
['Gallery Section'] = 'makeGallerySection',
}
 
function GalleryTemplate.new(frame, templateType, params)
local self = setmetatable({}, GalleryTemplate)
self.templateType= templateType
self.frame = frame
for field in pairs(GalleryTemplate.fields) do
self[field] = params[field] or ''
end


function p.render(frame)
self.images_in_section = 0
text = {}
self.cat = params.category or ''
_char = frame.args['character'] or ''
self.cat2 = params.category2 or ''
if (params.character == nil)
then self.character = frame.args.character or ''
else self.character = params.character or ''
end
 
return self
end
 
function GalleryTemplate:__tostring()
local method = GalleryTemplate.templateMethods[self.templateType]
if method then
return self[method](self)
end
return ''
end
 
function GalleryTemplate.makeGallerySectionCargo(self)
local expanded_template = nil
 
self.character = cargo_escape(self.character)
 
self.count_all = GalleryTemplate._countImages_GallerySectionCargo(self,false) or 0
self.count_cameos = GalleryTemplate._countImages_GallerySectionCargo(self,true) or 0
local total_images = self.count_all + self.count_cameos
for i,v in ipairs (ordering) do
if self.count_all > 0 then
category = v
self.see_all = 'y'
params = sections[v] or ''
end
 
if params == '' then
else
t_section = {}
t_galleries = {}
images_in_section = 0
current_subheader = ''
-- add a wrapper div if there's a class to apply to the section
class = params.class or ''
if class ~= '' then
table.insert(t_section, '<div class="' .. class .. '">')
end
-- v is a table of templates in this section
if self.count_cameos > 0 then
for k2,v2 in pairs (params) do
self.see_cameos = 'y'
end
template = v2.template or ''
params = {}
--fill in any missing template arguments
--Gallery Section (Cargo)
params.character = _char
params.source = v2.source or ''
params.section = v2.section or ''
params.limit = v2.limit or ''
params.widths = v2.widths or ''
params.header = v2.header or ''
params.title = v2.title or ''
params.sort = v2.sort or ''
params.see_all = v2.see_all or ''
params.see_cameos = v2.see_cameos or ''
--Gallery Section (BBRadio)
params.season = v2.season or ''
params.episode = v2.episode or ''
params.widths = v2.widths or ''
--Gallery Section
params.cat = v2.category or ''
params.cat2 = v2.category2 or ''
if template == 'Gallery Section (Cargo)' then
if total_images > 0 then
params.character = cargo_escape(params.character)
expanded_template = GalleryTemplate._expandTemplate_GallerySectionCargo(self, self.frame)
--table.insert(t_galleries, expanded_template)
self.images_in_section = self.images_in_section + total_images
end


params.count_all = p._countImages_GallerySectionCargo(params, false) or 0
return expanded_template
params.count_cameos = p._countImages_GallerySectionCargo(params, true) or 0
end
total_images = params.count_all + params.count_cameos
if params.count_all > 0 then
params.see_all = 'y'
end
if params.count_cameos > 0 then
params.see_cameos = 'y'
end
if total_images > 0 then
expanded_template = p._expandTemplate_GallerySectionCargo(frame, params)
table.insert(t_galleries, expanded_template)
images_in_section = images_in_section + total_images
end
elseif template == 'Gallery Section (BBRadio)' then
params.character = cargo_escape(params.character)
params.count_all = p._countImages_GallerySectionBBRadio(params) or 0
expanded_template = p._expandTemplate_GallerySectionBBRadio(frame, params)
table.insert(t_galleries, expanded_template)
images_in_section = images_in_section + params.count_all
elseif template == 'Gallery Section' then
params.count_all = p._countImages_GallerySection(params) or 0
expanded_template = p._expandTemplate_GallerySection(frame, params)
table.insert(t_galleries, expanded_template)
images_in_section = images_in_section + params.count_all
elseif template == 'Header' then
-- if this is not the first subheader in this section
if current_subheader ~= '' then
-- check if the previous subheader's galleries had images in them
if images_in_section > 0 then
-- insert the previous subheader into the section
table.insert(t_section, current_subheader)
-- insert the previous subheader's galleries into the section
g = table.concat(t_galleries)
if g ~= "" then
table.insert(t_section, g)
end
-- reset galleries and images for the next subsection
clear_table(t_galleries)
images_in_section = 0
end
end
-- save the new subheader and wait to see if the following galleries have any images in them
current_subheader = '<' .. params.header .. '>' .. params.title .. '</' .. params.header .. ">\n"
end
end


-- check the number of images in the section
function GalleryTemplate.makeGallerySectionBBRadio(self)
mw.log(category .. " images_in_section = " .. images_in_section)
self.character = cargo_escape(self.character)
self.count_all = GalleryTemplate._countImages_GallerySectionBBRadio(self) or 0
-- if there is a subheader to insert, then insert it
local expanded_template = GalleryTemplate._expandTemplate_GallerySectionBBRadio(self,self.frame)
if current_subheader ~= "" and images_in_section > 0 then
--table.insert(t_galleries, expanded_template)
table.insert(t_section, current_subheader)
self.images_in_section = self.images_in_section + self.count_all
end
return expanded_template
end
-- if there are galleries to insert, then insert them
g = table.concat(t_galleries)
if g ~= "" then
table.insert(t_section, g)
else
mw.log("t_galleries is empty, with " .. images_in_section .. " images total in this section")
end


-- close the wrapping div if one was added
function GalleryTemplate.makeGallerySection(self)
if class ~= "" then
self.count_all = GalleryTemplate._countImages_GallerySection(self) or 0
table.insert(t_section, "</div>")
local expanded_template = GalleryTemplate._expandTemplate_GallerySection(self,self.frame)
end
--table.insert(t_galleries, expanded_template)
self.images_in_section = self.images_in_section + self.count_all
s = table.concat(t_section)
return expanded_template
if s ~= "" then
-- insert the section, prepended by the section header, to the final text
table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
end
end
end
gallery = table.concat(text)
return gallery
end
end


-- counts the number of images with this character (or cameo) for sections using Template:Gallery Section (Cargo)
-- counts the number of images with this character (or cameo) for sections using Template:Gallery Section (Cargo)
-- countCameos: boolean
-- countCameos: boolean
function p._countImages_GallerySectionCargo(params, countCameos)
function GalleryTemplate._countImages_GallerySectionCargo(self, countCameos)
tables = 'Files'
tables = 'Files'
fields = 'COUNT(Files._pageName)'
fields = 'COUNT(Files._pageName)'


character = params.character or ''
character = self.character or ''
source = params.source or ''
source = self.source or ''
section = params.section or ''
section = self.section or ''


where_clause_parts = {}
where_clause_parts = {}
Line 172: Line 139:
end
end


function p._countImages_GallerySectionBBRadio(params)
function GalleryTemplate._countImages_GallerySectionBBRadio(self)
tables = 'Files,BBRadio_Cuts'
tables = 'Files,BBRadio_Cuts'
fields = 'COUNT(Files._pageName)'
fields = 'COUNT(Files._pageName)'
join_on = 'Files._pageName=BBRadio_Cuts._pageName'
join_on = 'Files._pageName=BBRadio_Cuts._pageName'
_character = params.character or ''
_season = params.season or ''
mw.log(_character)
mw.log("Count images for " .. self.character .. ' season ' .. self.season)
mw.log(_season)


where_clause = 'Files.Characters HOLDS "' .. _character .. '" AND BBRadio_Cuts.Season="' .. _season .. '"'
where_clause = 'Files.Characters HOLDS "' .. self.character .. '" AND BBRadio_Cuts.Season="' .. self.season .. '"'


local args = {
local args = {
Line 196: Line 159:
end
end


function p._countImages_GallerySection(params)
function GalleryTemplate._countImages_GallerySection(self)
cat1 = self.character or ''
cat1 = params.character or ''
cat2 = self.cat or ''
cat2 = params.cat or ''
cat3 = self.cat2 or ''
cat3 = params.cat2 or ''


local query = {}
local query = {}
Line 206: Line 168:
if cat2 ~= '' then table.insert(query, '[[Category:' .. cat2 .. ']]') end
if cat2 ~= '' then table.insert(query, '[[Category:' .. cat2 .. ']]') end
if cat3 ~= '' then table.insert(query, '[[Category:' .. cat3 .. ']]') end
if cat3 ~= '' then table.insert(query, '[[Category:' .. cat3 .. ']]') end
 
local result = mw.smw.getQueryResult( query )
local result = mw.smw.getQueryResult( query )
count = result.meta.count or 0
count = result.meta.count or 0


return count
return count
end
end


function p._expandTemplate_GallerySectionCargo(frame, params)
function GalleryTemplate._expandTemplate_GallerySectionCargo(self)
_character = params.character or ''
_limit = tonumber(self.limit) or 4
_source = params.source or ''
 
_section = params.section or ''
if self.frame.expandTemplate == nil then return '' end
_limit = tonumber(params.limit) or 4
gallery = self.frame:expandTemplate{ title = 'Gallery Section (Cargo)', args = {  
_title = params.title or ''
character = self.character,
_header = params.header or ''
source = self.source,
_see_all = params.see_all or ''
section = self.section,
_see_cameos = params.see_cameos or ''
_count_all = params.count_all or ''
_count_cameos = params.count_cameos or ''
gallery = frame:expandTemplate{ title = 'Gallery Section (Cargo)', args = {  
character = _character,
source = _source,
section = _section,
limit = _limit,
limit = _limit,
title = _title,
title = self.title,
header = _header,
header = self.header,
see_all = _see_all,
see_all = self.see_all,
see_cameos = _see_cameos,
see_cameos = self.see_cameos,
count_all = _count_all,
count_all = self.count_all,
count_cameos = _count_cameos
count_cameos = self.count_cameos
}}
}}


Line 242: Line 195:
end
end


function p._expandTemplate_GallerySectionBBRadio(frame, params)
function GalleryTemplate._expandTemplate_GallerySectionBBRadio(self)
_character = params.character or ''
_limit = tonumber(self.limit) or 4
_season = params.season or ''
_widths = tonumber(self.widths) or 250
_episode = params.episode or ''
_header = params.header or ''
_title = params.title or ''
_limit = tonumber(params.limit) or 4
_widths = tonumber(params.widths) or 250
_count_all = params.count_all or ''


gallery = frame:expandTemplate { title = 'Gallery Section (BBRadio)', args = {
if self.frame.expandTemplate == nil then return '' end
_character,
gallery = self.frame:expandTemplate { title = 'Gallery Section (BBRadio)', args = {
_season,
self.character,
_episode,
self.season,
_header,
self.episode,
_title,
self.header,
self.title,
widths = _widths,
widths = _widths,
limit = _limit,
limit = _limit,
count_all = _count_all
count_all = self.count_all
}}
}}


Line 266: Line 214:
end
end


function p._expandTemplate_GallerySection(frame, params)
function GalleryTemplate._expandTemplate_GallerySection(self)
_character = params.character or ''
_limit = tonumber(self.limit) or 4
_cat = params.cat or ''
_widths = tonumber(self.widths) or 250
_cat2 = params.cat2 or ''
_count_all = self.count_all or 0
_header = params.header or ''
_title = self.title or ''
_title = params.title or ''
_limit = tonumber(params.limit) or 4
_widths = tonumber(params.widths) or 250
_count_all = params.count_all or 0


gallery = frame:expandTemplate { title = 'Gallery Section', args = {
if self.frame.expandTemplate == nil then return '' end
_character,
gallery = self.frame:expandTemplate { title = 'Gallery Section', args = {
_cat,
self.character,
_cat2,
self.cat,
_header,
self.cat2,
_title,
self.header,
self.title,
widths = _widths,
widths = _widths,
limit = _limit,
limit = _limit,
Line 289: Line 234:
return gallery
return gallery
end
end
function GalleryTemplate:getNumberOfImages(self)
return self.images_in_section
end
-------------------------------------
-- Gallery Class
-------------------------------------
local Gallery = {}
Gallery.__index = Gallery
function Gallery.new(data, frame)
local self = setmetatable({}, Gallery)
self.galleryData = mw.loadData(data)
self.ordering = self.galleryData.ordering
self.sections = self.galleryData.sections
self.frame = frame
return self
end
function Gallery:__tostring()
local frame = self.frame
text = {}
_char = frame.args['character'] or ''
for i,v in ipairs (self.ordering) do
category = v
local params = self.sections[v] or ''
if params == '' then
else
local t_section = {}
local t_galleries = {}
local images_in_section = 0
local images_in_subsection = 0
local current_subheader = ''
-- add a wrapper div if there's a class to apply to the section
class = params.class or ''
if class ~= '' then
table.insert(t_section, '<div class="' .. class .. '">')
end
-- each v2 represents one template call
for k2,v2 in pairs(params) do
template = v2.template or ''
local title = v2.title or ''
mw.log(template .. ": " .. title)
if not (template == 'Header') and template ~= '' then
local g = nil
local expanded_g = nil
g = GalleryTemplate.new(frame, template, v2)
if g ~= nil then
expanded_g = tostring(g)
mw.log("imgs: " .. g:getNumberOfImages(g) or 0 )
if expanded_g ~= nil and expanded_g ~= '' then
table.insert(t_galleries, expanded_g)
num_images = tonumber(g:getNumberOfImages(g)) or 0
images_in_subsection = images_in_subsection  + num_images
images_in_section = images_in_section + num_images
end
end
elseif template == 'Header' then
-- if this is not the first subheader in this section
if current_subheader ~= '' then
-- check if the previous subheader's galleries had images in them
if images_in_subsection > 0 then
table.insert(t_section, current_subheader)
g = table.concat(t_galleries)
if g ~= "" then
table.insert(t_section, g)
end
-- reset galleries and images for the next subsection
clear_table(t_galleries)
images_in_subsection = 0
end
end
local header = v2.header or ''
-- save the new subheader and wait to see if the following galleries have any images in them
current_subheader = '<' .. header .. '>' .. title .. '</' .. header .. ">\n"
end
end
-- check the number of images in the section
mw.log("---\n" .. category .. " images_in_section = " .. images_in_section)
if images_in_section > 0 then
-- if there is a subheader to insert, then insert it
if current_subheader ~= "" and images_in_subsection > 0 then
table.insert(t_section, current_subheader)
end
-- if there are galleries to insert, then insert them
g = table.concat(t_galleries)
table.insert(t_section, g)
-- close the wrapping div if one was added
if class ~= "" then
table.insert(t_section, "</div>")
end
-- insert the section, prepended by the section header, to the final text
s = table.concat(t_section)
if s ~= "" then
table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
end
end
clear_table(t_galleries)
clear_table(t_section)
end
end
gallery = table.concat(text)
return gallery
end
-------------------------------------
-- Main
-------------------------------------
local p = {}
function p.main(frame)
local data = frame.args.data or ''
if data == '' then data = 'Module:Character Gallery/data' end
mw.log('Format: ' .. data)
gallery = Gallery.new(data, frame)
--mw.log(dump(tostring(gallery)))
return tostring(gallery)
end
-------------------------------------
-- Tests
-------------------------------------


function p.testExpandTemplate_1(frame)
function p.testExpandTemplate_1(frame)
Line 339: Line 423:
end
end
end
end
-------------------------------------
-- Utility Functions
-------------------------------------
-- clear a table
function clear_table(t)
for k in pairs (t) do
    t [k] = nil
end
end
end
end
Line 351: Line 446:
end
end


-- remove characters that can mess up cargo queries
function cargo_escape(s)
function cargo_escape(s)
return (string.gsub(s, "['\"]", {
return (string.gsub(s, "[']", {
["'"] = "",
["'"] = "",
['"'] = "",
['"'] = "",

Latest revision as of 18:37, 4 December 2021

This module creates a character gallery.

Please see Module:Character Gallery/data for the format of the character gallery and how to change it.

Usage

{{#invoke:Character Gallery|render|character=CHARACTER NAME}}

Lua Testing

frame={args={character="Es"}}
p.main(frame)

local cargo = mw.ext.cargo

-------------------------------------
-- Gallery Section Class
-------------------------------------

local GalleryTemplate = {}
GalleryTemplate.__index = GalleryTemplate

GalleryTemplate.fields = {
	character = true,
	source = true,
	section = true,
	limit = true,
	widths = true,
	header = true,
	title = true,
	sort = true,
	see_all = true,
	see_cameos = true,
	--Gallery Section (BBRadio)
	season = true,
	episode = true,
	widths = true,
	--Gallery Section
	cat = true,
	cat2 = true,
	--Misc/Shared
	count_all = true,
	count_cameos = true,
	images_in_section = true,
}

GalleryTemplate.templateMethods = {
	['Gallery Section (Cargo)'] = 'makeGallerySectionCargo',
	['Gallery Section (BBRadio)'] = 'makeGallerySectionBBRadio',
	['Gallery Section'] = 'makeGallerySection',
}

function GalleryTemplate.new(frame, templateType, params)
	local self = setmetatable({}, GalleryTemplate)
	self.templateType= templateType
	self.frame = frame
	for field in pairs(GalleryTemplate.fields) do
		self[field] = params[field] or ''
	end

	self.images_in_section = 0
	self.cat = params.category or ''
	self.cat2 = params.category2 or ''
	if (params.character == nil)
		then self.character = frame.args.character or ''
		else self.character = params.character or ''
	end

	return self
end

function GalleryTemplate:__tostring()
	local method = GalleryTemplate.templateMethods[self.templateType]
	if method then
		return self[method](self)
	end
	return ''
end

function GalleryTemplate.makeGallerySectionCargo(self)
	local expanded_template = nil

	self.character = cargo_escape(self.character)

	self.count_all = GalleryTemplate._countImages_GallerySectionCargo(self,false) or 0
	self.count_cameos = GalleryTemplate._countImages_GallerySectionCargo(self,true) or 0
	local total_images = self.count_all + self.count_cameos
	
	if self.count_all > 0 then
		self.see_all = 'y'
	end
	
	if self.count_cameos > 0 then
		self.see_cameos = 'y'
	end
	
	if total_images > 0 then
		expanded_template = GalleryTemplate._expandTemplate_GallerySectionCargo(self, self.frame)
		--table.insert(t_galleries, expanded_template)
		self.images_in_section = self.images_in_section + total_images
	end

	return expanded_template
end

function GalleryTemplate.makeGallerySectionBBRadio(self)
	self.character = cargo_escape(self.character)
	self.count_all = GalleryTemplate._countImages_GallerySectionBBRadio(self) or 0
	local expanded_template = GalleryTemplate._expandTemplate_GallerySectionBBRadio(self,self.frame)
	--table.insert(t_galleries, expanded_template)
	self.images_in_section = self.images_in_section + self.count_all
	return expanded_template
end

function GalleryTemplate.makeGallerySection(self)
	self.count_all = GalleryTemplate._countImages_GallerySection(self) or 0
	local expanded_template = GalleryTemplate._expandTemplate_GallerySection(self,self.frame)
	--table.insert(t_galleries, expanded_template)
	self.images_in_section = self.images_in_section + self.count_all
	return expanded_template
end

-- counts the number of images with this character (or cameo) for sections using Template:Gallery Section (Cargo)
-- countCameos: boolean
function GalleryTemplate._countImages_GallerySectionCargo(self, countCameos)
	tables = 'Files'
	fields = 'COUNT(Files._pageName)'

	character = self.character or ''
	source = self.source or ''
	section = self.section or ''

	where_clause_parts = {}
	if countCameos then
		table.insert(where_clause_parts, "Files.Cameos HOLDS '" .. character .. "'")
	else
		table.insert(where_clause_parts, "Files.Characters HOLDS '" .. character .. "'")
	end
	
	if source == '' then else table.insert(where_clause_parts, "Files.Source HOLDS '" .. source .. "'")	end
	if section == '' then else table.insert(where_clause_parts, "Files.Gallery_Sections HOLDS '" .. section .. "'")	end
	where_clause = concatvalues(where_clause_parts, " AND ")

	local args = {
		where = where_clause
	}

	result = cargo.query( tables, fields, args )
	count = result[1][fields] or '0'

	return tonumber(count)
end

function GalleryTemplate._countImages_GallerySectionBBRadio(self)
	tables = 'Files,BBRadio_Cuts'
	fields = 'COUNT(Files._pageName)'
	join_on = 'Files._pageName=BBRadio_Cuts._pageName'
	
	mw.log("Count images for " .. self.character .. ' season ' .. self.season)

	where_clause = 'Files.Characters HOLDS "' .. self.character .. '" AND BBRadio_Cuts.Season="' .. self.season .. '"'

	local args = {
		where = where_clause,
		join = join_on
	}

	result = cargo.query( tables, fields, args )
	count = result[1][fields] or '0'

	return tonumber(count)
end

function GalleryTemplate._countImages_GallerySection(self)
	cat1 = self.character or ''
	cat2 = self.cat or ''
	cat3 = self.cat2 or ''

	local query = {}
	if cat1 ~= '' then table.insert(query, '[[Category:' .. cat1 .. ']]') end
	if cat2 ~= '' then table.insert(query, '[[Category:' .. cat2 .. ']]') end
	if cat3 ~= '' then table.insert(query, '[[Category:' .. cat3 .. ']]') end

	local result = mw.smw.getQueryResult( query )
	count = result.meta.count or 0

	return count
end

function GalleryTemplate._expandTemplate_GallerySectionCargo(self)
	_limit = tonumber(self.limit) or 4

	if self.frame.expandTemplate == nil then return '' end
	gallery = self.frame:expandTemplate{ title = 'Gallery Section (Cargo)', args = { 
		character = self.character,
		source = self.source,
		section = self.section,
		limit = _limit,
		title = self.title,
		header = self.header,
		see_all = self.see_all,
		see_cameos = self.see_cameos,
		count_all = self.count_all,
		count_cameos = self.count_cameos
	}}

	return gallery
end

function GalleryTemplate._expandTemplate_GallerySectionBBRadio(self)
	_limit = tonumber(self.limit) or 4
	_widths = tonumber(self.widths) or 250

	if self.frame.expandTemplate == nil then return '' end
	gallery = self.frame:expandTemplate { title = 'Gallery Section (BBRadio)', args = {
		self.character,
		self.season,
		self.episode,
		self.header,
		self.title,
		widths = _widths,
		limit = _limit,
		count_all = self.count_all
	}}

	return gallery
end

function GalleryTemplate._expandTemplate_GallerySection(self)
	_limit = tonumber(self.limit) or 4
	_widths = tonumber(self.widths) or 250
	_count_all = self.count_all or 0
	_title = self.title or ''

	if self.frame.expandTemplate == nil then return '' end
	gallery = self.frame:expandTemplate { title = 'Gallery Section', args = {
		self.character,
		self.cat,
		self.cat2,
		self.header,
		self.title,
		widths = _widths,
		limit = _limit,
		count_all = _count_all,
	}}

	return gallery
end

function GalleryTemplate:getNumberOfImages(self)
	return self.images_in_section
end

-------------------------------------
-- Gallery Class
-------------------------------------

local Gallery = {}
Gallery.__index = Gallery

function Gallery.new(data, frame)
	local self = setmetatable({}, Gallery)
	self.galleryData = mw.loadData(data)
	self.ordering = self.galleryData.ordering
	self.sections = self.galleryData.sections
	self.frame = frame
	return self
end

function Gallery:__tostring()
	local frame = self.frame
	text = {}
	_char = frame.args['character'] or ''
	
	for i,v in ipairs (self.ordering) do
		category = v
		local params = self.sections[v] or ''
		
		if params == '' then
		else
			local t_section = {}
			local t_galleries = {}
			local images_in_section = 0
			local images_in_subsection = 0
			local current_subheader = ''
			
			-- add a wrapper div if there's a class to apply to the section
			class = params.class or ''
			if class ~= '' then
				table.insert(t_section, '<div class="' .. class .. '">')
			end

			-- each v2 represents one template call
			for k2,v2 in pairs(params) do
				template = v2.template or ''

				local title = v2.title or ''
				mw.log(template .. ": " .. title)

				if not (template == 'Header') and template ~= '' then
					local g = nil
					local expanded_g = nil

					g = GalleryTemplate.new(frame, template, v2)
					if g ~= nil then
						expanded_g = tostring(g)
						mw.log("imgs: " .. g:getNumberOfImages(g) or 0 )
						if expanded_g ~= nil and expanded_g ~= '' then
							table.insert(t_galleries, expanded_g)
							num_images = tonumber(g:getNumberOfImages(g)) or 0
							images_in_subsection = images_in_subsection  + num_images
							images_in_section = images_in_section + num_images
						end
					end
				elseif template == 'Header' then
					-- if this is not the first subheader in this section
					if current_subheader ~= '' then
						-- check if the previous subheader's galleries had images in them
						if images_in_subsection > 0 then
							table.insert(t_section, current_subheader)
							g = table.concat(t_galleries)
							if g ~= "" then
								table.insert(t_section, g)
							end
							-- reset galleries and images for the next subsection
							clear_table(t_galleries)
							images_in_subsection = 0
						end
					end
					local header = v2.header or ''
					-- save the new subheader and wait to see if the following galleries have any images in them
					current_subheader = '<' .. header .. '>' .. title .. '</' .. header .. ">\n"
				end
			end

			-- check the number of images in the section
			mw.log("---\n" .. category .. " images_in_section = " .. images_in_section)

			if images_in_section > 0 then
				-- if there is a subheader to insert, then insert it
				if current_subheader ~= "" and images_in_subsection > 0 then
					table.insert(t_section, current_subheader)
				end
			
				-- if there are galleries to insert, then insert them
				g = table.concat(t_galleries)
				table.insert(t_section, g)

				-- close the wrapping div if one was added
				if class ~= "" then
					table.insert(t_section, "</div>")
				end

				-- insert the section, prepended by the section header, to the final text
				s = table.concat(t_section)
				if s ~= "" then
					table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
				end
			end

			clear_table(t_galleries)
			clear_table(t_section)
		end
	end
	
	gallery = table.concat(text)
	return gallery
end

-------------------------------------
-- Main
-------------------------------------
local p = {}

function p.main(frame)
	local data = frame.args.data or ''
	if data == '' then data = 'Module:Character Gallery/data' end
	mw.log('Format: ' .. data)
	gallery = Gallery.new(data, frame)

	--mw.log(dump(tostring(gallery)))
	return tostring(gallery)
end

-------------------------------------
-- Tests
-------------------------------------

function p.testExpandTemplate_1(frame)
	
	v = {
		character = 'Noel Vermillion',
		source = 'BlazBlue: Central Fiction', 
		section = '', 
		limit = 8, 
		title = 'title', 
		header = 'h3', 
		see_all = 'y', 
		see_cameos = 'y', 
		count_all = '7'
	}
	text = p._expandTemplate_GallerySectionCargo(frame, v)
	
	return text
end

function p.testExpandTemplate_2(frame)
	
	v = {
		character = 'Noel Vermillion',
		season = 'NEO', 
		limit = 8, 
		title = 'title', 
		header = 'h3', 
		see_all = 'y', 
		count_all = '7',
	}
	text = p._expandTemplate_GallerySectionBBRadio(frame, v)
	
	return text
end

function p.testOrdering()
	for i,v in ipairs (ordering) do
		section = v
		k = sections[v] or ''

		mw.log('\n' .. i .. ': ' .. section)
		if k == '' then
			mw.log('no parameters found')
		else
			mw.log(k.class)
			for k2,v2 in pairs (k) do
				mw.log(k2)
			end
		end
		
	end
end

-------------------------------------
-- Utility Functions
-------------------------------------

-- clear a table
function clear_table(t)
	for k in pairs (t) do
    	t [k] = nil
	end
end

-- concat all the strings in table s together with the given delimiter
function concatvalues(s,delimiter)
    local t = { }
    for k,v in ipairs(s) do
        t[#t+1] = tostring(v)
    end
    return table.concat(t,delimiter)
end

function cargo_escape(s)
	return (string.gsub(s, "[']", {
		["'"] = "",
		['"'] = "",
	}))
end

-- helpful for printing tables
function dump(o)
   if type(o) == 'table' then
      local s = '{ '
      for k,v in pairs(o) do
         if type(k) ~= 'number' then k = '"'..k..'"' end
         s = s .. '['..k..'] = ' .. dump(v) .. ','
      end
      return s .. '} '
   else
      return tostring(o)
   end
end

return p