Module:Coordinates: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
(rv for now) |
(remerge changes, but without changes to displaytitle) |
||
Line 16: | Line 16: | ||
]] |
]] |
||
local math_mod = require( |
local math_mod = require("Module:Math") |
||
local globalFrame = nil |
|||
local coordinates = {}; |
local coordinates = {}; |
||
Line 32: | Line 31: | ||
--[[ Helper function, Replacement for {{coord/display/inline}} ]] |
--[[ Helper function, Replacement for {{coord/display/inline}} ]] |
||
local function displayinline |
local function displayinline(s, notes) |
||
return s .. notes |
return s .. notes |
||
end |
end |
||
Line 38: | Line 37: | ||
--[[ Helper function, used in detecting DMS formatting ]] |
--[[ Helper function, used in detecting DMS formatting ]] |
||
local function dmsTest (first, second) |
local function dmsTest (first, second) |
||
if type(first) ~= 'string' or type(second) ~= 'string' then |
|||
local concatenated = first:upper() .. second:upper(); |
|||
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 |
||
local s = (first .. second):upper() |
|||
return false; |
|||
return s:find('^[NS][EW]$') or s:find('^[EW][NS]$') |
|||
end |
end |
||
--[[ Helper function, handle optional args. ]] |
|||
--[[ Wrapper function to grab args, see Module:Arguments for this function's documentation. ]] |
|||
local function optionalArg(arg, suplement) |
|||
local function makeInvokeFunc(funcName) |
|||
if arg ~= nil and arg ~= "" then |
|||
return function (frame) |
|||
local args = require('Module:Arguments').getArgs(frame, { |
|||
wrappers = 'Template:Coord' |
|||
}) |
|||
return coordinates[funcName](args) |
|||
end |
end |
||
end |
|||
return "" |
|||
--[[ Helper function, handle optional args. ]] |
|||
local function optionalArg(arg, supplement) |
|||
return arg and arg .. supplement or '' |
|||
end |
end |
||
Line 98: | Line 103: | ||
return "ERROR param was empty" |
return "ERROR param was empty" |
||
end |
end |
||
if args["name"] |
if args["name"] then |
||
uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"]) |
uriComponents = uriComponents .. "&title=" .. mw.uri.encode(coordinateSpec["name"]) |
||
end |
end |
||
Line 111: | Line 116: | ||
if lat < 0 then |
if lat < 0 then |
||
-- FIXME this breaks the pre-existing precision |
-- FIXME this breaks the pre-existing precision |
||
geodeclat = coordinateSpec["dec-lat"]:sub(2) .. "°S" |
geodeclat = tostring(coordinateSpec["dec-lat"]):sub(2) .. "°S" |
||
else |
else |
||
geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°N" |
geodeclat = (coordinateSpec["dec-lat"] or 0) .. "°N" |
||
Line 120: | Line 125: | ||
if long < 0 then |
if long < 0 then |
||
-- FIXME does not handle unicode minus |
-- FIXME does not handle unicode minus |
||
geodeclong = coordinateSpec["dec-long"]:sub(2) .. "°W" |
geodeclong = tostring(coordinateSpec["dec-long"]):sub(2) .. "°W" |
||
else |
else |
||
geodeclong = (coordinateSpec["dec-long"] or 0) .. "°E" |
geodeclong = (coordinateSpec["dec-long"] or 0) .. "°E" |
||
Line 139: | Line 144: | ||
.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">'; |
.. '<span class="' .. displayDefault(coordinateSpec["default"], "dec" ) .. '">'; |
||
if |
if not args["name"] then |
||
inner = inner .. geodechtml |
inner = inner .. geodechtml |
||
.. '<span style="display:none"> / ' .. geonumhtml .. '</span></span>' |
.. '<span style="display:none"> / ' .. geonumhtml .. '</span></span>' |
||
Line 213: | Line 218: | ||
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 219: | Line 223: | ||
local precision = 0 |
local precision = 0 |
||
if seconds_str |
if 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 |
elseif minutes_str 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 312: | Line 316: | ||
local errors = {} |
local errors = {} |
||
if |
if not long then |
||
return nil, {{"parseDec", "Missing longitude"}} |
return nil, {{"parseDec", "Missing longitude"}} |
||
elseif not tonumber(long) then |
elseif not tonumber(long) then |
||
Line 326: | Line 330: | ||
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 |
if format then |
||
coordinateSpec.default = format |
coordinateSpec.default = format |
||
else |
else |
||
Line 366: | Line 370: | ||
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 not 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 372: | Line 376: | ||
end |
end |
||
if lat_m |
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 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 390: | Line 394: | ||
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 |
if format then |
||
coordinateSpec.default = format |
coordinateSpec.default = format |
||
else |
else |
||
Line 404: | Line 408: | ||
]] |
]] |
||
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 args[1] |
if not args[1] then |
||
-- no lat logic |
-- no lat logic |
||
return errorPrinter( {{"formatTest", "Missing latitude"}} ) |
return errorPrinter( {{"formatTest", "Missing latitude"}} ) |
||
Line 413: | Line 425: | ||
-- 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 args[4] |
elseif not args[4] and not args[5] and not args[6] then |
||
-- dec logic |
-- dec logic |
||
result, errors = parseDec( |
result, errors = parseDec(args[1], args[2], args.format) |
||
if result |
if not result then |
||
return errorPrinter( |
return errorPrinter(errors); |
||
end |
end |
||
result.param |
result.param = table.concat({args[1], 'N', args[2] or '', 'E', args[3] or ''}, '_') |
||
elseif dmsTest(args[4], args[8]) then |
elseif dmsTest(args[4], args[8]) then |
||
-- dms logic |
-- dms logic |
||
result, errors = parseDMS( |
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] |
if args[10] then |
||
table.insert( |
table.insert(errors, {'formatTest', 'Extra unexpected parameters'}) |
||
end |
end |
||
if result |
if not result then |
||
return errorPrinter( |
return errorPrinter(errors) |
||
end |
end |
||
result.param = |
result.param = getParam(args, 9) |
||
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( |
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] |
if args[8] then |
||
table.insert( |
table.insert(errors, {'formatTest', 'Extra unexpected parameters'}) |
||
end |
end |
||
if result |
if not result then |
||
return errorPrinter( |
return errorPrinter(errors) |
||
end |
end |
||
result.param = |
result.param = getParam(args, 7) |
||
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( |
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] |
if args[6] then |
||
table.insert( |
table.insert(errors, {'formatTest', 'Extra unexpected parameters'}) |
||
end |
end |
||
if result |
if not result then |
||
return errorPrinter( |
return errorPrinter(errors) |
||
end |
end |
||
result.param = |
result.param = getParam(args, 5) |
||
else |
else |
||
-- Error |
-- Error |
||
return errorPrinter( |
return errorPrinter({{"formatTest", "Unknown argument format"}}) |
||
end |
end |
||
result.name |
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( |
for _, v in ipairs(extra_param) do |
||
if |
if args[v] then |
||
table.insert( |
table.insert(errors, {'formatTest', 'Parameter: "' .. v .. '=" should be "' .. v .. ':"' }) |
||
end |
end |
||
end |
end |
||
local ret = specPrinter(args, result) |
|||
if #errors == 0 then |
|||
if #errors > 0 then |
|||
return specPrinter( args, result ) |
|||
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 '' |
|||
return specPrinter( args, result ) .. " " .. errorPrinter(errors) .. '[[Category:Pages with malformed coordinate tags]]'; |
|||
end |
end |
||
end |
end |
||
Line 502: | Line 541: | ||
to use. |
to use. |
||
]] |
]] |
||
coordinates.dec2dms = makeInvokeFunc('_dec2dms') |
|||
function coordinates._dec2dms(args) |
|||
globalFrame = frame |
|||
local coordinate = |
local coordinate = args[1] |
||
local firstPostfix = |
local firstPostfix = args[2] or '' |
||
local secondPostfix = |
local secondPostfix = args[3] or '' |
||
local precision = |
local precision = args[4] or '' |
||
return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision) |
return convert_dec2dms(coordinate, firstPostfix, secondPostfix, precision) |
||
Line 540: | Line 579: | ||
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 = makeInvokeFunc('_dms2dec') |
|||
function coordinates._dms2dec(args) |
|||
globalFrame = frame |
|||
local direction = |
local direction = args[1] |
||
local degrees = |
local degrees = args[2] |
||
local minutes = |
local minutes = args[3] |
||
local seconds = |
local seconds = args[4] |
||
return convert_dms2dec(direction, degrees, minutes, seconds) |
return convert_dms2dec(direction, degrees, minutes, seconds) |
||
Line 569: | Line 608: | ||
version of {{coord}}. |
version of {{coord}}. |
||
]] |
]] |
||
coordinates.coord = makeInvokeFunc('_coord') |
|||
function coordinates._coord(args) |
|||
globalFrame = frame |
|||
if not args[1] and not args[2] and mw.wikibase.getEntityObject() then |
|||
local args = frame.args |
|||
local entity = mw.wikibase.getEntityObject() |
|||
if entity |
|||
if args[1] == nil then |
|||
and entity.claims |
|||
args = pFrame.args; |
|||
and entity.claims.P625 |
|||
if pFrame.args[1] ~= nil then |
|||
and entity.claims.P625[1].mainsnak.snaktype == 'value' |
|||
for k,v in pairs( frame.args ) do |
|||
then |
|||
args[k] = v; |
|||
args[1] = entity.claims.P625[1].mainsnak.datavalue.value.latitude |
|||
end |
|||
args[2] = entity.claims.P625[1].mainsnak.datavalue.value.longitude |
|||
elseif pFrame.args[1] == nil and mw.wikibase.getEntityObject() ~= nil then |
|||
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 = args.display and args.display:lower() or 'inline' |
||
if Display == '' then |
|||
local function isInline(s) |
|||
Display = 'inline'; |
|||
-- 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 isInline(Display) then |
||
text = text .. displayinline(contents, Notes) |
|||
or Display == 'i' |
|||
or Display == 'it' |
|||
or Display == 'ti' |
|||
then |
|||
-- Coordinates are displayed inline. |
|||
text = displayinline(contents, Notes) |
|||
end |
end |
||
if |
if isInTitle(Display) then |
||
text = text |
|||
.. displaytitle(contents, Notes) |
|||
or Display == 'it' |
|||
.. makeWikidataCategories() |
|||
or Display == 'ti' |
|||
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 |