-- Fork from Module:Spatial image viewer. That's why there is some extra meaningless stuff here.
-- Similar to User:Bawolff/earth_rotation except using separate images instead of a sprite sheet.
local p = {}
local heightCache
local function getStart( axis, frame )
return tonumber(frame.args['start'..axis] or 0)
end
-- We assume all images have roughly the same aspect ratio
local function getHeight(frame, imageList)
if frame.args['height'] then
return frame.args['height']
end
if heightCache == nil then
local title = mw.title.new( imageList[1], 'File' )
assert( title and title.file, "Invalid file")
heightCache = math.ceil((tonumber(frame.args['width']) or 250) * (title.file.height/title.file.width))
end
return heightCache
end
local function parseImageList( images )
local imageList = mw.text.split( mw.text.trim( images ), "\n+" )
return imageList
end
local function getImages(frame, imageList)
local html = mw.html.create( 'div' )
html
:css( 'width', (frame.args['width'] or 250) .. 'px' )
:css( 'height', getHeight(frame, imageList) .. 'px' )
:css( 'position', 'relative' )
for imgColNumb, img in ipairs( imageList ) do
local zDefault = 0
if (imgColNumb-1 == getStart('X',frame)) then
zDefault = 1
end
local formula = 'ifequal(x,' .. (imgColNumb-1) .. ')'
html:tag( 'div' )
:css( 'position', 'absolute' )
:css( 'background', frame.args['background'] or '#fff' )
:css( 'width', (frame.args['width'] or 250) .. 'px' )
:css( 'height', getHeight(frame, imageList) .. 'px' )
:css( 'z-index', 'var( --calculator-x' .. (imgColNumb-1) .. ',' .. zDefault .. ')')
:wikitext( frame:preprocess(
'[[File:' .. img .. '|' .. (frame.args['width'] or 250) .. 'x' .. getHeight(frame,imageList) .. 'px]]' ..
'{{calculator|type=hidden|id=x' .. (imgColNumb-1) .. '|formula=' .. formula .. '|default=' .. zDefault .. '}}'
) )
end
-- For some reason this doesn't seem to work on Wikipedia android app.
if frame.args.fallbackImage then
html:tag( 'div' )
:css( 'position', 'absolute' )
:css( 'background', frame.args['background'] or '#fff' )
:css( 'width', (frame.args['width'] or 250) .. 'px' )
:css( 'height', getHeight(frame, imageList) .. 'px' )
:css( 'z-index', '3')
:addClass( 'calculatorgadget-fallback' ) -- if calc enabled with will be display:none
:wikitext( frame:preprocess(
'[[File:' .. frame.args.fallbackImage .. '|' .. (frame.args['width'] or 250) .. 'x' .. getHeight(frame,imageList) .. 'px]]'
) )
end
return tostring(html)
end
function p.makeViewer(frame)
local pFrame = frame:getParent()
local args = pFrame.args
local width = args['width'] or 250
assert( args['images'], "Images argument required")
local imageList = parseImageList( args['images'] )
local descId = mw.uri.anchorEncode( 'spatialviewer-desc-' .. imageList[1] )
local html = mw.html.create( 'div' )
html:addClass( 'spatialviewer calculator-container' )
-- TODO dark mode support. We set an explicit background to make sure that if some of the images
-- are different dimensions or transparent they don't show through each other. This messes up some
-- dark mode related styles
html:addClass( 'notheme' )
html:attr( 'aria-describedby', descId )
html:cssText( args['style'] )
html:css( 'float', args['float'] )
:css( 'display', 'grid' )
:css( 'width', 'max-content' )
:css( 'grid-template-columns', width .. 'px' )
:css( 'border', '1px var(--border-color-base,#a2a9b1) solid' )
:css( 'padding', '0.5em' )
:css( 'gap', '3px' )
:css( 'background', args['background'] or '#fff' ) -- Should this be var(--background-color-base, '#fff') ?
html:tag('div')
:addClass( 'calculator-skip-link' )
:wikitext( '[[#' .. descId .. '|Skip image slideshow]]' )
:wikitext( frame:extensionTag{ name = 'templatestyles', content = '', args = { src = 'Module:Spatial image viewer/skip.css' } } )
html:tag( 'div' )
-- The Wikipedia app has some dynamic image loading code that messes up the intrinsic height.
:css( 'min-height', getHeight(pFrame, imageList) .. 'px' )
:wikitext(
getImages( pFrame, imageList )
)
local sliderLabel = ''
if pFrame.args['slider-label'] ~= nil then
sliderLabel = 'aria-label=' .. pFrame.args['slider-label'] .. '|'
end
html:tag( 'div' )
:css( 'display', 'none' ) -- Only display if calculator gadget enabled
:addClass( 'calculatorgadget-enabled' )
:css( 'margin', 'auto' )
:wikitext(
frame:preprocess( '{{calculator|type=range|min=0|id=x|max=' .. (#imageList-1) .. '|' .. sliderLabel .. 'default=' .. getStart('X', frame ) .. '}}' )
)
if args.caption then
html:tag( 'div' )
:css( 'border-top', '1px solid #eaecf0' ) -- caption styles could probably be improved
:css( 'margin-top', '0.5em' )
:css( 'padding-top', '0.5em' )
:attr( 'id', descId )
:wikitext( frame:preprocess( args.caption ) )
end
return tostring(html)
end
return p