Module:Routelist row/sandbox 2

local p = {} -- Package to be exported

-- Change to "" upon deployment.
local moduleSuffix = ""

local lang = mw.getContentLanguage() -- Built-in locale for date formatting
local format = mw.ustring.format -- String formatting function
local insert = table.insert
local concat = table.concat
local util = require("Module:Road data/util")
local frame = mw.getCurrentFrame()

local parserModuleName = "Module:Road data/parser" .. moduleSuffix
local statenameModuleName = "Module:Jct/statename" .. moduleSuffix -- TODO transition

local concat = table.concat
local insert = table.insert
local format = mw.ustring.format
local trim = mw.text.trim

local parserModule = require(parserModuleName)
local parser = parserModule.parser

-- Shields
local defaultShieldSize = 28

local function addContextBanner(args, name, suffix, bannerSpec)
	local bannerModule = 'Module:Road data/banners/' .. string.upper(args.country)
	local shieldfield = name .. 'shield'
	local shield = parser(args, shieldfield)
	if shield == nil then
		-- This route type does not define shield.
		-- Find shield in the default banner table.
		shield = parser(args, 'shield', name, bannerModule)
		if shield and shield ~= '' then
			if suffix == nil then
				suffix = parser(args, 'shield', 'suffix', bannerModule)
			end
			if suffix and suffix ~= '' then
				shield = shield .. " " .. suffix
			end
			shield = shield .. ".svg"
		end
	end
	if shield and shield ~= '' then
		local shieldSize = defaultShieldSize
		-- Add banner plate.
		insert(bannerSpec, {shield, shieldSize})
	end
end

local function bannerSpec(banner, bannerSize, bannerSuffix, route)
	local banners = {}
	if type(banner) == "table" then
		local bannerSizeIsNotTable = type(bannerSize) ~= "table"
		for i,filename in ipairs(banner) do
			local bannersize = bannerSizeIsNotTable and bannerSize or bannerSize[i] or defaultShieldSize
			insert(banners, {filename, bannersize})
		end
	elseif banner ~= '' then
		insert(banners, {banner, bannerSize})
	end

	return banners
end

local function shieldSpec(args, mainShield, shieldList)
	local shieldSpec = {}

	local shield

	if not shield then shield = parser(args, 'shieldlist') or parser(args, 'shield') or '' end
	
	if shield == '' then return shieldSpec end
	
	local orientation = parser(args, 'orientation')

	local function size(args)
		if orientation == "upright" then
			return defaultShieldSize
			else return "x" .. defaultShieldSize
		end
	end
	
	local shieldsize = size(args)
	
	local banner = parser(args, 'banner') or {}
	local bannersize = defaultShieldSize
	local bannersuffix = parser(args, 'bannersuffix')

	local bannerIsNotTable = type(banner) ~= "table"
	local bannersizeIsNotTable = type(bannersize) ~= "table"
	local bannersuffixIsNotTable = type(bannersuffix) ~= "table"

	if type(shield) == "table" then
		for i,filename in ipairs(shield) do
			local size = shieldsize[i] or shieldsize
			if size == "" then size = nil end
			-- banner.all describes banners that apply to all multiple shields.
			local shieldBanner = bannerIsNotTable and banner or (banner[i] or banner.all or {})
			-- Banner size is default if the corresponding entry
			-- in bannerSize table is not set.
			local shieldBannerSize =
				bannersizeIsNotTable and bannersize
				or (bannersize[i] or bannersize.all or defaultShieldSize)
			local shieldBannerSuffix = bannersuffix and (bannersuffixIsNotTable and bannersuffix or bannersuffix[i])
			insert(shieldSpec, {
				shield = {filename, size},
				banners = bannerSpec(shieldBanner, shieldBannerSize, shieldBannerSuffix, route)
			})
		end
	elseif shield ~= '' then
		if shieldsize == "" then shieldsize = nil end
		insert(shieldSpec, {
			shield = {shield, shieldsize},
			banners = bannerSpec(banner, bannersize,  bannersuffix, route)
		})
	end

	return shieldSpec
end

local missingShields

local shieldExistsCache = {}

local function render(shieldEntry, scale, showLink)
	local shield = shieldEntry.shield
	local banners = shieldEntry.banners

	local size
	if shield[2] then
		local width, height = mw.ustring.match(shield[2], "(%d*)x?(%d*)")
		width = tonumber(width)
		height = tonumber(height)
		local sizeparts = {}
		if width then
			insert(sizeparts, format("%d", width * scale))
		end
		if height then
			insert(sizeparts, format("x%d", height * scale))
		end
		size = concat(sizeparts)
	else
		size = format("%s%d", landscape and "x" or "", defaultShieldSize * scale)
	end
	local shieldCode = format("[[File:%s|%spx|link=|alt=]]", shield[1], size)
	if not banners[1] then return shieldCode end

	for _,banner in ipairs(banners) do
		shieldCode = format("[[File:%s|%spx|link=|alt=]]<br>%s",
			banner[1],
			defaultShieldSize,
			shieldCode)
	end
	return '<span style="display: inline-block; vertical-align: baseline; line-height: 0; text-align: center;">' .. shieldCode .. '</span>'
