Editing Module:Limitation status list

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

This page is not enabled for semantic in-text annotations due to namespace restrictions. Details about how to enable the namespace can be found on the configuration help page.

Latest revision Your text
Line 1: Line 1:
local inArray = require('Module:TableTools').inArray
 
 
 
-- Shell object for the list itself
 
-- Shell object for the list itself
 
local List = {
 
local List = {
 
name = nil,
 
name = nil,
 
medium = nil,
 
medium = nil,
format = nil,
 
 
locality = nil,
 
locality = nil,
 
startDate = nil,
 
startDate = nil,
endDate = nil,
 
 
prev = nil,
 
prev = nil,
 
next = nil,
 
next = nil,
Line 33: Line 29:
 
cardType = nil,
 
cardType = nil,
 
status = nil,
 
status = nil,
-- If a card was on the list despite not being released while the list was in effect
 
unreleased = false,
 
afterDate = nil,
 
 
prevStatus = nil,
 
prevStatus = nil,
 
prevStatusNote = nil
 
prevStatusNote = nil
}
 
 
local statusDescriptions = {
 
['Forbidden']    = 'These cards cannot be used in the [[Main Deck]], [[Extra Deck]], or [[Side Deck]].',
 
['Limited']      = 'A maximum of one copy of each of these cards can be included in the [[Main Deck]], [[Extra Deck]], and [[Side Deck]] combined.',
 
['Semi-Limited'] = 'A maximum of two copies of each of these cards can be included in the [[Main Deck]], [[Extra Deck]], and [[Side Deck]] combined.',
 
['Limited 1']    = 'A maximum of one out of all of the following cards can be included in the [[Main Deck]], [[Extra Deck]], [[Side Deck]], and choice of [[Skill Card]] combined.',
 
['Limited 2']    = 'A maximum of two out of all of the following cards can be included in the [[Main Deck]], [[Extra Deck]], [[Side Deck]], and choice of [[Skill Card]] combined. This may be two copies of the same card or one copy one card and one copy of another.',
 
['Limited 3']    = 'A maximum of three out of all of the following cards can be included in the [[Main Deck]], [[Extra Deck]], [[Side Deck]], and choice of [[Skill Card]] combined. This can include multiple copies of the same card, as long as the combined total from this list is three or fewer.',
 
['Unlimited']    = 'Limitations have been removed from the following cards since the last list.'
 
}
 
 
-- Mediums that have only been released in Japanese
 
-- @todo: Come up with solution that doesn't involve hardcoding games in the module
 
local jaOnlyMediums = {
 
'Yu-Gi-Oh! Duel Monsters (video game)',
 
'Yu-Gi-Oh! Rush Duel',
 
 
}
 
}
  
Line 74: Line 50:
  
 
l:setData(args or {})
 
l:setData(args or {})
 
l:validateAfterParsing()
 
  
 
return l
 
return l
Line 85: Line 59:
 
self.name = args.name or mw.title.getCurrentTitle().text
 
self.name = args.name or mw.title.getCurrentTitle().text
 
self.medium = args.medium
 
self.medium = args.medium
self.format = args.format
 
 
self.locality = args.locality
 
self.locality = args.locality
 
self.startDate = args.start_date
 
self.startDate = args.start_date
self.endDate = args.end_date
 
 
self.prev = args.prev
 
self.prev = args.prev
 
self.next = args.next
 
self.next = args.next
Line 97: Line 69:
 
self:addItems('Limited', args.limited)
 
self:addItems('Limited', args.limited)
 
self:addItems('Semi-Limited', args.semi_limited)
 
self:addItems('Semi-Limited', args.semi_limited)
self:addItems('Limited 1', args.limited_1)
 
self:addItems('Limited 2', args.limited_2)
 
self:addItems('Limited 3', args.limited_3)
 
 
self:addItems('Unlimited', args.no_longer_on_list)
 
self:addItems('Unlimited', args.no_longer_on_list)
  
