PhotosLocation

Permanently protected module
From Wikipedia, the free encyclopedia


--[[

This module is intended to replace the functionality of {{Coord}} and related

templates.  It provides several methods, including



{{#invoke:Coordinates | coord }} : General function formatting and displaying

coordinate values.



{{#invoke:Coordinates | dec2dms }} : Simple function for converting decimal

degree values to DMS format.



{{#invoke:Coordinates | dms2dec }} : Simple function for converting DMS format

to decimal degree format.



{{#invoke:Coordinates | link }} : Export the link used to reach the tools



]]



require('strict')



local math_mod = require("Module:Math")

local coordinates = {};

local isSandbox = mw.getCurrentFrame():getTitle():find('sandbox', 1, true);



local current_page = mw.title.getCurrentTitle()

local page_name = mw.uri.encode( current_page.prefixedText, 'WIKI' );

local coord_link = 'https://geohack.toolforge.org/geohack.php?pagename=' .. page_name .. '&params='



--[[ Helper function, replacement for {{coord/display/title}} ]]

local function displaytitle(coords)

	return mw.getCurrentFrame():extensionTag{

		name = 'indicator',

		args = { name = 'coordinates' },

		content = '<span id="coordinates">[[Geographic coordinate system|Coordinates]]: ' .. coords .. '</span>'

	}

end



--[[ Helper function, used in detecting DMS formatting ]]

local function dmsTest(first, second)

	if type(first) ~= 'string' or type(second) ~= 'string' then

		return nil

	end

	local s = (first .. second):upper()

	return s:find('^[NS][EW]$') or s:find('^[EW][NS]$')

end





--[[ Wrapper function to grab args, see Module:Arguments for this function's documentation. ]]

local function makeInvokeFunc(funcName)

	return function (frame)

		local args = require('Module:Arguments').getArgs(frame, {

			wrappers = 'Template:Coord'

		})

		return coordinatesfuncName](args, frame)

	end

end



--[[ Helper function, handle optional args. ]]

local function optionalArg(arg, supplement)

	return arg and arg .. supplement or ''

end



--[[

Formats any error messages generated for display

]]

local function errorPrinter(errors)

	local result = ""

	for i,v in ipairs(errors) do

		result = result .. '<strong class="error">Coordinates: ' .. v2 .. '</strong><br />'

	end

	return result

end



--[[

Determine the required CSS class to display coordinates



Usually geo-nondefault is hidden by CSS, unless a user has overridden this for himself

default is the mode as specificied by the user when calling the {{coord}} template

mode is the display mode (dec or dms) that we will need to determine the css class for

]]

local function displayDefault(default, mode)

	if default == "" then

		default = "dec"

	end



	if default == mode then

		return "geo-default"

	else

		return "geo-nondefault"

	end

end



--[[

specPrinter



Output formatter.  Takes the structure generated by either parseDec

or parseDMS and formats it for inclusion on Wikipedia.

]]

local function specPrinter(args, coordinateSpec)

	local uriComponents = coordinateSpec"param"

	if uriComponents == "" then

		-- RETURN error, should never be empty or nil

		return "ERROR param was empty"

	end

	if args"name" then

		uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec"name"])

	end



	local geodmshtml = '<span class="geo-dms" title="Maps, aerial photos, and other data for this location">'

			.. '<span class="latitude">' .. coordinateSpec"dms-lat" .. '</span> '

			.. '<span class="longitude">' ..coordinateSpec"dms-long" .. '</span>'

			.. '</span>'



	local lat = tonumber( coordinateSpec"dec-lat" ) or 0

	local geodeclat

	if lat < 0 then

		-- FIXME this breaks the pre-existing precision

		geodeclat = tostring(coordinateSpec"dec-lat"]):sub(2) .. "°S"

	else

		geodeclat = (coordinateSpec"dec-lat" or 0) .. "°N"

	end



	local long = tonumber( coordinateSpec"dec-long" ) or 0

	local geodeclong

	if long < 0 then

		-- FIXME does not handle unicode minus

		geodeclong = tostring(coordinateSpec"dec-long"]):sub(2) .. "°W"

	else

		geodeclong = (coordinateSpec"dec-long" or 0) .. "°E"

	end



	local geodechtml = '<span class="geo-dec" title="Maps, aerial photos, and other data for this location">'

			.. geodeclat .. ' '

			.. geodeclong

			.. '</span>'



	local geonumhtml = '<span class="geo">'

			.. coordinateSpec"dec-lat" .. '; '

			.. coordinateSpec"dec-long"

			.. '</span>'



	local inner = '<span class="' .. displayDefault(coordinateSpec"default"], "dms" ) .. '">' .. geodmshtml .. '</span>'

				.. '<span class="geo-multi-punct">&#xfeff; / &#xfeff;</span>'

				.. '<span class="' .. displayDefault(coordinateSpec"default"], "dec" ) .. '">';



	if not args"name" then

		inner = inner .. geodechtml

				.. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span></span>'

	else

		inner = inner .. '<span class="vcard">' .. geodechtml

				.. '<span style="display:none">&#xfeff; / ' .. geonumhtml .. '</span>'

				.. '<span style="display:none">&#xfeff; (<span class="fn org">'

				.. args"name" .. '</span>)</span></span></span>'

	end



    local stylesheetLink = 'Module:Coordinates' .. ( isSandbox and '/sandbox' or '' ) .. '/styles.css'

	return mw.getCurrentFrame():extensionTag{

		name = 'templatestyles', args = { src = stylesheetLink }

	} .. '<span class="plainlinks nourlexpansion load-gadget" data-gadget="WikiMiniAtlas">[' .. coord_link .. uriComponents ..

	' ' .. inner .. ']</span>'

end



--[[ Helper function, convert decimal to degrees ]]

local function convert_dec2dms_d(coordinate)

	local d = math_mod._round( coordinate, 0 ) .. "°"

	return d .. ""

end



--[[ Helper function, convert decimal to degrees and minutes ]]

local function convert_dec2dms_dm(coordinate)

	coordinate = math_mod._round( coordinate * 60, 0 );

	local m = coordinate % 60;

	coordinate = math.floor( (coordinate - m) / 60 );

	local d = coordinate % 360 .."°"



	return d .. string.format( "%02d′", m )

end



--[[ Helper function, convert decimal to degrees, minutes, and seconds ]]

local function convert_dec2dms_dms(coordinate)

	coordinate = math_mod._round( coordinate * 60 * 60, 0 );

	local s = coordinate % 60

	coordinate = math.floor( (coordinate - s) / 60 );

	local m = coordinate % 60

	coordinate = math.floor( (coordinate - m) / 60 );

	local d = coordinate % 360 .."°"



	return d .. string.format( "%02d′", m ) .. string.format( "%02d″", s )

end



--[[

Helper function, convert decimal latitude or longitude to

degrees, minutes, and seconds format based on the specified precision.

]]

local function convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)

	local coord = tonumber(coordinate)

	local postfix

	if coord >= 0 then

		postfix = firstPostfix

	else

		postfix = secondPostfix

	end



	precision = precision:lower();

	if precision == "dms" then

		return convert_dec2dms_dms( math.abs( coord ) ) .. postfix;

	elseif precision == "dm" then

		return convert_dec2dms_dm( math.abs( coord ) ) .. postfix;

	elseif precision == "d" then

		return convert_dec2dms_d( math.abs( coord ) ) .. postfix;

	end

end



--[[

Convert DMS format into a N or E decimal coordinate

]]

local function convert_dms2dec(direction, degrees_str, minutes_str, seconds_str)

	local degrees = tonumber(degrees_str)

	local minutes = tonumber(minutes_str) or 0

	local seconds = tonumber(seconds_str) or 0



	local factor = 1

	if direction == "S" or direction == "W" then

		factor = -1

	end



	local precision = 0

	if seconds_str then

		precision = 5 + math.max( math_mod._precision(seconds_str), 0 );

	elseif minutes_str and minutes_str ~= '' then

		precision = 3 + math.max( math_mod._precision(minutes_str), 0 );

	else

		precision = math.max( math_mod._precision(degrees_str), 0 );

	end



	local decimal = factor * (degrees+(minutes+seconds/60)/60)

	return string.format( "%." .. precision .. "f", decimal ) -- not tonumber since this whole thing is string based.

end



--[[

Checks input values to for out of range errors.

]]

local function validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, source, strong )

	local errors = {};

	lat_d = tonumber( lat_d ) or 0;

	lat_m = tonumber( lat_m ) or 0;

	lat_s = tonumber( lat_s ) or 0;

	long_d = tonumber( long_d ) or 0;

	long_m = tonumber( long_m ) or 0;

	long_s = tonumber( long_s ) or 0;



	if strong then

		if lat_d < 0 then

			table.insert(errors, {source, "latitude degrees < 0 with hemisphere flag"})

		end

		if long_d < 0 then

			table.insert(errors, {source, "longitude degrees < 0 with hemisphere flag"})

		end

		--[[

		#coordinates is inconsistent about whether this is an error.  If globe: is

		specified, it won't error on this condition, but otherwise it will.



		For not simply disable this check.



		if long_d > 180 then

			table.insert(errors, {source, "longitude degrees > 180 with hemisphere flag"})

		end

		]]

	end



	if lat_d > 90 then

		table.insert(errors, {source, "latitude degrees > 90"})

	end

	if lat_d < -90 then

		table.insert(errors, {source, "latitude degrees < -90"})

	end

	if lat_m >= 60 then

		table.insert(errors, {source, "latitude minutes >= 60"})

	end

	if lat_m < 0 then

		table.insert(errors, {source, "latitude minutes < 0"})

	end

	if lat_s >= 60 then

		table.insert(errors, {source, "latitude seconds >= 60"})

	end

	if lat_s < 0 then

		table.insert(errors, {source, "latitude seconds < 0"})

	end

	if long_d >= 360 then

		table.insert(errors, {source, "longitude degrees >= 360"})

	end

	if long_d <= -360 then

		table.insert(errors, {source, "longitude degrees <= -360"})

	end

	if long_m >= 60 then

		table.insert(errors, {source, "longitude minutes >= 60"})

	end

	if long_m < 0 then

		table.insert(errors, {source, "longitude minutes < 0"})

	end

	if long_s >= 60 then

		table.insert(errors, {source, "longitude seconds >= 60"})

	end

	if long_s < 0 then

		table.insert(errors, {source, "longitude seconds < 0"})

	end



	return errors;

end



--[[

parseDec



Transforms decimal format latitude and longitude into the

structure to be used in displaying coordinates

]]

local function parseDec( lat, long, format )

	local coordinateSpec = {}

	local errors = {}



	if not long then

		return nil, {{"parseDec", "Missing longitude"}}

	elseif not tonumber(long) then

		return nil, {{"parseDec", "Longitude could not be parsed as a number: " .. long}}

	end



	errors = validate( lat, nil, nil, long, nil, nil, 'parseDec', false );

	coordinateSpec"dec-lat"  = lat;

	coordinateSpec"dec-long" = long;



	local mode = coordinates.determineMode( lat, long );

	coordinateSpec"dms-lat"  = convert_dec2dms( lat, "N", "S", mode)  -- {{coord/dec2dms|{{{1}}}|N|S|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}

	coordinateSpec"dms-long" = convert_dec2dms( long, "E", "W", mode)  -- {{coord/dec2dms|{{{2}}}|E|W|{{coord/prec dec|{{{1}}}|{{{2}}}}}}}



	if format then

		coordinateSpec.default = format

	else

		coordinateSpec.default = "dec"

	end



	return coordinateSpec, errors

end



--[[

parseDMS



Transforms degrees, minutes, seconds format latitude and longitude

into the a structure to be used in displaying coordinates

]]

local function parseDMS( lat_d, lat_m, lat_s, lat_f, long_d, long_m, long_s, long_f, format )

	local coordinateSpec, errors, backward = {}, {}



	lat_f = lat_f:upper();

	long_f = long_f:upper();



	-- Check if specified backward

	if lat_f == 'E' or lat_f == 'W' then

		lat_d, long_d, lat_m, long_m, lat_s, long_s, lat_f, long_f, backward = long_d, lat_d, long_m, lat_m, long_s, lat_s, long_f, lat_f, true;

	end



	errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true );

	if not long_d then

		return nil, {{"parseDMS", "Missing longitude" }}

	elseif not tonumber(long_d) then

		return nil, {{"parseDMS", "Longitude could not be parsed as a number:" .. long_d }}

	end



	if not lat_m and not lat_s and not long_m and not long_s and #errors == 0 then

		if math_mod._precision( lat_d ) > 0 or math_mod._precision( long_d ) > 0 then

			if lat_f:upper() == 'S' then

				lat_d = '-' .. lat_d;

			end

			if long_f:upper() == 'W' then

				long_d = '-' .. long_d;

			end



			return parseDec( lat_d, long_d, format );

		end

	end



	coordinateSpec"dms-lat"  = lat_d.."°"..optionalArg(lat_m,"′") .. optionalArg(lat_s,"″") .. lat_f

	coordinateSpec"dms-long" = long_d.."°"..optionalArg(long_m,"′") .. optionalArg(long_s,"″") .. long_f

	coordinateSpec"dec-lat"  = convert_dms2dec(lat_f, lat_d, lat_m, lat_s) -- {{coord/dms2dec|{{{4}}}|{{{1}}}|0{{{2}}}|0{{{3}}}}}

	coordinateSpec"dec-long" = convert_dms2dec(long_f, long_d, long_m, long_s) -- {{coord/dms2dec|{{{8}}}|{{{5}}}|0{{{6}}}|0{{{7}}}}}



	if format then

		coordinateSpec.default = format

	else

		coordinateSpec.default = "dms"

	end



	return coordinateSpec, errors, backward

end



--[[

Check the input arguments for coord to determine the kind of data being provided

and then make the necessary processing.

]]

local function formatTest(args)

	local result, errors

	local backward, primary = false, false



	local function getParam(args, lim)

		local ret = {}

		for i = 1, lim do

			reti = argsi or ''

		end

		return table.concat(ret, '_')

	end



	if not args1 then

		-- no lat logic

		return errorPrinter( {{"formatTest", "Missing latitude"}} )

	elseif not tonumber(args1]) then

		-- bad lat logic

		return errorPrinter( {{"formatTest", "Unable to parse latitude as a number:" .. args1]}} )

	elseif not args4 and not args5 and not args6 then

		-- dec logic

		result, errors = parseDec(args1], args2], args.format)

		if not result then

			return errorPrinter(errors);

		end

		-- formatting for geohack: geohack expects D_N_D_E notation or D;D notation

		-- wikiminiatlas doesn't support D;D notation

		-- #coordinates parserfunction doesn't support negative decimals with NSWE

		result.param = table.concat({

			math.abs(tonumber(args1])),

			((tonumber(args1]) or 0) < 0) and 'S' or 'N',

			math.abs(tonumber(args2])),

			((tonumber(args2]) or 0) < 0) and 'W' or 'E',

			args3 or ''}, '_')

	elseif dmsTest(args4], args8]) then

		-- dms logic

		result, errors, backward = parseDMS(args1], args2], args3], args4],

			args5], args6], args7], args8], args.format)

		if args10 then

			table.insert(errors, {'formatTest', 'Extra unexpected parameters'})

		end

		if not result then

			return errorPrinter(errors)

		end

		result.param = getParam(args, 9)

	elseif dmsTest(args3], args6]) then

		-- dm logic

		result, errors, backward = parseDMS(args1], args2], nil, args3],

			args4], args5], nil, args6], args'format'])

		if args8 then

			table.insert(errors, {'formatTest', 'Extra unexpected parameters'})

		end

		if not result then

			return errorPrinter(errors)

		end

		result.param = getParam(args, 7)

	elseif dmsTest(args2], args4]) then

		-- d logic

		result, errors, backward = parseDMS(args1], nil, nil, args2],

			args3], nil, nil, args4], args.format)

		if args6 then

			table.insert(errors, {'formatTest', 'Extra unexpected parameters'})

		end

		if not result then

			return errorPrinter(errors)

		end

		result.param = getParam(args, 5)

	else

		-- Error

		return errorPrinter({{"formatTest", "Unknown argument format"}}) .. '[[Category:Pages with malformed coordinate tags]]'

	end

	result.name = args.name



	local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'}

	for _, v in ipairs(extra_param) do

		if argsv then

			table.insert(errors, {'formatTest', 'Parameter: "' .. v .. '=" should be "' .. v .. ':"' })

		end

	end



	local ret = specPrinter(args, result)

	if #errors > 0 then

		ret = ret .. ' ' .. errorPrinter(errors) .. '[[Category:Pages with malformed coordinate tags]]'

	end

	return ret, backward

