Difference between revisions of "Module:Jctint/core/sandbox"

From blackwiki
Jump to navigation Jump to search
blackwiki>Happy5214
(Displaying primary unit value with thousands separator by default and accepting similar parameters for primary unit value)
blackwiki>Chinissai
(Use convertLengths function from road data module.)
Line 1: Line 1:
 
local p = {} -- Package to be exported
 
local p = {} -- Package to be exported
  
local format = string.format -- Local version of string formatting function
+
-- Local version of string formatting function
local lang = mw.getContentLanguage()
+
local format = mw.ustring.format
 +
-- Store this function in a local variable to avoid expensive table lookups.
 +
local insert = table.insert
  
local types = mw.loadData("Module:Road data/RJL types") -- Import type-based data for colors and tooltips
+
-- Type-based data for colors and tooltips
 +
local types = mw.loadData("Module:Road data/RJL types")
  
local row -- mw.html object for the generated row
+
-- mw.html object for the generated row
local jspan -- Junction span argument is stored here for efficiency
+
local row
local color -- Color specified by any supplied type
+
-- Default row span for all columns (`jspan` = "junction span")
local title -- Tooltip specified by any supplied type
+
local jspan
local errorMsg = {} -- Any error messages produced that will be added to the output
+
-- Color specified by any supplied type
 +
local color
 +
-- Tooltip specified by any supplied type
 +
local title
 +
-- Any error messages produced that will be added to the output
 +
local errorMsg = {}
  
local function conversion(unit, unitdef)
+
-- A specification for self-closing HTML tag.
-- This function converts the distance specified in unit from the unit specified in unitdef to the other supported unit
+
local selfClosing = {selfClosing = true}
local mwmath = require "Module:Math" -- Import math module
+
 
local precision = mwmath._precision -- Function to determine a numeric string's precision
+
---
local round = mwmath._precision_format -- Function to display a number rounded to a given number of digits
+
-- Converts the distance specified in unit from `unit` specified in `unitdef`
local primary
+
-- to the other supported unit.
if unit then -- If unit is nil, the function will return nil. If unit is a non-numeric string, primary will be nil. Otherwise, primary will be the string as a number.
+
local function convert(unit, unitdef)
primary = lang:parseFormattedNumber(unit)
+
if unit == nil then return {} end
else
+
 
return nil
+
-- Import module to convert length.
end
+
local util = require("Module:Road data/util")
if not primary then -- If primary is nil (unit was non-numeric), add the transcluding page to an error tracking category.
+
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 page = mw.title.getCurrentTitle() -- Get transcluding page's title
 
local pagename = page.prefixedText -- Extract page's full title as string
 
local pagename = page.prefixedText -- Extract page's full title as string
local category = format("[[Category:Jctint template using non-numeric parameter values|# %s]]", pagename) -- Create category string
+
-- Create category string
table.insert(errorMsg, category) -- Add error category to error message table.
+
local category = format("[[Category:Jctint template using non-numeric parameter values|# %s]]", pagename)
return unit -- Return supplied unit
+
insert(errorMsg, category) -- Add error category to error message table.
 
end
 
end
+
return lengths
local converted -- Distance converted into the secondary unit
 
if unitdef == 'mi' then -- If the primary unit is miles
 
converted = primary * 1.609344 -- Convert into kilometers
 
else -- Otherwise
 
converted = primary / 1.609344 -- Convert into miles
 
end
 
local prec = precision(unit) -- Retrieve precision of supplied distance
 
if prec < 0 then prec = 0 end -- Precision must be at least 0
 
return round(converted, prec) -- Return the converted distance rounded to the same number of digits as the supplied distance
 
 
end
 
end
  
 +
--- Creates cells for the location columns.
 
local function locations(args)
 
local function locations(args)
-- This function generates the cells for locations.
+
local unitary = args.unitary -- Value to span all of the location columns
local unitary = args.unitary -- The contents of this parameter will span all of the location columns.
 
 
if unitary then
 