end

function p.shield(args, scale, showLink, mainShield, shieldList)
	missingShields = {}

	scale = scale or 1

	local rendered = {}
	for _,entry in ipairs(shieldSpec(args, mainShield, shieldList)) do
		insert(rendered, render(entry, scale, showLink))
	end
	return concat(rendered), missingShields
end

-- Links/abbreviations
function p.link(args)
	local nolink = args.nolink
	local abbr = parser(args, 'abbr')
	if nolink then
		return abbr
	else
		local link = parser(args, 'link')
		if not link or link == '' then
			return abbr
		else
			return format("[[%s|%s]]", link, abbr)
		end
	end
end

local function stateName(args)
	-- TODO transition
	local data = mw.loadData(statenameModuleName) 
	local abbr = args.state or args.province
	local countryData = data[args.country]
	return countryData and countryData[abbr]
end

--------------------------
--[[-
@type status
@field #string row: The start of the row, for this particular type (color)
@field #string established: The string to be output in the "Formed" column.
	For future routes, "proposed" is displayed here.
	Otherwise, display the year passed in the established parameter.
@field #string removed: The string to be output in the "Removed" column.
	In the case of routeStates.former, the year that the route was
	decommissioned is output instead.
]]
--[[-
Route statuses.
@list <#status>
]]
local routeStatuses = {
	-- current routes
	current = {
		row = "|-",
		removed = "current"
	},
	-- future routes
	future = {
		row = '|- style="background-color:#ffdead;" title="Future route"',
		established = "proposed",
		removed = "—"
	},
	-- former routes
	former = {
		row = '|- style="background-color:#d3d3d3;" title="Former route"'
	},
	-- routes marked as former by override
	-- deprecated
	formeroverride = {
		row = '|- style="background-color:#d3d3d3;" title="Former route"',
		removed = "—"
	},
	-- route with unknown status
	unknown = {
		row = "|-",
		removed = "—"
	} 
}

--[[-
Return the route status.
@param #string established `established` argument passed to the module
@param #string decommissioned `decommissioned` argument passed to the module
@return #status the status of the route.
]]
local function getRouteStatus(established, decommissioned)
	if decommissioned == 'yes' then
		-- a former route with no decommission information
		return routeStatuses.formeroverride
	elseif decommissioned then
		-- If the route is decommissioned, then it must be a former route.
		return routeStatuses.former
	elseif not established then
		-- Without the establishment date, there is not enough information
		-- to determine the status of the route.
		return routeStatuses.unknown
	elseif established == 'proposed' then
		-- a future route
		return routeStatuses.future
	else
		-- a current route
		return routeStatuses.current
	end
end

--[[-
A limited replacement for {{dts}}.
Derive the sort key from a given date.
@param #string date
@param #string circa "yes" if `date` is tagged as circa
@return #string true the hidden sort key, along with the year of the original date
@return #boolean false if the sort key cannot be derived
]]
local function dtsYearCore(date)
	local year = lang:formatDate('Y', date) -- year for this date
	if year == date then -- If the provided date is just the year,
		-- tack on January 1 for the sort key to work right.
		date = date .. "-01-01"
	end
	local month = lang:formatDate('m', date) -- month for this date
	local day = lang:formatDate('d', date) -- day for this date
	-- Create and store the formatted hidden sort key.
	-- The year must be five digits, per convention.
	local dtsStr = format("%05d-%02d-%02d", year, month, day)
	-- Return the hidden sort key and the year for this date.
	return {dtsStr, year}
end

local function dtsYear(date, circa)
	local success, result = pcall(dtsYearCore, date)
	if not success then
		result = {
			"00001-01-01",
			util.err(format('Invalid date "%s".', date))
		}
	end
	-- Generate the HTML code necessary for the hidden sort key.
	local dtsStyle = format("style=\"white-space:nowrap;\" data-sort-value=\"%s\"", result[1])
	local year = result[2]
	if circa == 'yes' then -- If the date is tagged as circa,
		-- add the circa abbreviation to the display. Derived from {{circa}}.
		year = "<span style=\"white-space:nowrap;\"><abbr title=\"circa\">c.</abbr>&thinsp;" .. year .. "</span>"
	end
	return dtsStyle, year
end

--- Return formatting and output for a date column.
local function date(text, date, circa, ref)
	-- Returns the text if specified, or the dtsYear-formatted date, and an em-dash.
	local style, output
	if text then
		output = text
	elseif date then
		style, output = dtsYear(date, circa)
	else
		output = "—"
	end
	return format("|align=center %s|%s%s", style or "", output, ref)
