Module:Jctint/sandbox
Appearance
![]() | 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
-- Local version of string formatting function
local format = mw.ustring.format
-- Store functions in a local variable to avoid expensive table lookups.
local concat = table.concat
local insert = table.insert
-- Road data utility functions
local util = require("Module:Road data/util")
-- mw.html object for the generated row
local row
-- Default row span for all columns (`jspan` = "junction span")
local jspan
-- 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.
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 lengths = util.convertLengths({[unitdef] = unit})
if lengths.error then -- An error occurred during conversion.
errors.convert = lengths.error
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
local roadDataModule = require("Module:Road data")
local locns = roadDataModule.locations(args, "jctint")
-- Create cells for regular location columns.
-- 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]]", locns.region))
end
-- 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 = locns.indep_city -- Value to span both subdivision columns.
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
local sub1Text = locns.sub1 -- Value for first-level subdivision column.
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 = locns.sub2 -- Value for second-level subdivision column.
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])
local secondary = row:tag('td') -- Create the secondary unit cell.
:css('text-align', 'right')
:css('background-color', '#f2f2f2')
:attr('rowspan', uspan)
:wikitext(lengths[lengths.comp]) -- Store the secondary distance in the cell.
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])
-- Add the converted second distance to the secondary distance cell.
secondary:wikitext(lengths2[lengths2.comp])
end
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
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
local oldExits = {}
if args.old then insert(oldExits, 1, args.old) end
local num = 0
repeat
num = num + 1
local key = "old" .. num
if args[key] then insert(oldExits, 1, args[key]) end
until num > 1 and args[key] == nil
local oldExitText
if #oldExits > 1 then
-- Create a collapsible table for multiple old exit numbers.
-- Most recent number is at the top of the table.
local tbl = mw.html.create()
:tag("table")
:attr("class", "collapsible collapsed nowrap")
:css("border-collapse", "collapse")
for num,oldExit in ipairs(oldExits) do
local tag
if num == 1 then
tag = tbl:tag("th")
:attr("scope", "col")
:css("font-weight", "normal")
else
tag = tbl:tag("tr"):tag("td")
end
tag:css("padding", "0px")
:css("text-align", "left")
:wikitext(oldExit)
end
oldExitText = tostring(tbl)
else
oldExitText = concat(oldExits)
end
-- 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(oldExitText) -- 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)
-- 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(args.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
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
errors.type = util.err("Invalid type: " .. argType)
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
-- Prepare error messages.
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
--- 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