end



--[[

Generate Wikidata tracking categories.

]]

local function makeWikidataCategories(qid)

	local ret

	local qid = qid or mw.wikibase.getEntityIdForCurrentPage()

	if mw.wikibase and current_page.namespace == 0 then

		if qid and mw.wikibase.entityExists(qid) and mw.wikibase.getBestStatements(qid, "P625") and mw.wikibase.getBestStatements(qid, "P625")[1 then

			local snaktype = mw.wikibase.getBestStatements(qid, "P625")[1].mainsnak.snaktype

			if snaktype == 'value' then

				-- coordinates exist both here and on Wikidata, and can be compared.

				ret = 'Coordinates on Wikidata'

			elseif snaktype == 'somevalue' then

				ret = 'Coordinates on Wikidata set to unknown value'

			elseif snaktype == 'novalue' then

				ret = 'Coordinates on Wikidata set to no value'

			end

		else

			-- We have to either import the coordinates to Wikidata or remove them here.

			ret = 'Coordinates not on Wikidata'

		end

	end

	if ret then

		return string.format('[[Category:%s]]', ret)

	else

		return ''

	end

end



--[[

link



Simple function to export the coordinates link for other uses.



Usage:

	{{#invoke:Coordinates | link }}



]]

function coordinates.link(frame)

	return coord_link;

end



--[[

dec2dms



Wrapper to allow templates to call dec2dms directly.



Usage:

	{{#invoke:Coordinates | dec2dms | decimal_coordinate | positive_suffix |

		negative_suffix | precision }}



decimal_coordinate is converted to DMS format.  If positive, the positive_suffix

is appended (typical N or E), if negative, the negative suffix is appended.  The

specified precision is one of 'D', 'DM', or 'DMS' to specify the level of detail

to use.

]]

coordinates.dec2dms = makeInvokeFunc('_dec2dms')

function coordinates._dec2dms(args)

	local coordinate = args1

	local firstPostfix = args2 or ''

	local secondPostfix = args3 or ''

	local precision = args4 or ''



	return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision)

end



--[[

Helper function to determine whether to use D, DM, or DMS

format depending on the precision of the decimal input.

]]

function coordinates.determineMode( value1, value2 )

	local precision = math.max( math_mod._precision( value1 ), math_mod._precision( value2 ) );

	if precision <= 0 then

		return 'd'

	elseif precision <= 2 then

		return 'dm';

	else

		return 'dms';

	end

end



--[[

dms2dec



Wrapper to allow templates to call dms2dec directly.



Usage:

	{{#invoke:Coordinates | dms2dec | direction_flag | degrees |

		minutes | seconds }}



Converts DMS values specified as degrees, minutes, seconds too decimal format.

direction_flag is one of N, S, E, W, and determines whether the output is

positive (i.e. N and E) or negative (i.e. S and W).

]]

coordinates.dms2dec = makeInvokeFunc('_dms2dec')

function coordinates._dms2dec(args)

	local direction = args1

	local degrees = args2

	local minutes = args3

	local seconds = args4



	return convert_dms2dec(direction, degrees, minutes, seconds)

end



--[[

coord



Main entry point for Lua function to replace {{coord}}



Usage:

	{{#invoke:Coordinates | coord }}

	{{#invoke:Coordinates | coord | lat | long }}

	{{#invoke:Coordinates | coord | lat | lat_flag | long | long_flag }}

	...



	Refer to {{coord}} documentation page for many additional parameters and

	configuration options.



Note: This function provides the visual display elements of {{coord}}.  In

order to load coordinates into the database, the {{#coordinates:}} parser

function must also be called, this is done automatically in the Lua

version of {{coord}}.

]]

coordinates.coord = makeInvokeFunc('_coord')

function coordinates._coord(args)

	if not tonumber(args1]) and not args2 then

		args3 = args1]; args1 = nil

		local entity = mw.wikibase.getEntityObject(args.qid)

		if entity

			and entity.claims

			and entity.claims.P625

			and entity.claims.P6251].mainsnak.snaktype == 'value'

		then

			local precision = entity.claims.P6251].mainsnak.datavalue.value.precision

			args1 = entity.claims.P6251].mainsnak.datavalue.value.latitude

			args2 = entity.claims.P6251].mainsnak.datavalue.value.longitude

			if precision then

				precision = -math_mod._round(math.log(precision)/math.log(10),0)

				args1 = math_mod._round(args1],precision)

				args2 = math_mod._round(args2],precision)

			end

		end

	end



	local contents, backward = formatTest(args)

	local Notes = args.notes or ''

	local Display = args.display and args.display:lower() or 'inline'



	-- it and ti are short for inline,title and title,inline

	local function isInline(s)

		-- Finds whether coordinates are displayed inline.

		return s:find('inline') ~= nil or s == 'i' or s == 'it' or s == 'ti'

	end

	local function isInTitle(s)

		-- Finds whether coordinates are displayed in the title.

		return s:find('title') ~= nil or s == 't' or s == 'it' or s == 'ti'

	end



	local function coord_wrapper(in_args)

		-- Calls the parser function {{#coordinates:}}.

		return mw.getCurrentFrame():callParserFunction('#coordinates', in_args) or ''

	end



	local text = ''

	if isInline(Display) then

		text = text .. '<span class="geo-inline">' .. contents .. Notes .. '</span>'

	end

	if isInTitle(Display) then

		-- Add to output since indicator content is invisible to Lua later on

		if not isInline(Display) then

			text = text .. '<span class="geo-inline-hidden noexcerpt">' .. contents .. Notes .. '</span>'

		end

		text = text .. displaytitle(contents .. Notes) .. makeWikidataCategories(args.qid)

	end

	if not args.nosave then

		local page_title, count = mw.title.getCurrentTitle(), 1

		if backward then

			local tmp = {}

			while not string.find((argscount-1 or ''), '[EW]') do tmpcount = (argscount or ''); count = count+1 end

			tmp.count = count; count = 2*(count-1)

			while count >= tmp.count do table.insert(tmp, 1, (argscount or '')); count = count-1 end

			for i, v in ipairs(tmp) do argsi = v end

		else

			while count <= 9 do argscount = (argscount or ''); count = count+1 end

		end

		if isInTitle(Display) and not page_title.isTalkPage and page_title.subpageText ~= 'doc' and page_title.subpageText ~= 'testcases' then args10 = 'primary' end

		args.notes, args.format, args.display = nil

		text = text .. coord_wrapper(args)

	end

	return text

end



--[[

coord2text



Extracts a single value from a transclusion of {{Coord}}.

IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.



Usage:



    {{#invoke:Coordinates | coord2text | {{Coord}} | parameter }}



Valid values for the second parameter are: lat (signed integer), long (signed integer), type, scale, dim, region, globe, source



]]

function coordinates._coord2text(coord,type)

	if coord == '' or type == '' or not type then return nil end

	type = mw.text.trim(type)

	if type == 'lat' or type == 'long' then

		local result, negative = mw.text.split((mw.ustring.match(coord,'[%.%d]+°[NS] [%.%d]+°[EW]') or ''), ' ')

		if type == 'lat' then

			result, negative = result1], 'S'

		else

			result, negative = result2], 'W'

		end

		result = mw.text.split(result, '°')

		if result2 == negative then result1 = '-'..result1 end

		return result1

	else

		return mw.ustring.match(coord, 'params=.-_' .. type .. ':(.-)[ _]')

	end

end



function coordinates.coord2text(frame)

	return coordinates._coord2text(frame.args1],frame.args2])

end



--[[

coordinsert



Injects some text into the Geohack link of a transclusion of {{Coord}} (if that text isn't already in the transclusion). Outputs the modified transclusion of {{Coord}}.

IF THE GEOHACK LINK SYNTAX CHANGES THIS FUNCTION MUST BE MODIFIED.



Usage:



    {{#invoke:Coordinates | coordinsert | {{Coord}} | parameter:value | parameter:value | … }}



Do not make Geohack unhappy by inserting something which isn't mentioned in the {{Coord}} documentation.



]]

function coordinates.coordinsert(frame)

	-- for the 2nd or later integer parameter (the first is the coord template, as above)

	for i, v in ipairs(frame.args) do

		if i ~= 1 then

			-- if we cannot find in the coord_template the i_th coordinsert parameter e.g. region

			if not mw.ustring.find(frame.args1], (mw.ustring.match(frame.argsi], '^(.-:)') or '')) then

				-- find from the params= up to the first possibly-present underscore

				-- and append the i_th coordinsert parameter and a space

				-- IDK why we're adding a space but it does seem somewhat convenient

				frame.args1 = mw.ustring.gsub(frame.args1], '(params=.-)_? ', '%1_'..frame.argsi..' ')

			end

		end

	end

	if frame.args.name then

		-- if we can't find the vcard class

		if not mw.ustring.find(frame.args1], '<span class="vcard">') then

			-- take something that looks like a coord template and add the vcard span with class and fn org class

			local namestr = frame.args.name

			frame.args1 = mw.ustring.gsub(

				frame.args1],

				'(<span class="geo%-default">)(<span[^<>]*>[^<>]*</span><span[^<>]*>[^<>]*<span[^<>]*>[^<>]*</span></span>)(</span>)',

				'%1<span class="vcard">%2<span style="display:none">&#xfeff; (<span class="fn org">' .. namestr .. '</span>)</span></span>%3'

			)

			-- then find anything from coordinates parameters to the 'end' and attach the title parameter

			frame.args1 = mw.ustring.gsub(

				frame.args1],

				'(&params=[^&"<>%[%] ]*) ',

				'%1&title=' .. mw.uri.encode(namestr) .. ' '

			)

		end

	end

	

	-- replace the existing indicator with a new indicator using the modified content

	frame.args1 = mw.ustring.gsub(

		frame.args1],

		'(<span class="geo%-inline[^"]*">(.+)</span>)\127[^\127]*UNIQ%-%-indicator%-%x+%-%-?QINU[^\127]*\127',

		function (inline, coord) return inline .. displaytitle(coord) end

	)



	return frame.args1

end



return coordinates