Module:Jct

local p = {}
-- Change to "" upon deployment.
local moduleSuffix = ""

local parserModuleName = "Module:Road data/parser" .. moduleSuffix
local statenameModuleName = "Module:Jct/statename" .. moduleSuffix -- TODO transition
local cityModuleName = "Module:Jct/city" .. moduleSuffix

local concat = table.concat
local insert = table.insert
local format = mw.ustring.format
local trim = mw.text.trim

local parserModule = require(parserModuleName)
local parser = parserModule.parser
local util = require("Module:Road data/util")


-- Shields
local defaultShieldSize = 24

local function addContextBanner(route, name, suffix, bannerSpec)
	local bannerModule = 'Module:Road data/banners/' .. string.upper(route.country)
	local shieldfield = name .. 'shield'
	local shield = parser(route, shieldfield)
	if shield == nil then
		-- This route type does not define shield.
		-- Find shield in the default banner table.
		shield = parser(route, 'shield', name, bannerModule)
		if shield and shield ~= '' then
			if suffix == nil then
				suffix = parser(route, 'shield', 'suffix', bannerModule)
			end
			if suffix and suffix ~= '' then
				shield = shield .. " " .. suffix
			end
			shield = shield .. ".svg"
		end
	end
	if shield and shield ~= '' then
		local shieldSize = defaultShieldSize
		-- Add banner plate.
		insert(bannerSpec, {shield, shieldSize})
	end
end

local function bannerSpec(banner, bannerSize, bannerSuffix, route)
	local banners = {}
	if type(banner) == "table" then
		local bannerSizeIsNotTable = type(bannerSize) ~= "table"
		for i,filename in ipairs(banner) do
			local bannersize = bannerSizeIsNotTable and bannerSize or bannerSize[i] or defaultShieldSize
			insert(banners, {filename, bannersize})
		end
	elseif banner ~= '' then
		insert(banners, {banner, bannerSize})
	end

	if route.dir then
		addContextBanner(route, 'dir', bannerSuffix, banners)
	end
	if route.to then
		addContextBanner(route, 'to', bannerSuffix, banners)
	end

	return banners
end

local function shieldSpec(route, mainShield, shieldList)
	local shieldSpec = {}

	local shield
	local shieldto = parser(route, 'shieldto')
	
	if route.to then
		if not shield then shield = shieldto or parser(route, 'shield') or '' end
	else
		if not shield then shield = parser(route, 'shield') or '' end
	end
	if shield == '' then return shieldSpec end
	local orientation = parser(route, 'orientation')

	local function size(route)
		if orientation == "upright" then
			return defaultShieldSize
			else return "x" .. defaultShieldSize
		end
	end
	
	local shieldsize = size(route)
	
	local banner = parser(route, 'banner') or {}
	local bannersize = defaultShieldSize
	local bannersuffix = parser(route, 'bannersuffix')

	local bannerIsNotTable = type(banner) ~= "table"
	local bannersizeIsNotTable = type(bannersize) ~= "table"
	local bannersuffixIsNotTable = type(bannersuffix) ~= "table"

	if type(shield) == "table" then
		for i,filename in ipairs(shield) do
			local size = shieldsize or shieldsize[i]
			if size == "" then size = nil end
			-- banner.all describes banners that apply to all multiple shields.
			local shieldBanner = bannerIsNotTable and banner or (banner[i] or banner.all or {})
			-- Banner size is default if the corresponding entry
			-- in bannerSize table is not set.
			local shieldBannerSize =
				bannersizeIsNotTable and bannersize
				or (bannersize[i] or bannersize.all or defaultShieldSize)
			local shieldBannerSuffix = bannersuffix and (bannersuffixIsNotTable and bannersuffix or bannersuffix[i])
			insert(shieldSpec, {
				shield = {filename, size},
				banners = bannerSpec(shieldBanner, shieldBannerSize, shieldBannerSuffix, route)
			})
		end
	elseif shield ~= '' then
		if shieldsize == "" then shieldsize = nil end
		insert(shieldSpec, {
			shield = {shield, shieldsize},
			banners = bannerSpec(banner, bannersize,  bannersuffix, route)
		})
	end

	return shieldSpec
end

local missingShields

local shieldExistsCache = {}

