Module:Routelist row: Difference between revisions

Content deleted Content added
Jackmcbarn (talk | contribs)
m make this work with non-ASCII characters
drop nowrap - was causing horizontal scrolling on List of Ontario provincial highways for 407
 
(39 intermediate revisions by 6 users not shown)
Line 2:
local getArgs = require('Module:Arguments').getArgs -- Import module function to work with passed arguments
local lang = mw.getContentLanguage() -- Retrieve built-in locale for date formatting
local format = mw.ustring.format -- String formatting function
local frame = mw.getCurrentFrame()
 
local routeStates = { } -- Table with route statuses.
Line 32 ⟶ 34:
end
 
function getLengthdtsYearCore(argsdate, circa)
-- This function is passed the length fields from the {{routelist row}} invocation, and calculates the missing length from the other.
local math = require "Module:Math" -- This module contains functions needed later in this function.
local precision = math._precision -- The math._precision function provides the precision of a given string representing a number.
local round = math._precision_format -- This method rounds a given number to the given number of digits. In Lua, storing these functions locally results in more efficient execution.
local length = {} -- This table will store the computed lengths.
local km = args["length_km"] -- The kilometer length from the {{routelist row}} call.
local mi = args["length_mi"] -- The length in miles as passed to {{routelist row}}.
if not km then -- This signifies that a length in kilometers was not passed.
local n = tonumber(mi) -- The first step is to convert the miles (passed as a string from the template) into a number.
if n then -- If the passed mile value is an empty string, n will equal nil, which would make this statement false. Otherwise, the length in kilometers is computed and stored.
local prec = precision(mi) -- Retrieve the precision of the passed mile value (as a string).
length.km = round(tostring(n * 1.609344), tostring(prec)) -- Compute and round the length in kilometers, and store it in the length table.
else -- No mile value was passed
length.km = 0
end
else -- If the length in kilometers was passed, the computed lengths table will simply contain the passed length.
local prec = precision(km)
length.mi = round(km, tostring(prec))
end
if not mi then -- The same as above, but this time converting kilometers to mile if necessary.
local n = tonumber(km) -- Kilometers as a number
if n then -- If a kilometer value was passed:
local prec = precision(km) -- Precision of the passed length
length.mi = round(tostring(n / 1.609344), tostring(prec)) -- Compute and store the conversion into miles.
else -- If not:
length.mi = 0 -- Store 0.
end
else -- And if the length in miles was passed:
local prec = precision(mi) -- Get the precision...
length.mi = round(mi, tostring(prec)) -- and format it appropriately
end
return length -- Return the length table with the computed lengths.
end
 