if unitary then
local tag = row:tag('td'):attr('colspan', 3):wikitext(unitary) -- Simply create a cell that spans all three possible columns, and store the contents of unitary in the cell.
+
-- Text alignment of the cell contents, default to "left".
local align = args.unitary_align or 'left' -- Determine the alignment of the cell contents, using the unitary_align argument with 'left' as a default.
+
local align = args.unitary_align or 'left'
tag:css('text-align', align) -- Apply the text alignment to the cell.
+
row:tag('td') -- Create unitary cell
else -- We don't have a single cell to create, so now comes the hard work.
+
:attr('colspan', 3) -- spanning three possible columns
local areas = {village = "Village", city = "City", town = "Town", community = "Community", CDP = "Community", hamlet = "Hamlet", ["unorganized territory"] = "Unorganized Territory"} -- This is a table of different area types.
+
:css('text-align', align)
+
:wikitext(unitary) -- Store the contents of unitary in the cell.
local notPrimaryTopic = args.primary_topic == 'no' -- If the primary_topic argument equals 'no', then this is true. Otherwise, this is false.
+
return
+
end
-- Regions
+
 
local regionSpan = args.regionspan -- If this is supplied, a region cell will be created with this as its row span.
+
-- Create cells for regular location columns.
local region = args.region -- This will be the region stored in a possible region cell, and will also be used for disambiguating other locations.
+
 
if regionSpan then
+
-- Region, for disambiguation and potentially for display
local regionCell = row:tag('td'):attr('rowspan', regionSpan) -- Create a region cell with the supplied row span.
+
local region = args.region
local regionSpecial = args.region_special or ('[[' .. region .. ']]') -- The region_special argument overrides the region argument. If it is not provided, simply wikilink the supplied region.
+
-- Row span for region; must be specified to display a region cell.
regionCell:wikitext(regionSpecial) -- Store either the contents of the region_special argument or the wikilinked region in the cell.
+
local regionSpan = args.regionspan
 +
if regionSpan then
 +
local regionCell = 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
 +
 
 +
-- 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
 +
-- Row span for the last column, default to 1
 +
local sub2span = args.sub2span or 1
 +
 
 +
-- 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)
 +
else
 +
-- Specialize independent city to the region.
 +
cityLink = format('[[%s, %s|%s]]', indepCity, region, indepCity)
 +
end
 +
indepCityText = "[[Independent city|City]] of " .. cityLink
 +
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
 +
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", sub1name, sub1) or sub1
 +
sub1Text = format('[[%s|%s]]', sub1Link, sub1)
 +
else
 +
-- 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 1.
 +
local sub1span = args.sub1span or 1
 +
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
+
end
-- Independent Cities
+
 
local indepCity = args.indep_city -- Independent cities span both subdivision columns.
+
-- Second-level subdivision, e.g., city and town
local indepCitySpecial = args.indep_city_special -- This will override the indep_city argument.
+
local sub2Text -- Value for second-level subdivision column.
local sub1note = args.sub1_note -- This may be used to place a note in small text below the name of an independent city or other first-level subdivision.
+
if args.sub2_special then
local sub2span = args.sub2span or 1 -- This is the row span for any independent city or second-level subdivision. 1 is the default.
+
sub2Text = args.sub2_special -- Overrides `sub2` argument.
if indepCity or indepCitySpecial then -- If an independent city is provided, create the appropriate cell.
+
elseif args.sub2 then
local indepCityCell = row:tag('td'):attr('colspan', 2):attr('rowspan', sub2span) -- Create a cell that spans two columns, and has the calculated row span.
+
local sub2 = args.sub2
local align = args.indep_city_align or 'left' -- Determine the alignment of the cell contents, using the indep_city_align argument with 'left' as a default.
+
if sub2 == "none" or sub2 == "&nbsp;" then
indepCityCell:css('text-align', align) -- Apply the text alignment to the cell.
+
sub2Text = "&#8203;" -- Zero-width space
if indepCitySpecial then -- If indep_city_special is supplied, simply stuff it in the cell.
+
elseif primaryTopic then
indepCityCell:wikitext(indepCitySpecial)
+
sub2Text = format("[[%s]]", sub2)
elseif notPrimaryTopic then -- Otherwise, if primary_topic == 'no', then create a wikilink with the independent city and region, and store it in the cell.
+
else
local text = format('[[Independent city|City]] of [[%s, %s|%s]]', indepCity, region, indepCity)
+
local sub2Link = {sub2}
indepCityCell:wikitext(text)
+
local sub2Name = sub2
else -- If neither is true, then create a wikilink with just the independent city and store it in the cell.
+
-- Type of area, e.g., city and village, as a form of disambiguation
local text = format('[[Independent city|City]] of [[%s]]', indepCity)
+
local area = args.area
indepCityCell:wikitext(text)
+
if area then
 +
