Notwendiges Modul für die Benutzung der Vorlage {{Marker}}


-- module import
local mc = require( 'Modul:Marker/Colors' )
local mi = require( 'Modul:Marker/Maki icons' )
local mp = require( 'Modul:Marker/Params' )
local ma = require( 'Modul:Map' )
local pc = require( 'Modul:ParamsCheck' )
local vt = require( 'Modul:Marker/Types' ) -- types to groups like drink, eat, go, see, sleep, ...
local pt = require( 'Modul:Marker/POITypes' ) -- WD types to vCard/Poi types
local cd = require( 'Modul:Coordinates' )
local uc = require( 'Modul:UrlCheck' )
local yn = require( 'Modul:Yesno' )

local mk = {}

mk.categories = {
	['poiNumbersUsed']  = '[[Category:Poi-Nummer manuell vergeben]]',
	['poiNumberIsZero'] = '[[Category:Poi-Nummer auf Null gesetzt]]',
	['missingCoord']    = '[[Category:Marker: Ohne Koordinaten]]',
	['missingName']     = '[[Category:Marker: Ohne Namen]]',
	['unknownFormat']   = '[[Category:Marker: Unbekanntes Format]]',
	['unknownIcon']     = '[[Category:Marker: Unbekanntes Symbol]]',
	['unknownType']     = '[[Category:Marker: Unbekannter Typ]]',
	['dmsCoordinate']   = '[[Category:Marker: DMS-Koordinate]] <span class="listing-vcardInfo" title="DMS-Koordinate">DMS-Koordinate</span>'
}

mk.errorMsg = {
	['poiNumbersUsed']    = 'Poi-Nummer manuell vergeben',
	['poiNumberIsZero']   = 'Poi-Nummer auf Null gesetzt',
	['missingCoord']      = 'Länge und/oder Breite fehlt',
	['missingName']       = 'Name fehlt',
	['missingImg']        = '[[Category:Marker: Datei existiert nicht]] Nicht vorhandenes Bild:',
	['missingParameter1'] = 'Parameter 1 fehlt',
	['unknownFormat']     = 'Unbekanntes Format',
	['unknownIcon']       = 'Unbekanntes Marker-Symbol',
	['unknownType']       = 'Unbekannter Typ',
	['wrongQualifier']    = '[[Category:Marker: Fehlerhafter Wikidata-Qualifikator]] Fehlerhafter Wikidata-Qualifikator',
	['wrongUrl']          = '[[Category:URL ist ungültig]] <span class="error" title="URL ist ungültig">URL ist ungültig</span>',
	['UrlWithIP']         = '[[Category:URL enthält IP-Adresse]] <span class="listing-vcardInfo" title="URL enthält IP-Adresse">URL enthält IP-Adresse</span>',
	['nonASCII']          = '[[Category:URL enthält Unicode-Zeichen]] <span class="listing-vcardInfo" title="URL enthält Unicode-Zeichen">URL enthält Unicode-Zeichen</span>'
}

mk.Icons = {
	['commons']   = '[[File:Commons-logo.svg|x16px|text-bottom|link=|Wikimedia Commons – Sammlung von Bildern, Videos und Audiodateien zu dieser Einrichtung]]',
	['internet']  = '[[File:Applications-internet.svg|16px|text-bottom|link=|Website dieser Einrichtung]]',
	['wikidata']  = '[[File:Wikidata-logo.svg|16px|middle|link=|Wikidata – Daten zu dieser Einrichtung]]',
	['wikipedia'] = '[[File:Antu wikipedia.svg|16px|text-bottom|link=|Wikipedia-Artikel zu dieser Einrichtung]]',
	['wikivoyage']= '[[File:Wikivoyage-Logo-v3-icon.svg|16px|text-bottom|link=|Wikivoyage-Artikel zu dieser Einrichtung in einer anderen Sprache]]',
}

mk.mapServer = 'http://maps.wikivoyage-ev.org'
mk.coordURL  = 'https://de.wikivoyage.org/w/index.php?title=Special%3AMapsources&params='