local function render(shieldEntry, scale, showLink)
	local shield = shieldEntry.shield
	local banners = shieldEntry.banners

	local size
	if shield[2] then
		local width, height = mw.ustring.match(shield[2], "(%d*)x?(%d*)")
		width = tonumber(width)
		height = tonumber(height)
		local sizeparts = {}
		if width then
			insert(sizeparts, format("%d", width * scale))
		end
		if height then
			insert(sizeparts, format("x%d", height * scale))
		end
		size = concat(sizeparts)
	else
		size = format("%s%d", landscape and "x" or "", defaultShieldSize * scale)
	end
	local shieldCode = format("[[File:%s|%spx|link=|alt=]]", shield[1], size)
	if not banners[1] then return shieldCode end

	for _,banner in ipairs(banners) do
		shieldCode = format("[[File:%s|%spx|link=|alt=]]<br>%s",
			banner[1],
			defaultShieldSize,
			shieldCode)
	end
	return '<span style="display: inline-block; vertical-align: baseline; line-height: 0; text-align: center;">' .. shieldCode .. '</span>'
end

function p.shield(route, scale, showLink, mainShield, shieldList)
	missingShields = {}

	scale = scale or 1

	local rendered = {}
	for _,entry in ipairs(shieldSpec(route, mainShield, shieldList)) do
		insert(rendered, render(entry, scale, showLink))
	end
	return concat(rendered), missingShields
end

-- Links/abbreviations
function p.link(route)
	local nolink = route.nolink
	local abbr = parser(route, 'abbr')
	if nolink then
		return abbr
	else
		local link = parser(route, 'link')
		if not link or link == '' then
			return abbr
		else
			return format("[[%s|%s]]", link, abbr)
		end
	end
end
-------------------------------------------

-- Links/abbreviations
local function routeText(route, jctname, frame)
	local link
	local type = route.type
	if not type or type == '' then
		link = route.route
	else
		link = p.link(route)
	end

	local dir = route.dir and ' ' .. string.lower(route.dir) or ''
	local routeText = link .. dir

	local name = route.name
	if name and name ~= '' then
		local mainText = jctname and name or routeText
		local parenText = jctname and routeText or name
		
		return format('%s (%s)', mainText, parenText)
	else
		return routeText
	end
end

local function extra(args)
	local extraTypes = mw.loadData('Module:Road data/extra')
	local extraIcon = extraTypes[string.lower(args.extra or '')]
	if not extraIcon then return '' end
	local size = defaultShieldSize .. 'px'
	local countryIcon = extraIcon[args.country] or extraIcon.default
	if type(countryIcon) == 'table' then
		local localIcon = countryIcon[args.state] or countryIcon.default
		return string.format("[[File:%s|%s|alt=|link=]]", localIcon, size)
	else
		return string.format("[[File:%s|%s|alt=|link=]]", countryIcon, size)
	end
end

local function parseArgs(args)
	local state = args.state or args.province or ''
	args.state = state
	local country
	if args.country and args.country ~= '' then
		country = string.upper(args.country)
	else
		local countryModule = mw.loadData("Module:Road data/countrymask")
		country = countryModule[state] or 'UNK'
	end
	args.country = country

	local params = {'denom', 'county', 'township', 'dab', 'nolink', 'noshield', 'to', 'dir', 'name'}
	local routes = {}
	local routeCount = 1
	local seenTo = false
	while true do
		local routeType = args[routeCount * 2 - 1]
		if not routeType then break end
		local route = {type = routeType, route = args[routeCount * 2]}
		for _,v in pairs(params) do
			route[v] = args[v .. routeCount]
		end
		
		if args.nolink then
			route.nolink = args.nolink
		end
		
		route.country = country
		route.state = state

		-- Set the first .to to true.
		-- Set all following .to to ''.
		if seenTo then
			if route.to then
				-- Report duplicate to flag.
				route.toerror = true
			end
			route.to = ''
		elseif route.to then
			route.to = true
			seenTo = true
		end

		insert(routes, route)
		routeCount = routeCount + 1
	end
	return routes
end

local function prefix(to, num)
	if to and to ~= '' then
		return num == 1 and 'To ' or ' to '
	end
	return num == 1 and '' or '&nbsp;/ '
end

local function addErrorMsg(catCode, msg, errorMsg)
	errorMsg.code = errorMsg.code or catCode
	insert(errorMsg, format('<span style="display: none;">Module:Jct %s</span>', msg))
end