insert(sub2Link, format(' (%s)', area)) -- Add area to wikilink.
 +
local areas = { -- table of different area types
 +
village = "Village",
 +
city = "City",
 +
town = "Town",
 +
community = "Community",
 +
CDP = "Community",
 +
hamlet = "Hamlet",
 +
["unorganized territory"] = "Unorganized Territory"
 +
}
 +
-- Add area name to displayed wikitext.
 +
sub2Name = format("%s of %s", areas[area], sub2Name)
 
end
 
end
if sub1note then -- If a note is provided, store that in the cell as well.
+
insert(sub2Link, ", ")
indepCityCell:tag('br', {selfClosing = true}) -- Add a line break to the cell.
+
-- Some second-level subdivisions are not unique in a given region.
indepCityCell:tag('small'):wikitext(sub1note) -- Add the note to the cell, within an HTML <small> tag.
+
-- `sub1dab` is the first-level subdivision to be used for disambiguation.
end
+
local sub1dab = args.sub1dab  
else -- If no independent city is provided, create two cells for the first- and second-level subdivisions.
+
if sub1dab then
-- First-level Subdivisions
+
insert(sub2Link, format('%s %s, ', sub1dab, sub1name))
local sub1 = args.sub1 -- First-level subdivisions include counties and other similar areas.
 
local sub1Special = args.sub1_special -- This will override sub1.
 
local sub1name = args.sub1name -- This is the name of the type of subdivision, like "County" or "Parish"
 
if sub1 or sub1Special then -- If a first-level subdivision is provided, create a table cell for it.
 
local sub1span = args.sub1span or 1 -- This is the row span for the first-level subdivision. 1 is the default.
 
local sub1Cell = row:tag('td'):attr('rowspan', sub1span) -- Create a cell for the location, with the appropriate row span
 
if sub1Special then -- If sub1_special is provided, stuff it in the cell.
 
sub1Cell:wikitext(sub1Special)
 
elseif notPrimaryTopic then -- Otherwise, if primary_topic == 'no', then create a wikilink with the subdivision name, type, and region, and store it in the cell.
 
local text = format('[[%s %s, %s|%s]]', sub1, sub1name, region, sub1)
 
sub1Cell:wikitext(text)
 
else -- If neither is true, create a wikilink with the subdivision name, and optionally the type, and store it in the cell.
 
local text = '[[' .. sub1
 
if sub1name then -- The type is optional in this case.
 
text = text .. format(' %s|%s', sub1name, sub1)
 
end
 
sub1Cell:wikitext(text .. ']]')
 
end
 
if sub1note then -- If a note is provided, store that in the cell as well.
 
sub1Cell:tag('br', {selfClosing = true}) -- Add a line break to the cell.
 
sub1Cell:tag('small'):wikitext(sub1note) -- Add the note to the cell, within an HTML <small> tag.
 
end
 
end
 
 
-- Second-level Subdivisions
 
local sub2 = args.sub2 -- Second-level subdivisions include cities and towns
 
local sub2Special = args.sub2_special -- This will override sub2
 
if (sub2 == 'none') or (sub2 == '&nbsp;') then -- If sub2 is 'none' or a non-breaking space, store a non-breaking space in the cell.
 
row:tag('td'):wikitext("&nbsp;") -- Create a cell and store a non-breaking space in it.
 
elseif sub2Special then -- If sub2_special is supplied, simply stuff it in the cell.
 
row:tag('td'):attr('rowspan', sub2span):wikitext(sub2Special) -- Create a cell, apply the proper row span, and store the contents of sub2_special.
 
elseif sub2 then -- If sub is supplied, then create and fill the cell.
 
local sub2Cell = row:tag('td'):attr('rowspan', sub2span) -- Create a new cell, and apply the appropriate row span to it.
 
