Module:MetroStationInfobox

From Tyne and Wear Metro wiki

Documentation for this module may be created at Module:MetroStationInfobox/doc

local p = {}

local LENGTH_555 = 59.9
local LENGTH_METROCAR = 55.6

function p.main(frame)
	local args = frame:getParent().args
	
	local semanticData = {}
	
	-- Aliases
	args['Nexus code'] = args['Nexus code'] or args['Code']
	args['Coordinates'] = args['Coordinates'] or args['Coords']
	
	local tableElement = mw.html.create( 'table' ):addClass( 'infobox' )
	
	local stationName = args['Name'] or mw.title.getCurrentTitle().text
	tableElement:tag( 'caption' ):wikitext( stationName )
	semanticData['Has station name'] = stationName
	
	local pillsRow = mw.html.create( 'tr' )
	local pillsList = pillsRow
		:tag( 'td' ):attr( 'colspan', '2' )
			:tag( 'ul' ):addClass( 'pills' )
	local thereArePills = false
	local function createPill()
		thereArePills = true
		return pillsList:tag( 'li' )
	end
	
	if args['Is on green line'] then
		createPill()
			:css( 'background-color', '#0f0' ):css( 'border-color', '#0a0' )
			:wikitext( '[[Category:Green Line stations]][[GRN]]' )
	end
	if args['Is on yellow line'] then
		createPill()
			:css( 'background-color', '#ff0' ):css( 'border-color', '#aa0' )
			:wikitext( '[[Category:Yellow Line stations]][[YEL]]' )
	end
	
	if args['Fare zones'] then
	    local zones = {
	        A = { bg = '#FEF797', accent = '#FAAA4D' },
	        B = { bg = '#B3DBB4', accent = '#FEFEFE' },
	        C = { bg = '#F9D5E5', accent = '#ED008C' },
	        D = { bg = '#D4E7F7', accent = '#0081EA' },
	    }
	    for zone in mw.text.gsplit(args['Fare zones'], ',') do
	        zone = mw.text.trim(zone):upper()
	        if zones[zone] then
	        	semanticData['Has Metro fare zone'] = semanticData['Has Metro fare zone'] or {}
	        	table.insert(semanticData['Has Metro fare zone'], zone)
	        	
	        	createPill():addClass( 'zone' )
	        		:attr( 'title', "Zone " .. zone )
	        		:wikitext( zone .. '[[Category:Railway stations in fare zone ' .. zone .. ']]' )
	        		-- Can't use CSS variables with TemplateStyles
					:css( 'background-color', zones[zone].bg )
					:css( 'border-color', zones[zone].accent )
					:css( 'color', zones[zone].accent )
	        end
	    end
	end
	
	if args['Nexus code'] then
		semanticData['Has Nexus code'] = args['Nexus code']
		createPill()
			:attr( 'title', 'Nexus code' )
			:wikitext( '[[Image:Nexus_icon.svg|link=Nexus|12px]]' .. args['Nexus code'] )
	end
	if args['Alternative codes'] then
        for code in mw.text.gsplit(args['Alternative codes'], ',') do
            code = mw.text.trim(code)
            if code ~= '' then
				createPill():addClass( 'alternative-code' )
					:attr( 'title', 'Alternative code' )
				:wikitext( '[[Image:Nexus_icon.svg|link=Nexus|12px]]' .. code  )
            end
        end
	end
	if args['CRS code'] then
		semanticData['Has CRS code'] = args['CRS code']
		createPill()
			:attr( 'title', 'CRS code' )
			:wikitext( '[[Image:National_Rail_logo.svg|alt=National Rail logo|12px]]' .. args['CRS code'] )
	end
	
	if args['Has bus interchange'] then
		createPill()
			:attr( 'title', 'Bus interchange' )
			:wikitext( '[[Category:Railway stations with bus interchange]]🚍' )
	end
	if args['Has rail interchange'] then
		createPill()
			:attr( 'title', 'Rail interchange' )
			:wikitext( '[[Category:Metro stations with rail interchange]][[Image:National_Rail_logo.svg|alt=National Rail logo|12px]]' )
	end
	
	if args['Car parking spaces'] then
		semanticData['Has car parking'] = args['Car parking spaces']
		createPill()
			:attr( 'title', args['Car parking spaces'] .. ' car parking spaces' )
			:wikitext( '🅿️×' .. args['Car parking spaces'] .. '[[Category:Railway stations with car parking]]' )
	end
	if args['Cycle parking spaces'] then
		semanticData['Has cycle parking'] = args['Cycle parking spaces']
		createPill()
			:attr( 'title', args['Cycle parking spaces'] .. ' cycle parking spaces' )
			:wikitext( '🚲️×' .. args['Cycle parking spaces'] .. '[[Category:Railway stations with cycle parking]]' )
	end
	
	if thereArePills then
		tableElement:node(pillsRow)
	end
	
	if args['Image'] then
		semanticData['Has primary image'] = 'File:' .. args['Image']
		tableElement:tag( 'tr' )
			:tag( 'td' ):attr( 'colspan', '2' )
				:wikitext( '[[File:' .. args['Image'] .. '|300px]]' )
	end
	
	if args['Coordinates'] then
        local lat, lon = args['Coordinates']:match("([-%d.]+),([-%d.]+)")
        if lat and lon then
        	semanticData['Has coordinates'] = args['Coordinates']
			tableElement:tag( 'tr' ):addClass( 'coordinates' )
				:tag( 'td' ):attr( 'colspan', '2' )
					:wikitext(
						frame:callParserFunction('#display_map', {
							'',
							coordinates = args['Coordinates'],
							zoom = 18
						})
					)
		end
	end
	
	if args['Address'] then
		semanticData['Has address'] = args['Address']
		tableElement:tag( 'tr' )
			:tag( 'td' ):attr( 'colspan', '2' )
				:wikitext( args['Address'] )
	end
	
	if args['Distance from datum'] then
		semanticData['Has distance from Gosforth datum'] = args['Distance from datum']
		tableElement:tag( 'tr' )
			:tag( 'td' ):attr( 'colspan', '2' )
				:wikitext( args['Distance from datum'] .. ' from Gosforth datum' )
	end
	
    local dates = {}
    if args['Date originally opened'] then
    	semanticData['Has date opened'] = args['Date originally opened']
        table.insert(dates, 'Originally opened ' .. args['Date originally opened'])
    end
    if args['Date closed before Metro'] then
    	semanticData['Has date closed before Metro'] = args['Date closed before Metro']
        table.insert(dates, 'Closed before Metro ' .. args['Date closed before Metro'])
    end
    if args['Date opened for Metro'] then
    	semanticData['Has date opened for Metro'] = args['Date opened for Metro']
        table.insert(dates, 'Opened for Metro ' .. args['Date opened for Metro'])
    end
    if args['Other key dates'] then
        local parts = mw.text.split(args['Other key dates'], ';')
        for i = 1, #parts, 2 do
            if parts[i+1] then
                table.insert(dates, mw.text.trim(parts[i]) .. ' ' .. mw.text.trim(parts[i+1]))
            end
        end
    end
    
    if #dates == 1 then
		tableElement:tag( 'tr' )
			:tag( 'td' ):attr( 'colspan', '2' )
				:wikitext( dates[1] )
	elseif #dates > 1 then
		local row = tableElement:tag( 'tr' )
		row:tag( 'th' ):attr( 'scope', 'row' ):wikitext( 'Key dates' )
		local list = row:tag( 'td' )
			:tag( 'ul' ):addClass( 'key-dates' )
        for _, date in ipairs(dates) do
            list:tag('li'):wikitext(date)
        end
	end
	
	if args['Platforms'] then
	    local parsedPlatforms = {}
	    local anyHaveLength = false
	    local maxLength = math.max(LENGTH_555, LENGTH_METROCAR)
	
	    for pStr in mw.text.gsplit(args['Platforms'], ';') do
			pStr = mw.text.trim(pStr)
	        if pStr ~= '' then
				local pData = mw.text.split(pStr, ',')
				local platform = {
					num = tonumber(mw.text.trim(pData[1])),
					route = tonumber(mw.text.trim(pData[2])),
					len = tonumber(mw.text.trim(pData[3]))
				}
				
				local smwPlatformVal = (platform.num or '') .. ';' .. (platform.route or '') .. ';' .. (platform.len and (platform.len .. ' m') or '')
				semanticData['Has platform'] = semanticData['Has platform'] or {}
				table.insert(semanticData['Has platform'], smwPlatformVal)
	
				local extras = {}
				if platform.route then
					table.insert(extras, 'route code ' .. platform.route)
				end
				if platform.len then
					table.insert(extras, platform.len .. ' m')
				end
	
				platform.display = 'P' .. (platform.num or '?')
				if #extras > 0 then
					platform.display = platform.display .. ' (' .. table.concat(extras, ', ') .. ')'
				end
	
				if platform.len then
					anyHaveLength = true
					if platform.len > maxLength then
						maxLength = platform.len
					end
				end
	
				table.insert(parsedPlatforms, platform)
			end
	    end
	    
	    if #parsedPlatforms > 0 then
			local row = tableElement:tag( 'tr' )
			row:tag( 'th' ):attr( 'scope', 'row' ):wikitext( 'Platforms' )
			
			if anyHaveLength then
        		local list = row:tag( 'td' )
        			:tag( 'ul' ):addClass( 'platforms-visualizer' )
    			list:tag( 'li' ):addClass( 'reference-train' ):addClass( 'reference-555' )
    				:css( 'width', (LENGTH_555/maxLength*100) .. '%' )
    				:wikitext( '[[Class 555|Class 555 for reference]]' )
    			list:tag( 'li' ):addClass( 'reference-train' ):addClass( 'reference-metrocar' )
    				:css( 'width', (LENGTH_METROCAR/maxLength*100) .. '%' )
    				:wikitext( '[[Metrocar|Metrocar for reference]]' )
			
		        for _, platform in ipairs(parsedPlatforms) do
		            if platform.len and platform.len > 0 then
		                local width = platform.len / maxLength * 100
		                list:tag('li'):addClass('reference-platform')
		                  :css('width', (platform.len/maxLength*100) .. '%')
		                  :attr('title', platform.display)
		                  :wikitext(platform.display)
		            else
		                list:tag('li'):attr('title', platform.display)
		                  :wikitext(platform.display)
		            end
		        end
			else
		        local texts = {}
		        for _, platform in ipairs(parsedPlatforms) do
		            platform.display = mw.ustring.gsub(platform.display, ' ', ' ') -- non-breaking space
            		table.insert(texts, platform.display)
		        end
				row:tag( 'td' ):wikitext(table.concat(texts, ', '))
			end
    	end
	end
	
	local smwResult = mw.smw.set( semanticData )
	if smwResult ~= true then
		tableElement:tag('tr')
			:tag('td')
			:attr('colspan', '2')
			:css('color', 'red')
			:css('font-weight', 'bold')
			:wikitext('SMW Error: ' .. smwResult.error)
	end
	
    return tableElement
end

return p