Module:Inventory slot: Difference between revisions
Rewrite for better readability; add i18n; improve performance; support subframes; improve randomness; support already parsed frames |
No edit summary |
||
(39 intermediate revisions by 8 users not shown) | |||
Line 2: | Line 2: | ||
local i18n = { | local i18n = { | ||
modLink = '$1:$2', | |||
modLink = ' | |||
moduleAliases = [[Module:Inventory slot/Aliases]], | moduleAliases = [[Module:Inventory slot/Aliases]], | ||
moduleRandom = [[Module:Random]], | moduleRandom = [[Module:Random]], | ||
-- List of special prefixes which should be handled by | -- List of special prefixes which should be handled by | ||
-- other modules (such as being moved outside links) | -- other modules (such as being moved outside links) | ||
prefixes = { | prefixes = { | ||
any = 'Any', | any = 'Any', | ||
matching = 'Matching', | matching = 'Matching', | ||
damaged = 'Damaged', | damaged = 'Damaged', | ||
unwaxed = 'Unwaxed', | |||
}, | |||
suffixes = { | |||
be = 'BE', | |||
lce = 'LCE', | |||
}, | }, | ||
} | } | ||
p.i18n = i18n | p.i18n = i18n | ||
local random = require( i18n.moduleRandom ).random | local random = require( i18n.moduleRandom ).random | ||
local aliases = mw.loadData( i18n.moduleAliases ) | local aliases = mw.loadData( i18n.moduleAliases ) | ||
local pageName = mw.title.getCurrentTitle().text | local pageName = mw.title.getCurrentTitle().text | ||
--[[Splits a given text into fragments separated by semicolons that are not | |||
inside square brackets. Written by AttemptToCallNil for the Russian wiki | |||
--]] | |||
local function splitOnUnenclosedSemicolons(text) | |||
local semicolon, lbrace, rbrace = (";[]"):byte(1, 3) | |||
local nesting = false | |||
local splitStart = 1 | |||
local frameIndex = 1 | |||
local frames = {} | |||
for index = 1, text:len() do | |||
local byte = text:byte(index) | |||
if byte == semicolon and not nesting then | |||
frames[frameIndex] = text:sub(splitStart, index - 1) | |||
frameIndex = frameIndex + 1 | |||
splitStart = index + 1 | |||
elseif byte == lbrace then | |||
assert(not nesting, "Excessive square brackets found") | |||
nesting = true | |||
elseif byte == rbrace then | |||
assert(nesting, "Unbalanced square brackets found") | |||
nesting = false | |||
end | |||
end | |||
assert(not nesting, "Unbalanced square brackets found") | |||
frames[frameIndex] = text:sub(splitStart, text:len()) | |||
for index = 1, #frames do | |||
frames[index] = (frames[index]:gsub("^%s+", ""):gsub("%s+$", "")) -- faster mw.text.trim | |||
end | |||
return frames | |||
end | |||
-- Performs a simple recursive clone of a table's values | -- Performs a simple recursive clone of a table's values | ||
Line 68: | Line 94: | ||
end | end | ||
if frame.name == '' then | if frame.name == '' then | ||
return item | return item | ||
end | end | ||
local category | local category | ||
local title = frame.title or mw.text.trim( args.title or '' ) | local title = frame.title or mw.text.trim( args.title or '' ) | ||
local num = frame.num | local num = frame.num | ||
local description = frame.text | local description = frame.text | ||
local | local mod = frame.mod or 'Minecraft' | ||
local name = frame.name | |||
if frame.name:match( '%.gif$' ) and frame.name:match( '%.png$' ) then | |||
name = frame.name | |||
mod = '' | |||
end | |||
local minecraft = mod == "Minecraft" or mod == "minecraft" | |||
local img = frame.img | |||
if not img then | |||
if name:match( '%.gif$' ) or name:match( '%.png$' ) then | |||
img = name | |||
-- Remove file extension from name | |||
name = name:sub( 0, -5 ) | |||
elseif minecraft then | |||
img = 'Invicon ' .. name .. '.png' | |||
elseif mod then | |||
img = mod .. ' ' .. name .. '.png' | |||
else | else | ||
img = | img = name | ||
end | end | ||
end | |||
if name:match( ' Revision %d+' ) then | |||
name = name:gsub( ' Revision %d+', '' ) | |||
end | end | ||
local link = args.link or '' | local link = args.link or '' | ||
if link == '' then | if link == '' then | ||
link = i18n.modLink:gsub( '%$1', mod ):gsub( '%$2', name ) | |||
elseif link:lower() == 'none' then | elseif link:lower() == 'none' then | ||
link = nil | link = nil | ||
Line 121: | Line 148: | ||
plainTitle = title:gsub( '\\\\', '\' ):gsub( '\\&', '&' ) | plainTitle = title:gsub( '\\\\', '\' ):gsub( '\\&', '&' ) | ||
local | local formatPatterns = {'&[0-9a-jl-qs-vyzr]', '&#%x%x%x%x%x%x', '&$%x%x%x'} | ||
if plainTitle:match( formatPattern ) then | for _, formatPattern in ipairs( formatPatterns ) do | ||
if plainTitle:match( formatPattern ) then | |||
formattedTitle = title | |||
plainTitle = plainTitle:gsub( formatPattern, '' ) | |||
end | |||
end | end | ||
Line 133: | Line 162: | ||
end | end | ||
elseif link then | elseif link then | ||
formattedTitle = '' | |||
end | end | ||
Line 145: | Line 170: | ||
} | } | ||
-- & is re-escaped because mw.html treats attributes | |||
-- as plain text, but MediaWiki doesn't | |||
local escapedTitle = ( plainTitle or '' ):gsub( '&', '&' ) | |||
local altText = img .. ': Inventory sprite for ' .. name .. ' in Minecraft as shown in-game' | |||
if link then | |||
altText = altText .. ' linking to ' .. link | |||
end | |||
if formattedTitle or plainTitle or link then | |||
if | altText = altText .. ' with description: ' .. ( formattedTitle or plainTitle or link ) | ||
if description then | |||
altText = altText .. ' ' .. description:gsub( '/', ' ' ) | |||
end | end | ||
altText = altText:gsub( '&[0-9a-jl-qs-wr]', '' ) | |||
end | end | ||
item:addClass( 'invslot-item-image' ) | |||
:wikitext( '[[File:', img, '|32x32px|link=', link or '', '|alt=', altText, '|', escapedTitle, ']]' ) | |||
if num and num > 1 and num < 1000 then | if num and num > 1 and num < 1000 then | ||
if | if link then | ||
item:wikitext( '[[', link, '|' ) | item:wikitext( '[[', link, '|' ) | ||
end | end | ||
Line 176: | Line 198: | ||
:attr{ title = plainTitle } | :attr{ title = plainTitle } | ||
:wikitext( num ) | :wikitext( num ) | ||
if | if args.numstyle then | ||
number:cssText( | number:cssText( args.numstyle ) | ||
end | end | ||
if | if link then | ||
item:wikitext( ']]' ) | item:wikitext( ']]' ) | ||
end | end | ||
end | end | ||
Line 238: | Line 256: | ||
end | end | ||
if ( args.default or '' ) ~= '' then | if ( args.default or '' ) ~= '' then | ||
body: | body:addClass( 'invslot-default-' .. string.lower( args.default ):gsub( ' ', '-' ) ) | ||
end | end | ||
--mw.logObject( frames ) | --mw.logObject( frames ) | ||
if not frames then | if not frames then | ||
return tostring( body ) | return tostring( body ) | ||
end | end | ||
Line 253: | Line 270: | ||
if frame[1] then | if frame[1] then | ||
item = body:tag( 'span' ):addClass( 'animated-subframe' ) | item = body:tag( 'span' ):addClass( 'animated-subframe' ) | ||
local subActiveFrame = frame.randomise and random( #frame ) or 1 | local subActiveFrame = frame.randomise == true and random( #frame ) or 1 | ||
for sI, sFrame in ipairs( frame ) do | for sI, sFrame in ipairs( frame ) do | ||
local sItem = makeItem( sFrame, sI, args ) | local sItem = makeItem( sFrame, sI, args ) | ||
Line 283: | Line 300: | ||
local subframe | local subframe | ||
local expandedAliases | local expandedAliases | ||
local splitFrames = | local splitFrames = splitOnUnenclosedSemicolons( framesText ) | ||
for | for i, frameText in ipairs( splitFrames ) do | ||
frameText = frameText:gsub( '^%s*{%s*', function() | frameText = frameText:gsub( '^%s*{%s*', function() | ||
subframe = true | subframe = true | ||
Line 341: | Line 358: | ||
-- or the subframe being the only frame | -- or the subframe being the only frame | ||
if #subframes == 1 or #splitFrames == i and #frames == 0 then | if #subframes == 1 or #splitFrames == i and #frames == 0 then | ||
local lastFrame = #frames | |||
mergeList( frames, subframes ) | mergeList( frames, subframes ) | ||
-- Inherit the randomise flag if it's the only frame | |||
if #splitFrames == 1 then | |||
frames.randomise = subframes.randomise | |||
end | |||
-- Append alias reference data, if present | |||
if aliasReference and subframes.aliasReference then | |||
if not expandedAliases then | |||
expandedAliases = {} | |||
end | |||
for i, aliasRefData in pairs(subframes.aliasReference) do | |||
expandedAliases[lastFrame + i] = aliasRefData | |||
end | |||
end | |||
else | else | ||
table.insert( frames, subframes ) | table.insert( frames, subframes ) | ||
Line 350: | Line 383: | ||
else | else | ||
-- Randomise starting frame for "Any *" aliases, as long as the alias is the only frame | -- Randomise starting frame for "Any *" aliases, as long as the alias is the only frame | ||
if frames.randomise = | if frames.randomise ~= 'never' and frame.name:match( '^' .. i18n.prefixes.any .. ' ' ) then | ||
frames.randomise = true | frames.randomise = true | ||
else | |||
frames.randomise = false | frames.randomise = false | ||
end | end | ||
Line 408: | Line 441: | ||
end | end | ||
return string.format( | return string.format( | ||
'[%s] | '[%s]%s,%s[%s]', | ||
frame.title or '', | frame.title or '', | ||
frame.name, | frame.name, | ||
frame.num or '', | frame.num or '', |