if not notPrimaryTopic then -- If primary_topic ~= 'no', simply wikilink the supplied location and store it in the cell.
 
sub2Cell:wikitext('[[' .. sub2 .. ']]')
 
else -- Otherwise, create a wikilink that includes the region, and store it in the cell.
 
local text = {'[[', sub2}
 
local area = args.area -- This can include a type of area, such as city or village, as a form of disambiguation. The type will appear in the wikilink.
 
local insert = table.insert -- Store this function in a local variable to avoid expensive table lookups.
 
if area then -- If a specific type of area is supplied, put it in the wikilink.
 
insert(text, format(' (%s)', area))
 
end
 
insert(text, ", ")
 
local sub1dab = args.sub1dab -- Some location names are shared by multiple locations in the same state. This allows for the county to be used to disambiguate the location.
 
if sub1dab then
 
insert(text, format('%s %s, ', sub1dab, sub1name))
 
end
 
insert(text, region .. '|')
 
if area then -- If a specific type of area is supplied, put a properly-formatted form of it in the wikilink.
 
local linktext = areas[area]
 
insert(text, linktext .. ' of ')
 
end
 
insert(text, sub2 .. ']]')
 
sub2Cell:wikitext(table.concat(text)) -- Concatenate the table's contents and store the result in the cell.
 
end
 
 
end
 
end
 +
insert(sub2Link, region) -- Add region to wikilink
 +
 +
sub2Text = format("[[%s|%s]]", table.concat(sub2Link), sub2Name)
 
end
 
end
 +
end
 +
if sub2Text then -- Display second-level subdivision.
 +
local sub1Cell = 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.
 +
return
 
end
 
end
 
end
 
end
  
function units(args)
+
--- Creates cells for the distance columns.
-- This function creates the table cells for the distance.
+
local function units(args)
local alt_unit = args.altunit -- Alternate units include California's postmiles.
+
-- Alternate units, e.g., California's postmiles.
if alt_unit then -- Alternate units take precedence over standard units.
+
local alt_unit = args.altunit
local tag = row:tag('th'):attr('scope', 'row'):css('text-align', 'right') -- Create the alternate unit cell. It is treated as a header cell for the row, since it is usually unique within the table.
+
if alt_unit then -- Alternate units override standard units.
local span = args.auspan or jspan or 1 -- Determine row span ("auspan" = "alt[ernate] unit span"), using global row span argument jspan and 1 as backups, in that order.
+
-- Row span (`auspan` = "alt[ernate] unit span")
tag:attr('rowspan', span) -- Apply row span to cell.
+
local auspan = args.auspan or jspan
tag:attr('title', title) -- Apply any type-derived tooltip.
+
-- Create the alternate unit cell as a header cell for the row,
tag:wikitext(alt_unit) -- Store the contents of alt_unit in the cell.
+
-- since it is usually unique within the table.
else -- Numeric distances will be converted to a secondary unit, and both will be displayed.
+
row:tag('th'):attr('scope', 'row')
local unit = args.unit -- Numeric distance in the primary unit, or 'none' if no cells are to be displayed
+
:css('text-align', 'right')
if unit ~= 'none' then -- If unit == 'none', don't display any cells.
+
:attr('rowspan', auspan)
local primary = row:tag('th'):attr('scope', 'row'):css('text-align', 'right') -- Create cell for distance in primary unit. As with alt_unit, this cell is a header cell for the row.
+
:attr('title', title) -- Apply any type-derived tooltip.
local span = args.uspan or jspan or 1 -- Determine row span ("uspan" = "unit span"), using global row span argument jspan and 1 as backups, in that order.
+
:wikitext(alt_unit) -- Store the contents of alt_unit in the cell.
primary:attr('rowspan', span) -- Apply row span to cell.
+
else
primary:attr('title', title) -- Apply any type-derived tooltip.
+
-- Convert numeric distances to a secondary unit, and display both units.
+
-- Distance in the primary unit, or 'none'
local secondary = row:tag('td'):css('text-align', 'right'):css('background-color', '#f2f2f2'):attr('rowspan', span) -- Create the cell for the distance in the secondary unit, and format it like the cell for the primary unit.
+
local unit = args.unit
secondary:attr('title', title) -- Apply any type-derived tooltip.
+
-- If `unit` is "none", no cells are displayed.
+
if unit == "none" then return end
local unitdef = args.unitdef -- The unit of the supplied distance ('mi' or 'km')
+
local unitdef = args.unitdef -- The primary unit ('mi' or 'km')
local unitnum = lang:parseFormattedNumber(unit) -- Convert unit to number, only to convert it back into a string in the next line.
+
-- Convert and format the distance.
primary:wikitext(lang:formatNum(unitnum)) -- Store the supplied distance in the primary distance cell.
+
local lengths = convert(unit, unitdef)
secondary:wikitext(conversion(unit, unitdef)) -- Convert the distance into the secondary unit, as determined by unitdef, and store it in the secondary distance cell.
+
-- Row span (`uspan` = "unit span")
+
local uspan = args.uspan or jspan
local unit2 = args.unit2 -- A second distance may be provided.
+
-- Create the primary unit cell as a header cell for the row,
if unit2 then -- If one is provided, repeat the process.
+
-- since it is usually unique within the table.
local line = args.line -- A horizontal line may be displayed between the distances.
+
local primary = row:tag('th'):attr('scope', 'row')
if line then -- If a line is requested, add one to both cells.
+
:css('text-align', 'right')
primary:tag('hr', {selfClosing = true})
+
:attr('rowspan', uspan)
secondary:tag('hr', {selfClosing = true})
+
:attr('title', title) -- Apply any type-derived tooltip.
else -- Otherwise, add an en-dash and line break.
+
-- Store the primary distance and any conversion error message in the cell.
primary:wikitext('–'):tag('br', {selfClosing = true})
+
:wikitext(lengths[lengths.orig], lengths.error)
secondary:wikitext('–'):tag('br', {selfClosing = true})
+
local secondary = row:tag('td') -- Create the secondary unit cell.
end
+
:css('text-align', 'right')
primary:wikitext(unit2) -- Add the second distance to the primary distance cell
+
:css('background-color', '#f2f2f2')
secondary:wikitext(conversion(unit2, unitdef)) -- Convert the second distance into the secondary unit, and add it to the secondary distance cell.
+
:attr('rowspan', uspan)
 +
