Module:Coordinates/sandbox
See also the companion subpage for test cases (run).
To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them.
Note: The code which this module's main function (coord) outputs is directly parsed and/or manipulated by Module:Location map and other functions of this module itself (coord2text and coordinsert). If the structure of the output changes (for example, to use the <mapframe> and <maplink> tags), please update the aforementioned scripts as well.
Using the module with coordinsert
[edit ]When using the {{Coord }} template inside another template, like an infobox, there may be parameters (like type:airport) which should be added automatically. To do so, do something like this:
{{#if:{{{coordinates|}}}|{{#invoke:Coordinates|coordinsert|{{{coordinates|}}}|parameter1:value1|parameter2:value2|parameter3:value3...}}|
Do not add more vertical bars | than necessary.
Using the module with coord2text to extract latitude or longitude
[edit ]Developers maintaining legacy code may need to extract latitude or longitude to use a parameters in other code, or a mathematical expression. The module's "coord2text" function can be used to extract data from the {{Coord }} template. To extract the latitude from a Coord template, use:
{{#invoke:coordinates|coord2text|{{Coord|57|18|22|N|4|27|32|E}}|lat}} → 57.30611
To extract the longitude, use:
{{#invoke:coordinates|coord2text|{{Coord|57|18|22|N|4|27|32|E}}|long}} → 4.45889
Modules using this module directly
[edit ]Tracking categories
[edit ]Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Add categories to the /doc subpage. Subpages of this module.
--[[ 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') localmath_mod=require("Module:Math") localcoordinates={}; localisSandbox=mw.getCurrentFrame():getTitle():find('sandbox',1,true); localcurrent_page=mw.title.getCurrentTitle() localpage_name=mw.uri.encode(current_page.prefixedText,'WIKI'); localcoord_link='https://geohack.toolforge.org/geohack.php?pagename='..page_name..'¶ms=' --[[ Helper function, replacement for {{coord/display/title}} ]] localfunctiondisplaytitle(coords) returnmw.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 ]] localfunctiondmsTest(first,second) iftype(first)~='string'ortype(second)~='string'then returnnil end locals=(first..second):upper() returns:find('^[NS][EW]$')ors:find('^[EW][NS]$') end --[[ Wrapper function to grab args, see Module:Arguments for this function's documentation. ]] localfunctionmakeInvokeFunc(funcName) returnfunction(frame) localargs=require('Module:Arguments').getArgs(frame,{ wrappers='Template:Coord' }) returncoordinates[funcName](args,frame) end end --[[ Helper function, handle optional args. ]] localfunctionoptionalArg(arg,supplement) returnargandarg..supplementor'' end --[[ Formats any error messages generated for display ]] localfunctionerrorPrinter(errors) localresult="" fori,vinipairs(errors)do result=result..'<strong class="error">Coordinates: '..v[2]..'</strong><br />' end returnresult 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 ]] localfunctiondisplayDefault(default,mode) ifdefault==""then default="dec" end ifdefault==modethen 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. ]] localfunctionspecPrinter(args,coordinateSpec) localuriComponents=coordinateSpec["param"] ifuriComponents==""then -- RETURN error, should never be empty or nil return"ERROR param was empty" end ifargs["name"]then uriComponents=uriComponents.."&title="..mw.uri.encode(coordinateSpec["name"]) end localgeodmshtml='<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>' locallat=tonumber(coordinateSpec["dec-lat"])or0 localgeodeclat iflat<0then -- FIXME this breaks the pre-existing precision geodeclat=tostring(coordinateSpec["dec-lat"]):sub(2).."°S" else geodeclat=(coordinateSpec["dec-lat"]or0).."°N" end locallong=tonumber(coordinateSpec["dec-long"])or0 localgeodeclong iflong<0then -- FIXME does not handle unicode minus geodeclong=tostring(coordinateSpec["dec-long"]):sub(2).."°W" else geodeclong=(coordinateSpec["dec-long"]or0).."°E" end localgeodechtml='<span class="geo-dec" title="Maps, aerial photos, and other data for this location">' ..geodeclat..' ' ..geodeclong ..'</span>' localgeonumhtml='<span class="geo">' ..coordinateSpec["dec-lat"]..'; ' ..coordinateSpec["dec-long"] ..'</span>' localinner='<span class="'..displayDefault(coordinateSpec["default"],"dms")..'">'..geodmshtml..'</span>' ..'<span class="geo-multi-punct"> / </span>' ..'<span class="'..displayDefault(coordinateSpec["default"],"dec")..'">'; ifnotargs["name"]then inner=inner..geodechtml ..'<span style="display:none"> / '..geonumhtml..'</span></span>' else inner=inner..'<span class="vcard">'..geodechtml ..'<span style="display:none"> / '..geonumhtml..'</span>' ..'<span style="display:none"> (<span class="fn org">' ..args["name"]..'</span>)</span></span></span>' end localstylesheetLink='Module:Coordinates'..(isSandboxand'/sandbox'or'')..'/styles.css' returnmw.getCurrentFrame():extensionTag{ name='templatestyles',args={src=stylesheetLink} }..'<span class="plainlinks nourlexpansion">['..coord_link..uriComponents.. ' '..inner..']</span>'..'[[Category:Pages using gadget WikiMiniAtlas]]' end --[[ Helper function, convert decimal to degrees ]] localfunctionconvert_dec2dms_d(coordinate) locald=math_mod._round(coordinate,0).."°" returnd.."" end --[[ Helper function, convert decimal to degrees and minutes ]] localfunctionconvert_dec2dms_dm(coordinate) coordinate=math_mod._round(coordinate*60,0); localm=coordinate%60; coordinate=math.floor((coordinate-m)/60); locald=coordinate%360.."°" returnd..string.format("%02d′",m) end --[[ Helper function, convert decimal to degrees, minutes, and seconds ]] localfunctionconvert_dec2dms_dms(coordinate) coordinate=math_mod._round(coordinate*60*60,0); locals=coordinate%60 coordinate=math.floor((coordinate-s)/60); localm=coordinate%60 coordinate=math.floor((coordinate-m)/60); locald=coordinate%360.."°" returnd..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. ]] localfunctionconvert_dec2dms(coordinate,firstPostfix,secondPostfix,precision) localcoord=tonumber(coordinate) localpostfix ifcoord>=0then postfix=firstPostfix else postfix=secondPostfix end precision=precision:lower(); ifprecision=="dms"then returnconvert_dec2dms_dms(math.abs(coord))..postfix; elseifprecision=="dm"then returnconvert_dec2dms_dm(math.abs(coord))..postfix; elseifprecision=="d"then returnconvert_dec2dms_d(math.abs(coord))..postfix; end end --[[ Convert DMS format into a N or E decimal coordinate ]] localfunctionconvert_dms2dec(direction,degrees_str,minutes_str,seconds_str) localdegrees=tonumber(degrees_str) localminutes=tonumber(minutes_str)or0 localseconds=tonumber(seconds_str)or0 localfactor=1 ifdirection=="S"ordirection=="W"then factor=-1 end localprecision=0 ifseconds_strthen precision=5+math.max(math_mod._precision(seconds_str),0); elseifminutes_strandminutes_str~=''then precision=3+math.max(math_mod._precision(minutes_str),0); else precision=math.max(math_mod._precision(degrees_str),0); end localdecimal=factor*(degrees+(minutes+seconds/60)/60) returnstring.format("%."..precision.."f",decimal)-- not tonumber since this whole thing is string based. end --[[ Checks input values to for out of range errors. ]] localfunctionvalidate(lat_d,lat_m,lat_s,long_d,long_m,long_s,source,strong) localerrors={}; lat_d=tonumber(lat_d)or0; lat_m=tonumber(lat_m)or0; lat_s=tonumber(lat_s)or0; long_d=tonumber(long_d)or0; long_m=tonumber(long_m)or0; long_s=tonumber(long_s)or0; ifstrongthen iflat_d<0then table.insert(errors,{source,"latitude degrees < 0 with hemisphere flag"}) end iflong_d<0then 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 iflat_d>90then table.insert(errors,{source,"latitude degrees > 90"}) end iflat_d<-90then table.insert(errors,{source,"latitude degrees < -90"}) end iflat_m>=60then table.insert(errors,{source,"latitude minutes >= 60"}) end iflat_m<0then table.insert(errors,{source,"latitude minutes < 0"}) end iflat_s>=60then table.insert(errors,{source,"latitude seconds >= 60"}) end iflat_s<0then table.insert(errors,{source,"latitude seconds < 0"}) end iflong_d>=360then table.insert(errors,{source,"longitude degrees >= 360"}) end iflong_d<=-360then table.insert(errors,{source,"longitude degrees <= -360"}) end iflong_m>=60then table.insert(errors,{source,"longitude minutes >= 60"}) end iflong_m<0then table.insert(errors,{source,"longitude minutes < 0"}) end iflong_s>=60then table.insert(errors,{source,"longitude seconds >= 60"}) end iflong_s<0then table.insert(errors,{source,"longitude seconds < 0"}) end returnerrors; end --[[ parseDec Transforms decimal format latitude and longitude into the structure to be used in displaying coordinates ]] localfunctionparseDec(lat,long,format) localcoordinateSpec={} localerrors={} ifnotlongthen returnnil,{{"parseDec","Missing longitude"}} elseifnottonumber(long)then returnnil,{{"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; localmode=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}}}}}}} ifformatthen coordinateSpec.default=format else coordinateSpec.default="dec" end returncoordinateSpec,errors end --[[ parseDMS Transforms degrees, minutes, seconds format latitude and longitude into the a structure to be used in displaying coordinates ]] localfunctionparseDMS(lat_d,lat_m,lat_s,lat_f,long_d,long_m,long_s,long_f,format) localcoordinateSpec,errors,backward={},{} lat_f=lat_f:upper(); long_f=long_f:upper(); -- Check if specified backward iflat_f=='E'orlat_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); ifnotlong_dthen returnnil,{{"parseDMS","Missing longitude"}} elseifnottonumber(long_d)then returnnil,{{"parseDMS","Longitude could not be parsed as a number:"..long_d}} end ifnotlat_mandnotlat_sandnotlong_mandnotlong_sand#errors==0then ifmath_mod._precision(lat_d)>0ormath_mod._precision(long_d)>0then iflat_f:upper()=='S'then lat_d='-'..lat_d; end iflong_f:upper()=='W'then long_d='-'..long_d; end returnparseDec(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}}}}} ifformatthen coordinateSpec.default=format else coordinateSpec.default="dms" end returncoordinateSpec,errors,backward end --[[ Check the input arguments for coord to determine the kind of data being provided and then make the necessary processing. ]] localfunctionformatTest(args) localresult,errors localbackward,primary=false,false localfunctiongetParam(args,lim) localret={} fori=1,limdo ret[i]=args[i]or'' end returntable.concat(ret,'_') end ifnotargs[1]then -- no lat logic returnerrorPrinter({{"formatTest","Missing latitude"}}) elseifnottonumber(args[1])then -- bad lat logic returnerrorPrinter({{"formatTest","Unable to parse latitude as a number:"..args[1]}}) elseifnotargs[4]andnotargs[5]andnotargs[6]then -- dec logic result,errors=parseDec(args[1],args[2],args.format) ifnotresultthen returnerrorPrinter(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(args[1])), ((tonumber(args[1])or0)<0)and'S'or'N', math.abs(tonumber(args[2])), ((tonumber(args[2])or0)<0)and'W'or'E', args[3]or''},'_') elseifdmsTest(args[4],args[8])then -- dms logic result,errors,backward=parseDMS(args[1],args[2],args[3],args[4], args[5],args[6],args[7],args[8],args.format) ifargs[10]then table.insert(errors,{'formatTest','Extra unexpected parameters'}) end ifnotresultthen returnerrorPrinter(errors) end result.param=getParam(args,9) elseifdmsTest(args[3],args[6])then -- dm logic result,errors,backward=parseDMS(args[1],args[2],nil,args[3], args[4],args[5],nil,args[6],args['format']) ifargs[8]then table.insert(errors,{'formatTest','Extra unexpected parameters'}) end ifnotresultthen returnerrorPrinter(errors) end result.param=getParam(args,7) elseifdmsTest(args[2],args[4])then -- d logic result,errors,backward=parseDMS(args[1],nil,nil,args[2], args[3],nil,nil,args[4],args.format) ifargs[6]then table.insert(errors,{'formatTest','Extra unexpected parameters'}) end ifnotresultthen returnerrorPrinter(errors) end result.param=getParam(args,5) else -- Error returnerrorPrinter({{"formatTest","Unknown argument format"}})..'[[Category:Pages with malformed coordinate tags]]' end result.name=args.name localextra_param={'dim','globe','scale','region','source','type'} for_,vinipairs(extra_param)do ifargs[v]then table.insert(errors,{'formatTest','Parameter: "'..v..'=" should be "'..v..':"'}) end end localret=specPrinter(args,result) if#errors>0then ret=ret..' '..errorPrinter(errors)..'[[Category:Pages with malformed coordinate tags]]' end returnret,backward end --[[ Generate Wikidata tracking categories. ]] localfunctionmakeWikidataCategories(qid) localret localqid=qidormw.wikibase.getEntityIdForCurrentPage() ifmw.wikibaseandcurrent_page.namespace==0then ifqidandmw.wikibase.entityExists(qid)andmw.wikibase.getBestStatements(qid,"P625")andmw.wikibase.getBestStatements(qid,"P625")[1]then localsnaktype=mw.wikibase.getBestStatements(qid,"P625")[1].mainsnak.snaktype ifsnaktype=='value'then -- coordinates exist both here and on Wikidata, and can be compared. ret='Coordinates on Wikidata' elseifsnaktype=='somevalue'then ret='Coordinates on Wikidata set to unknown value' elseifsnaktype=='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 ifretthen returnstring.format('[[Category:%s]]',ret) else return'' end end --[[ link Simple function to export the coordinates link for other uses. Usage: {{#invoke:Coordinates | link }} ]] functioncoordinates.link(frame) returncoord_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') functioncoordinates._dec2dms(args) localcoordinate=args[1] localfirstPostfix=args[2]or'' localsecondPostfix=args[3]or'' localprecision=args[4]or'' returnconvert_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. ]] functioncoordinates.determineMode(value1,value2) localprecision=math.max(math_mod._precision(value1),math_mod._precision(value2)); ifprecision<=0then return'd' elseifprecision<=2then 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') functioncoordinates._dms2dec(args) localdirection=args[1] localdegrees=args[2] localminutes=args[3] localseconds=args[4] returnconvert_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') functioncoordinates._coord(args) ifnottonumber(args[1])andnotargs[2]then args[3]=args[1];args[1]=nil localentity=mw.wikibase.getEntityObject(args.qid) ifentity andentity.claims andentity.claims.P625 andentity.claims.P625[1].mainsnak.snaktype=='value' then localprecision=entity.claims.P625[1].mainsnak.datavalue.value.precision args[1]=entity.claims.P625[1].mainsnak.datavalue.value.latitude args[2]=entity.claims.P625[1].mainsnak.datavalue.value.longitude ifprecisionthen precision=-math_mod._round(math.log(precision)/math.log(10),0) args[1]=math_mod._round(args[1],precision) args[2]=math_mod._round(args[2],precision) end end end localcontents,backward=formatTest(args) localNotes=args.notesor'' localDisplay=args.displayandargs.display:lower()or'inline' localPrecedence=args.precedenceandargs.precedence:lower()or'secondary' -- it and ti are short for inline,title and title,inline localfunctionisInline(s) -- Finds whether coordinates are displayed inline. returns:find('inline')~=nilors=='i'ors=='it'ors=='ti' end localfunctionisInTitle(s) -- Finds whether coordinates are displayed in the title. returns:find('title')~=nilors=='t'ors=='it'ors=='ti' end localfunctionisPrimary(s) -- Finds whether coordinates are marked primary. returns=='primary' end localfunctioncoord_wrapper(in_args) -- Calls the parser function {{#coordinates:}}. returnmw.getCurrentFrame():callParserFunction('#coordinates',in_args)or'' end localtext='' ifisInline(Display)then text=text..'<span class="geo-inline">'..contents..Notes..'</span>' end ifisInTitle(Display)then -- Add to output since indicator content is invisible to Lua later on ifnotisInline(Display)then text=text..'<span class="geo-inline-hidden noexcerpt">'..contents..Notes..'</span>' end text=text..displaytitle(contents..Notes)..makeWikidataCategories(args.qid) end ifnotargs.nosavethen localpage_title,count=mw.title.getCurrentTitle(),1 ifbackwardthen localtmp={} whilenotstring.find((args[count-1]or''),'[EW]')dotmp[count]=(args[count]or'');count=count+1end tmp.count=count;count=2*(count-1) whilecount>=tmp.countdotable.insert(tmp,1,(args[count]or''));count=count-1end fori,vinipairs(tmp)doargs[i]=vend else whilecount<=9doargs[count]=(args[count]or'');count=count+1end end if(notisPrimary(Precedence))andisInTitle(Display)then args[10]='' elseifisPrimary(Precedence)orisInTitle(Display)andnotpage_title.isTalkPageandpage_title.subpageText~='doc'andpage_title.subpageText~='testcases'then args[10]='primary' end args.notes,args.format,args.display,args.precedence=nil text=text..coord_wrapper(args) end returntext 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 ]] functioncoordinates._coord2text(coord,type) ifcoord==''ortype==''ornottypethenreturnnilend type=mw.text.trim(type) iftype=='lat'ortype=='long'then localresult,negative=mw.text.split((mw.ustring.match(coord,'[%.%d]+°[NS] [%.%d]+°[EW]')or''),' ') iftype=='lat'then result,negative=result[1],'S' else result,negative=result[2],'W' end result=mw.text.split(result,'°') ifresult[2]==negativethenresult[1]='-'..result[1]end returnresult[1] else returnmw.ustring.match(coord,'params=.-_'..type..':(.-)[ _]') end end functioncoordinates.coord2text(frame) returncoordinates._coord2text(frame.args[1],frame.args[2]) 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. ]] functioncoordinates.coordinsert(frame) -- for the 2nd or later integer parameter (the first is the coord template, as above) fori,vinipairs(frame.args)do ifi~=1then -- if we cannot find in the coord_template the i_th coordinsert parameter e.g. region ifnotmw.ustring.find(frame.args[1],(mw.ustring.match(frame.args[i],'^(.-:)')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.args[1]=mw.ustring.gsub(frame.args[1],'(params=.-)_? ','%1_'..frame.args[i]..' ') end end end ifframe.args.namethen -- if we can't find the vcard class ifnotmw.ustring.find(frame.args[1],'<span class="vcard">')then -- take something that looks like a coord template and add the vcard span with class and fn org class localnamestr=frame.args.name frame.args[1]=mw.ustring.gsub( frame.args[1], '(<span class="geo%-default">)(<span[^<>]*>[^<>]*</span><span[^<>]*>[^<>]*<span[^<>]*>[^<>]*</span></span>)(</span>)', '%1<span class="vcard">%2<span style="display:none"> (<span class="fn org">'..namestr..'</span>)</span></span>%3' ) -- then find anything from coordinates parameters to the 'end' and attach the title parameter frame.args[1]=mw.ustring.gsub( frame.args[1], '(¶ms=[^&"<>%[%] ]*) ', '%1&title='..mw.uri.encode(namestr)..' ' ) end end -- replace the existing indicator with a new indicator using the modified content frame.args[1]=mw.ustring.gsub( frame.args[1], '(<span class="geo%-inline[^"]*">(.+)</span>)127円[^127円]*UNIQ%-%-indicator%-%x+%-%-?QINU[^127円]*127円', function(inline,coord)returninline..displaytitle(coord)end ) returnframe.args[1] end returncoordinates