Line 112: Line 81:
 
self.locality == 'Korean'
 
self.locality == 'Korean'
 
) then
 
) then
self.localColumnHeading = self.locality .. ' name'
+
self.localColumnHeading = self.locality
 
self.localColumnProperty = self.locality .. ' name'
 
self.localColumnProperty = self.locality .. ' name'
return
 
end
 
  
local isJaOnly = inArray(jaOnlyMediums, self.medium)
+
elseif self.medium == 'OCG' or self.medium == 'Yu-Gi-Oh! Official Card Game' then
local isOcg = self.medium == 'OCG' or self.medium == 'Yu-Gi-Oh! Official Card Game'
+
self.localColumnHeading = 'Japanese'
 +
self.localColumnProperty = 'Japanese name'
  
if (isJaOnly or (isOcg and self.locality ~= 'Asian-English')) then
+
else
self.localColumnHeading = 'Japanese name'
+
self.localColumnHeading = nil
self.localColumnProperty = 'Japanese name'
+
self.localColumnProperty = nil
return
 
 
end
 
end
 
self.localColumnHeading = nil
 
self.localColumnProperty = nil
 
 
end
 
end
  
Line 147: Line 111:
  
 
-- Extract data from content after the `//`
 
-- Extract data from content after the `//`
local unreleased = options and options:match('unreleased::true') and true or false
 
local afterDate = options and options:match('after::([^;]*)')
 
 
local prevStatus = options and options:match('prev::([^;]*)')
 
local prevStatus = options and options:match('prev::([^;]*)')
 
local prevStatusNote = options and options:match('prev%-note::([^;]*)')
 
local prevStatusNote = options and options:match('prev%-note::([^;]*)')
Line 156: Line 118:
  
 
listItem.status = status
 
listItem.status = status
listItem.unreleased = unreleased
 
listItem.afterDate = afterDate
 
 
listItem.prevStatus = prevStatus
 
listItem.prevStatus = prevStatus
 
listItem.prevStatusNote = prevStatusNote
 
listItem.prevStatusNote = prevStatusNote
Line 169: Line 129:
 
local cardData = self:lookupCardData(itemText)
 
local cardData = self:lookupCardData(itemText)
  
listItem.cardFound    = cardData and true or false
+
if (not cardData) then
-- The original name that was supplied
+
table.insert(self.errors, 'Failed to look up details for card: "' .. itemText .. '"')
 +
end
 +
 
 
listItem.card          = itemText
 
listItem.card          = itemText
-- The name that SMW found
 
listItem.pageName      = cardData and cardData.pageName  or nil
 
 
listItem.cardName      = cardData and cardData.name      or itemText
 
listItem.cardName      = cardData and cardData.name      or itemText
 
listItem.localCardName = cardData and cardData.localName or ''
 
listItem.localCardName = cardData and cardData.localName or ''
Line 187: Line 147:
 
function List:setSmwData()
 
function List:setSmwData()
 