:attr('title', title) -- Apply any type-derived tooltip.
 +
: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
 
end
+
-- Convert and format the second distance.
local unit_ref = args.unit_ref -- A reference may be provided for the distance.
+
local lengths2 = convert(unit2, unitdef)
if unit_ref then primary:wikitext(unit_ref) end -- If one is provided, simply add it to the primary distance cell.
+
-- 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 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
 
end
 
end
 
end
  
function place(args)
+
--- Creates a cell for places, such as bridges and rest areas.
-- This function generates a cell for places, such as bridges and rest areas
+
local function place(args)
local tag = row:tag('td'):css('text-align', 'center') -- Create cell and center-align its future contents
+
local colspan = 2 -- Initial column span
local pspan = args.pspan or jspan or 1 -- Determine row span ("pspan" = "place span"), using global row span argument jspan and 1 as backups, in that order
+
local exit = args[1] -- Whether this table has exit number columns
tag:attr('rowspan', pspan) -- Apply row span to cell
+
local named = args[2] -- Whether this table has named junction column
+
-- Adjust column span
local colspan -- Create local variable to store column span
+
if exit == "old" then colspan = colspan + 2
local exit = args[1] -- Whether this table has exit numbers, both old and current exit numbers, or neither
+
elseif exit == "exit" then colspan = colspan + 1
local named = args[2] -- Whether this table includes named junctions
 
if exit == 'exit' then -- Calculate column span
 
if named == 'name' then
 
colspan = 4
 
else
 
colspan = 3
 
end
 
elseif exit == 'old' then
 
if named == 'name' then
 
colspan = 5
 
else
 
colspan = 4
 
end
 
else
 
colspan = 2
 
 
end
 
end
tag:attr('colspan', colspan) -- Apply column span to cell
+
if named == "name" then colspan = colspan + 1 end
tag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip
+
-- Row span (`pspan` = "place span")
tag:wikitext(args.place) -- Store the place in the cell
+
-- Defaults to `jspan` and 1, in that order
 +
local pspan = args.pspan or jspan or 1
 +
