Module:Jctco

From the AARoads Wiki: Read about the road before you go
Jump to navigation Jump to search
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}

local roadDataModule = require('Module:Road data')
local format = mw.ustring.format
local frame = mw.getCurrentFrame()
local getArgs = require('Module:Arguments').getArgs

local function country(args)
	local state = args.state or args.province or args.department
	local country
	local countryModule = mw.loadData("Module:Road data/countrymask")
	local country = args.country or countryModule[state] or nil
	
	return country
end

local function state(args)
	local state = args.state or args.province
	local country = country(args)
	
	if country == 'FRA' then
		return ''
	else
		return frame:expandTemplate ({title='Country name', args = { country .. "-" .. state}})
	end
end

local function sub1name(args)
	local country = country(args)
	local state = state(args)
	local sub1name
	
	if args.department then
		sub1name = ''
	elseif args.borough then
		sub1name = "Borough"
	elseif args.municipality then
		if state == 'Québec' then
			sub1name = "Regional County Municipality"
		else
			sub1name = "Municipality"
		end
	elseif args.parish then
		sub1name = "Parish"
	elseif args.district then
		sub1name = "District"
	else
		sub1name = "County"
	end
	
	return sub1name
end

local function category(args)
	local country = country(args)
	local state = state(args)
	local sub1name = sub1name(args)
	
	local sub1 = args.department or args.borough or args.municipality or args.parish or args.district or args.county -- add more as needed
	
	if sub1 then
		if country == 'FRA' then
			return format('[[Category:%s]]', sub1)
		else
			return format('[[Category:%s %s, %s]]', sub1, sub1name, state)
		end
	else
		return nil
	end
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 = state(args)
	if region or args.region_special then
		-- Row span for region; must be specified to display a region cell.
		local regionSpan = args.regionspan or args.sspan
		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("[[w:%s|%s]]", region, 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.county_note -- check existence later
	-- Row span for the last location column, default to `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('[[w:%s|%s]]', indepCity, indepCity)
		elseif region then
			-- Specialize independent city to the region.
			cityLink = format('[[w:%s, %s|%s]]', indepCity, region, indepCity)
		end
		if cityLink then
			indepCityText = "[[w: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', jspan) -- 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 country = country(args)
	local state = state(args)
	local sub1 = args.department or args.borough or args.municipality or args.parish or args.district or args.county -- add more as needed

	-- Name of the type of subdivision, e.g., "County" and "Parish"
	local sub1name = sub1name(args)

	local sub1Text -- Value for first-level subdivision column.
	if args.sub1_special then
		sub1Text = args.special -- Overrides `sub1` argument.
	elseif sub1 then
		if country == 'BLZ' then
			-- Add type (if specified) to wikilink for first-level subdivision.
			local sub1Link = format("%s %s", sub1, sub1name)
			sub1Text = format('[[w:%s|%s]]', sub1Link, sub1)
		elseif country == 'FRA' then
			sub1Text = format('[[w:%s|%s]]', sub1, 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('[[w:%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
end

--- Creates a cell for places, such as bridges and rest areas.
local function place(args)
	local place = "No major intersections"
	local colspan = 5 -- 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
	local indepCity = args.indep_city

	-- Adjust column span
	if exit == "old" then colspan = colspan + 2
	elseif exit == "exit" then colspan = colspan + 1
	elseif indepCity 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
end

---
-- Returns a row in the junction list.
-- Accessible from other Lua modules
function p._jctco(args)
	local country = country(args)
	jspan = args.jspan or 1 -- Global row span for all columns; defaults to 1

	if country == nil then
		return nil
	else
		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
		place(args) -- Create cell for place
		category(args) -- Create location category
	
		-- 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 {{jctco/core}}
function p.jctco(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._jctco(args)
end

return p -- Return package