mw.smw.set({
 
mw.smw.set({
['Effective date'] = self.startDate, -- deprecated
+
['Effective date'] = self.startDate,
['Start date']    = self.startDate,
 
['End date']      = self.endDate,
 
 
['Medium']        = self.medium,
 
['Medium']        = self.medium,
 
['Release']        = self.medium,
 
['Release']        = self.medium,
['Format']        = self.format or self.locality or self.medium,
 
 
['Locality']      = self.locality,
 
['Locality']      = self.locality,
 
['Page type']      = 'Status list'
 
['Page type']      = 'Status list'
Line 213: Line 170:
 
local queryParams = {
 
local queryParams = {
 
'[[' .. pageName  .. ']]',
 
'[[' .. pageName  .. ']]',
'? = pageName#',
 
 
'?English name = name',
 
'?English name = name',
'?Card type#  = cardType'
+
'?Card type#  = cardType',
 
}
 
}
  
-- If there is a column for another language
 
-- also query for the card's name in that language
 
 
if (self.localColumnProperty) then
 
if (self.localColumnProperty) then
 
table.insert(queryParams, '?' .. self.localColumnProperty .. ' = localName')
 
table.insert(queryParams, '?' .. self.localColumnProperty .. ' = localName')
Line 227: Line 181:
  
 
return cardData and cardData[1] or nil
 
return cardData and cardData[1] or nil
end
 
 
-- Validate the data after it has been parsed
 
-- Checks for errors and adds them to the `errors` attribute
 
function List:validateAfterParsing()
 
for i, item in pairs(self.items) do
 
-- If not a card, go to the next iteration of the loop.
 
-- (Any validation after this line is only applicable to cards.)
 
if (not item.card) then break end
 
 
-- Check if card data was found for the looked up name.
 
if (item.cardFound == false) then
 
table.insert(self.errors, 'Failed to look up details for card: <code>' .. item.card .. '</code>.')
 
 
-- If the card wasn't found, move on to the next list item.
 
-- No need to perform the next few checks.
 
break
 
end
 
 
-- Check if a card is listed more than once
 
for i2, item2 in pairs(self.items) do
 
-- `i < i2`: Only look at records that come after this one,
 
-- so the same error isn't reported again for the duplicate(s)
 
if (i < i2 and item.pageName == item2.pageName) then
 
table.insert(self.errors, '<code>' .. item.pageName .. '</code> is listed more than once.')
 
 
-- Duplicate found, so no need to keep looking.
 
break
 
end
 
end
 
 
-- Check if the supplied name doesn't match the found page name
 
if (item.card ~= item.pageName) then
 
table.insert(self.errors, 'The supplied page name, <code>' .. item.card .. '</code>, does not match the looked-up page name, <code>' .. item.pageName .. '</code>.')
 
end
 
 
if (item.status == 'Unlimited' and not item.prevStatus) then
 
table.insert(self.errors, '<code>' .. item.card .. '</code> has been removed from the list, but does not specify its previous status.')
 
end
 
end
 
 
end
 
end
  
Line 289: Line 203:
 
-- @return string
 
-- @return string
 
function List:render()
 
function List:render()
self:renderDisplayTitle()
 
 
 
local output = ''
 
local output = ''
 
output = output .. self:renderErrors()
 
output = output .. self:renderErrors()
Line 297: Line 209:
 
output = output .. self:renderStatusList('Limited')
 
output = output .. self:renderStatusList('Limited')
 
output = output .. self:renderStatusList('Semi-Limited')
 
output = output .. self:renderStatusList('Semi-Limited')
output = output .. self:renderStatusList('Limited 1')
 
output = output .. self:renderStatusList('Limited 2')
 
output = output .. self:renderStatusList('Limited 3')
 
 
output = output .. self:renderStatusList('Unlimited', 'No longer on list')
 
output = output .. self:renderStatusList('Unlimited', 'No longer on list')
 
output = output .. self:renderCategories()
 
output = output .. self:renderCategories()
  
 
return output
 
return output
end
 
 
-- Format the page name, if necessary
 
function List:renderDisplayTitle()
 
local italicTitle = nil
 
local pageName    = mw.title.getCurrentTitle().text
 
-- Medium without the word "Yu-Gi-Oh!"
 
local mediumShort = mw.text.trim(replacePlain(self.medium, 'Yu-Gi-Oh!', ''), '%s')
 
 
-- If the medium or a shortened version of it is mentioned in the page name italicize it
 
if pageName:find(self.medium) then
 
italicTitle = replacePlain(pageName, self.medium, '<i>' .. self.medium .. '</i>')
 
elseif pageName:find(mediumShort) then
 
italicTitle = replacePlain(pageName, mediumShort, '<i>' .. mediumShort .. '</i>')
 
end
 
 
-- Use the italicized name as the page name
 
if italicTitle then
 
mw.getCurrentFrame():callParserFunction('DISPLAYTITLE', italicTitle)
 
end
 
 
end
 
end
  
Line 345: Line 234:
 
-- @return string
 
-- @return string
 
function List:renderNavigation()
 
function List:renderNavigation()
-- Strip disambiguation text from the medium's page name
+
-- If prev and next are both empty, don't show a navigation menu
local mediumName = mw.text.split(self.medium, ' %(')[1]
+
if (not isFilled(self.prev) and not isFilled(self.next)) then
 +
return ''
 +
end
  
local currText = (self.locality or '') .. ' <i>' .. mediumName .. '</i> ' .. (self.format or '') .. ' Forbidden & Limited Lists'
+
local currText = self:pageNameToShortName(self.name)
 
local prevText = isFilled(self.prev) and ('← [[' .. self.prev .. '|' .. self:pageNameToShortName(self.prev) .. ']]') or '&nbsp;'
 
local prevText = isFilled(self.prev) and ('← [[' .. self.prev .. '|' .. self:pageNameToShortName(self.prev) .. ']]') or '&nbsp;'
 
local nextText = isFilled(self.next) and ('[[' .. self.next .. '|' .. self:pageNameToShortName(self.next) .. ']] →') or '&nbsp;'
 
local nextText = isFilled(self.next) and ('[[' .. self.next .. '|' .. self:pageNameToShortName(self.next) .. ']] →') or '&nbsp;'
Line 357: Line 248:
 
output = output .. '<div style="flex: 1; text-align: right;">' .. nextText .. '</div>'
 
output = output .. '<div style="flex: 1; text-align: right;">' .. nextText .. '</div>'
 
output = output .. '</div>'
 
output = output .. '</div>'
 
if isFilled(self.startDate) and isFilled(self.endDate) then
 
output = output .. '<p style="font-size: .9em; text-align: center;"><b>Effective</b>: '
 
output = output .. self.startDate .. ' – ' ..  self.endDate
 
output = output .. '</p>'
 
end
 
  
 
return output
 
return output
Line 368: Line 253:
  
 
-- Convert a page name to a short name
 
-- Convert a page name to a short name
-- e.g. "March 2020 Lists (Duel Links)" -> "March 2020"
+
-- e.g. "March 2020 Lists (Duel Links)" -> "March 2020 Lists"
-- e.g. "OCG April 2014 Lists" -> "April 2014"
+
-- e.g. "OCG April 2014 Lists" -> "April 2014 Lists"
 
-- @param pageName string
 
-- @param pageName string
 
-- @return string
 
-- @return string
Line 377: Line 262:
  
 
-- Remove mention of the medium
 
-- Remove mention of the medium
shortName = replacePlain(shortName, self.medium, '')
+
shortName = shortName:gsub(self.medium, '')
 
 
-- Remove the word 'Lists'
 
shortName = replacePlain(shortName, ' Lists', '')
 
  
 
-- Clear any leading/trailing spaces
 
-- Clear any leading/trailing spaces
Line 390: Line 272:
 
if (isFilled(mw.title.getCurrentTitle().nsText)) then return '' end
 
if (isFilled(mw.title.getCurrentTitle().nsText)) then return '' end
  
local output = '[[Category:' .. (self.locality or '') .. ' ' .. (self.medium or '') .. ' ' .. (self.format or '') .. ' Forbidden & Limited Lists]]'
+
local output = '[[Category:' .. (self.region or '') .. ' ' .. (self.medium or '') .. ' Forbidden & Limited Lists]]'
  
 
if (#self.errors > 0) then
 
if (#self.errors > 0) then
Line 414: Line 296:
  
 
local headingRow = list:tag('tr')
 
local headingRow = list:tag('tr')
headingRow:tag('th'):attr('scope', 'col'):wikitext('Card')
+
headingRow:tag('th'):wikitext('Card')
 
if self.localColumnHeading then
 
if self.localColumnHeading then
headingRow:tag('th'):attr('scope', 'col'):wikitext(self.localColumnHeading)
+
headingRow:tag('th'):wikitext(self.localColumnHeading)
 
end
 
end
headingRow:tag('th'):attr('scope', 'col'):wikitext('Card type')
+
headingRow:tag('th'):wikitext('Card type')
headingRow:tag('th'):attr('scope', 'col'):wikitext('Status')
+
headingRow:tag('th'):wikitext('Status')
headingRow:tag('th'):attr('scope', 'col'):wikitext('Changes')
+
headingRow:tag('th'):wikitext('Changes')
  
 
for _, item in pairs(items) do
 
for _, item in pairs(items) do
 
local cardTypeLink = item.cardType
 
local cardTypeLink = item.cardType
and ('[[' .. item.cardType .. '|' .. replacePlain(item.cardType, ' Card', '') .. ']]')
+
and ('[[' .. item.cardType .. '|' .. string.gsub(item.cardType, ' Card', '') .. ']]')
 
or ''
 
or ''
  
 
-- Form the CSS class that styles the cells in the status column
 
-- Form the CSS class that styles the cells in the status column
local statusClass = 'status-' .. (item.status:gsub(' ', '-')):lower()
+
local statusClass = 'status-' .. (item.status):lower()
 
 
local statusText = '[[' .. item.status .. ']]'
 
 
if item.afterDate then
 
statusText = statusText .. ' (after: ' .. item.afterDate .. ')';
 
end
 
 
 
-- If the card was unreleased, add an extra bit of text to explain that.
 
if item.unreleased then
 
local explainText = 'This card was not released' .. (self.locality and (' in ' .. self.locality) or '') .. ' while this list was in effect.'
 
statusText = statusText .. ' (<span class="explain" title="' .. explainText .. '">Unreleased</span>)'
 
end
 
  
 
local row = list:tag('tr')
 
local row = list:tag('tr')
Line 448: Line 318:
 
end
 
end
 
row:tag('td'):wikitext(cardTypeLink)
 
row:tag('td'):wikitext(cardTypeLink)
row:tag('td'):addClass(statusClass):wikitext(statusText)
+
row:tag('td'):addClass(statusClass):wikitext('[[' .. item.status .. ']]')
 
row:tag('td'):wikitext(
 
row:tag('td'):wikitext(
 
(item.prevStatus and 'was [[' .. item.prevStatus .. ']]' or '') ..
 
(item.prevStatus and 'was [[' .. item.prevStatus .. ']]' or '') ..
Line 455: Line 325:
 
end
 
end
  
local description = statusDescriptions[status] or ''
+
return tostring(heading) .. tostring(list)
 
 
return tostring(heading) .. description .. tostring(list)
 
 
end
 
end
  
Line 466: Line 334:
 
function isFilled(value)
 
function isFilled(value)
 
return value ~= nil and value ~= ''
 
return value ~= nil and value ~= ''
end
 
 
-- Replace all occurances of a string with another
 
-- Unlike `string.gsub`, do not treat the searched term as a pattern.
 
--
 
-- @param source  str - The text to perform the replacement in
 
-- @param search  str - The text to search for
 
-- @param replace str - The text to replace the searched text with
 
-- @return str
 
function replacePlain(source, search, replace)
 
-- Escape any patterns in the search term
 
search = mw.ustring.gsub(search, '([%(%)%.%%%+%-%*%?%[%^%$%]])', '%%%1')
 
 
-- Replace all instances of the search term, with the replace term
 
return mw.ustring.gsub(source, search, replace)
 
 
end
 
end
  
 
return List
 
return List

Please note that all contributions to Yugipedia are considered to be released under the Creative Commons Attribution-ShareAlike 4.0 International License (see Yugipedia:Licensing for more details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

Cancel Editing help (opens in new window)
Preview page with this template
Below are some commonly used wiki markup codes. Simply click on what you want to use and it will appear in the edit box above.

View this template