Module:Jctint/sandbox: Difference between revisions
Appearance
Content deleted Content added
m Removed unused new parameter. |
Sync with live version |
||
Line 8: | Line 8: | ||
-- Local version of string formatting function |
-- Local version of string formatting function |
||
local format = mw.ustring.format |
local format = mw.ustring.format |
||
-- Store |
-- Store this function in a local variable to avoid expensive table lookups. |
||
local concat = table.concat |
|||
local insert = table.insert |
local insert = table.insert |
||
-- Road data functions |
|||
local roadDataModule = require("Module:Road data") |
|||
-- Road data utility functions |
|||
local util = require("Module:Road data/util") |
|||
-- mw.html object for the generated row |
-- mw.html object for the generated row |
||
Line 20: | Line 15: | ||
-- Default row span for all columns (`jspan` = "junction span") |
-- Default row span for all columns (`jspan` = "junction span") |
||
local jspan |
local jspan |
||
-- Any error messages produced that will be added to the output |
|||
local errorMsg = {} |
|||
-- Error types |
|||
local errorTypes = { |
|||
convert = {cat = "Category:Jctint template using non-numeric parameter values", prefix = "#"}, |
|||
type = {cat = "Category:Jctint template with invalid type"} |
|||
} |
|||
-- Error messages to be added to the output |
|||
local errors = {} |
|||
-- A specification for self-closing HTML tag. |
-- A specification for self-closing HTML tag. |
||
Line 40: | Line 28: | ||
-- Import module to convert length. |
-- Import module to convert length. |
||
local util = require("Module:Road data/util") |
|||
local lengths = util.convertLengths({[unitdef] = unit}) |
local lengths = util.convertLengths({[unitdef] = unit}) |
||
if lengths.error then -- An error occurred during conversion. |
if lengths.error then -- An error occurred during conversion. |
||
-- Add the transcluding page to an error tracking category. |
|||
errors.convert = lengths.error |
|||
local page = mw.title.getCurrentTitle() -- Get transcluding page's title |
|||
local pagename = page.prefixedText -- Extract page's full title as string |
|||
-- Create category string |
|||
local category = format("[[Category:Jctint template using non-numeric parameter values|# %s]]", pagename) |
|||
insert(errorMsg, category) -- Add error category to error message table. |
|||
end |
end |
||
return lengths |
return lengths |
||
end |
|||
--- Prepare wikitext for a given location cell. |
|||
local function locnSub(args, config, subType) |
|||
local locns = {warnings = {}} |
|||
local origParam |
|||
local group |
|||
local subTypeConfig = config[subType .. "_params"] or {subType} |
|||
if args[subType .. "_special"] then |
|||
locns[subType] = args[subType .. "_special"] |
|||
return locns |
|||
end |
|||
local paramPrefix = subTypeConfig[#subTypeConfig] |
|||
if paramPrefix and args[paramPrefix .. "_special"] then |
|||
locns[subType] = args[paramPrefix .. "_special"] |
|||
return locns |
|||
end |
|||
-- Find parameter. |
|||
for _,p in ipairs(subTypeConfig) do |
|||
if args[p] then |
|||
origParam = p |
|||
group = false |
|||
break |
|||
elseif args[p .. 1] then |
|||
origParam = p |
|||
group = true |
|||
break |
|||
end |
|||
end |
|||
if origParam then |
|||
local subParts = {} |
|||
-- Retrieve wikilinks for subdivisions. |
|||
local num = 1 |
|||
local paramSuffix = group and num or "" |
|||
while num == 1 or group and args[origParam .. paramSuffix] do |
|||
local param = origParam |
|||
local saved = {} |
|||
saved[param] = args[param] or false |
|||
args[param] = args[origParam .. paramSuffix] |
|||
if subType == "sub1" then |
|||
-- Handle sub1area |
|||
local sub1area_param = config.sub1area_param or "sub1area" |
|||
saved.sub1area = args.sub1area or false |
|||
args.sub1area = args[sub1area_param .. paramSuffix] |
|||
elseif subType == "sub2" then |
|||
-- Handle sub1dab and sub2area |
|||
local sub1dab_param = config.sub1dab_param or "sub1dab" |
|||
saved.sub1dab = args.sub1dab or false |
|||
args.sub1dab = args[sub1dab_param .. paramSuffix] or args[sub1dab_param] |
|||
local sub2area_param = config.sub2area_param or "sub2area" |
|||
saved.sub2area = args.sub2area or false |
|||
args.sub2area = args[sub2area_param .. paramSuffix] |
|||
end |
|||
while config[param] and config[param].alias do |
|||
-- Resolve alias and save parameters. |
|||
for key,value in pairs(config[param].alias) do |
|||
if key == "param" then |
|||
saved[value] = args[value] or false |
|||
args[value] = args[param] |
|||
param = value |
|||
else |
|||
saved[key] = args[key] or false |
|||
args[key] = value |
|||
end |
|||
end |
|||
end |
|||
local subTypeCall = roadDataModule.locations(args, "jctint", group) |
|||
insert(subParts, subTypeCall[subType]) |
|||
util.addAll(locns.warnings, subTypeCall.warnings, true) |
|||
-- Restore parameters. |
|||
for key,value in pairs(saved) do |
|||
args[key] = value or nil |
|||
end |
|||
num = num + 1 |
|||
paramSuffix = group and num or "" |
|||
end |
|||
if group then |
|||
if #subParts > 1 then |
|||
-- Construct wikitext for multiple subs. |
|||
local textParts = {} |
|||
insert(textParts, subParts[1]) |
|||
for i = 2, #subParts do |
|||
insert(textParts, "–") |
|||
if i % 2 ~= 0 then |
|||
-- Odd subs after first begin a new line. |
|||
insert(textParts, "<br>") |
|||
end |
|||
insert(textParts, subParts[i]) |
|||
end |
|||
local groupSuffix = args[origParam .. "_group"] or config[origParam] and config[origParam].group |
|||
if groupSuffix then |
|||
insert(textParts, |
|||
format("%s%s", #subParts % 2 == 0 and "<br>" or " ", groupSuffix)) |
|||
end |
|||
if #subParts == 2 then |
|||
local borderSuffix = config.bordersuffix or "border" |
|||
if borderSuffix ~= "" then |
|||
insert(textParts, " " .. borderSuffix) |
|||
end |
|||
elseif #subParts == 3 then |
|||
insert(textParts, " tripoint") |
|||
elseif #subParts == 4 then |
|||
insert(textParts, " quadripoint") |
|||
else |
|||
insert(textParts, " [[Quadripoint#Multipoints of greater numerical complexity|multipoint]]") |
|||
end |
|||
locns[subType] = concat(textParts) |
|||
else |
|||
locns.warnings.group = "Singleton list for " .. origParam |
|||
end |
|||
else |
|||
locns[subType] = concat(subParts) |
|||
end |
|||
end |
|||
return locns |
|||
end |
|||
--- Prepare wikitext for location cells. |
|||
local function locns(args) |
|||
local parserModule = require(parserModuleName) |
|||
local config = parserModule.parser(args, "jctrow", " config ") or {} |
|||
local locns = {warnings = {}} |
|||
local regionCall = roadDataModule.locations(args, "jctint") |
|||
locns.region = regionCall.region |
|||
util.addAll(locns.warnings, regionCall.warnings, true) |
|||
local indepCityCall = locnSub(args, config, "indep_city") |
|||
locns.indep_city = indepCityCall.indep_city |
|||
util.addAll(locns.warnings, indepCityCall.warnings, true) |
|||
if locns.indep_city then return locns end |
|||
local sub1Call = locnSub(args, config, "sub1") |
|||
locns.sub1 = sub1Call.sub1 |
|||
util.addAll(locns.warnings, sub1Call.warnings, true) |
|||
local sub2Call = locnSub(args, config, "sub2") |
|||
locns.sub2 = sub2Call.sub2 |
|||
util.addAll(locns.warnings, sub2Call.warnings, true) |
|||
return locns |
|||
end |
end |
||
Line 203: | Line 55: | ||
end |
end |
||
-- Prepare text for location cells. |
|||
local locns = locns(args) |
|||
-- Create cells for regular location columns. |
-- Create cells for regular location columns. |
||
-- |
-- Region, for disambiguation and potentially for display |
||
local |
local region = args.region |
||
if |
if region or args.region_special then |
||
-- Row span for region; must be specified to display a region cell. |
|||
local regionSpan = args.regionspan |
|||
if regionSpan then |
|||
-- Store region text in the cell. |
|||
row:tag('td') -- Create a region cell |
|||
-- `region_special` argument overrides wikilinked `region` argument. |
|||
:attr('rowspan', regionSpan) |
|||
:wikitext(args.region_special or locns.region) |
|||
-- Store region text in the cell. |
|||
-- `region_special` argument overrides wikilinked `region` argument. |
|||
:wikitext(args.region_special or format("[[%s]]", region)) |
|||
end |
|||
end |
end |
||
-- Primary topic requires no specialization to supplied locations. |
|||
local primaryTopic = args.primary_topic ~= 'no' |
|||
-- Note below main text in the next column |
-- Note below main text in the next column |
||
Line 223: | Line 80: | ||
-- Independent city |
-- Independent city |
||
local indepCityText |
local indepCityText -- Value to span both subdivision columns. |
||
if args.indep_city_special then |
|||
indepCityText = args.indep_city_special -- Overrides `indep_city` argument. |
|||
elseif args.indep_city then |
|||
local indepCity = args.indep_city |
|||
local cityLink -- Wikilink for independent city |
|||
if primaryTopic then |
|||
cityLink = format('[[%s]]', indepCity) |
|||
elseif region then |
|||
-- Specialize independent city to the region. |
|||
cityLink = format('[[%s, %s|%s]]', indepCity, region, indepCity) |
|||
end |
|||
if cityLink then |
|||
indepCityText = "[[Independent city|City]] of " .. cityLink |
|||
end |
|||
end |
|||
if indepCityText then -- Display independent city. |
if indepCityText then -- Display independent city. |
||
-- Text alignment of the cell contents, default to "left". |
-- Text alignment of the cell contents, default to "left". |
||
Line 243: | Line 115: | ||
-- First-level subdivision, e.g., county |
-- First-level subdivision, e.g., county |
||
-- Name of the type of subdivision, e.g., "County" and "Parish" |
|||
local sub1name = args.sub1name -- check existence later |
|||
local sub1Text -- Value for first-level subdivision column. |
|||
if args.sub1_special then |
|||
sub1Text = args.sub1_special -- Overrides `sub1` argument. |
|||
elseif args.sub1 then |
|||
local sub1 = args.sub1 |
|||
if primaryTopic then |
|||
-- Add type (if specified) to wikilink for first-level subdivision. |
|||
local sub1Link = sub1name and format("%s %s", sub1, sub1name) or sub1 |
|||
sub1Text = format('[[%s|%s]]', sub1Link, sub1) |
|||
elseif region and sub1name then |
|||
-- Specialize first-level subdivision, with type added, to the region. |
|||
sub1Text = format('[[%s %s, %s|%s]]', sub1, sub1name, region, sub1) |
|||
end |
|||
end |
|||
if sub1Text then -- Display first-level subdivision. |
if sub1Text then -- Display first-level subdivision. |
||
-- Row span for first-level subdivision, default to `jspan`. |
-- Row span for first-level subdivision, default to `jspan`. |
||
Line 258: | Line 145: | ||
-- Second-level subdivision, e.g., city and town |
-- Second-level subdivision, e.g., city and town |
||
local sub2Text |
local sub2Text -- Value for second-level subdivision column. |
||
if args.sub2_special then |
|||
sub2Text = args.sub2_special -- Overrides `sub2` argument. |
|||
elseif args.sub2 then |
|||
local sub2 = args.sub2 |
|||
if sub2 == "none" or sub2 == " " then |
|||
sub2Text = "​" -- Zero-width space |
|||
elseif primaryTopic then |
|||
sub2Text = format("[[%s]]", sub2) |
|||
else |
|||
local sub2Link = {sub2} |
|||
local sub2Name = sub2 |
|||
-- Type of area, e.g., city and village, as a form of disambiguation |
|||
local area = args.area |
|||
if area then |
|||
insert(sub2Link, format(' (%s)', area)) -- Add area to wikilink. |
|||
local areas = { -- table of different area types |
|||
borough = "Borough", |
|||
city = "City", |
|||
community = "Community", |
|||
CDP = "Community", |
|||
hamlet = "Hamlet", |
|||
town = "Town", |
|||
village = "Village", |
|||
["unorganized territory"] = "Unorganized Territory" |
|||
} |
|||
-- Add area name to displayed wikitext. |
|||
sub2Name = format("%s of %s", areas[area], sub2Name) |
|||
end |
|||
insert(sub2Link, ", ") |
|||
-- Some second-level subdivisions are not unique in a given region. |
|||
-- `sub1dab` is the first-level subdivision to be used for disambiguation. |
|||
local sub1dab = args.sub1dab |
|||
if sub1dab and sub1name then |
|||
insert(sub2Link, format('%s %s, ', sub1dab, sub1name)) |
|||
end |
|||
if region then |
|||
insert(sub2Link, region) -- Add region to wikilink |
|||
end |
|||
sub2Text = format("[[%s|%s]]", table.concat(sub2Link), sub2Name) |
|||
end |
|||
end |
|||
if sub2Text then -- Display second-level subdivision. |
if sub2Text then -- Display second-level subdivision. |
||
row:tag('td') -- Create second-level subdivision cell |
row:tag('td') -- Create second-level subdivision cell |
||
Line 296: | Line 225: | ||
:attr('rowspan', uspan) |
:attr('rowspan', uspan) |
||
-- Store the primary distance and any conversion error message in the cell. |
-- Store the primary distance and any conversion error message in the cell. |
||
:wikitext(lengths[lengths.orig]) |
:wikitext(lengths[lengths.orig], lengths.error) |
||
local secondary = row:tag(' |
local secondary = row:tag('td') -- Create the secondary unit cell. |
||
:css('text-align', 'right') |
:css('text-align', 'right') |
||
:css('background-color', '#eaecf0') |
|||
:attr('rowspan', uspan) |
:attr('rowspan', uspan) |
||
:wikitext(lengths[lengths.comp]) -- Store the secondary distance in the cell. |
:wikitext(lengths[lengths.comp]) -- Store the secondary distance in the cell. |
||
local unit_ref = args.unit_ref |
|||
if unit_ref then -- A reference is provided for the distance. |
|||
primary:wikitext(unit_ref) -- Add reference to the primary distance cell. |
|||
end |
|||
local unit2 = args.unit2 |
local unit2 = args.unit2 |
||
Line 317: | Line 252: | ||
local lengths2 = convert(unit2, unitdef) |
local lengths2 = convert(unit2, unitdef) |
||
-- Add the second distance and any conversion error message to the primary distance cell. |
-- Add the second distance and any conversion error message to the primary distance cell. |
||
primary:wikitext(lengths2[lengths2.orig]) |
primary:wikitext(lengths2[lengths2.orig], lengths2.error) |
||
-- Add the converted second distance to the secondary distance cell. |
-- Add the converted second distance to the secondary distance cell. |
||
secondary:wikitext(lengths2[lengths2.comp]) |
secondary:wikitext(lengths2[lengths2.comp]) |
||
end |
end |
||
local |
local unit2_ref = args.unit2_ref |
||
if |
if unit2_ref then -- A reference is provided for the distance. |
||
primary:wikitext( |
primary:wikitext(unit2_ref) -- Add reference to the primary distance cell. |
||
end |
end |
||
end |
end |
||
end |
end |
||
-- Color specified by any supplied type |
|||
-- Spec for formatting cell background colors and tooltip based on types |
|||
local |
local color |
||
-- Tooltip specified by any supplied type |
|||
local title |
|||
--- Apply any type-derived coloring and tooltip to the given cell. |
--- Apply any type-derived coloring and tooltip to the given cell. |
||
local function applyTypeStyle(cell |
local function applyTypeStyle(cell) |
||
cell:attr('title', |
cell:attr('title', title):css('background-color', color) |
||
:css('background', multiple and typesSpec.colors or typesSpec.color) |
|||
if multiple and typesSpec.minWidth then |
|||
-- minimum cell width to make enough room for all colors |
|||
cell:css('min-width', format('%dpx', typesSpec.minWidth)) |
|||
end |
|||
end |
end |
||
Line 362: | Line 294: | ||
:attr('rowspan', pspan) |
:attr('rowspan', pspan) |
||
:wikitext(place) -- Store the place in the cell |
:wikitext(place) -- Store the place in the cell |
||
applyTypeStyle(placeCell |
applyTypeStyle(placeCell) |
||
end |
end |
||
Line 371: | Line 303: | ||
if exit == 'old' then -- Add old exit number cell |
if exit == 'old' then -- Add old exit number cell |
||
local oldExits = {} |
|||
if args.old then insert(oldExits, args.old) end |
|||
local num = 0 |
|||
repeat |
|||
num = num + 1 |
|||
local key = "old" .. num |
|||
if args[key] then insert(oldExits, args[key]) end |
|||
until num > 1 and args[key] == nil |
|||
-- Row span (`ospan` = "old span") |
-- Row span (`ospan` = "old span") |
||
local ospan = args.ospan or jspan |
local ospan = args.ospan or jspan |
||
row:tag('td') -- Create old exit number cell |
|||
:css('text-align', 'center') |
:css('text-align', 'center') |
||
:css('background-color', '#d3d3d3') |
:css('background-color', '#d3d3d3') |
||
:attr('title', 'Former exit number') |
:attr('title', 'Former exit number') |
||
:attr('rowspan', ospan) |
:attr('rowspan', ospan) |
||
:wikitext(args.old) -- Store the old exit number in the cell |
|||
if #oldExits > 2 then |
|||
-- Create a collapsible table for many old exit numbers. |
|||
local numOldExits = #oldExits |
|||
local tbl = oldExitCell:tag("table") |
|||
:attr("class", "collapsible collapsed") |
|||
:css("margin", "auto") |
|||
:css("border-collapse", "collapse") |
|||
tbl:tag("th"):attr("scope", "col") |
|||
local ul = tbl:tag("tr"):tag("td"):tag("div") |
|||
:attr("class", "plainlist") |
|||
:tag("ul") |
|||
:css("text-align", "center") |
|||
for num,oldExit in ipairs(oldExits) do |
|||
if num < numOldExits then |
|||
ul:tag("li"):wikitext(oldExit) |
|||
end |
|||
end |
|||
-- Most recent number is always shown below the table. |
|||
oldExitCell:wikitext(oldExits[numOldExits]) |
|||
else |
|||
-- Create an hlist for few old exit numbers. |
|||
local ul = oldExitCell:tag("div") |
|||
:attr("class", "hlist") |
|||
:tag("ul") |
|||
:css("text-align", "center") |
|||
for _,oldExit in ipairs(oldExits) do |
|||
ul:tag("li"):wikitext(oldExit) |
|||
end |
|||
end |
|||
end |
end |
||
Line 463: | Line 358: | ||
:attr('rowspan', nspan) |
:attr('rowspan', nspan) |
||
:wikitext(notes) -- Store the notes in the cell |
:wikitext(notes) -- Store the notes in the cell |
||
applyTypeStyle(notesCell |
applyTypeStyle(notesCell) |
||
end |
end |
||
Line 474: | Line 369: | ||
local argType = args.type |
local argType = args.type |
||
if argType then -- {{{type}}} was passed |
if argType then -- {{{type}}} was passed |
||
local types = mw.text.split(argType, ",") |
|||
table.sort(types, function(a, b) return a > b end) |
|||
-- Type-based data for colors and tooltips |
-- Type-based data for colors and tooltips |
||
if argType == 'mplex' then |
|||
local definedTypes = mw.loadData("Module:Road data/RJL types") |
|||
local page = mw.title.getCurrentTitle() -- Get transcluding page's title |
|||
local colors = {} |
|||
local pagename = page.prefixedText -- Extract page's full title as string |
|||
local titles = {} |
|||
insert(errorMsg, |
|||
for _,type in ipairs(types) do |
|||
format("[[Category:Jctint template with invalid type|$ %s]]", pagename)) |
|||
local typeSpec = definedTypes[string.lower(type)] -- Retrieve the type spec |
|||
if typeSpec then |
|||
insert(colors, typeSpec.color) |
|||
insert(titles, 1, typeSpec.jctint) |
|||
title = typeSpec.jctint -- Store the tooltip globally |
|||
else |
|||
errors.type = util.err("Invalid type: " .. argType) |
|||
end |
|||
end |
end |
||
local types = mw.loadData("Module:Road data/RJL types") |
|||
local colorWidth = 36 |
|||
local typeData = types[string.lower(argType)] -- Retrieve the type data |
|||
local colorSpec = {} |
|||
if typeData then |
|||
local lastColor |
|||
color = typeData.color -- Store the color globally |
|||
local colorCount = 0 |
|||
title = typeData.jctint -- Store the tooltip globally |
|||
for _,color in ipairs(colors) do |
|||
else |
|||
if lastColor then |
|||
-- Add error category to error message table. |
|||
insert(colorSpec, format("%s %dpx", lastColor, colorCount * colorWidth)) |
|||
local page = mw.title.getCurrentTitle() -- Get transcluding page's title |
|||
end |
|||
local pagename = page.prefixedText -- Extract page's full title as string |
|||
insert(colorSpec, format("%s %dpx", color, colorCount * colorWidth)) |
|||
insert(errorMsg, |
|||
lastColor = color |
|||
format("[[Category:Jctint template with invalid type|%s]]", pagename)) |
|||
colorCount = colorCount + 1 |
|||
end |
end |
||
if colorCount > 1 then |
|||
typesSpec.colors = format("linear-gradient(-90deg, %s);", concat(colorSpec, ", ")) |
|||
typesSpec.minWidth = (colorCount - 1) * colorWidth |
|||
end |
|||
typesSpec.color = lastColor |
|||
typesSpec.title = concat(titles, ", ") |
|||
end |
end |
||
Line 524: | Line 404: | ||
end |
end |
||
-- |
-- Return the HTML code in the mw.html object as a string, plus any error messages |
||
return tostring(root) .. table.concat(errorMsg) |
|||
local errorMsg = {} |
|||
for key,msg in pairs(errors) do |
|||
-- Add the transcluding page to an error tracking category. |
|||
local prefix = errorTypes[key].prefix and errorTypes[key].prefix .. " " or "" |
|||
insert(errorMsg, format("%s[[%s|%s%%page%%]]", msg, errorTypes[key].cat, prefix)) |
|||
end |
|||
if #errorMsg > 0 then |
|||
local page = mw.title.getCurrentTitle().prefixedText -- Get transcluding page's title |
|||
-- Add error cell |
|||
local msg = mw.ustring.gsub(concat(errorMsg, " "), "%%page%%", page) |
|||
row:tag("td"):wikitext(msg) |
|||
end |
|||
-- Return the HTML code in the mw.html object as a string |
|||
return tostring(root) |
|||
end |
end |
||
Revision as of 03:28, 18 March 2020
![]() | This is the module sandbox page for Module:Jctint (diff). |
![]() | This Lua module is used on 15,000+ pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
This module implements the {{jctint/core}} template. Please see the template page for usage instructions.
Usage
From wikitext
{{#invoke:Jctint/sandbox|jctint}}
From Lua
local jctintCoreSandboxModule = require("Module:Jctint/sandbox")
jctintCoreSandboxModule._jctint(args)
Tracking categories
local p = {} -- Package to be exported
-- Change to "" upon deployment.
local moduleSuffix = "/sandbox"
local parserModuleName = "Module:Road data/parser" .. moduleSuffix
-- Local version of string formatting function
local format = mw.ustring.format
-- Store this function in a local variable to avoid expensive table lookups.
local insert = table.insert
-- mw.html object for the generated row
local row
-- Default row span for all columns (`jspan` = "junction span")
local jspan
-- Any error messages produced that will be added to the output
local errorMsg = {}
-- A specification for self-closing HTML tag.
local selfClosing = {selfClosing = true}
---
-- Converts the distance specified in unit from `unit` specified in `unitdef`
-- to the other supported unit.
local function convert(unit, unitdef)
if unit == nil or unitdef == nil then return {} end
-- Import module to convert length.
local util = require("Module:Road data/util")
local lengths = util.convertLengths({[unitdef] = unit})
if lengths.error then -- An error occurred during conversion.
-- Add the transcluding page to an error tracking category.
local page = mw.title.getCurrentTitle() -- Get transcluding page's title
local pagename = page.prefixedText -- Extract page's full title as string
-- Create category string
local category = format("[[Category:Jctint template using non-numeric parameter values|# %s]]", pagename)
insert(errorMsg, category) -- Add error category to error message table.
end
return lengths
end
--- Creates cells for the location columns.
local function locations(args)
-- Unitary, e.g., state line
local unitary = args.unitary -- Value to span all of the location columns
if unitary then
-- Text alignment of the cell contents, default to "left".
local align = args.unitary_align or 'left'
row:tag('td') -- Create unitary cell
:attr('colspan', 3) -- spanning three possible columns
:css('text-align', align)
:wikitext(unitary) -- Store the contents of unitary in the cell.
return
end
-- Create cells for regular location columns.
-- Region, for disambiguation and potentially for display
local region = args.region
if region or args.region_special then
-- Row span for region; must be specified to display a region cell.
local regionSpan = args.regionspan
if regionSpan then
row:tag('td') -- Create a region cell
:attr('rowspan', regionSpan)
-- Store region text in the cell.
-- `region_special` argument overrides wikilinked `region` argument.
:wikitext(args.region_special or format("[[%s]]", region))
end
end
-- Primary topic requires no specialization to supplied locations.
local primaryTopic = args.primary_topic ~= 'no'
-- Note below main text in the next column
local sub1note = args.sub1_note -- check existence later
-- Row span for the last location column, default to `jspan`
local sub2span = args.sub2span or jspan
-- Independent city
local indepCityText -- Value to span both subdivision columns.
if args.indep_city_special then
indepCityText = args.indep_city_special -- Overrides `indep_city` argument.
elseif args.indep_city then
local indepCity = args.indep_city
local cityLink -- Wikilink for independent city
if primaryTopic then
cityLink = format('[[%s]]', indepCity)
elseif region then
-- Specialize independent city to the region.
cityLink = format('[[%s, %s|%s]]', indepCity, region, indepCity)
end
if cityLink then
indepCityText = "[[Independent city|City]] of " .. cityLink
end
end
if indepCityText then -- Display independent city.
-- Text alignment of the cell contents, default to "left".
local align = args.indep_city_align or 'left'
local indepCityCell = row:tag('td') -- Create independent city cell
:attr('colspan', 2) -- spanning two columns
:attr('rowspan', sub2span) -- with the calculated row span.
:css('text-align', align)
:wikitext(indepCityText) -- Store the independent city in the cell.
if sub1note then -- A note is provided.
indepCityCell:tag('br', selfClosing) -- Add a line break to the cell.
-- Add the note to the cell, within an HTML <small> tag.
indepCityCell:tag('small'):wikitext(sub1note)
end
return
end
-- Create two cells for the first- and second-level subdivisions.
-- First-level subdivision, e.g., county
-- Name of the type of subdivision, e.g., "County" and "Parish"
local sub1name = args.sub1name -- check existence later
local sub1Text -- Value for first-level subdivision column.
if args.sub1_special then
sub1Text = args.sub1_special -- Overrides `sub1` argument.
elseif args.sub1 then
local sub1 = args.sub1
if primaryTopic then
-- Add type (if specified) to wikilink for first-level subdivision.
local sub1Link = sub1name and format("%s %s", sub1, sub1name) or sub1
sub1Text = format('[[%s|%s]]', sub1Link, sub1)
elseif region and sub1name then
-- Specialize first-level subdivision, with type added, to the region.
sub1Text = format('[[%s %s, %s|%s]]', sub1, sub1name, region, sub1)
end
end
if sub1Text then -- Display first-level subdivision.
-- Row span for first-level subdivision, default to `jspan`.
local sub1span = args.sub1span or jspan
local sub1Cell = row:tag('td') -- Create first-level subdivision cell
:attr('rowspan', sub1span) -- with the calculated row span.
:wikitext(sub1Text) -- Store the first-level subdivision in the cell.
if sub1note then -- A note is provided.
sub1Cell:tag('br', selfClosing) -- Add a line break to the cell.
-- Add the note to the cell, within an HTML <small> tag.
sub1Cell:tag('small'):wikitext(sub1note)
end
end
-- Second-level subdivision, e.g., city and town
local sub2Text -- Value for second-level subdivision column.
if args.sub2_special then
sub2Text = args.sub2_special -- Overrides `sub2` argument.
elseif args.sub2 then
local sub2 = args.sub2
if sub2 == "none" or sub2 == " " then
sub2Text = "​" -- Zero-width space
elseif primaryTopic then
sub2Text = format("[[%s]]", sub2)
else
local sub2Link = {sub2}
local sub2Name = sub2
-- Type of area, e.g., city and village, as a form of disambiguation
local area = args.area
if area then
insert(sub2Link, format(' (%s)', area)) -- Add area to wikilink.
local areas = { -- table of different area types
borough = "Borough",
city = "City",
community = "Community",
CDP = "Community",
hamlet = "Hamlet",
town = "Town",
village = "Village",
["unorganized territory"] = "Unorganized Territory"
}
-- Add area name to displayed wikitext.
sub2Name = format("%s of %s", areas[area], sub2Name)
end
insert(sub2Link, ", ")
-- Some second-level subdivisions are not unique in a given region.
-- `sub1dab` is the first-level subdivision to be used for disambiguation.
local sub1dab = args.sub1dab
if sub1dab and sub1name then
insert(sub2Link, format('%s %s, ', sub1dab, sub1name))
end
if region then
insert(sub2Link, region) -- Add region to wikilink
end
sub2Text = format("[[%s|%s]]", table.concat(sub2Link), sub2Name)
end
end
if sub2Text then -- Display second-level subdivision.
row:tag('td') -- Create second-level subdivision cell
:attr('rowspan', sub2span) -- with the calculated row span.
:wikitext(sub2Text) -- Store the second-level subdivision in the cell.
end
end
--- Creates cells for the distance columns.
local function units(args)
-- Alternate units, e.g., California's postmiles.
local alt_unit = args.altunit
if alt_unit then -- Alternate units override standard units.
-- Row span (`auspan` = "alt[ernate] unit span")
local auspan = args.auspan or jspan
-- Create the alternate unit cell as a header cell for the row,
-- since it is usually unique within the table.
row:tag('th'):attr('scope', 'row')
:css('text-align', 'right')
:attr('rowspan', auspan)
:wikitext(alt_unit) -- Store the contents of alt_unit in the cell.
else
-- Convert numeric distances to a secondary unit, and display both units.
-- Distance in the primary unit, or 'none'
local unit = args.unit
-- If `unit` is "none", no cells are displayed.
if unit == "none" then return end
local unitdef = args.unitdef or "km" -- The primary unit ('mi' or 'km')
-- Convert and format the distance.
local lengths = convert(unit, unitdef)
-- Row span (`uspan` = "unit span")
local uspan = args.uspan or jspan
-- Create the primary unit cell as a header cell for the row,
-- since it is usually unique within the table.
local primary = row:tag('th'):attr('scope', 'row')
:css('text-align', 'right')
:attr('rowspan', uspan)
-- Store the primary distance and any conversion error message in the cell.
:wikitext(lengths[lengths.orig], lengths.error)
local secondary = row:tag('td') -- Create the secondary unit cell.
:css('text-align', 'right')
:css('background-color', '#eaecf0')
:attr('rowspan', uspan)
:wikitext(lengths[lengths.comp]) -- Store the secondary distance in the cell.
local unit_ref = args.unit_ref
if unit_ref then -- A reference is provided for the distance.
primary:wikitext(unit_ref) -- Add reference to the primary distance cell.
end
local unit2 = args.unit2
if unit2 then -- A second distance is provided.
local line = args.line -- A horizontal rule may be requested between the distances.
if line then
-- Add a horizontal rule to both cells.
primary:tag('hr', selfClosing)
secondary:tag('hr', selfClosing)
else
-- Add an en-dash and a line break to both cells.
primary:wikitext('–'):tag('br', selfClosing)
secondary:wikitext('–'):tag('br', selfClosing)
end
-- Convert and format the second distance.
local lengths2 = convert(unit2, unitdef)
-- Add the second distance and any conversion error message to the primary distance cell.
primary:wikitext(lengths2[lengths2.orig], lengths2.error)
-- Add the converted second distance to the secondary distance cell.
secondary:wikitext(lengths2[lengths2.comp])
end
local unit2_ref = args.unit2_ref
if unit2_ref then -- A reference is provided for the distance.
primary:wikitext(unit2_ref) -- Add reference to the primary distance cell.
end
end
end
-- Color specified by any supplied type
local color
-- Tooltip specified by any supplied type
local title
--- Apply any type-derived coloring and tooltip to the given cell.
local function applyTypeStyle(cell)
cell:attr('title', title):css('background-color', color)
end
--- Creates a cell for places, such as bridges and rest areas.
local function place(args)
local place = args.place -- Contents of the place cell
-- Do nothing if `place` is "none"
if place == "none" then return end
local colspan = 2 -- Initial column span
local exit = args[1] -- Whether this table has exit number columns
local named = args[2] -- Whether this table has named junction column
-- Adjust column span
if exit == "old" then colspan = colspan + 2
elseif exit == "exit" then colspan = colspan + 1
end
if named == "name" then colspan = colspan + 1 end
-- Row span (`pspan` = "place span")
local pspan = args.pspan or jspan
local placeCell = row:tag('td') -- Create place cell
:css('text-align', 'center')
:attr('colspan', colspan)
:attr('rowspan', pspan)
:wikitext(place) -- Store the place in the cell
applyTypeStyle(placeCell)
end
--- Creates cells for exit number and named junction columns.
local function exits(args)
local exit = args[1] -- 'exit', 'old', or nil
local named = args[2] -- 'name' or nil
if exit == 'old' then -- Add old exit number cell
-- Row span (`ospan` = "old span")
local ospan = args.ospan or jspan
row:tag('td') -- Create old exit number cell
:css('text-align', 'center')
:css('background-color', '#d3d3d3')
:attr('title', 'Former exit number')
:attr('rowspan', ospan)
:wikitext(args.old) -- Store the old exit number in the cell
end
if exit then -- "exit" or "old" is defined; add current exit number cell
-- Row span (`espan` = "exit span")
local espan = args.espan or jspan
local exitCell = row:tag('td') -- Create exit number cell
:css('text-align', 'center')
:attr('rowspan', espan)
:wikitext(args.exit) -- Store the exit number in the cell
applyTypeStyle(exitCell)
end
if named then -- Junction list has a junction name column
local namespan = args.namespan or jspan -- Row span
local nameCell = row:tag('td') -- Create junction name cell
:attr('rowspan', namespan)
:wikitext(args.name) -- Store the junction name in the cell
applyTypeStyle(nameCell)
end
end
--- Creates cell for the destinations column.
local function destinations(args)
local road = args.road -- Contents of the destinations cell
-- Do nothing if `road` is "none"
if road == "none" then return end
-- Column span (`rcspan` = "road column span"), default to 1
local rcspan = args.rcspan or 1
-- Row span (`rspan` = "road span")
local rspan = args.rspan or jspan
local destCell = row:tag('td') -- Create destination cell
:attr('colspan', rcspan)
:attr('rowspan', rspan)
:wikitext(road) -- Store the destination in the cell
applyTypeStyle(destCell)
end
--- Creates cell for the notes column.
local function notes(args)
local notes = args.notes -- Contents of the notes cell
-- Do nothing if `notes` is "none"
if notes == "none" then return end
-- Row span (`nspan` = "notes span")
local nspan = args.nspan or jspan
local notesCell = row:tag('td') -- Create notes cell
:attr('rowspan', nspan)
:wikitext(notes) -- Store the notes in the cell
applyTypeStyle(notesCell)
end
---
-- Returns a row in the junction list.
-- Accessible from other Lua modules
function p._jctint(args)
jspan = args.jspan or 1 -- Global row span for all columns; defaults to 1
-- {{{type}}} argument to determine color and tooltips
local argType = args.type
if argType then -- {{{type}}} was passed
-- Type-based data for colors and tooltips
if argType == 'mplex' then
local page = mw.title.getCurrentTitle() -- Get transcluding page's title
local pagename = page.prefixedText -- Extract page's full title as string
insert(errorMsg,
format("[[Category:Jctint template with invalid type|$ %s]]", pagename))
end
local types = mw.loadData("Module:Road data/RJL types")
local typeData = types[string.lower(argType)] -- Retrieve the type data
if typeData then
color = typeData.color -- Store the color globally
title = typeData.jctint -- Store the tooltip globally
else
-- Add error category to error message table.
local page = mw.title.getCurrentTitle() -- Get transcluding page's title
local pagename = page.prefixedText -- Extract page's full title as string
insert(errorMsg,
format("[[Category:Jctint template with invalid type|%s]]", pagename))
end
end
local root = mw.html.create() -- Create the root mw.html object to return
-- Create the table row and store it globally
row = root:tag('tr'):css('text-align', 'left')
locations(args) -- Handle location arguments
units(args) -- Handle distance arguments
if args.place then -- {{{place}}} spans all columns to the right of the distances
place(args) -- Create cell for place
else
exits(args) -- Handle exit/named junction arguments
destinations(args) -- Handle destinations
notes(args) -- Handle notes
end
-- Return the HTML code in the mw.html object as a string, plus any error messages
return tostring(root) .. table.concat(errorMsg)
end
--- Entry function for {{jctint/core}}
function p.jctint(frame)
-- Import module function to work with passed arguments
local getArgs = require('Module:Arguments').getArgs
-- Gather passed arguments into easy-to-use table
local args = getArgs(frame)
return p._jctint(args)
end
return p -- Return package