row:tag('td') -- Create place cell
 +
:css('text-align', 'center')
 +
:attr('colspan', colspan)
 +
:attr('rowspan', pspan)
 +
-- Apply any type-derived coloring and tooltip
 +
:attr('title', title):css('background-color', color)
 +
:wikitext(args.place) -- Store the place in the cell
 
end
 
end
  
function exits(args)
+
--- Creates cells for exit number and named junction columns.
-- This function generates table cells for exit and named junction data
+
local function exits(args)
local exit = args[1] -- Is either 'exit', 'old', or nil
+
local exit = args[1] -- 'exit', 'old', or nil
local named = args[2] -- Is either 'name' or nil
+
local named = args[2] -- 'name' or nil
+
 
 
if exit == 'old' then -- Add old exit number cell
 
if exit == 'old' then -- Add old exit number cell
local oldTag = row:tag('td'):css('text-align', 'center'):css('background-color', '#d3d3d3'):attr('title', 'Former exit number') -- Create cell and properly style it
+
-- Row span (`ospan` = "old span")
local ospan = args.ospan or jspan or 1 -- Determine row span ("ospan" = "old span"), using global row span argument jspan and 1 as backups, in that order
+
local ospan = args.ospan or jspan
oldTag:attr('rowspan', ospan):wikitext(args.old) -- Apply row span and add old exit number
+
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
 
end
+
 
if exit == 'exit' or exit == 'old' then -- If either is true, add current exit number cell
+
if exit then -- "exit" or "old" is defined; add current exit number cell
local exitTag = row:tag('td'):css('text-align', 'center') -- Create cell and center-align its contents
+
-- Row span (`espan` = "exit span")
local espan = args.espan or jspan or 1 -- Determine row span ("espan" = "exit span"), using global row span argument jspan and 1 as backups, in that order
+
local espan = args.espan or jspan
exitTag:attr('rowspan', espan) -- Apply row span to cell
+
row:tag('td') -- Create exit number cell
exitTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip
+
:css('text-align', 'center')
exitTag:wikitext(args.exit) -- Store the exit number in the cell
+
:attr('rowspan', espan)
 +
-- Apply any type-derived coloring and tooltip
 +
:attr('title', title):css('background-color', color)
 +
:wikitext(args.exit) -- Store the exit number in the cell
 
end
 
end
+
 
if named == 'name' then -- This junction list has a junction name column, so a cell must be produced
+
if named then -- Junction list has a junction name column
local nameTag = row:tag('td') -- Create a cell for the junction name
+
local namespan = args.namespan or jspan -- Row span
local namespan = args.namespan or jspan or 1 -- Determine row span, using global row span argument jspan and 1 as backups, in that order
+
row:tag('td') -- Create junction name cell
nameTag:attr('rowspan', namespan) -- Apply row span to cell
+
:attr('rowspan', namespan)
nameTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip
+
-- Apply any type-derived coloring and tooltip
nameTag:wikitext(args.name) -- Store the junction name in the cell
+
:attr('title', title):css('background-color', color)
 +
:wikitext(args.name) -- Store the junction name in the cell
 
end
 
end
 
end
 
end
  
function destinations(args)
+
--- Creates cell for the destinations column.
-- This function creates the cells for destinations and notes
+
local function destinations(args)
local destTag = row:tag('td') -- Create destination cell
+
-- Column span (`rcspan` = "road column span"), using 1 as a default
local rcspan = args.rcspan or 1 -- Determine column span ("rcspan" = "road column span"), using 1 as a default
+
local rcspan = args.rcspan or 1
destTag:attr('colspan', rcspan) -- Apply column span to cell
+
-- Row span (`rspan` = "road span")
local rspan = args.rspan or jspan or 1 -- Determine row span ("rspan" = "road span"), using global row span argument jspan and 1 as backups, in that order
+
local rspan = args.rspan or jspan
destTag:attr('rowspan', rspan) -- Apply row span to cell
+
row:tag('td') -- Create destination cell
destTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip
+
:attr('colspan', rcspan)
destTag:wikitext(args.road) -- Store the supplied cell contents
+
:attr('rowspan', rspan)
+
-- Apply any type-derived coloring and tooltip
 +