end

--- Return output for the date columns for a given route.
local function dates(established, decommissioned, routeStatus, args)
	local established_ref = args.established_ref or '' -- Reference for date established
	local decommissioned_ref = args.decommissioned_ref or '' -- Reference for date decommissioned
	return format("%s\n%s",
		date(routeStatus.established, established, args.circa_established, established_ref),
		date(routeStatus.removed, decommissioned, args.circa_decommissioned, decommissioned_ref))
end

--- Return output for the termini columns for a given route.
local function termini(args)
	local beltway = args["beltway"]
	if beltway then
		-- The given route is a beltway. 
		-- `beltway` text will span both termini columns.
		return "|colspan=2 align=center|" .. beltway
	else
		local terminus_a = args["terminus_a"] or '—' -- Southern or western terminus
		local terminus_b = args["terminus_b"] or '—' -- Northern or eastern terminus
		-- Fill in the termini columns
		return '|' .. terminus_a .. '||' .. terminus_b
	end
end

--- Return output for the length columns for a given route, with the appropriate conversions.
local function length(args)
	local km = args["length_km"] or '' -- Length in kilometers
    local mi = args["length_mi"] or '' -- Length in miles
    local ref = args["length_ref" ] or ''

    if mi == '' and km == '' then
        return format("|align=right|—||align=right|—")
	elseif mi ~= '0' and km == '' then
		return format("|") .. frame:expandTemplate{ title = 'convert', args = { mi, "mi", "km", disp = "table"}}
	else
		return format("|") .. frame:expandTemplate{ title = 'convert', args = { km, "km", "mi", disp = "table"}}
	end
end


--- Generate a "Local names" cell if necessary.
local function localname(args)
	local enabled = args[1] or ''
	if enabled == "local" then
		local localName = args["local"] or ''
		return "|" .. localName
	else
		return ''
	end
end

--- Generate a "Notes" cell if necessary.
local function notes(notes)
	if notes == 'none' then
		return '| ' --create empty cell
	elseif notes then
		return '|' .. notes --display notes in cell
	else
		return '' --create no cell
	end
end

--- Derive the sort key from a given route.
local function sortkey(abbr)
	-- Split `abbr` into three possibly empty parts, with number in the middle.
	local prefix, num, suffix = mw.ustring.match(abbr, "([^0-9]*)(%d*)(.*)")
	-- If `abbr` does not contain a number, the entry appears at the bottom.
	num = tonumber(num)
	num = type(num) == "number" and format("%04d", num) or ""
	-- The sort key is `abbr`, but with route number zero-padded to 4 digits
	-- and prefix moved to the end.
	return mw.text.trim(
		mw.ustring.gsub(format("%s%s %s", num, suffix, prefix), "&nbsp;", " "),
		"- ")
end

local function route(args, shieldSize)
	local link, abbr = p.link(args)
	-- Use the sort key if already specified.
	local sortkey = args.sortkey or sortkey(abbr or "")
	local shield = p.shield(args)

	if shield == nil or args.noshield then
		return format('!scope="row" class="nowrap" data-sort-value="%s"|%s',
			sortkey, link)
	else
		return format('!scope="row" class="nowrap" data-sort-value="%s"|%s %s',
			sortkey, shield, link)
	end
end

--- Derive the anchor from a given route.
local function anchor(routeType, routeNo)
	-- Split `routeNo` into three possibly empty parts, with number in the middle.
	local prefix, num, suffix = mw.ustring.match(routeNo, "([^0-9]*)(%d*)(.*)")
	-- Zero-pad route number to 4 digits if `routeNo` does contain a number.
	num = tonumber(num)
	num = type(num) == "number" and format("%04d", num) or ""
	-- The anchor is the concatenation of `type` and zero-padded `routeNo`.
	return format("%s%s%s%s", routeType, prefix, num, suffix)
end

function p._row(args)
	local established = args.established
	local decommissioned = args.decommissioned
	local routeStatus = getRouteStatus(established, decommissioned)
	local anchor = args.anchor or anchor(args.type, args.route)
	local rowdef = format('%s id="%s"', routeStatus.row, anchor)
	local route = route(args)
	local length = length(args)
	local termini = termini(args)
	local localname = localname(args)
	local dates = dates(established, decommissioned, routeStatus, args)
	local notes = notes(args.notes)

	local row = {rowdef, route, length, termini, localname, dates, notes}
	return concat(row, '\n')
end

function p.row(frame)
	-- Import module function to work with passed arguments
	local getArgs = require('Module:Arguments').getArgs
	local args = getArgs(frame) -- Gather passed arguments into easy-to-use table
	return p._row(args);
end

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.