Module:Coordinates: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
(merge prior edit) |
(rv for now) |
||
Line 16: | Line 16: | ||
]] |
]] |
||
local math_mod = require("Module:Math") |
local math_mod = require( "Module:Math" ); |
||
local globalFrame = nil |
|||
local coordinates = {}; |
local coordinates = {}; |
||
Line 24: | Line 25: | ||
--[[ Helper function, replacement for {{coord/display/title}} ]] |
--[[ Helper function, replacement for {{coord/display/title}} ]] |
||
local function displaytitle(s, notes) |
local function displaytitle (s, notes) |
||
local l = "[[Geographic coordinate system|Coordinates]]: " .. s |
|||
local title = mw.html.create('span') |
|||
local co = '<span id="coordinates">' .. l .. notes .. '</span>'; |
|||
title |
|||
return '<span style="font-size: small;">' .. co .. '</span>'; |
|||
:attr('id', 'coordinates') |
|||
:css('font-size', 'small') |
|||
:wikitext('[[Geographic coordinate system|Coordinates]]: ' .. s .. notes) |
|||
return tostring(title) |
|||
end |
end |
||
--[[ Helper function, Replacement for {{coord/display/inline}} ]] |
--[[ Helper function, Replacement for {{coord/display/inline}} ]] |
||
local function displayinline(s, notes) |
local function displayinline (s, notes) |
||
return s .. notes |
return s .. notes |
||
end |
end |
||
Line 40: | Line 38: | ||
--[[ Helper function, used in detecting DMS formatting ]] |
--[[ Helper function, used in detecting DMS formatting ]] |
||
local function dmsTest (first, second) |
local function dmsTest (first, second) |
||
local concatenated = first:upper() .. second:upper(); |
|||
if type(first) ~= 'string' or type(second) ~= 'string' then |
|||
return nil |
|||
if concatenated == "NE" or concatenated == "NW" or concatenated == "SE" or concatenated == "SW" or |
|||
concatenated == "EN" or concatenated == "WN" or concatenated == "ES" or concatenated == "WS" then |
|||
return true; |
|||
end |
end |
||
return false; |
|||
local s = (first .. second):upper() |
|||
return s:find('^[NS][EW]$') or s:find('^[EW][NS]$') |
|||
end |
end |
||
--[[ Helper function, handle optional args. ]] |
|||
local function optionalArg(arg, suplement) |
|||
--[[ Wrapper function to grab args, see Module:Arguments for this function's documentation. ]] |
|||
if arg ~= nil and arg ~= "" then |
|||
local function makeInvokeFunc(funcName) |
|||
return arg .. suplement |
|||
local args = require('Module:Arguments').getArgs(frame, { |
|||
wrappers = 'Template:Coord' |
|||
}) |
|||
return coordinates[funcName](args) |
|||
end |
end |
||
return "" |
|||
end |
|||
--[[ Helper function, handle optional args. ]] |
|||
local function optionalArg(arg, supplement) |
|||
return arg and arg .. supplement or '' |
|||
end |
end |
||
Line 106: | Line 98: | ||
return "ERROR param was empty" |
return "ERROR param was empty" |
||
end |
end |
||
if args["name"] then |
if args["name"] ~= "" and args["name"] ~= nil then |
||
uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"]) |
uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"]) |
||
end |
end |
||
Line 119: | Line 111: | ||
if lat < 0 then |
if lat < 0 then |
||
-- FIXME this breaks the pre-existing precision |
-- FIXME this breaks the pre-existing precision |
||
geodeclat = |
geodeclat = coordinateSpec["dec-lat"]:sub(2) .. "°S" |
||
else |
else |
||
geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°N" |
geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°N" |
||
Line 128: | Line 120: | ||
if long < 0 then |
if long < 0 then |
||
-- FIXME does not handle unicode minus |
-- FIXME does not handle unicode minus |
||
geodeclong = |
geodeclong = coordinateSpec["dec-long"]:sub(2) .. "°W" |
||
else |
else |
||
geodeclong = (coordinateSpec["dec-long"] or 0) .. "°E" |
geodeclong = (coordinateSpec["dec-long"] or 0) .. "°E" |
||
Line 147: | Line 139: | ||
.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">'; |
.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">'; |
||
if |
if args["name"] == "" or args["name"] == nil then |
||
inner = inner .. geodechtml |
inner = inner .. geodechtml |
||
.. '<span style="display:none"> / ' .. geonumhtml .. '</span></span>' |
.. '<span style="display:none"> / ' .. geonumhtml .. '</span></span>' |
||
Line 221: | Line 213: | ||
local factor = 1 |
local factor = 1 |
||
direction = direction:gsub('^ *(.-) *$', '%1'); |
|||
if direction == "S" or direction == "W" then |
if direction == "S" or direction == "W" then |
||
factor = -1 |
factor = -1 |
||
Line 226: | Line 219: | ||
local precision = 0 |
local precision = 0 |
||
if seconds_str then |
if seconds_str ~= nil and seconds_str ~= '' then |
||
precision = 5 + math.max( math_mod._precision(seconds_str), 0 ); |
precision = 5 + math.max( math_mod._precision(seconds_str), 0 ); |
||
elseif minutes_str and minutes_str ~= '' then |
elseif minutes_str ~= nil and minutes_str ~= '' then |
||
precision = 3 + math.max( math_mod._precision(minutes_str), 0 ); |
precision = 3 + math.max( math_mod._precision(minutes_str), 0 ); |
||
else |
else |
||
Line 319: | Line 312: | ||
local errors = {} |
local errors = {} |
||
if |
if long == "" or long == nil then |
||
return nil, {{"parseDec", "Missing longitude"}} |
return nil, {{"parseDec", "Missing longitude"}} |
||
elseif not tonumber(long) then |
elseif not tonumber(long) then |
||
Line 333: | Line 326: | ||
coordinateSpec["dms-long"] = convert_dec2dms( long, "E", "W", mode) -- {{coord/dec2dms|{{{2}}}|E|W|{{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 |
if format ~= "" then |
||
coordinateSpec.default = format |
coordinateSpec.default = format |
||
else |
else |
||
Line 373: | Line 366: | ||
errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true ); |
errors = validate( lat_d, lat_m, lat_s, long_d, long_m, long_s, 'parseDMS', true ); |
||
if |
if long_d == nil or long_d == "" then |
||
return nil, {{"parseDMS", "Missing longitude" }} |
return nil, {{"parseDMS", "Missing longitude" }} |
||
elseif not tonumber(long_d) then |
elseif not tonumber(long_d) then |
||
Line 379: | Line 372: | ||
end |
end |
||
if |
if lat_m == nil and lat_s == nil and long_m == nil and long_s == nil and #errors == 0 then |
||
if math_mod._precision( lat_d ) > 0 or math_mod._precision( long_d ) > 0 then |
if math_mod._precision( lat_d ) > 0 or math_mod._precision( long_d ) > 0 then |
||
if lat_f:upper() == 'S' then |
if lat_f:upper() == 'S' then |
||
Line 397: | Line 390: | ||
coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) -- {{coord/dms2dec|{{{8}}}|{{{5}}}|0{{{6}}}|0{{{7}}}}} |
coordinateSpec["dec-long"] = convert_dms2dec(long_f, long_d, long_m, long_s) -- {{coord/dms2dec|{{{8}}}|{{{5}}}|0{{{6}}}|0{{{7}}}}} |
||
if format then |
if format ~= "" then |
||
coordinateSpec.default = format |
coordinateSpec.default = format |
||
else |
else |
||
Line 411: | Line 404: | ||
]] |
]] |
||
local function formatTest(args) |
local function formatTest(args) |
||
local result, errors |
local result, errors; |
||
local primary = false |
local primary = false; |
||
local function getParam(args, lim) |
|||
local ret = {} |
|||
for i = 1, lim do |
|||
ret[i] = args[i] or '' |
|||
end |
|||
return table.concat(ret, '_') |
|||
end |
|||
if |
if args[1] == "" then |
||
-- no lat logic |
-- no lat logic |
||
return errorPrinter( {{"formatTest", "Missing latitude"}} ) |
return errorPrinter( {{"formatTest", "Missing latitude"}} ) |
||
Line 428: | Line 413: | ||
-- bad lat logic |
-- bad lat logic |
||
return errorPrinter( {{"formatTest", "Unable to parse latitude as a number:" .. args[1]}} ) |
return errorPrinter( {{"formatTest", "Unable to parse latitude as a number:" .. args[1]}} ) |
||
elseif |
elseif args[4] == "" and args[5] == "" and args[6] == "" then |
||
-- dec logic |
-- dec logic |
||
result, errors = parseDec(args[1], args[2], args |
result, errors = parseDec( args[1], args[2], args['format'] ) |
||
if |
if result == nil then |
||
return errorPrinter(errors); |
return errorPrinter( errors ); |
||
end |
end |
||
result.param |
result.param = table.concat( {args[1], "_N_", args[2], "_E_", args[3] } ); |
||
elseif dmsTest(args[4], args[8]) then |
elseif dmsTest(args[4], args[8]) then |
||
-- dms logic |
-- dms logic |
||
result, errors = parseDMS(args[1], args[2], args[3], args[4], |
result, errors = parseDMS( args[1], args[2], args[3], args[4], |
||
args[5], args[6], args[7], args[8], args |
args[5], args[6], args[7], args[8], args['format'] ) |
||
if args[10] then |
if args[10] ~= '' then |
||
table.insert(errors, {'formatTest', 'Extra unexpected parameters'}) |
table.insert( errors, { 'formatTest', 'Extra unexpected parameters' } ); |
||
end |
end |
||
if |
if result == nil then |
||
return errorPrinter(errors) |
return errorPrinter( errors ); |
||
end |
end |
||
result.param = |
result.param = table.concat( { args[1], args[2], args[3], args[4], args[5], |
||
args[6], args[7], args[8], args[9] } , '_' ); |
|||
elseif dmsTest(args[3], args[6]) then |
elseif dmsTest(args[3], args[6]) then |
||
-- dm logic |
-- dm logic |
||
result, errors = parseDMS(args[1], args[2], nil, args[3], |
result, errors = parseDMS( args[1], args[2], nil, args[3], |
||
args[4], args[5], nil, args[6], args['format']) |
args[4], args[5], nil, args[6], args['format'] ) |
||
if args[8] then |
if args[8] ~= '' then |
||
table.insert(errors, {'formatTest', 'Extra unexpected parameters'}) |
table.insert( errors, { 'formatTest', 'Extra unexpected parameters' } ); |
||
end |
end |
||
if |
if result == nil then |
||
return errorPrinter(errors) |
return errorPrinter( errors ); |
||
end |
end |
||
result.param = |
result.param = table.concat( { args[1], args[2], args[3], args[4], args[5], |
||
args[6], args[7] } , '_' ); |
|||
elseif dmsTest(args[2], args[4]) then |
elseif dmsTest(args[2], args[4]) then |
||
-- d logic |
-- d logic |
||
result, errors = parseDMS(args[1], nil, nil, args[2], |
result, errors = parseDMS( args[1], nil, nil, args[2], |
||
args[3], nil, nil, args[4], args |
args[3], nil, nil, args[4], args['format'] ) |
||
if args[6] then |
if args[6] ~= '' then |
||
table.insert(errors, {'formatTest', 'Extra unexpected parameters'}) |
table.insert( errors, { 'formatTest', 'Extra unexpected parameters' } ); |
||
end |
end |
||
if |
if result == nil then |
||
return errorPrinter(errors) |
return errorPrinter( errors ); |
||
end |
end |
||
result.param = |
result.param = table.concat( { args[1], args[2], args[3], args[4], args[5] } , '_' ); |
||
else |
else |
||
-- Error |
-- Error |
||
return errorPrinter({{"formatTest", "Unknown argument format"}}) |
return errorPrinter( {{"formatTest", "Unknown argument format"}} ) |
||
end |
end |
||
result.name = args |
result.name = args["name"] |
||
local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'} |
local extra_param = {'dim', 'globe', 'scale', 'region', 'source', 'type'} |
||
for _, v in ipairs(extra_param) do |
for _, v in ipairs( extra_param ) do |
||
if args[v] then |
if (args[v] or '') ~= '' then |
||
table.insert(errors, {'formatTest', 'Parameter: "' .. v .. '=" should be "' .. v .. ':"' }) |
table.insert( errors, {'formatTest', 'Parameter: "' .. v .. '=" should be "' .. v .. ':"' } ); |
||
end |
end |
||
end |
end |
||
if #errors == 0 then |
|||
local ret = specPrinter(args, result) |
|||
return specPrinter( args, result ) |
|||
if #errors > 0 then |
|||
ret = ret .. ' ' .. errorPrinter(errors) .. '[[Category:Pages with malformed coordinate tags]]' |
|||
end |
|||
return ret |
|||
end |
|||
--[[ |
|||
Generate Wikidata tracking categories. |
|||
]] |
|||
local function makeWikidataCategories() |
|||
local ret |
|||
if mw.wikibase and current_page.namespace == 0 then |
|||
local entity = mw.wikibase.getEntityObject() |
|||
if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1] then |
|||
local snaktype = entity.claims.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 |
else |
||
return specPrinter( args, result ) .. " " .. errorPrinter(errors) .. '[[Category:Pages with malformed coordinate tags]]'; |
|||
return '' |
|||
end |
end |
||
end |
end |
||
Line 544: | Line 502: | ||
to use. |
to use. |
||
]] |
]] |
||
coordinates.dec2dms |
function coordinates.dec2dms(frame) |
||
globalFrame = frame |
|||
function coordinates._dec2dms(args) |
|||
local coordinate = args[1] |
local coordinate = frame.args[1] |
||
local firstPostfix = args[2] |
local firstPostfix = frame.args[2] |
||
local secondPostfix = args[3] |
local secondPostfix = frame.args[3] |
||
local precision = args[4] |
local precision = frame.args[4] |
||
return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision) |
return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision) |
||
Line 582: | Line 540: | ||
positive (i.e. N and E) or negative (i.e. S and W). |
positive (i.e. N and E) or negative (i.e. S and W). |
||
]] |
]] |
||
coordinates.dms2dec |
function coordinates.dms2dec(frame) |
||
globalFrame = frame |
|||
function coordinates._dms2dec(args) |
|||
local direction = args[1] |
local direction = frame.args[1] |
||
local degrees = args[2] |
local degrees = frame.args[2] |
||
local minutes = args[3] |
local minutes = frame.args[3] |
||
local seconds = args[4] |
local seconds = frame.args[4] |
||
return convert_dms2dec(direction, degrees, minutes, seconds) |
return convert_dms2dec(direction, degrees, minutes, seconds) |
||
Line 611: | Line 569: | ||
version of {{coord}}. |
version of {{coord}}. |
||
]] |
]] |
||
coordinates.coord |
function coordinates.coord(frame) |
||
globalFrame = frame |
|||
function coordinates._coord(args) |
|||
local args = frame.args |
|||
if not args[1] and not args[2] and mw.wikibase.getEntityObject() then |
|||
local pFrame = frame:getParent(); |
|||
if args[1] == nil then |
|||
if entity |
|||
args = pFrame.args; |
|||
and entity.claims |
|||
if pFrame.args[1] ~= nil then |
|||
and entity.claims.P625 |
|||
for k,v in pairs( frame.args ) do |
|||
and entity.claims.P625[1].mainsnak.snaktype == 'value' |
|||
args[k] = v; |
|||
then |
|||
end |
|||
args[1] = entity.claims.P625[1].mainsnak.datavalue.value.latitude |
|||
elseif pFrame.args[1] == nil and mw.wikibase.getEntityObject() ~= nil then |
|||
args[2] = entity.claims.P625[1].mainsnak.datavalue.value.longitude |
|||
local entity = mw.wikibase.getEntityObject() |
|||
if entity and entity.claims and entity.claims.P625 and |
|||
entity.claims.P625[1].mainsnak.snaktype == "value" then |
|||
args[1] = entity.claims.P625[1].mainsnak.datavalue.value.latitude |
|||
args[2] = entity.claims.P625[1].mainsnak.datavalue.value.longitude |
|||
end |
|||
end |
end |
||
end |
end |
||
for i=1,10 do |
|||
if args[i] == nil then |
|||
args[i] = "" |
|||
else |
|||
args[i] = string.match(args[i], '^%s*(.-)%s*$' ); --remove whitespace |
|||
end |
|||
end |
|||
args['format'] = args['format'] or ''; |
|||
local contents = formatTest(args) |
local contents = formatTest(args) |
||
local Notes = args.notes or |
local Notes = args.notes or "" |
||
local Display = |
local Display = string.lower(args.display or "inline") |
||
if Display == '' then |
|||
Display = '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 |
end |
||
local text = '' |
local text = '' |
||
if |
if string.find( Display, 'inline' ) ~= nil |
||
or Display == 'i' |
|||
text = text .. displayinline(contents, Notes) |
|||
or Display == 'it' |
|||
or Display == 'ti' |
|||
then |
|||
-- Coordinates are displayed inline. |
|||
text = displayinline(contents, Notes) |
|||
end |
end |
||
if |
if string.find( Display, 'title' ) ~= nil |
||
or Display == 't' |
|||
or Display == 'it' |
|||
.. displaytitle(contents, Notes) |
|||
or Display == 'ti' |
|||
.. makeWikidataCategories() |
|||
then |
|||
-- Coordinates are displayed in the title. |
|||
text = text .. displaytitle(contents, Notes) |
|||
-- Add a Wikidata category for mainspace pages. |
|||
if mw.wikibase and current_page.namespace == 0 then |
|||
local wikidata_cat |
|||
local entity = mw.wikibase.getEntityObject() |
|||
if entity and entity.claims and entity.claims.P625 then |
|||
local snaktype = entity.claims.P625[1].mainsnak.snaktype |
|||
if snaktype == 'value' then |
|||
wikidata_cat = '[[Category:Coordinates on Wikidata]]' -- coordinates exist both here and on Wikidata, and can be compared |
|||
elseif snaktype == 'somevalue' then |
|||
wikidata_cat = '[[Category:Coordinates on Wikidata set to unknown value]]' |
|||
elseif snaktype == 'novalue' then |
|||
wikidata_cat = '[[Category:Coordinates on Wikidata set to no value]]' |
|||
end |
|||
else |
|||
wikidata_cat = '[[Category:Coordinates not on Wikidata]]' -- we have to either import the coordinates to Wikidata or remove them here |
|||
end |
|||
if wikidata_cat then |
|||
text = text .. wikidata_cat |
|||
end |
|||
end |
|||
end |
end |
||
return text |
return text |
||
end |
end |