:attr('title', title):css('background-color', color)
 +
:wikitext(args.road) -- Store the destination in the cell
 +
end
 +
 
 +
--- Creates cell for the notes column.
 +
local function notes(args)
 
local notes = args.notes -- Contents of the notes cell
 
local notes = args.notes -- Contents of the notes cell
if notes ~= 'none' then -- If the contents equal the string 'none', then no cell will be produced. Otherwise...
+
-- Do nothing if `notes` is "none"
local notesTag = row:tag('td') -- Create notes cell
+
if notes == "none" then return end
local nspan = args.nspan or jspan or 1 -- Determine row span ("nspan" = "notes span"), using global row span argument jspan and 1 as backups, in that order
+
-- Row span (`nspan` = "notes span")
notesTag:attr('rowspan', nspan) -- Apply row span to cell
+
local nspan = args.nspan or jspan
notesTag:attr('title', title):css('background-color', color) -- Apply any type-derived coloring and tooltip
+
row:tag('td') -- Create notes cell
notesTag:wikitext(notes) -- Store the notes in the cell
+
:attr('rowspan', nspan)
end
+
-- Apply any type-derived coloring and tooltip
 +
:attr('title', title):css('background-color', color)
 +
:wikitext(notes) -- Store the notes in the cell
 
end
 
end
  
 +
---
 +
-- Returns a row in the junction list.
 +
-- Accessible from other Lua modules
 
function p._jctint(args)
 
function p._jctint(args)
-- This function creates the table row and calls other functions to popluate it.
+
jspan = args.jspan or 1 -- Global row span for all columns; defaults to 1
-- This function is accessible from other Lua modules
+
-- {{{type}}} argument to determine color and tooltips
jspan = args.jspan -- Junction span (backup for row span that is applicable to all columns)
+
local argType = args.type
local argType = args.type -- {{{type}}} argument to determine color and tooltips
+
if argType then -- {{{type}}} was passed
if argType then -- If a type was passed
 
 
local typeData = types[string.lower(argType)] -- Retrieve the type data
 
local typeData = types[string.lower(argType)] -- Retrieve the type data
 
if typeData then
 
if typeData then
 
color = typeData.color -- Store the color globally
 
color = typeData.color -- Store the color globally
 
title = typeData.jctint -- Store the tooltip globally
 
title = typeData.jctint -- Store the tooltip globally
else -- If there is no type data, add an error category.
+
else
 +
-- Add error category to error message table.
 
local page = mw.title.getCurrentTitle() -- Get transcluding page's title
 
local page = mw.title.getCurrentTitle() -- Get transcluding page's title
 
local pagename = page.prefixedText -- Extract page's full title as string
 
local pagename = page.prefixedText -- Extract page's full title as string
table.insert(errorMsg, format("[[Category:Jctint template with invalid type|%s]]", pagename)) -- Add error category to error message table.
+
insert(errorMsg,
 +
format("[[Category:Jctint template with invalid type|%s]]", pagename))
 
end
 
end
 
end
 
end
local root = mw.html.create() -- Create the root mw.html object
+
 
row = root:tag('tr'):css('text-align', 'left') -- Create the table row and store it globally
+
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
 
locations(args) -- Handle location arguments
 
units(args) -- Handle distance arguments
 
units(args) -- Handle distance arguments
Line 294: Line 375:
 
else
 
else
 
exits(args) -- Handle exit/named junction arguments
 
exits(args) -- Handle exit/named junction arguments
destinations(args) -- Handle destinations and notes
+
destinations(args) -- Handle destinations
 +
notes(args) -- Handle notes
 
end
 
end
+
 
return tostring(root) .. table.concat(errorMsg) -- Return the HTML code in the mw.html object as a string, plus any error messages
+
-- Return the HTML code in the mw.html object as a string, plus any error messages
 +
return tostring(root) .. table.concat(errorMsg)
 
end
 
end
  
 +
--- Entry function for {{jctint/core}}
 
function p.jctint(frame)
 
function p.jctint(frame)
-- Entry function for {{jctint/core}}
+
-- Import module function to work with passed arguments
return p._jctint(require('Module:Arguments').getArgs(frame)) -- Simply call another function with those arguments to actually create the row
+
local getArgs = require('Module:Arguments').getArgs
 +
