Module:Jctint

local p = {} -- Package to be exported

-- Local version of string formatting function
local format = mw.ustring.format
-- Local version of string trimming function
local trim = mw.text.trim
-- 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
			-- Add type to first-level subdivision.
			local sub1Typed = trim(format('%s %s', sub1, sub1name))
			-- Specialize first-level subdivision, with type added, to the region.
			sub1Text = format('[[%s, %s|%s]]', sub1Typed, 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 == "&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
					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, trim(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

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.