mk.texts = {
	latitude  = 'Breitengrad',
	longitude = 'Längengrad',
	tooltip   = 'Nummer in der Karte&#10;KLICK: direkt zur Karte',
	legend    = 'Legende für Typ '
}

function mk.errorInfo( s )
	return '<span class="error" title="' .. s .. '">' .. s .. '</span>'
end

-- Wikidata related functions

local wrongQualifier = false
local mkEntity = nil -- marker entity
local searchLimit = 4 -- for P31

local function checkId( id )
	local i = id and id:upper() or ''
	local l
	if i ~= '' then
		if string.match( i, '^[%d]+$') ~= nil then -- only number
			i = 'Q' .. i
		elseif string.match( i, '^Q[%d]+$') == nil then -- Q and number
			wrongQualifier = true
			i = ''
		end
	end
	if i ~= '' then
		mkEntity = mw.wikibase.getEntity( i )
		if mkEntity == nil then
			i = ''
			wrongQualifier = true
		end
	end
	return i
end

local function getEntWDvalue( anEntity, p )
	if anEntity == nil then return '' end

	local w = anEntity:getBestStatements( p )
	local i = ''

	if (#w > 0) and (w[1].mainsnak.snaktype == 'value') then
		i = w[1].mainsnak.datavalue.value
	end

	return i
end

local function getEntWDid( anEntity, p )
	if anEntity == nil then return '' end

	local w = anEntity:getBestStatements( p )
	local i = ''

	if (#w > 0) and (w[1].mainsnak.snaktype == 'value') then
		i = w[1].mainsnak.datavalue.value['id']
	end

	return i
end

local function getWDid( id, p )
	return getEntWDid( mw.wikibase.getEntity( id ), p )
end

-- types to groups translation for map legend

local function translateType( aType )
	local t = vt.groups[aType]
	if (t ~= nil) and (t ~= '') then return t else return aType end
end

local function outputCoordinates( lat, long, name )
	local latDMS  = ''
	local longDMS = ''
	local latMs   = '' -- Map sources parameters
	local longMs  = ''

	latDMS, _, latMs = cd.getDMSString( lat, 4, 'lat', '', '', 'f1' )
	longDMS, _, longMs = cd.getDMSString( long, 4, 'long', '', '', 'f1' )

	return '<span class="listing-dms-coordinates printNoLink plainlinks">['
		.. mk.coordURL .. latMs
		.. '_' .. longMs .. '_' .. mw.uri.encode( 'type:landmark_globe:earth' )
		.. '&locname=' .. mw.uri.encode( name )
		.. ' <span class="coordStyle" title="' .. mk.texts.latitude .. '">'
		.. latDMS .. '</span>'
		.. ' <span class="coordStyle" title="' .. mk.texts.longitude .. '">'
		.. longDMS .. '</span>]</span>'
end

local function getWikiLink( langArray, wiki, entity )
	local i, lang
	local result = ''
	local prefix = '' -- empty in case of Wikivoyage
	if wiki == 'wiki' then prefix = 'w:' end

	for i, lang in ipairs( langArray ) do
		if entity.sitelinks[lang .. wiki] ~= nil then
			result = tostring( mw.uri.fullUrl( prefix .. lang .. ':'
				.. mw.uri.encode( entity.sitelinks[lang .. wiki].title, 'WIKI' ) ) )
			break
		end
	end
	return result
end

-- main marker function

function mk._marker( args, frame )
	args.zoom      = tonumber( args.zoom or '' )
	args.name      = args.name or ''
	args.alt       = args.alt or ''
	args.symbol    = args.symbol or ''
	args.symbol    = args.symbol:lower()
	args.text      = args.text or ''
	args['map-group'] = args['map-group'] or ''
	args['type']   = string.lower( args['type'] or '' )
	args.counter   = string.lower( args.counter or '' ) -- for backward compatibility
	if args['type'] == '' then args['type'] = args.counter end
	args.url       = args.url or ''
	args.addMf     = args.addMf or ''
	args.wikidata  = checkId( args.wikidata or '' )

	local r, t, a, j
	local noURL = false

	-- checking coordinates given as template parameters

	local dms = false
	if args.lat ~= '' then
		t = tonumber( args.lat )
		if t == nil then 
			r = cd.toDec( args.lat, 'lat', 6 )
			if r.error > 0 then args.lat = ''
			else
				args.lat = r.dec
				dms = true
			end
		else
			if (t < -90) or (t > 90) then args.lat = ''
			else args.lat = t end
		end
	end
	if args.long ~= '' then
		t = tonumber( args.long )
		if t == nil then 
			r = cd.toDec( args.long, 'long', 6 )
			if r.error > 0 then args.long = ''
			else
				args.long = r.dec
				dms = true
			end
		else
			if (t <= -180) or (t > 180) then args.long = ''
			else args.long = t end
		end
	end

	-- getting values from Wikidata
	t = ''
	local wikipedia = ''
	local wikivoyage = ''
	local thisWikivoyage = '' -- current Wikivoyage branch
	local wmCommons = ''
	local wmCommonsCat = ''
	local wikiLang = mw.getContentLanguage():getCode()

	if args.url ~= '' then
		a = yn( args.url, nil )
		if a ~= nil then -- is boolean
			args.url = ''
			noURL = not a
		end
	end

	if args.wikidata ~= '' then
		if args.name == '' then
			args.name = mkEntity:getLabel() or ''
			if args.name == '' then args.name = mkEntity:getLabel( 'en' ) or '' end
		end
		
		if (mkEntity ~= nil) and (mkEntity.sitelinks ~= nil) then
			if mkEntity.sitelinks[wikiLang .. 'wikivoyage'] ~= nil then
				thisWikivoyage = mkEntity.sitelinks[wikiLang .. 'wikivoyage'].title
				if thisWikivoyage == mw.title.getCurrentTitle().text then
					thisWikivoyage = '' end -- no link to the article itself
			end
			wikipedia = getWikiLink( {wikiLang, 'en'}, 'wiki', mkEntity )
			wikivoyage = getWikiLink( {'en'}, 'wikivoyage', mkEntity )
		end
		wmCommonsCat = getEntWDvalue( mkEntity, 'P373' )
		if (wmCommonsCat ~= '') then
			wmCommonsCat = mw.ustring.gsub( wmCommonsCat, ' ', '_' )
			wmCommons = tostring( mw.uri.fullUrl( 'c:Category:' .. mw.uri.encode( wmCommonsCat, 'WIKI' ) ) )
		end

		if args.image == '' then args.image = getEntWDvalue( mkEntity, 'P18' ) end
		
		if (args.url == '') and (not noURL) then
			args.url = getEntWDvalue( mkEntity, 'P856' ) end

		if (args.lat == '') or (args.long == '') then
			t = mkEntity:getBestStatements( 'P625' )
			if (#t > 0) and t[1].mainsnak.snaktype == 'value' then
				args.lat = t[1].mainsnak.datavalue.value.latitude
				args.long = t[1].mainsnak.datavalue.value.longitude
			end
		end
	
		if args['type'] == '' then
			t = getEntWDid( mkEntity, 'P31' )
			if t == '' then a = vt.types.default else a = pt[t] end
			if a == nil then
				j = 0
				repeat
					t = getWDid( t, 'P279' )
					if t ~= '' then a = pt[t] end
					j = j + 1
				until (j >= searchLimit) or (t == '') or (a ~= nil)
			end
			if a == nil then a = vt.types.default end
			args['type'] = a
		end
	end

	args['type'] = args['type']:gsub( ' ', '_' )
	local origType = args['type']
	if vt.groups[args['type']] == nil then args['type'] = vt.types[args['type']] end
	if args['type'] == nil then args['type'] = vt.types.default end

	if args.symbol ~= 'legend' then
		if (args.lat == '') or (args.long == '') then
			return mk.categories.missingCoord .. mk.errorInfo( mk.errorMsg.missingCoord )
		end
	end

	local imageMsg = ''
	local imageEx = false
	if args.image ~= '' then
		imageEx = frame:callParserFunction( '#ifexist', { 'Media:' .. args.image , 1 , 0 } ) == '1'
		if not imageEx then
			imageMsg = ' <span class="error">' .. mk.errorMsg.missingImg .. ' '
				.. args.image .. '</span>'
		end
	end
	if dms then imageMsg = imageMsg .. mk.categories.dmsCoordinate end

	if ( args.url ~= '' ) then
		j = uc.isUrl( args.url )
		if j > 2 then
			imageMsg = imageMsg .. ' ' .. mk.errorMsg.wrongUrl
			args.url = ''
		end
		if j == 2 then imageMsg = imageMsg .. ' ' .. mk.errorMsg.UrlWithIP end
		if j == 1 then imageMsg = imageMsg .. ' ' .. mk.errorMsg.nonASCII end
	end

	local result = ''
	local color = ''

	if (args.zoom == nil) or (args.zoom == '') or (type( args.zoom ) ~= 'number')
		then args.zoom = 17
	else
		args.zoom = math.floor( args.zoom )
		if (args.zoom < 0) or (args.zoom > 19) then
			args.zoom = 17
		end
	end
	if args.name == '' then
		args.name = mk.errorMsg.missingName
		imageMsg = imageMsg .. ' ' .. mk.categories.missingName .. mk.errorInfo( mk.errorMsg.missingName )
	end
	args.linkName = mw.ustring.gsub( args.name, '^(.*)%[%[(.*)%]%](.*)$', '%2' )
	if args.linkName ~= '' then
		local t = mw.ustring.gsub( args.linkName, '^(.*)|(.*)$', '%2' )
		if t ~= '' then args.linkName = t end
		args.linkName = mw.text.trim( args.linkName )
	end
	if args.linkName == '' then args.linkName = args.name end
	if (args.linkName == args.name) and (thisWikivoyage ~= '') then
		args.name = '[[' .. thisWikivoyage .. '|' .. args.name .. ']]'
	end

	color, args['type'] = mc.getColor( args['type'] )

	local useIcon = false
	if args.symbol == 'legend' then
		if args.name == '' then args.name = '1' end
		return '<span class="plainlinks printNoLink poi" style="background-color: #' .. color
			.. '; border-color: #' .. color .. ';" title="' .. mk.texts.legend .. args['type']
			.. '"><span class="mw-kartographer-autostyled">' .. args.name .. '</span></span>'
	end
	if args.symbol == 'letter' then
		args.symbol = '-letter-' .. args['type']
	elseif (args.symbol == '') or (args.symbol == 'number') then
		args.symbol = '-number-' .. args['type']
	elseif (args.symbol ~= '') and (mi[args.symbol] == nil) then
		args.symbol = 'cross'
		color, args['type'] = mc.getColor( 'error' )
		args.text = '[[Datei:Close x - white.png|15px|' .. mk.errorMsg.unknownIcon .. '|link=]]'
		imageMsg = imageMsg .. ' ' .. mk.categories.unknownIcon
	elseif (args.text == '' ) then
		args.text = string.upper( string.sub( args.symbol, 1, 1 ) )
		useIcon = true
	end

	if args['type'] == 'error' then
		imageMsg = imageMsg .. ' ' .. mk.categories.unknownType .. mk.errorInfo( mk.errorMsg.unknownType )
	end

	local mArgs = {}
	mArgs['type'] = 'maplink'
	mArgs.geotype = 'Point'
	if args.alt == '' then args.alt = args.name end
	mArgs.title = args.alt
	if args.text == '' then mArgs.text = nil
	else
		mArgs.text = args.text
		if not useIcon then mArgs.class = 'no-icon' end
	end
		if not useIcon then mArgs.class = 'no-icon' end
		-- hier muss ich mal sehen, was passiert: args.text
	mArgs['marker-symbol'] = args.symbol
	mArgs['marker-color'] = color
	mArgs.latitude = args.lat
	mArgs.longitude = args.long
	mArgs.zoom = args.zoom
	if args['map-group'] == '' then mArgs.group = translateType( args['type'] )
	else mArgs.group = args['map-group'] end
	mArgs.show = vt.showAll
	if imageEx then mArgs.image = args.image else mArgs.image = nil end

	local tag, geojson, tagArgs = ma._tag( mArgs )
	local result = frame:extensionTag( tag, geojson, tagArgs )
	result = '<span class="plainlinks printNoLink poi listing-map" style="background-color: #' .. color
		.. '; border-color: #' .. color .. ';" title="' .. mk.texts.tooltip .. '">'
		.. result .. '</span>'

	local s = ''
	
	if args['format'] == 'f2' then
		-- marker only

	elseif args['format'] == 'f3' then -- marker and coordinates
		result = result .. ' ' .. outputCoordinates( args.lat, args.long, args.linkName )

	elseif (args['format'] == 'f0') or (args['format'] == 'f1') then
		-- f0: default: marker and name
		-- f1: marker and name (coordinates)
		if args.name ~= '' then
			if result ~= '' then result = result .. ' ' end
			s = '<span id="vCard_' .. mw.uri.anchorEncode( args.linkName )
				.. '" class="p-name fn org listing-name">' .. args.name .. '</span>'
			if args.url == '' then
				result = result .. s
			else
				if args.linkName == args.name then
					result = result .. '[' .. args.url .. ' ' .. s .. ']'
				else
					-- both article and web links
					result = result .. s .. ' <span class="listing-url">['
						.. args.url .. ' ' .. mk.Icons['internet'] .. ']</span>'
				end
			end
		else
			if args.url ~= '' then
				if result ~= '' then result = result .. ' ' end
				result = result .. '[' .. args.url .. ']'
			end
		end

		-- adding Wikimedia icons

		if (thisWikivoyage == '') and (wikivoyage ~= '') then
			result = result .. ' <span class="listing-sister-icons">['
				.. wikivoyage .. ' ' .. mk.Icons['wikivoyage'] .. ']</span>'
		end
		if wikipedia ~= '' then
			result = result .. ' <span class="listing-sister-icons">['
				.. wikipedia .. ' ' .. mk.Icons['wikipedia'] .. ']</span>'
		end
		if wmCommons ~= '' then
			result = result	.. ' <span class="listing-sister-icons">['
				.. wmCommons .. ' ' .. mk.Icons['commons'] .. ']</span>'
		end
		if args.wikidata ~= '' then
			result = result .. '<span class="listing-sister-icons listing-sister-wikidata">['
				.. tostring( mw.uri.fullUrl( 'd:' .. args.wikidata ) )
				.. ' ' .. mk.Icons['wikidata'] .. ']</span>'
		end

		if args['format'] == 'f1' then
			result = result .. ' (' .. outputCoordinates( args.lat, args.long, args.linkName ) .. ')'
		end
	else
		result = result .. ' ' .. mk.categories.unknownFormat
			.. mk.errorInfo( mk.errorMsg.unknownFormat ) .. ' '
	end

	if args.addMf == 'true' then
		s = '<span class="h-card vcard Marker"'
			.. ' data-wikilang="' .. wikiLang .. '"'
			.. ' data-color="#' .. color .. '"'
			.. ' data-type="' .. origType .. '"'
			.. ' data-group="' .. args['type'] .. '"'
		if args.url ~= '' then
			s = s .. ' data-url="' .. mw.text.nowiki( args.url ) .. '"' end
		if args['map-group'] ~= '' then
			s = s .. ' data-mapgroup="' .. args['map-group'] .. '"' end
		if args.wikidata ~= '' then
			s = s .. ' data-wikidata="' .. args.wikidata .. '"' end
		if wmCommonsCat ~='' then
			s = s .. ' data-commonscat="' .. wmCommonsCat .. '"' end

		result = s .. '><span class="p-geo geo listing-coordinates" style="display: none">'
			.. '<abbr class="p-latitude latitude">' .. args.lat .. '</abbr>'
			.. '<abbr class="p-longitude longitude">' .. args.long .. '</abbr></span>'
			.. result
		if (args['format'] == 'f2') or (args['format'] == 'f3') then
			result = result .. '<span class="p-name fn org listing-name" style="display: none">'
				.. args.linkName .. '</span>'
		end
		result = result .. '</span>'
		-- result = result .. frame:callParserFunction{ name = '#coordinates',
		-- 	args = { args.lat, args.long, 'type:landmark_globe:earth', name = args.linkName } }
	end

	if wrongQualifier then result = result .. '<span class="error">'
		.. mk.errorMsg.wrongQualifier .. '</span>' end

	if args.demo == 'true' then return result
	else return result .. imageMsg end
end

function mk.marker( frame )
	local args     = frame:getParent().args
	args.lat       = args.lat or ''
	args.long      = args.long or ''
	args.image     = args.image or ''
	args.addMf     = args.addMf or 'true'
	args.symbol    = args.symbol or ''
	args['format'] = args['format'] or 'f0'

	return mk._marker( args, frame ) .. pc.checkParams( args, mp._marker, '' )
end

-- the following templates are used only at the German Wikivoyage
-- evtl. marker-dummy

function mk.externalMapService( args )
	return '<span class="plainlinks printNoLink poi poi_man type_' .. args['type']
		.. '" title="Nummer in der Karte&#10;KLICK: direkt zur Karte&#10;(externe Webseite)">'
		.. '[' .. mk.mapServer .. '/w/poimap2.php?lat=' .. args.lat .. '&lon='
		.. args.long .. '&zoom=17&layer=' .. args[7] .. '&lang=' .. mw.getContentLanguage():getCode()
		.. '&name=' .. mw.uri.encode( mw.title.getCurrentTitle().text ) .. ' '
		.. args[1] .. ']</span>'
end

function mk.poi( frame )
	local args     = frame:getParent().args
	args[1]        = mw.text.trim( args[1] or '' )
	args['type']   = mw.text.trim( string.lower( args[2] or '' ) )
	if args['type'] == '' then args['type'] = 'other' end
	args.lat       = pc.checkNumber( args[3] or '' )
	args.long      = pc.checkNumber( args[4] or '' )
	args.name      = mw.text.trim( args[5] or '' )
	args.image     = mw.text.trim( args[6] or '' )
	args[7]        = mw.text.trim( args[7] or '' )
	if args[7] == '' then args[7] = 'W' end
	args['format'] = 'f2'
	args.addMf     = 'true'

	local function vcardInfo( s )
		return '<span class="wv-vcardInfo" title="' .. s .. '">' .. s .. '</span>'
	end

	local categs = ''
	if args[1] ~= '' then
		if (args[1] == '0') or (args[1] == 0) then
			categs = mk.categories.poiNumberIsZero .. vcardInfo( mk.errorMsg.poiNumberIsZero )
		else
			categs = mk.categories.poiNumbersUsed .. vcardInfo( mk.errorMsg.poiNumbersUsed )
			return mk.externalMapService( args ) .. pc.checkParams( args, mp._poi, '' ) .. categs
		end
	end

	return mk._marker( args, frame ) .. pc.checkParams( args, mp._poi, '' ) .. categs
end

function mk.poidummy( frame )
	local args   = frame:getParent().args
	args[1]      = mw.text.trim( args[1] or '' ) -- is necessary
	args['type'] = mw.text.trim( string.lower( args[2] or '' ) )
	if args['type'] == '' then args['type'] = 'other' end
	args.lat     = pc.checkNumber( args[3] or '' )
	args.long    = pc.checkNumber( args[4] or '' )
	args[7]      = mw.text.trim( args[7] or '' )
	if args[7] == '' then args[7] = 'W' end

	if args[1] == '' then return mk.errorInfo( mk.errorMsg.missingParameter1 ) end

	if (args.lat == '') or (args.long == '') then
		return mk.categories.missingCoord .. mk.errorInfo( mk.errorMsg.missingCoord )
	end

	return mk.externalMapService( args ) .. pc.checkParams( args, mp._poi, '' )
end

return mk