-- Gather passed arguments into easy-to-use table
 +
local args = getArgs(frame)
 +
return p._jctint(args)
 
end
 
end
  
 
return p -- Return package
 
return p -- Return package

Revision as of 11:14, 8 May 2016

Documentation for this module may be created at Module:Jctint/core/sandbox/doc

local p = {} -- Package to be exported

-- 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

-- Type-based data for colors and tooltips
local types = mw.loadData("Module:Road data/RJL types")

-- mw.html object for the generated row
local row
-- Default row span for all columns (`jspan` = "junction span")
local jspan
-- Color specified by any supplied type
local color
-- Tooltip specified by any supplied type
local title
-- 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 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)
	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
	-- Row span for region; must be specified to display a region cell.
	local regionSpan = args.regionspan
	if regionSpan then
		local regionCell = 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

	-- 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
	-- Row span for the last column, default to 1
	local sub2span = args.sub2span or 1

	-- 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)
		else
			-- Specialize independent city to the region.
			cityLink = format('[[%s, %s|%s]]', indepCity, region, indepCity)
		end
		indepCityText = "[[Independent city|City]] of " .. cityLink
	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
	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", sub1name, sub1) or sub1
			sub1Text = format('[[%s|%s]]', sub1Link, sub1)
		else
			-- 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 1.
		local sub1span = args.sub1span or 1
		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 == "&nbsp;" then
			sub2Text = "&#8203;" -- 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
					village = "Village",
					city = "City",
					town = "Town",
					community = "Community",
					CDP = "Community",
					hamlet = "Hamlet",
					["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 then
				insert(sub2Link, format('%s %s, ', sub1dab, sub1name))
			end
			insert(sub2Link, region) -- Add region to wikilink

			sub2Text = format("[[%s|%s]]", table.concat(sub2Link), sub2Name)
		end
	end
	if sub2Text then -- Display second-level subdivision.
		local sub1Cell = 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.
		return
	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)
			:attr('title', title) -- Apply any type-derived tooltip.
			: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 -- 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)
			:attr('title', title) -- Apply any type-derived tooltip.
			-- 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', '#f2f2f2')
			:attr('rowspan', uspan)
			:attr('title', title) -- Apply any type-derived tooltip.
			: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], lengths2.error)
			-- 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

--- Creates a cell for places, such as bridges and rest areas.
local function place(args)
	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")
	-- Defaults to `jspan` and 1, in that order
	local pspan = args.pspan or jspan or 1
	row:tag('td') -- Create place cell
		:css('text-align', 'center')
		:attr('colspan', colspan)
		:attr('rowspan', pspan)
		-- Apply any type-derived coloring and tooltip
		:attr('title', title):css('background-color', color)
		:wikitext(args.place) -- Store the place in the cell
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
		row:tag('td') -- Create exit number cell
			:css('text-align', 'center')
			:attr('rowspan', espan)
			-- Apply any type-derived coloring and tooltip
			:attr('title', title):css('background-color', color)
			:wikitext(args.exit) -- Store the exit number in the cell
	end

	if named then -- Junction list has a junction name column
		local namespan = args.namespan or jspan -- Row span
		row:tag('td') -- Create junction name cell
			:attr('rowspan', namespan)
			-- Apply any type-derived coloring and tooltip
			:attr('title', title):css('background-color', color)
			:wikitext(args.name) -- Store the junction name in the cell
	end
end

--- Creates cell for the destinations column.
local function destinations(args)
	-- Column span (`rcspan` = "road column span"), using 1 as a default
	local rcspan = args.rcspan or 1
	-- Row span (`rspan` = "road span")
	local rspan = args.rspan or jspan
	row:tag('td') -- Create destination cell
		:attr('colspan', rcspan)
		:attr('rowspan', rspan)
		-- Apply any type-derived coloring and tooltip
		:attr('title', title):css('background-color', color)
		:wikitext(args.road) -- Store the destination in the cell
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
	row:tag('td') -- Create notes cell
		:attr('rowspan', nspan)
		-- Apply any type-derived coloring and tooltip
		:attr('title', title):css('background-color', color)
		:wikitext(notes) -- Store the notes in the cell
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
		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