Moduł:Mapa/temp

Z Wikipedii, wolnej encyklopedii
 Dokumentacja modułu [stwórz] [odśwież]
-- {{ek}}
local function getMapParams(map, frame)
	mw.logObject(map, "map")
	if not map or (#map == 0) then
		mw.log("Brak nazwy mapy lokalizacyjnej")
	end
	local moduleprefix = "Module:Mapa/dane/"
	if map then
		local moduletitle = mw.title.new(moduleprefix..map)
		if not moduletitle then
			mw.log("„"..map.."” nie jest prawidłową nazwą definicji mapy lokalizacyjnej")
		elseif moduletitle.exists then
			mw.log("Ładuję mapę z „"..moduleprefix..map.."”")
			local mapData = mw.loadData(moduleprefix..map)
			return function(name, variant)
				if name == nil then
					return moduleprefix..map
				elseif mapData[1][name] == nil then
					return ""
				elseif variant and mapData[variant] then
					return mapData[variant][name] or mapData[1][name]
				else
					return mapData[1][name]
				end
			end
		elseif mw.title.new("Szablon:Mapa dane "..map).exists then
			local cache = {}
			if type(frame) ~= "table" or type(frame.expandTemplate) ~= "function" then
				error("Aby używać starych szablonów wymagane jest podanie ramki standardowych parametrów")
			end
			mw.log("Ładuję mapę z „Szablon:Mapa dane "..map.."”")
			return function(name, variant)
				if name == nil then
					return "Szablon:Mapa dane "..map
				elseif variant and (cache[name.."-"..variant] == nil) then
					local result = frame:expandTemplate{ title = "Mapa dane "..map, args = { "#switch:"..name.."-"..variant }}
					if #result == 0 then
						result = frame:expandTemplate{ title = "Mapa dane "..map, args = { "#switch:"..name }}
					end
					cache[name.."-"..variant] = result
				elseif cache[name] == nil then
					cache[name] = frame:expandTemplate{ title = "Mapa dane "..map, args = { "#switch:"..name }}
				end
				return variant and cache[name.."-"..variant] or cache[name]
			end
		else
			mw.log("Nie mogę znaleźć definicji podanej mapy lokalizacyjnej. Nie istnieje ani „"..moduleprefix..map.."”, ani „Szablon:Mapa dane "..map.."”.")
		end
	end
	
	-- default fallback
	local mapData = mw.loadData(moduleprefix.."brak")
	return function(name, variant)
		if name == nil then
			return false
		elseif name == false then
			return (map and (#map > 0)) and map or false
		elseif mapData[1][name] == nil then
			return ""
		elseif variant and mapData[variant] then
			return mapData[variant][name] or mapData[1][name]
		else
			return mapData[1][name]
		end
	end
end

local function getX(longitude, left, right)
	local width = (right - left) % 360
	if width == 0 then
		width = 360
	end
	local distanceFromLeft = (longitude - left) % 360
	-- the distance needed past the map to the right equals distanceFromLeft - width. the distance needed past the map to the left equals 360 - distanceFromLeft. to minimize page stretching, go whichever way is shorter
	if distanceFromLeft - width / 2 >= 180 then
		distanceFromLeft = distanceFromLeft - 360
	end
	return 100 * distanceFromLeft / width
end

local function getY(latitude, top, bottom)
	return 100 * (top - latitude) / (top - bottom)
end

local function formatCoordinates(parameters)
	mw.logObject(parameters, "formatCoordinates parameters")
	if not parameters.coordinates then
		return false
	end
	
	local placement = parameters.placement
	if not placement then
		placement = ((parameters.linkFlag == false) or (mw.title.getCurrentTitle().namespace ~= 0)) and "w tekście" or "w tekście i na górze"
	end
	local frame = { args = {
		parameters.coordinates,
		parameters.geohack,
		["umieść"] = placement,
		["dokładność"] = precision,
	}}
	local m = require("Moduł:Koordynaty")
	local result = (parameters.linkFlag == false) and m.format(frame) or m.link(frame)
	mw.logObject(result, "formatCoordinates result")
	return result
end

local function loadMap(frame, map, variant)
	local getMapParam = getMapParams(map, frame)
	return function(param)
		return getMapParam(param, variant)
	end
end

local function decodePoints(pointsData)
	if pointsData and (#pointsData > 0) then
		mw.logObject("["..pointsData.."{\"dummy\":false}]", "pda")
		local data = mw.text.jsonDecode("["..pointsData.."{\"dummy\":false}]")
		mw.logObject(data, "data")
		table.remove(data) -- remove last dummy
		mw.logObject(data, "data last removed")
		return data
	end
end

local function drawMap(builder, get, width, fontSize, data)
	local reliefImage = get("mapa")
	local reliefTitle = mw.title.new("Plik:"..reliefImage)
	local file = reliefTitle.file
	local height = file.height *  width / file.width
	
	-- przeliczanie punktów na mapie
	local inside = {}
	local outside = {}
	local errors = {}
	if data and (#data > 0) then
		local x_func = mw.text.trim(get("x") or "")
		local y_func = mw.text.trim(get("y") or "")
		local top = get("top")
		local left = get("left")
		local bottom = get("bottom")
		local right = get("right")
		if #x_func == 0 then
			x_func = false
		end
		if #y_func == 0 then
			y_func = false
		end
		for i, v in ipairs(data) do
			if v.latitude and v.longitude and v.mark and v.size then
				-- przeliczanie współrzędnych na pozycje rysowania
				if x_func then
					local expx = mw.ustring.gsub(mw.ustring.gsub(x_func, "{{{szerokość}}}", v.latitude), "{{{długość}}}", v.longitude)
					v.x = tonumber(mw.ext.ParserFunctions.expr(expx))
				else
					v.x = getX(v.longitude, left, right)
				end
				if y_func then
					local expy = mw.ustring.gsub(mw.ustring.gsub(y_func, "{{{szerokość}}}", v.latitude), "{{{długość}}}", v.longitude)
					v.y = tonumber(mw.ext.ParserFunctions.expr(expy))
				else
					v.y = getY(v.latitude, top, bottom)
				end
				
				v.rx = width * v.x / 100
				v.ry = height * v.y / 100
				if (v.x < 0) or (v.x > 100) or (v.y < 0) or (v.y > 100) then
					table.insert(outside, v)
				else
					table.insert(inside, v)
				end
			elseif v.error then
				table.insert(errors, v)
			else
				-- TODO illegal data or "dummy: false"
				mw.logObject(v, "illegal at "..tostring(i))
			end
		end
	end
	
	-- automatyczne pozycjonowanie dwóch punktów
	if (#inside == 2) and inside[1].description and inside[2].description and not inside[1].position and not inside[2].position then
		local y1 = inside[1].ry
		local y2 = inside[2].ry
		if (math.abs(y1 - y2) < 16) and (y1 > 8) and (y2 > 8) and ((height - y1) > 8) and ((height - y2) > 8) and (math.abs(inside[1].rx - inside[2].rx) < 80) then
			inside[1].position = y2 > y1 and "top" or "bottom"
			inside[2].position = y1 > y2 and "top" or "bottom"
		end
	end
	
	mw.logObject(outside, "outside")
	mw.logObject(inside, "inside")
	mw.logObject(errors, "errors")

	-- tło mapy
	local relief = builder:tag("div")
	relief:css({ position = "relative", border = "0 solid #aaa", padding = "0", width = tostring(width).."px" })
	relief:wikitext("[[Plik:", reliefImage, "|", width, "px|link=")
	local reliefInfo = get("dopełniacz")
	if reliefInfo then
		relief:wikitext("|Mapa lokalizacyjna ", reliefInfo)
	end
	
	relief:wikitext("]]")
	
	function showError(category, ...)
		local catLink = ""
		local known = {
			["brak mapy"] = { "'''Brak mapy:''' ''%s''", "[[Kategoria:Szablony lokalizacyjne - brak mapy]]", },
			["brak kodu mapy"] = { "'''Brak kodu mapy'''", "[[Kategoria:Szablony lokalizacyjne - brak kodu mapy]]", },
			["współrzędne spoza mapy"] = { "'''Współrzędne spoza mapy:''' ''%f %f''", "[[Kategoria:Szablony lokalizacyjne - współrzędne spoza mapy]]", },
			["brak współrzędnych"] = { "'''Brak współrzędnych'''", "[[Kategoria:Szablony lokalizacyjne – brak współrzędnych]]", },
			[true] = { "%s", false },
			[false] = { "'''''Inny błąd'''''", false, },
		}
		local k = known[category] or known[false]
		local message = mw.ustring.format(k[1], ...)
		if k[2] and (mw.title.getCurrentTitle().namespace == 0) then
			message = message..k[2]
		end
		local absolute = relief:tag("div")
			:css( { position = "absolute", ["z-index"] = 200, top = "50%", left = "50%", height = 0, width = 0, margin = 0, padding = 0, } )
		local msg = absolute:tag("div")
			:css( { ["font-size"] = "90%", ["line-height"] = "110%", position = "relative", width = "16em", ["z-index"] = 202, top = "-0.5em", left = "-8em", float = "center", ["text-align"] = "center", background = "white", color = "red", } )
			:wikitext(message)
	end
	
	-- brak mapy
	if not get() then
		local map = get(false)
		showError(map and "brak mapy" or "brak kodu mapy", map)
		if (#inside == 1) and (#outside == 0) then
			local v = inside[1]
			if (v.longitude == 0) and (v.latitude == 0) then
				mw.log("dummy (0 0) bez mapy nie jest rysowany")
				return
			end
		end
	end
	
	-- błędy
	if (#inside == 0) and (#outside == 0) then
		showError("brak współrzędnych")
	end
	
	for i, v in ipairs(outside) do
		mw.logObject(v, "outside["..tostring(i).."]")
		showError("współrzędne spoza mapy", v.latitude, v.longitude)
	end
	
	for i, v in ipairs(errors) do
		mw.logObject(v, "error["..tostring(i).."]")
		showError(true, v.error or "?")
	end
	
	-- punkty na mapie
	for i, v in ipairs(inside) do
		mw.logObject(v, "inside["..tostring(i).."]")
		local hsize = tostring(v.size/2).."px"
		local size = tostring(v.size).."px"
		local absolute = relief:tag("div")
			:css( { position = "absolute", ["z-index"] = 2, top = tostring(v.y).."%", left = tostring(v.x).."%", height = 0, width = 0, margin = 0, padding = 0, } )
		local file = absolute:tag("div")
			:css( { position = "relative", ["text-align"] = "center", left = "-"..hsize, top = "-"..hsize, width = size, ["font-size"] = size, ["line-height"] = size, } )
		file:wikitext("[[Plik:", v.mark, "|", v.size, "x", size, "|link=", v.link)
		if v.description then
			file:wikitext("|", v.description)
		end
		file:wikitext("]]")
		-- TODO description
		if v.description then
			local desc = absolute:tag("div")
				:css( { ["font-size"] = tostring(fontSize).."px", ["line-height"] = tostring(1.2*fontSize).."px", ["z-index"] = "90", ["position"] = "relative", ["width"] = "10em", } )
			local css = {}
			if v.position == "right" then
				css = { top = "-1.1em", left = tostring((v.size / 2) + 2).."px", ["text-align"] = "left", float = "left" }
			elseif v.position == "left" then
				css = { top = "-1.1em", left = "-"..tostring((v.size / 2) + 2).."px", ["text-align"] = "right", float = "right" }
			elseif v.position == "top" then
				css = { top = "-2.0em", left = "-5em", ["text-align"] = "center", float = "center" }
			elseif v.position == "bottom" then
				css = { top = "-0.1em", left = "-5em", ["text-align"] = "center", float = "center" }
			else -- auto
				if (v.x < 50) or ((v.rx + 60) < width) then -- right
					css = { left = tostring((v.size / 2) + 2).."px", ["text-align"] = "left", float = "left" }
				else -- left
					css = { top = "-1.1em", left = "-"..tostring((v.size / 2) + 2).."px", ["text-align"] = "right", float = "right" }
				end
					
				css.top = v.y < 10 and "-0.85em" or "-1.1em"
			end
			
			desc:css(css)
			desc:tag("span")
				:css({ padding = "1px" })
				:wikitext(v.description)
		end
	end
end

return {
	
	["Wartość"] = function(frame)
		local f = frame.args[1] and frame or frame:getParent()
		return getMapParams(f.args[1], frame)(f.args[2], f.args[3])
	end,
	
	["Dobre punkty"] = function(frame)
		local args = require('Module:Arguments').getArgs(frame, {
			trim = true,
			removeBlanks = true,
		})
		local points = args["punkty mapy"]
		if not points or string.match(points, "%s*{") then
			return "DOBRE"
		end
	end,

	["Infobox"] = function(frame)
		mw.log("{{#invoke:Moduł:Mapa|Infobox}}")
		local args = require('Module:Arguments').getArgs(frame, {
			trim = true,
			removeBlanks = true,
		})
		local defaultIcon = "[[Plik:Geographylogo.svg|20px|alt=Ziemia|link=Ziemia]]"
		local map = args["mapa"]
		local variant = args["wariant"]
		local description = args["opis"]
		local mark = args["znak na mapie"] or "Red pog.svg"
		local markSize = tonumber(args["wielkość znaku"]) or 6
		local coordinates = args["współrzędne"]
		if not coordinates then
			local latitude = tonumber(args["szerokość"])
			local longitude = tonumber(args["długość"])
			if latitude and longitude then
				coordinates = tostring(latitude).." "..tostring(longitude)
				mw.log("współrzędne tylko w starym stylu: "..coordinates)
			else
				mw.log("infobox może wyszukać współrzędne w wikidanych")
			end
		else
			mw.log("współrzędne: "..coordinates)
		end
		--local linkFlag = args["linkuj"] ~= "nie"
		local precision = args["dokładność"]
		local twoMaps = args["dwie mapy"]
		local category = args["kategoria"]
		local geohack = args["opcje geohack"]
		local position = args["pozycja opisu"]
		local points = args["punkty mapy"]
		local display = false
		mw.logObject({precision = precision, twoMaps = twoMaps, category = category, geohack = geohack, position = position, points = points}, "argumenty")
		if points and not string.match(points, "%s*{") then
			mw.log("załączone punkty do mapy są w nieodpowiednim formacie")
			return
		end
		if not points and not coordinates then
			if args["wikidane"] == "nie" then
				mw.log("brak punktów na mapę, a nie ma pozwolenia na Wikidane")
			else
				mw.log("brak punktów na mapę i współrzędnych, nadszedł czas na Wikidane")
				local p = require("Moduł:Koordynaty").punkt({
					["opcje geohack"] = geohack,
					["znak"] = mark,
					["rozmiar znaku"] = markSize,
					["opis"] = description,
					["pozycja"] = position,
					["dokładność"] = precision,
					display = true,
				})
				if not p then
					mw.log("brak punktów na mapę nawet w Wikidanych")
				end
				
				mw.logObject(p, "p")
				points = p
			end
		end
		if not points and not coordinates then
			if not category or (mw.title.getCurrentTitle().namespace ~= 0) or (map == "żadna") or (map == "osobna") or (map == "pusta") or (map == "niedostępna") then
				return
			end

			mw.log("[[Kategoria:Szablony lokalizacyjne – brak współrzędnych – "..category.."]]")
			return '|- style="display:none;"\n!colspan="2"|brak współrzędnych[[Kategoria:Szablony lokalizacyjne – brak współrzędnych – '..category..']]\n|-'
		end
		if coordinates then
			local p = require("Moduł:Koordynaty").punkt({
				coordinates,
				["opcje geohack"] = geohack,
				["znak"] = mark,
				["rozmiar znaku"] = markSize,
				["opis"] = description,
				["pozycja"] = position,
			})
			mw.logObject(p, "p")
			points = points and (p..points) or p
			mw.logObject(points, "points (2)")
		end
		
		local pointsData = decodePoints(points)
		
		local result = {}
		local coords = false
		local icon = false
		if map == "żadna" then
			-- TODO współrzędne, geohack, linkuj=tak, dokładność=kątowo, umieść=w tekście (i na górze)
			icon = defaultIcon
			coords = formatCoordinates({
				coordinates = coordinates,
				geohack = geohack,
				linkFlag = true,
				precision = precision or "kątowo",
			})
		elseif map == "osobna" then
			-- TODO współrzędne, geohack, linkuj=tak, dokładność=kątowo, umieść=w tekście
			icon = defaultIcon
			coords = formatCoordinates({
				coordinates = coordinates,
				geohack = "globe:none",
				linkFlag = true,
				precision = precision or "kątowo",
				placement = "w tekście"
			})
		elseif map == "pusta" then
			-- no map nor coordinates
		elseif map == "niedostępna" then
			-- TODO współrzędne, globe:none, linkuj=nie, dokładność=dziesiętnie, normalizacja=auto, ikona=
			coords = formatCoordinates({
				coordinates = coordinates,
				geohack = "globe:none",
				linkFlag = false,
				precision = precision or "dziesiętnie",
			})
		else
			local get = loadMap(frame, map, variant)
			local map1 = mw.html.create("div")
				:css( { margin="0 auto", ["text-align"]="center", width="242px" } )
			map1:tag("div")
				:css( { ["font-weight"]= "bold", color="gray" } )
				:wikitext("Położenie na mapie ", get("dopełniacz"))
			drawMap(map1:tag("div"):addClass("mapa-lokalizacyjna"), get, 238, 12.6, pointsData)
			table.insert(result, '|- id="locationmap-infobox-primary" style="background-color:white; text-align:center; border-top:1px solid #aaa;"\n|colspan="2"|')
			table.insert(result, tostring(map1:allDone()))
			table.insert(result, "\n|-")
			if twoMaps ~= "nie" then
				local second = get("nadrzędna")
				if second and (#second > 0) then
					mw.logObject(second, "nadrzędna")
					local get2 = loadMap(frame, second, variant)
					local map2 = mw.html.create("div")
						:css( { margin="0 auto", ["text-align"]="center", width="242px" } )
					map2:tag("div")
						:css( { ["font-weight"]= "bold", color="gray" } )
						:wikitext("Położenie na mapie ", get2("dopełniacz"))
					drawMap(map2:tag("div"):addClass("mapa-lokalizacyjna"), get2, 238, 12.6, pointsData)
					table.insert(result, ' id="locationmap-infobox-secondary" style="background-color:white; text-align:center; border-top:1px solid #aaa;"\n|colspan="2"|')
					table.insert(result, tostring(map2:allDone()))
					table.insert(result, "\n")
				end
			end
		
			icon = get("ikona")
			if not icon or #icon == 0 then
				icon = defaultIcon
			end
			
			coords = formatCoordinates({
				coordinates = coordinates,
				geohack = get("globe") or geohack,
				linkFlag = true,
				precision = precision or "kątowo",
			})
			if not coords and pointsData and (#pointsData > 0) then
				icon = false
				coords = pointsData[1].display
			end
		end
		
		if coords then
			table.insert(result, '|-\n|colspan="2" style="background-color:white; text-align:center; border-bottom:1px solid #aaa;"|')
			table.insert(result, icon and (icon.." ") or "")
			table.insert(result, coords)
			table.insert(result, "\n")
		end
		
		if #result > 0 then
			table.insert(result, "|-")
		end
		
		return table.concat(result)
	end,
	
	["Thumb"] = function(frame)
		local args = require('Module:Arguments').getArgs(frame, {
			trim = true,
			removeBlanks = false,
		})
		local map = args["mapa"] or args[1] or "{{{1}}}"
		if #map == 0 then
			map = nil
		end
		local variant = args["wariant"]
		local width = tonumber(args["rozmiar"]) or 238
		local fontSize = tonumber(args["font-size"]) or 12.6
		local align = args["wyrównanie"] or "right"
		local footer = args["podpis"]
		local pointsData = decodePoints(args["punkty mapy"])
		
		local get = loadMap(frame, map, variant)
		
		local positionClass = {
			["center"] = "center",
			["right"] = "tright",
			["left"] = "tleft",
			[""] = "tnone",
		}
		local thumb = mw.html.create("div")
			:addClass("thumb")
			:addClass(positionClass[align] or align)
			:css({ overflow = "auto" })
			:wikitext('\n')
		local thumbinner = thumb:tag("div")
			:addClass("thumbinner")
			:css({ width = tostring(width + 2).."px" })
			:wikitext('\n')
		local border = thumbinner:tag("div")
			:css({ border = "1px solid #ccc", width = tostring(width).."px !important" })
		local builder = border:tag("div")
			--:addClass("mapa-lokalizacyjna")
			:css({ margin = "0 auto", width = tostring(width).."px", border = "0" })
		drawMap(builder, get, width, fontSize, pointsData)
		thumbinner
			:wikitext('\n')
		local thumbcaption = thumbinner:tag("div")
			:addClass("thumbcaption")
		thumbcaption:tag("div")
			:addClass("magnify")
			:wikitext("[[Plik:Geographylogo.svg|16x16px|link=Wikiprojekt:Szablony lokalizacyjne]]")
		if footer and (#footer > 0) then
			thumbcaption:wikitext(footer)
		else
			thumbcaption:wikitext("Położenie na mapie ", mw.text.nowiki(get("dopełniacz") or ""))
		end
		thumbinner
			:wikitext('\n')
		thumb
			:wikitext('\n')
		return thumb:allDone()
	end,
	
	["Inline"] = function(frame)
		local args = require('Module:Arguments').getArgs(frame, {
			trim = true,
			removeBlanks = false,
		})
		local map = args["mapa"] or args[1] or "{{{1}}}"
		if #map == 0 then
			map = nil
		end
		local variant = args["wariant"]
		local width = tonumber(args["rozmiar"]) or 238
		local fontSize = tonumber(args["font-size"]) or 12.6
		local pointsData = decodePoints(args["punkty mapy"])
		
		local get = loadMap(frame, map, variant)
		local builder = mw.html.create("div")
			:addClass("mapa-lokalizacyjna")
			:css({ margin ="0 auto", width = tostring(width + 2).."px", padding = "3px", margin = "3px" })
		drawMap(builder, get, width, fontSize, pointsData)
		return builder:allDone()
	end,

}