function dtsYear(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.
if not date then return false end -- If the date is an empty string, stop and go back to whence it came.
Line 78 ⟶ 45:
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 spanParams = {style = "display:none; speak:none"} -- These CSS properties hide the sort key from normal view.
local dtsSpan = mw.text.tag({name='span', contentscontent=dtsStr, paramsattrs=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>" -- Add the circa abbreviation to the display. Derived from {{circa}}
else -- Otherwise,
return dtsSpan .. year -- Return the hidden sort key concatenated with the year for this date.
end
end
 
function dtsYear(date, circa)
local success, result = pcall(dtsYearCore, date, circa)
if success then
return result
else
return string.format('%s<span class="error">Error: Invalid date "%s".</span>', circa and '<abbr title="circa">c.</abbr>&thinsp;' or '', date)
end
end
Line 109 ⟶ 85:
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
if not suffix then error(route) end
routeKey = string.format('%04d', num) .. suffix
end
return type .. routeKey -- Return the sort key for this route, composed of the type and zero-padded route number.
Line 132 ⟶ 107:
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
if args.gazette == 'yes' then
return "|align=center|" .. formed(routeState, established, args.circa_established) ..
local established = args.established or "—"
established_ref .. "||align=center|" .. removed(routeState, decommissioned, args.circa_decommissioned) ..
local established_ref = args.established_ref or ''
decommissioned_ref
return "|align=center|" .. established .. established_ref
else
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
end
 
--- Return output for the length columns for a given route, with the appropriate conversions.
function length(args)
local function length(args)
-- This function generate the length columns, with the appropriate conversions.
local mileskm = args["length_milength_km"] or '' -- Length in mileskilometers
local kilometersmi = args["length_kmlength_mi"] or '' -- Length in kilometersmiles
local ref = args["length_ref" ] or ''
local lengths = {length_mi = miles, length_km = kilometers} -- This time, we compile the lengths into a table,
 
local Lengths = getLength(lengths) -- which makes for an easy parameter. This function call will return the lengths in both miles and kilometers,
if mi == '' and km == '' then
return format("|align=right|—||align=right|—")
local lengthRef = args["length_ref"] or ''
elseif mi ~= '0' and km == '' then
local first, second
return format("|align=right|") .. mi .. ref .. format("||align=right|") .. frame:expandTemplate{ title = 'convert', args = { mi, "mi", "km", disp = "output number only"}}
if kilometers then
first = Lengths.km
second = Lengths.mi
else
return format("|align=right|") .. km .. ref .. format("||align=right|") .. frame:expandTemplate{ title = 'convert', args = { km, "km", "mi", disp = "output number only"}}
first = Lengths.mi
second = Lengths.km
end
return "|align=right|" .. first .. lengthRef .. "||align=right|" .. second -- which are then spliced in here and returned to the template.
end
 
Line 178 ⟶ 157:
else
return '' --create no cell
end
end
 
function gap(args)
local text = args.text or "''Number not designated''"
if notes then
return '|align=center colspan=7|' .. text --display notes in cell
else
return '|align=center colspan=6|' .. text --display notes in cell
end
end
Line 187 ⟶ 176:
local parser = parserModule.parser
local doubleShieldTypesnoshield = {Both = true}args.noshield
local bannerFile = parser(args, 'banner')
local banner
if not noshield and bannerFile and bannerFile ~= '' then
local widthCode = parser(args, 'width') or 'square'
if widthCode == 'square' then
banner = format("[[File:%s|25px|link=|alt=]]", bannerFile)
elseif widthCode == 'expand' then
local route = args.route
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 shield
if doubleShieldTypes[args.type]not noshield then
local shieldFile1shieldFile, second = parser(args, 'shieldshieldlist') or parser(args, 1'shield') or ''
if shieldFile == nil or shieldFile == '' then
local shield1 = format("[[File:%s|x25px|alt=|link=]]", shieldFile1)
shield = ''
local shieldFile2 = parser(args, 'shield', 2)
elseif type(shieldFile) == 'table' then
local shield2 = format("[[File:%s|x25px|alt=|link=]]", shieldFile2)
shieldFile, second = shieldFile[1], shieldFile[2]
shield = shield1 .. shield2
end
if second and type(second) == 'string' then
local shield1 = format("[[File:%s|x25px|alt=|link=]]", shieldFile)
local shield2 = format("[[File:%s|x25px|alt=|link=]]", second)
shield = shield1 .. shield2
elseif shield == '' then
shield = ''
else
shield = shieldFile and format("[[File:%s|x25px|alt=|link=]]", shieldFile) or ''
end
else
shield = ''
local shieldFile = parser(args, 'shield')
shield = shieldFile and format("[[File:%s|x25px|alt=|link=]]", shieldFile) or ''
end
Line 208 ⟶ 252:
link = abbr
end
if not link then error("Type not in database: " .. args.type, 0) end
local sortkey = sortkey(args)
local sortedLink = format("<span styledata-sort-value=\"display:none\" class=\"sortkey\">%s&#32;!</span><span class=\"sorttext\">%s</span>", sortkey, link)
local route = banner .. shield .. ' ' .. sortedLink
return '!scope="row" class="nowrap"|' .. route
end
 
Line 232 ⟶ 276:
local row = {rowdef, route, length, termini, localname, dates, notes}
return table.concat(row, '\n')
end
 
function p.gap(frame)
local args = getArgs(frame) -- Gather passed arguments into easy-to-use table
 
local routeState = getRouteState(established, decommissioned)
local anchor = args.anchor or sortkey(args)
local rowdef = routeState.row .. string.format(' id="%s"', anchor)
local route = route(args)
local gap = gap(args)
local row = {rowdef, route, gap}
return table.concat(row, '\n')
end