function p._jct(args, frame)
	local routes = parseArgs(args)
	local shields = {}
	local links = {}
	local allMissingShields = {}
	local typeErr = false
	local toErr = false
	frame = frame or mw.getCurrentFrame()
	for num,route in ipairs(routes) do
		if not (args.noshield or route.noshield) then
			local shield, missingShields = p.shield(route)
			insert(shields, shield)
			if missingShields[1] then
				insert(allMissingShields, concat(missingShields, ' / '))
			end
		end
		local prefix = prefix(route.to, num)
		if prefix ~= '' then insert(links, prefix) end
		insert(links, routeText(route, args.jctname, frame))
		typeErr = typeErr or route.typeerror or false
		toErr = toErr or route.toerror or false
	end
	local graphics = concat(shields) .. extra(args) .. ' '
	local linkText = concat(links)
	local cities = ''
	if args.city1 or args.location1 then
		local citiesPrefix
		if args.citiesprefix then
			citiesPrefix = args.citiesprefix ~= '' and format(" %s ", args.citiesprefix) or ''
		else
			citiesPrefix = '&nbsp;'
		end
		local cityModule = require(cityModuleName)
		cities = citiesPrefix .. cityModule.city(args)
	end

	local errorMsg = {}
	-- Errors must be reported by the level of severity, most severe first.
	if typeErr then
		-- Report invalid type errors.
		addErrorMsg("§", 'error: Invalid route type', errorMsg)
	end
	if #allMissingShields > 0 then
		-- Report missing shield error.
		-- shieldExists() would have populated missingShields if shields are missing.
		addErrorMsg("¶", 'error: Missing route marker graphics: ' .. concat(allMissingShields, ' / '), errorMsg)
	end
	if toErr then
		-- Report invalid to errors.
		addErrorMsg("&", 'error: Invalid "to" argument', errorMsg)
	end
	if args.road then
		-- Report deprecated "road" warning.
		addErrorMsg("∆", 'warning: "road" parameter is deprecated', errorMsg)
	end
	if args.rdt then
		-- Report deprecated "rdt" warning.
		addErrorMsg("£", 'warning: "rdt" parameter is deprecated', errorMsg)
	end
	if #errorMsg > 0 then
		local page = mw.title.getCurrentTitle().prefixedText -- Get transcluding page's title
		-- Add a category for the first, most severe error.
		insert(errorMsg, format('[[Category:Jct template errors|%s %s]]', errorMsg.code, page))
		errorMsg = concat(errorMsg)
	else
		errorMsg = ''
	end

	return graphics .. linkText .. cities .. errorMsg
end

function p.jct(frame)
	-- Import module function to work with passed arguments
	local getArgs = require('Module:Arguments').getArgs
	local args = getArgs(frame, {removeBlanks = false})
	return p._jct(args, frame)
end

function p._roadlink(args, frame)
	local routes = parseArgs(args)
	local links = {}
	local typeErr = false
	local toErr = false
	frame = frame or mw.getCurrentFrame()
	for num,route in ipairs(routes) do
		local prefix = prefix(route.to, num)
		if prefix ~= '' then insert(links, prefix) end
		insert(links, routeText(route, args.jctname, frame))
		typeErr = typeErr or route.typeerror or false
		toErr = toErr or route.toerror or false
	end
	local linkText = concat(links)
	local cities = ''
	if args.city1 or args.location1 then
		local citiesPrefix
		if args.citiesprefix then
			citiesPrefix = args.citiesprefix ~= '' and format(" %s ", args.citiesprefix) or ''
		else
			citiesPrefix = '&nbsp;'
		end
		local cityModule = require(cityModuleName)
		cities = citiesPrefix .. cityModule.city(args)
	end

	local errorMsg = {}
	-- Errors must be reported by the level of severity, most severe first.
	if typeErr then
		-- Report invalid type errors.
		addErrorMsg("2", 'error: Invalid route type', errorMsg)
	end
	if toErr then
		-- Report invalid to errors.
		addErrorMsg("3", 'error: Invalid "to" argument', errorMsg)
	end
	if args.road then
		-- Report deprecated "road" warning.
		addErrorMsg("W", 'warning: "road" parameter is deprecated', errorMsg)
	end
	if #errorMsg > 0 then
		local page = mw.title.getCurrentTitle().prefixedText -- Get transcluding page's title
		-- Add a category for the first, most severe error.
		insert(errorMsg, format('[[Category:Jct template errors|%s %s]]', errorMsg.code, page))
		errorMsg = concat(errorMsg)
	else
		errorMsg = ''
	end

	return linkText .. cities
end

function p.roadlink(frame)
	-- Import module function to work with passed arguments
	local getArgs = require('Module:Arguments').getArgs
	local args = getArgs(frame, {removeBlanks = true})
	return p._roadlink(args, frame)
end

return p

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.