Module:Sandbox/RedWolf
Appearance
local p = {}
--local wd = require('Module:Wd')
local titled_coords = require('Module:Titled_coords')
-- Information about a mountain from Module arguments and Wikidata.
local Mountain = { rank, page, name, eid, elevation, elevation_wd,
prominence , range, fa, coords, notes }
-- Runtime options about what information to display
local Options = { debug = false, showFA = false, showCoord = false, showTCoord = false,
showNotes = false, showRank = false, showRange = false}
-- Wikidata properties
local WD_PROPERTIES = {
elevation = "P2044",
prominence = "P2660",
mtn_range = "P4552",
coords = "P625",
sig_event = "P793",
pt_in_time = "P585"
}
local QID_FIRST_ASCENT = "Q1194369"
local FS = ";" -- field separator
local errors, dbgout
local function addError(msg)
errors = errors .. "<br><font color=red>" .. msg .. "</font>"
end
local function debug(msg)
mw.log(msg)
dbgout = dbgout .. msg .. "<br/>\n"
end
local function debugv(var, value)
local s = var .. "=" .. value
mw.log(s)
dbgout = dbgout .. s .. "\n"
end
-- Split a string based on a separator
local function split(istring, sep)
-- if sep is null, use default
if sep == nil then sep = FS end
local t = {}
for str in string.gmatch(istring, '([^'..sep..']+)') do
table.insert(t, str)
end
return t
end
-- Extract raw elevation/prominence value
local function extractRaw(value)
local i, i1, i2, n
if value == nil then return -1 end
i = string.find(value, " metre")
if i then
-- remove thousands separator while we are it
n = string.sub(value, 1, i-1):gsub(',', '')
else
n = -1
end
return n
end
-- Call {{elevation_cells} to format the values
local function getElevationCells(frame, elev, unit) --23
if frame.expandTemplate then
return frame:expandTemplate{title='elevation_cells', args= { elev, unit}}
end
return "{{elevation_cells|" .. elev .. "|" .. unit .. "}}"
end
local function getPage(name)
local parts = split(name,"|")
local page = parts[1]
local n = string.find(page, "%[%[")
if n then
page = string.sub(page,3)
end
n = string.find(page, "%]%]")
if n then
page = string.sub(page,1,n-1)
end
return page
end
--[[
Retrieve a entity's property value from Wikidata. Unfortunately
the interface only supports one property at a time.
]]
local function getWD(frame, eid, name, flag)
if not frame.preprocess then
return "{{Wikidata|property|" .. name .. "|eid=" .. eid .. "}}"
end
local args = "property|"
if flag then args = args .. flag .. "|" end
args = args .. name .. "|eid=" .. eid
local invoke = "{{#invoke:Wd|" .. args .. "}}"
local value = frame:preprocess(invoke)
mw.log(invoke .. " => " .. value)
return value
end
-- Get a wiki linked property value
local function getWDLinked(frame, eid, name)
return getWD(frame, eid, name, "linked")
end
-- Get the raw value of a property value
local function getWDRaw(frame, eid, name)
return getWD(frame, eid, name, "raw")
end
-- Get an entity's property from Wikidata
local function getWDProperty(frame, eid, name, linked)
mw.log("eid=" .. eid .. " name=" .. name)
--[[ local stmts = mw.wikibase.getBestStatements(eid, name)
if stmts ~= nil then
mw.logObject(stmts)
for i=1,#stmts do
mw.log("stmts["..i.."]="..stmts[i]);
end
end ]]
if frame.preprocess then
local args = "property|"
if linked then args = args .. "linked|" end
args = args .. name .. "|eid=" .. eid
local invoke = "{{#invoke:Wd|" .. args .. "}}"
local value = frame:preprocess(invoke)
debug(invoke .. " => " .. value)
return value
end
return "{{Wikidata|property|" .. name .. "|eid=" .. eid .. "}}"
end
-- if frame.expandTemplate then
-- local args = { ['1'] = name, ['page'] = page }
-- return wd._property({eid, args})
-- local args = { ['1'] = 'property', ['2'] = name, ['page'] = page }
-- return frame:expandTemplate{title='Wikidata', args= args}
local function getCoords(frame, eid)
return getWDLinked(frame, eid, WD_PROPERTIES.coords)
end
local function getTitledCoords(frame, eid, title)
local raw_coords = getWDRaw(frame, eid, WD_PROPERTIES.coords)
local invoke = "{{#invoke:Titled_coords|main|" .. raw_coords .. "|" .. title .. "}}"
local fmt_coords = frame:preprocess(invoke)
debug(invoke .. " => " .. fmt_coords)
return fmt_coords
end
local function getElevation(frame, eid)
value = getWD(frame, eid, WD_PROPERTIES.elevation, nil)
return extractRaw(value)
end
local function getFirstAscent(frame, eid)
if frame.preprocess == nil then return "????" end
local names = WD_PROPERTIES.sig_event .. "|" .. QID_FIRST_ASCENT .. "|" .. WD_PROPERTIES.pt_in_time
local value = frame:preprocess("{{#invoke:Wd|property|qualifier|" .. names .. "|eid=" .. eid .. "}}")
debug("FA value = " .. value)
if value == "" then
debugv("No FA found for eid", eid)
return " "
end
-- Find date such as: 10 July 1913
local i1, i2 = string.find(value, "%(%d+%s%a*%s%d%d%d%d%)")
if i1 then
--mw.log("i1="..i1)
local date = string.sub(value, i1+1, i2-1)
debugv("FA date", date)
local len = string.len(date)
local year = string.sub(date, len-4, len)
return year
end
-- Find date with just the year; e.g. (2025)
i1, i2 = string.find(value, "%(%d+%)")
if i1 then
local year = string.sub(value, i1+1, i2-1)
return year
end
return "FA date format unknown"
end
-- get prominence from Wikidata
local function getProminence(frame, eid)
local prom = getWD(frame, eid, WD_PROPERTIES.prominence, nil)
return extractRaw(prom)
end
-- get mountain range from Wikidata. We want it wiki-linked for
-- the first occurence of it in the output.
local function getRange(frame, eid)
return getWDLinked(frame, eid, WD_PROPERTIES.mtn_range)
end
-- generate table header
local function header(options, unit)
local unit_1, unit_2
if unit == nil or unit == "" then
unit = 'm'
end
if unit == 'm' then unit_1 = 'm'; unit_2 = 'ft'
else unit_1 = 'ft'; unit_2 = 'm'
end
local s = '{| class="wikitable sortable"\n!'
if options.showRank then s = s .. " align=\"left\" rowspan=2|Rank||" end
s = s .. "rowspan=2|Mountain/Peak ||colspan=2|Elevation ||colspan=2| Prominence "
if options.showRange then s = s .. "||rowspan=2| Subrange" end
if options.showFA then s = s .. "||rowspan=2| FA " end
if options.showCoord or options.showTCoord then s = s .. "||rowspan=2| Coordinates" end
if options.showNotes then s = s .. "||rowspan=2| Notes" end
s = s .. "\n|-\n"
s = s .. '!' .. unit_1 .. '||' .. unit_2 .. '||' .. unit_1 .. '||' .. unit_2 .. "\n"
return s
end
local function finish()
return "|}"
end
--[[ Process run options
rank - show ranking
range - show mountain range or subrange from WD
fa - show first ascent (year only) from WD
coords - show coordinates from WD
tcoords - show titled coordinates from WD
notes - show notes
debug - show debug information
]]
local function processOptions(runOptions)
local o = Options
if runOptions == nil then return o end
mw.log("runOptions=" .. runOptions)
local parts = split(runOptions, ",")
for i=1,#parts do
option = parts[i]
mw.log("option=" .. option)
if option == "rank" then o.showRank = true end
if option == "fa" then o.showFA = true end
if option == "coords" then o.showCoord = true end
if option == "tcoords" then o.showTCoord = true end
if option == "range" then o.showRange = true end
if option == "notes" then o.showNotes = true end
if option == "debug" then o.debug = true end
end
return o
end
local function processLine(frame, options, line)
local parts, n
local name, elev, page, notes
-- argument contains elevation, page link and notes
parts = split(line, FS)
if #parts < 3 then
local m = "<br/>Bad format on argument (<nowiki>" .. line .. "</nowiki>) -- skipped"
errors = errors .. m
mw.log(m)
return nil
end
local mtn = Mountain
elev = parts[1]
name = parts[2]
if name then
page = getPage(name)
mw.log("name = " .. name .. ";page = " .. page)
else
debug("name is null")
return nil
end
mtn.name = name
mtn.page = page
mtn.elevation = elev;
if options.showNotes then
notes = parts[3]
n = string.find(notes, "\n")
if n then
notes = string.sub(notes, 1, n-1)
end
debugv("notes", notes)
mtn.notes = notes
end
local eid = mw.wikibase.getEntityIdForTitle(page)
if not eid then
addError("Cannot find entity id for page " .. page)
return nil
end
debug("page="..page .. ",eid=" .. eid)
mtn.eid = eid
mtn.elevation_wd = getElevation(frame, eid)
mtn.prominence = getProminence(frame, eid)
if options.showRange then
mtn.range = getRange(frame, eid)
end
if options.showFA then
mtn.fa = getFirstAscent(frame, eid)
end
if options.showCoord then
mtn.coords = getCoords(frame, eid)
end
if options.showTCoord then
mtn.coords = getTitledCoords(frame, eid, page)
end
return mtn
end
local function processRange(ranges, mtn)
local found = false;
local range = mtn.range
for k,v in pairs(ranges) do
if v == range then
found = true; break
end
end
if not found then
debug("Adding range " .. range)
table.insert(ranges, range)
else
local i1, i2 = string.find(range, "|")
if i1 then
name = string.sub(range, i1+1, i2-2)
else
local len = string.len(range)
name = string.sub(range, 3, len-2)
end
mtn.range = name
end
end
function p.list(frame)
local debug_on = false
local rank_number = 0
local last_elev = ""
errors = ""; dbgout = ""
local unit = frame.args[1]
local options = processOptions(frame.args[2])
if options.showCoord and options.showTCoord then
return "<p><font color=red>Can only specify one of coords or tcoords</font>"
end
local output = header(options, unit)
local ranges = {}
for i=3,999,1 do
line = frame.args[i]
if line == nil then break end
debug("line=" .. line)
local mtn = processLine(frame, options, line)
if mtn then
if options.showRank and last_elev ~= mtn.elevation then
rank_number = rank_number + 1
mtn.rank = rank_number
last_elev = mtn.elevation
end
if options.showRange then
processRange(ranges, mtn)
end
elev_cells = getElevationCells(frame, mtn.elevation, unit)
prom = mtn.prominence
if prom ~= nil and prom ~= "-1" and prom ~= "" then
prom_cells = getElevationCells(frame, prom, unit)
else
prom_cells = " || "
end
debug("elev=" .. mtn.elevation ..";elev_wd="..mtn.elevation_wd)
if options.showNotes and mtn.elevation ~= mtn.elevation_wd then
local mm = "<br/><font color=green>Local/WD elevations mismatch: " .. "\"" .. mtn.elevation .. "\"".. "/\"" .. mtn.elevation_wd.. "\"</font>"
mtn.notes = mtn.notes .. mm
end
local s = "|-\n|"
if options.showRank then s = s .. "align=center|" .. mtn.rank .. "||" end
s = s .. mtn.name .. '\n|' .. elev_cells .. '\n|' .. prom_cells .. '\n|'
if options.showRange then s = s .. '|' .. mtn.range .. '\n' end
if options.showFA then s = s .. '|' .. mtn.fa .. '\n' end
if options.showCoord or options.showTCoord then s = s .. '|' .. mtn.coords .. '\n' end
if options.showNotes then s = s .. '|' .. mtn.notes .. '\n' end
output = output .. s
end
end -- for
output = output .. finish()
if debug_on then
output = "</br><nowiki>"..output.."</nowiki>".."\n"..output
end
if string.len(errors) > 0 then
output = output .. "<font color=red>" .. errors .. "</font>"
end
if options.debug and string.len(dbgout) > 0 then
output = output .. "<br/><font color=green>" .. dbgout .. "</font>"
end
return output
end
--[[
Test via Preview Window Debug console
print(p.test())
]]
function p.test()
local frame = mw.getCurrentFrame()
-- if frame then mw.logObject(frame) end
-- local test_data = { {["e"]="3954",["p"]="[[Mount Robson]]",
-- ["n"]="Highest point in the Canadian Rockies<ref name=robson/>"},
-- {["e"]="3747",["p"]="[[Mount Columbia (Canada)|Mount Columbia]]",
-- ["n"]="Highest point in [[Alberta]]<ref name=columbia/>"}
-- }
frame.args = {}
frame.args[1] = 'm'
frame.args[2] = "debug,rank,range,fa,xtcoords,xcoords,notes"
frame.args[3] = "3954"..FS.."[[Mount Robson]]"..FS.."Highest point in the Canadian Rockies<ref name=robson/>"
frame.args[4] = "3747"..FS.."[[Mount Columbia (Canada)|Mount Columbia]]"..FS.."Highest point in [[Alberta]]<ref name=columbia/>"
frame.args[5] = "3731"..FS.."[[North Twin Peak]]"..FS.."Highest peak of The Twins Massif"
frame.args[6] = "3648"..FS.."[[Mount Clemenceau]]"..FS.."Named for [[Georges Clemenceau]], premier of France during WWI"
frame.args[7] = "3619"..FS.."[[Mount Alberta]]"..FS.."Most difficult +11,000 climbing objective<ref name=alberta/>"
frame.args[8] = "3618"..FS.."[[Mount Assiniboine]]"..FS.."Highest point in the Southern Rockies<ref name=assiniboine/>"
frame.args[9] = "3612"..FS.."[[Mount Forbes]]"..FS.."Highest point within the confines of [[Banff National Park|Banff Nat'l Park]]<ref name=forbes/>"
frame.args[10] = "3567"..FS.."[[Mount Goodsir]]"..FS.."Two major summits: South Tower and North Tower (lowest)"
frame.args[11] = "3556"..FS.."[[South Twin Peak]]"..FS.."Lowest peak of The Twins Massif"
frame.args[12] = "3543"..FS.."[[Mount Temple (Alberta)|Mount Temple]]"..FS.."Highest point near [[Lake Louise, Alberta|Lake Louise]]<ref name=temple/>"
frame.args[13] = "3425"..FS.."[[Resplendent Mountain]]"..FS.."tbd"
-- frame.args[7] = ""
-- frame.args[8] = " "
--[[
local fi = 3
for i=1,#test_data do
frame.args[fi] = test_data[i]["e"] .. FS .. test_data[i]["l"] .. FS .. test_data[i]["n"]
fi = fi + 1
end ]]
return p.list(frame)
end
function p.test2()
local s = '<a href="/wiki/Rainbow_Range_(Rocky_Mountains)" title="Rainbow Range (Rocky Mountains)">Rainbow Range</a>'
--local i1,i2 = string.find(s,"%>(.*)%<%/a%>")
local i1,i2 = string.find(s,"%b><")
if i1 then
mw.log("i1=" .. i1 .. " i2=" .. i2)
mw.log(string.sub(s,i1+1,i2-1))
else
mw.log("not found")
end
end
return p
--[[
{| class="wikitable sortable"
|- bgcolor="#ffffcc"
! align="left" rowspan=2|Rank||rowspan=2|Mountain/Peak ||colspan=2|Elevation ||colspan=2| Prominence ||rowspan=2| Subrange
!rowspan=2| FA ||rowspan=2| Notes ||rowspan=2| References
|-
!m || ft || m || ft
|-
|align=center|1||Mount Robson
|{{elevation_cells|3,959|m}}|{{elevation_cells|2829|m}}||Rainbow Range
|1913||Highest point in the Canadian Rockies|| <ref name=robson/>
]]