Module:Routelist row: Difference between revisions

Content deleted Content added
taking sandbox 2 live
Tag: Reverted
Restored revision 1042981718 by Fredddie (talk): Shit
Line 1:
local p = { } -- Package to be exported
local getArgs = require('Module:Arguments').getArgs -- Import module function to work with passed arguments
 
local lang = mw.getContentLanguage() -- BuiltRetrieve 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 roadDataModule = require("Module:Road data/routelist")
local parserModule = require 'Module:Road data/parser'
local parser = parserModule.parser
 
local routeStates = { } -- Table with route statuses.
local shieldScale = 1
--[[ The following tables include the following entries:
 
row: The start of the row, for this particular type (color)
--[[-
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.
@type status
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.
@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.
routeStates.current = {row = "|-", removed = "current"} -- Data for current routes
For future routes, "proposed" is displayed here.
routeStates.future = {row = '|- style="background-color:#ffdead;" title="Future route"', established = "proposed", removed = "—"} -- Data for future routes
Otherwise, display the year passed in the established parameter.
routeStates.former = {row = '|- style="background-color:#d3d3d3;" title="Former route"'} -- Data for former routes
@field #string removed: The string to be output in the "Removed" column.
routeStates.formeroverride = {row = '|- style="background-color:#d3d3d3;" title="Former route"', removed = "—"} -- Data for routes marked as former by override
In the case of routeStates.former, the year that the route was
routeStates.unknown = {row = "|-", removed = "—"} -- Data for route with unknown status
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
 
function getRouteState(established, decommissioned)
--[[-
--[[ This function is passed the dates given for the established and decommissioned fields to the template.
A limited replacement for {{dts}}.
It then returns the entry in the routeStates table corresponding to the status of the route.
Derive the sort key from a given date.
]]--
@param #string date
if decommissioned == 'yes' then --If the decommissioned property just says "yes", then mark it as a former route and display default data.
@param #string circa "yes" if `date` is tagged as circa
return routeStates.formeroverride
@return #string true the hidden sort key, along with the year of the original date
elseif decommissioned then -- If the route is decommissioned, then it must be a former route.
@return #boolean false if the sort key cannot be derived
return routeStates.former
]]
elseif not established then -- Without the establishment date, there is not enough information to determine the status of the route.
local function dtsYearCore(date)
return routeStates.unknown
local year = lang:formatDate('Y', date) -- year for this date
ifelseif yearestablished == date'proposed' then -- If the provided"established date" is just the yearstring 'proposed', then it must be a future route.
return routeStates.future
-- tack on January 1 for the sort key to work right.
else -- If none of the first three conditions are true, then it must be a current route.
date = date .. "-01-01"
return routeStates.current
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 dtsYeardtsYearCore(date, circa)
-- A limited replacement for {{dts}}. This is passed a date and derives a sort key from it. It returns a string with the hidden sort key, along with the year of the original date.
local success, result = pcall(dtsYearCore, date)
if not date then return false end -- If the date is an empty string, stop and go back to whence it came.
if not success then
local year = lang:formatDate('Y', date) -- This invocation of lang:formatDate returns just the year.
result = {
if year == date then -- If the provided date is just the year:
"00001-01-01",
date = date .. "-01-01" -- Tack on January 1 for the sort key to work right.
util.err(format('Invalid date "%s".', date))
}
end
local month = lang:formatDate('m', date) -- Stores the month of the date.
-- Generate the HTML code necessary for the hidden sort key.
local day = lang:formatDate('d', date) -- Stores the day for this date.
local dtsStyle = format("style=\"white-space:nowrap;\" data-sort-value=\"%s\"", result[1])
local dtsStr = string.format("%05d-%02d-%02d", year, month, day) -- Create and store the formatted hidden sort key. The year must be five digits, per convention.
local year = result[2]
local spanParams = {style = "display:none; speak:none"} -- These CSS properties hide the sort key from normal view.
local dtsSpan = mw.text.tag({name='span', content=dtsStr, attrs=spanParams}) -- This generates the HTML code necessary for the hidden sort key.
if circa == 'yes' then -- If the date is tagged as circa,
return dtsSpan .. "<abbr title=\"circa\">c.</abbr><span style=\"white-space:nowrap;\">&thinsp;" .. year .. "</span>" -- addAdd the circa abbreviation to the display. Derived from {{circa}}.
else -- Otherwise,
year = "<span style=\"white-space:nowrap;\"><abbr title=\"circa\">c.</abbr>&thinsp;" .. year .. "</span>"
return dtsSpan .. year -- Return the hidden sort key concatenated with the year for this date.
end
return dtsStyle, year
end
 
function dtsYear(date, circa)
--- Return formatting and output for a date column.
local functionsuccess, dateresult = pcall(textdtsYearCore, date, circa, ref)
if success then
-- Returns the text if specified, or the dtsYear-formatted date, and an em-dash.
return result
local style, output
if text then
output = text
elseif date then
style, output = dtsYear(date, circa)
else
return string.format('%s<span class="error">Error: Invalid date "%s".</span>', circa and '<abbr title="circa">c.</abbr>&thinsp;' or '', date)
output = "—"
end
return format("|align=center %s|%s%s", style or "", output, ref)
end
 
function removed(routeState, decommissioned, circa)
--- Return output for the date columns for a given route.
-- This function returns the proper value for the removed column.
local function dates(established, decommissioned, routeStatus, args)
return routeState.removed or dtsYear(decommissioned, circa) -- Returns the removed attribute of the provided routeState table or, if empty, the dtsYear-formatted decommissioned date.
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
 
function formed(routeState, established, circa)
--- Return output for the termini columns for a given route.
-- This function returns the proper value for the formed column.
local function termini(args)
return routeState.established or dtsYear(established, circa) or "—" -- Returns 'proposed' if the route is proposed, the dtsYear-formatted established date if one was provided, or an em-dash.
local beltway = args["beltway"]
end
 
function sortkey(args)
-- This function return the sort key for the route (not to be confused with the previous function, which generates a sort key for the established and decommissioned dates.)
local key = args.sortkey
local type = args.type
local route = args.route or ''
if key then -- If a sort key already exists:
return key -- Simply return it.
else -- Otherwise:
local routeKey
local routeNum = tonumber(route)
if routeNum then
routeKey = string.format('%04d', route) -- This invocation is equivalent to the {{0000expr}} template. It zero-pads the given route number up to 4 digits.
else
local num, suffix = string.match(route, "(%d*)(.+)")
routeKey = (tonumber(num) and string.format('%04d', num) or '') .. suffix
end
return type .. routeKey -- Return the sort key for this route, composed of the type and zero-padded route number.
end
end
 
function termini(args)
-- This function determines if this is a beltway or not, and displays the termini columns appropriately.
local beltway = args["beltway"] -- Text in this parameter will span both termini columns.
local terminus_a = args["terminus_a"] or '—' -- Southern or western terminus
local terminus_b = args["terminus_b"] or '—' -- Northern or eastern terminus
if beltway then
return "|colspan=2 align=center|" .. beltway -- This text will, again, span both columns.
-- The given route is a beltway.
-- `beltway` text will span both termini columns.
return "|colspan=2 align=center|" .. beltway
else
localreturn terminus_a'|' =.. args["terminus_a"] or.. '||' .. terminus_b -- SouthernFill in orthe westerntermini terminuscolumns
local terminus_b = args["terminus_b"] or '—' -- Northern or eastern terminus
-- Fill in the termini columns
return '|' .. terminus_a .. '||' .. terminus_b
end
end
 
function dates(established, decommissioned, routeState, args)
-- This function displays the date columns.
local established_ref = args.established_ref or '' -- Reference for date established
local decommissioned_ref = args.decommissioned_ref or '' -- Reference for date decommissioned
return "|align=center|" .. formed(routeState, established, args.circa_established) ..
established_ref .. "||align=center|" .. removed(routeState, decommissioned, args.circa_decommissioned) ..
decommissioned_ref
end
 
Line 170 ⟶ 123:
return format("|align=right|—||align=right|—")
elseif mi ~= '0' and km == '' then
return format("|align=right|") .. mi .. ref .. format("||align=right|") .. frame:expandTemplate{ title = 'convert', args = { mi, "mi", "km", disp = "tableoutput number only"}}
else
return format("|align=right|") .. km .. ref .. format("||align=right|") .. frame:expandTemplate{ title = 'convert', args = { km, "km", "mi", disp = "tableoutput number only"}}
end
end
 
function localname(args)
 
--- GenerateThis function generates a "Local names" cell if necessary.
local function localname(args)
local enabled = args[1] or ''
iflocal enabledlocalName == args["local"] or then''
local if localNamemw.text.trim(enabled) == args["local"] or ''then
return "|" .. localName
else
Line 188 ⟶ 140:
end
 
function notes(notes)
--- Generate a "Notes" cell if necessary.
-- This function generates a "Notes" cell if necessary.
local function notes(notes)
if notes == 'none' then
return '| ' --create empty cell
Line 199 ⟶ 151:
end
 
function route(args)
--- Derive the sort key from a given route.
local -- This function sortkey(abbr)displays the shield and link.
local format = mw.ustring.format
-- Split `abbr` into three possibly empty parts, with number in the middle.
local parserModule = require "Module:Road data/parser"
local prefix, num, suffix = mw.ustring.match(abbr, "([^0-9]*)(%d*)(.*)")
local parser = parserModule.parser
-- 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
 
--- Return output for displaying the shield, banner, and link for a given route.
local function banner(args, bannerSize)
if args.marker_image then return nil end
local noshield = args.noshield
if args.shielderr then return nil end
local bannerFile = parser(args, 'banner')
local shield = parser(args, 'banner')
if not shieldnoshield orand shieldbannerFile =and bannerFile ~= '' then return nil end
local widthCode = parser(args, 'width') or 'square'
if widthCode == 'square' then
local alt = parser(args, 'banner')
banner = format("[[File:%s|25px|link=|alt=]]", bannerFile)
elseif widthCode == 'expand' then
return string.format('[[File:%s|%s|alt=%s|link=]]', shield, bannerSize, alt)
local route = args.route
end
if #route >= 3 then
banner = format("[[File:No image.svg|3px|link=|alt=]][[File:%s|25px|link=|alt=]][[File:No image.svg|3px|link=|alt=]]", bannerFile)
else
banner = format("[[File:%s|25px|link=|alt=]]", bannerFile)
end
elseif widthCode == 'wide' then
banner = format("[[File:No image.svg|3px|link=|alt=]][[File:%s|25px|link=|alt=]][[File:No image.svg|3px|link=|alt=]]", bannerFile)
elseif widthCode == 'MOSupp' then
local route = args.route
if #route >= 2 then
banner = format("[[File:No image.svg|3px|link=|alt=]][[File:%s|25px|link=|alt=]][[File:No image.svg|3px|link=|alt=]]", bannerFile)
else
banner = format("[[File:%s|25px|link=|alt=]]", bannerFile)
end
elseif widthCode == 'US1926' then
banner = format("[[File:%s|25px|link=|alt=]][[File:No image.svg|1px|link=|alt=]]", bannerFile)
elseif args.state == 'CA' then
local route = args.route
local type = args.type
if type == 'US-Bus' then
if #route >= 3 then
banner = format("[[File:No image.svg|2px|link=|alt=]][[File:%s|25px|link=|alt=]][[File:No image.svg|2px|link=|alt=]]", bannerFile)
else
banner = format("[[File:%s|25px|link=|alt=]]", bannerFile)
end
elseif type == 'CA-Bus' or type == 'SR-Bus' then
if #route >= 3 then
banner = format("[[File:No image.svg|1px|link=|alt=]][[File:%s|25px|link=|alt=]][[File:No image.svg|2px|link=|alt=]]", bannerFile)
else
banner = format("[[File:%s|24px|link=|alt=]]", bannerFile)
end
end
end
banner = banner .. '<br>'
else
banner = ''
end
 
local function shield(args, shieldSize)
if not noshield then
if args.marker_image then return args.marker_image end
local shieldFile, second = parser(args, 'shield')
 
if type(shieldFile) == 'table' then
local shield = parser(args, 'shieldlist') or parser(args, 'shield')
shieldFile, second = shieldFile[1], shieldFile[2]
end
if not shield or shield == '' then return nil end
if second and type(second) == 'string' then
local shield1 = format("[[File:%s|x25px|alt=|link=]]", shieldFile)
local label = parser(args, 'name') or parser(args, 'abbr') or ''
local shield2 = format("[[File:%s|x25px|alt=|link=]]", second)
local alt = label .. ' marker'
shield = shield1 .. shield2
local orientation = parser(args, 'orientation')
local function shield_size(image_name, orientation)
local image = 'File:' .. image_name
local title = mw.title.new(image)
 
local width = title.file.width
local height = title.file.height
if (orientation and orientation == 'upright') or height > width then
return shieldSize
else
shield = shieldFile and format("[[File:%s|x25px|alt=|link=]]", shieldFile) or ''
return 'x' .. shieldSize
end
else
shield = ''
end
local linkTarget = (not args.nolink) and parser(args, 'link')
if type(shield) == 'table' then
local resabbr = {}parser(args, 'abbr')
local sizes = {}link
if linkTarget then
for i,v in ipairs(shield) do
link = format("[[%s|%s]]", linkTarget, abbr)
sizes[i] = v
res[i] = string.format('[[File:%s|%s|alt=%s|link=]]', v, shield_size(v), alt)
end
return table.concat(res, '')
else
link = abbr
return string.format('[[File:%s|%s|alt=%s|link=]]', shield, shield_size(shield, orientation), alt)
end
if not link then error("Type not in database: " .. args.type) end
local sortkey = sortkey(args)
local sortedLink = format("<span data-sort-value=\"%s&#32;!\">%s</span>", sortkey, link)
local route = banner .. shield .. ' ' .. sortedLink
return '!scope="row" class="nowrap"|' .. route
end
 
local function routep.row(args, shieldSizeframe)
local args = getArgs(frame) -- Gather passed arguments into easy-to-use table
local link, abbr = roadDataModule.link(args)
-- Use the sort key if already specified.
local sortkey = args.sortkey or sortkey(abbr or "")
local banner = banner(args, require('Module:Road data/size').size({style = "list"}))
local shield = shield(args, require('Module:Road data/size').size({style = "list"}))
local container = mw.html.create('span'):cssText('display: inline-block; vertical-align: baseline; line-height: 0; text-align: center;'):wikitext(banner):wikitext("<br>"):wikitext(shield)
 
return format('!scope="row" class="nowrap" data-sort-value="%s"|%s %s',
sortkey, tostring(container), link)
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 routeStatusrouteState = getRouteStatusgetRouteState(established, decommissioned)
local anchor = args.anchor or anchorsortkey(args.type, args.route)
local rowdef = routeState.row .. string.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, routeStatusrouteState, args)
local notesnotesArg = notes(args.notes)
local notes = notes(notesArg)
 
local row = {rowdef, route, length, termini, localname, dates, notes}
return table.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