More actions
m (return values) |
m (insert subheader only when there are images to include below it) |
||
(78 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
--[[ | |||
{{#invoke:Sandbox/Chao|GallerySection|character=Noel Vermillion|section=Portraits}} | |||
simulate passing a frame to the function in the console with: | |||
myFrame = { args = { character='Noel Vermillion' } } | |||
=p.main(myFrame) | |||
=p.GallerySection ( myFrame ) | |||
=p.testExpandTemplate( myFrame ) | |||
--]] | |||
local cargo = mw.ext.cargo | local cargo = mw.ext.cargo | ||
function | ------------------------------------- | ||
-- 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 '' | |||
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 | |||
} | } | ||
mw.log( | result = cargo.query( tables, fields, args ) | ||
return | 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 | |||
mw.log("expanded_g: " .. expanded_g) | |||
end | |||
mw.log("t_galleries: " .. table.concat(t_galleries)) | |||
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) | |||
mw.log("t_galleries: " .. table.concat(t_galleries)) | |||
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 = concatvaluesonly(t_section, '') | |||
mw.log('t_section ' .. category .. ' ' .. s) | |||
if s ~= "" then | |||
table.insert(text, '<h2>' .. category .. '</h2>\n' .. s) | |||
end | |||
end | |||
mw.log("\n") | |||
clear_table(t_galleries) | |||
clear_table(t_section) | |||
end | |||
end | |||
gallery = table.concat(text) | |||
return gallery | |||
end | |||
------------------------------------- | |||
-- Main | |||
------------------------------------- | |||
local p = {} | |||
function p.main(frame) | |||
data = frame.args.data or 'Module:Character Gallery/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 | end | ||
Line 44: | Line 455: | ||
end | end | ||
return table.concat(t,delimiter) | return table.concat(t,delimiter) | ||
end | |||
-- concat all the strings in table s together with the given delimiter | |||
-- skips blank entries (where value v = "") | |||
function concatvaluesonly(s,delimiter) | |||
local t = { } | |||
for k,v in ipairs(s) do | |||
if not (v == '') then | |||
t[#t+1] = tostring(v) | |||
end | |||
end | |||
return table.concat(t,delimiter) | |||
end | |||
function cargo_escape(s) | |||
return (string.gsub(s, "[']", { | |||
["'"] = "", | |||
['"'] = "", | |||
})) | |||
end | |||
function quote_escape(s) | |||
return (string.gsub(s, "[\"']", { | |||
["\'"] = "\\'", | |||
['\"'] = '\\"' | |||
})) | |||
end | end | ||
Line 56: | Line 493: | ||
[","] = "%2C" | [","] = "%2C" | ||
})) | })) | ||
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 | end | ||
return p | return p |
Latest revision as of 01:26, 29 April 2020
Main Visuals
[[Category:Noel Vermillion]][[Category:Main Artwork]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Main Artwork
|sources=
}}
Character Crest
[[Category:Noel Vermillion]][[Category:Crests]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Crests
|sources=
}}
Chibi
[[Category:Noel Vermillion]][[Category:Chibi]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Chibi
|sources=
}}
Gameplay
C-Series
[[Category:Noel Vermillion]][[Category:Lobby Avatars]][[Category:BlazBlue: Central Fiction]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Lobby Avatars
|sources=BlazBlue: Central Fiction
}}
[[Category:Noel Vermillion]][[Category:Battle]][[Category:BlazBlue: Central Fiction]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Battle
|sources=BlazBlue: Central Fiction
}}
BlazBlue: Cross Tag Battle
[[Category:Noel Vermillion]][[Category:Battle]][[Category:BlazBlue: Cross Tag Battle]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Battle
|sources=BlazBlue: Cross Tag Battle
}}
Arcade
BlazBlue: Calamity Trigger
[[Category:Noel Vermillion]][[Category:Arcade Mode]][[Category:BlazBlue: Calamity Trigger]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Arcade Mode
|sources=BlazBlue: Calamity Trigger
}}
BlazBlue: Continuum Shift
[[Category:Noel Vermillion]][[Category:Arcade Mode]][[Category:BlazBlue: Continuum Shift]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Arcade Mode
|sources=BlazBlue: Continuum Shift
}}
BlazBlue: Chrono Phantasma
[[Category:Noel Vermillion]][[Category:Arcade Mode]][[Category:BlazBlue: Chrono Phantasma]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Arcade Mode
|sources=BlazBlue: Chrono Phantasma
}}
BlazBlue: Central Fiction
[[Category:Noel Vermillion]][[Category:Arcade Mode]][[Category:BlazBlue: Central Fiction]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Arcade Mode
|sources=BlazBlue: Central Fiction
}}
Story
Portraits
[[Category:Noel Vermillion]][[Category:Portraits]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Portraits
|sources=
}}
Short Stories
[[Category:Noel Vermillion]][[Category:Short Story Illustrations]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Short Story Illustrations
|sources=
}}
BlazBlue: Calamity Trigger
[[Category:Noel Vermillion]][[Category:Story]][[Category:BlazBlue: Calamity Trigger]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Story
|sources=BlazBlue: Calamity Trigger
}}
BlazBlue: Continuum Shift
[[Category:Noel Vermillion]][[Category:Story]][[Category:BlazBlue: Continuum Shift]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Story
|sources=BlazBlue: Continuum Shift
}}
BlazBlue: Chrono Phantasma
[[Category:Noel Vermillion]][[Category:Story]][[Category:BlazBlue: Chrono Phantasma]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Story
|sources=BlazBlue: Chrono Phantasma
}}
BlazBlue: Central Fiction
[[Category:Noel Vermillion]][[Category:Story]][[Category:BlazBlue: Central Fiction]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Story
|sources=BlazBlue: Central Fiction
}}
BlazBlue: Cross Tag Battle
[[Category:Noel Vermillion]][[Category:Story]][[Category:BlazBlue: Cross Tag Battle]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Story
|sources=BlazBlue: Cross Tag Battle
}}
BlazBlue: Clone Phantasma
[[Category:Noel Vermillion]][[Category:Story]][[Category:BlazBlue: Clone Phantasma]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Story
|sources=BlazBlue: Clone Phantasma
}}
Novels
BlazBlue: Calamity Trigger - Part 1
[[Category:Noel Vermillion]][[Category:BlazBlue: Calamity Trigger - Part 1]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=
|sources=BlazBlue: Calamity Trigger - Part 1
}}
BlazBlue: Calamity Trigger - Part 2
[[Category:Noel Vermillion]][[Category:BlazBlue: Calamity Trigger - Part 2]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=
|sources=BlazBlue: Calamity Trigger - Part 2
}}
BlazBlue: Continuum Shift - Part 1
[[Category:Noel Vermillion]][[Category:BlazBlue: Continuum Shift - Part 1]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=
|sources=BlazBlue: Continuum Shift - Part 1
}}
BlazBlue: Continuum Shift - Part 2
[[Category:Noel Vermillion]][[Category:BlazBlue: Continuum Shift - Part 2]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=
|sources=BlazBlue: Continuum Shift - Part 2
}}
Radio Show
Chibi Portraits
[[Category:Noel Vermillion]][[Category:Chibi Portraits]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Chibi Portraits
|sources=
}}
Blazblue Radio
Blazblue Radio Continued
Blazblue Radio Wide
Blazblue Radio Hyper
Blazblue Radio Ace
Blazblue Radio Quick
Blazblue Radio Dynamic
Blazblue Radio NEO
Blazblue Radio Repeat
Blazblue Radio Repeat 2
BlazBlue Alternative: Dark War
All Related Files
... further resultsArtwork
Promotional
[[Category:Noel Vermillion]][[Category:Promotional Artwork]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Promotional Artwork
|sources=
}}
Birthday Art
[[Category:Noel Vermillion]][[Category:Birthday Art]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Birthday Art
|sources=
}}
2008. Included message:
12/25 is Noel's birthday.
She may be a Praetorian Guard who's bad at reading people, but she works hard and entered the military to help her parents. She's weak to cute things, and during the main scenario asked Litchi to "let go of the panda"..."It's cowardly to fight while using a panda as a shield! And that body too!" From such a misunderstanding, she held a grudge and fought haphazardly. But, well, from another point of view, they seem like an older sister and a younger sister; a heartwarming pair. From now on, I'd like to bless each characters' birthdays a little. Thank you for continuing to follow BlazBlue, as well as Noel!
Arc System Works "BLAZBLUE" Director:
Toshimichi Mori
Staff Extras
[[Category:Noel Vermillion]][[Category:Staff Extras]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Staff Extras
|sources=
}}
Special Artwork
[[Category:Noel Vermillion]][[Category:Special Artwork]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Special Artwork
|sources=
}}
Pre-order Bonuses
[[Category:Noel Vermillion]][[Category:Pre-order Bonuses]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Pre-order Bonuses
|sources=
}}
Wallpapers
[[Category:Noel Vermillion]][[Category:Wallpapers]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Wallpapers
|sources=
}}
Stickers
[[Category:Noel Vermillion]][[Category:Stickers]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Stickers
|sources=
}}
Icons
[[Category:Noel Vermillion]][[Category:Icons]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion OR
|cameos=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Icons
|sources=
}}
Production Art
Model Sheets
[[Category:Noel Vermillion]][[Category:Model Sheets]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Model Sheets
|sources=
}}
Early Designs
[[Category:Noel Vermillion]][[Category:Early Designs]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Early Designs
|sources=
}}
Storyboards
[[Category:Noel Vermillion]][[Category:Storyboards]]
OR make sure the file has the following filled out on its page:
{{Gallery Metadata
|characters=Noel Vermillion
|locations=
|weapons=
|artists=
|section=Storyboards
|sources=
}}
Collaborations
Destiny Child
We of the Librarium swear to capture the Grim Reaper.
Profile: A Praetorian Guard of Novus Orbis Librarium's Fourth Squadron. She ranks as a Lieutenant.
Adopted by the noble Vermillion family of Kagutsuchi as a child, she has high Ars Magus Aptitude and achieved record-breaking grades at the Military Academy. She likes writing poetry and has entire notebooks chock full of her verses that she never shows anyone. She's obsessed with pandas and becomes blind to her surroundings when she sees one.Artist: punc_
Girls' Frontline
Lord of Vermilion Re:2
Mabinogi Duel
Unlimited VS
... further resultsFantasy War Tactics
--[[
{{#invoke:Sandbox/Chao|GallerySection|character=Noel Vermillion|section=Portraits}}
simulate passing a frame to the function in the console with:
myFrame = { args = { character='Noel Vermillion' } }
=p.main(myFrame)
=p.GallerySection ( myFrame )
=p.testExpandTemplate( myFrame )
--]]
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 ''
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
mw.log("expanded_g: " .. expanded_g)
end
mw.log("t_galleries: " .. table.concat(t_galleries))
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)
mw.log("t_galleries: " .. table.concat(t_galleries))
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 = concatvaluesonly(t_section, '')
mw.log('t_section ' .. category .. ' ' .. s)
if s ~= "" then
table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
end
end
mw.log("\n")
clear_table(t_galleries)
clear_table(t_section)
end
end
gallery = table.concat(text)
return gallery
end
-------------------------------------
-- Main
-------------------------------------
local p = {}
function p.main(frame)
data = frame.args.data or 'Module:Character Gallery/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
-- concat all the strings in table s together with the given delimiter
-- skips blank entries (where value v = "")
function concatvaluesonly(s,delimiter)
local t = { }
for k,v in ipairs(s) do
if not (v == '') then
t[#t+1] = tostring(v)
end
end
return table.concat(t,delimiter)
end
function cargo_escape(s)
return (string.gsub(s, "[']", {
["'"] = "",
['"'] = "",
}))
end
function quote_escape(s)
return (string.gsub(s, "[\"']", {
["\'"] = "\\'",
['\"'] = '\\"'
}))
end
function html_escape(s)
return (string.gsub(s, "[<>\"'/ ,]", {
["<"] = "%3C",
[">"] = "%3E",
['"'] = "%22",
["'"] = "%27",
["/"] = "%2F",
[" "] = "+",
[","] = "%2C"
}))
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