Module:Map/sandbox
Appearance
Lua
CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules
See User:Jheald/BL18C/template_tests for some testcases
Code
--[[
__ __ _ _ __ __
| \/ | ___ __| |_ _| | ___ _| \/ | __ _ _ __
| |\/| |/ _ \ / _` | | | | |/ _ (_) |\/| |/ _` | '_ \
| | | | (_) | (_| | |_| | | __/_| | | | (_| | |_) |
|_| |_|\___/ \__,_|\__,_|_|\___(_)_| |_|\__,_| .__/
|_|
This module is intended to be the engine behind "Template:Map.
Please do not modify this code without applying the changes first at
"Module:Map/sandbox" and testing at "Module:Map/testcases".
Authors and maintainers:
* User:Jarekt - original version
]]
-- =======================================
-- === Dependencies ======================
-- =======================================
require('strict') -- used for debugging purposes as it detects cases of unintended global variables
local ISOdate = require('Module:ISOdate')._ISOdate -- date localization
local labels = require("Module:I18n/map") -- internationalization of
local core = require('Module:Core')
local formatnum = require('Module:Formatnum')
-- ==================================================
-- === Internal functions ===========================
-- ==================================================
-------------------------------------------------------------------------------
local function getBareLabel(id, userLang)
-- code equivalent to require("Module:Wikidata label")._getLabel with Wikidata=- option
local label, link
-- build language fallback list
local langList = mw.language.getFallbacksFor(userLang)
table.insert(langList, 1, userLang)
for _, lang in ipairs(langList) do -- loop over language fallback list looking for label in the specific language
label = mw.wikibase.getLabelByLang(id, lang)
if label then break end -- label found and we are done
end
return label or id
end
-------------------------------------------------------------------------------
local function message(name, lang)
return mw.message.new( 'wm-license-'..name ):inLanguage(lang):plain()
end
-- ====================================================================
-- === This function is just responsible for producing HTML of the ===
-- === template. At this stage all the fields are already filed ===
-- ====================================================================
local function build_html(args, cats)
local lang = args.lang -- user's language
local dir = mw.language.new( lang ):getDir() -- get text direction
local desTag = mw.ustring.format('<span class="summary fn" style="display:none">%s</span>', args.pagename)
local prmTag = mw.ustring.format("<br /><small>([[%s|%s]])</small>", message('information-permission-reusing-link', lang),
message('information-permission-reusing-text', lang))
-- files with no source will be flagged
if (not args.source) and (args.strict==true) and (args.demo or (args.namespace==6)) then
args.nosource = mw.getCurrentFrame():expandTemplate{ title = 'Source missing' }
end
-- boolean field controling if horizontal section bar will be added
args.addGeotemporalBar = args.demo or args.location or args.map_date or args.scale or args.zoom or args.projection or args.centroid or args.heading or args.latitude or (args.warp_status and not args.warp_status=="skip") or args.other_fields_2
args.addBibliographicBar = args.demo or args.set or args.sheet or args.book_title or args.book_author or args.volume or args.page or args.language or args.other_fields_3 or args.place_of_publication or args.publisher or args.printer or args.publication_date or args.authority
args.addArchivalBar = args.demo or args.institution or args.id or args.dimensions or args.scan_resolution or args.other_fields_4 or args.medium or args.inscriptions or args.notes or args.references or args.other_fields_5
args.addDigitalBar = args.demo
local nCol = 2
if not args.image and args.demo then
args.image = args.demo_image
end
if args.image then
nCol = 3
end
-- Top line
local top, results = {}, {}
if args.name then
table.insert(top, string.format('<span class="fn" id="artwork"><bdi>%s\n</bdi></span>', args.name ) )
end
if args.linkback then -- Wikidata Link
table.insert(top, string.format('[[File:Blue pencil.svg|15px|%s|link=%s]]', args.linkback, args.linkback) )
end
if args.wikidata then -- Wikidata Link
table.insert(top, string.format('[[File:Wikidata-logo.svg|20px|wikidata:%s|link=wikidata:%s]]', args.wikidata, args.wikidata) )
end
if args.QS then -- quick_statement link to upload missing info to wikidata
table.insert(top, string.format('%s', args.QS) )
end
if #top>0 then
local line = string.format('<th colspan="%i" style="background-color:#ccf; font-weight:bold; border:1px solid #aaa" text-align="left">%s</th>', nCol, table.concat(top, ' '))
table.insert(results, string.format('<tr valign="top">\n%s\n</tr>\n', line))
end
-- add other fields
local params = {
-- field name machine readable tag field name i18n approach field value wrapper
-- {field='representation' , id='fileinfotpl_representation' , tag='P6243'},
{field='title' , id='fileinfotpl_art_title' , tag='P1476', wrapper='<div class="fn">\n%s</div>'},
{field='subtitle' , id='fileinfotpl_art_subtitle' , tag='P1680'},
{field='description' , id='fileinfotpl_desc' , tag='Q1200750', wrapper='<div class="description">\n%s</div>', tag2=desTag},
{field='other_fields_1'},
{field='legend' , id='fileinfotpl_map_legend' , tag='legend'},
{field='adjacent_sheets' , id='fileinfotpl_adjacent_sheets' , tag='adjacentsheets'},
{field='sheet_index' , id='fileinfotpl_sheet_index' , tag='sheetindex'},
{field='other_fields'},
{field='date' , id='fileinfotpl_date' , tag='wm-license-information-date'},
{field='source' , id='fileinfotpl_src' , tag='wm-license-information-source'},
{field='nosource' , id='fileinfotpl_nosrc' , tag='wm-license-information-source'},
{field='author' , id='fileinfotpl_aut' , tag='P170', wrapper='<div class="fn value">\n%s</div>'},
{field='contributor' , id='fileinfotpl_contrib' , tag='Q20204892', wrapper='<div class="fn value">\n%s</div>'},
{field='credit_line' , id='fileinfotpl_art_credit_line' , tag='wm-license-artwork-credit-line'},
{field='permission' , id='fileinfotpl_perm' , tag='wm-license-information-permission', tag2=prmTag},
-- Geotemporal Data
{field='addGeotemporalBar' , tag='geotemporal_data'},
{field='map_date' , id='fileinfotpl_map_date' , tag='P2913'},
{field='location' , id='fileinfotpl_map_location' , tag='maplocation'},
{field='type' , id='fileinfotpl_type' , tag='type'},
{field='projection' , id='fileinfotpl_map_projection' , tag='P3037'},
{field='scale' , id='fileinfotpl_map_scale' , tag='P1752'},
{field='zoom' , id='fileinfotpl_map_zoom' , tag='P6592'},
{field='heading' , id='fileinfotpl_map_heading' , tag='heading'},
{field='bbox' , id='fileinfotpl_map_bbox' , tag='limits'},
{field='centroid' , id='fileinfotpl_map_centroid' , tag='Q511093'},
{field='warp' , id='fileinfotpl_map_warped' , tag='warper'},
{field='other_fields_2'},
-- Bibliographic Data
{field='addBibliographicBar' , tag='bibliographic_data'},
{field='set' , id='fileinfotpl_map_parent' , tag='P179'},
{field='sheet' , id='fileinfotpl_map_sheet' , tag='sheet'},
{field='book_title' , id='fileinfotpl_book_title' , tag='Q732577', wrapper='<div class="fn">\n%s</div>'},
{field='book_author' , id='fileinfotpl_aut' , tag='wm-license-information-author', wrapper='<div class="fn value">\n%s</div>'},
{field='volume' , id='fileinfotpl_book_volume' , tag='P478'},
{field='page' , id='fileinfotpl_book_volume' , tag='P304'},
{field='language' , id='fileinfotpl_book_language' , tag='Q34770'},
{field='other_fields_3'},
{field='publication_place' , id='fileinfotpl_book_place-of-publication' , tag='wm-license-book-place-of-publication', },
{field='publisher' , id='fileinfotpl_book_publisher' , tag='wm-license-book-publisher', wrapper='<div class="fn value">\n%s</div>'},
{field='printer' , id='fileinfotpl_book_printer' , tag='P872', wrapper='<div class="fn value">\n%s</div>'},
{field='publication_date' , id='fileinfotpl_publication_date' , tag='P577'},
{field='authority' , id='fileinfotpl_art_authority' , tag='Q36524'},
-- Archival Data
{field='addArchivalBar' , tag='archival_data'},
{field='institution' , id='fileinfotpl_art_gallery' , tag='Q2668072'},
{field='id' , id='fileinfotpl_art_id' , tag='wm-license-artwork-id', wrapper='<div class="identifier">\n%s</div>'},
{field='dimensions' , id='fileinfotpl_art_dimensions' , tag='wm-license-artwork-dimensions'},
{field='other_fields_4'},
{field='medium' , id='fileinfotpl_art_medium' , tag='wm-license-artwork-medium'},
{field='inscriptions' , id='fileinfotpl_art_inscriptions' , tag='wm-license-artwork-inscriptions'},
{field='notes' , id='fileinfotpl_art_notes' , tag='wm-license-artwork-notes'},
{field='references' , id='fileinfotpl_art_references' , tag='artwork-references'},
{field='other_fields_5'},
-- Data about the digital copy
{field='addDigitalBar' , tag='digital_data'},
{field='resolution' , id='fileinfotpl_map_scan_resolution' , tag='resolution'},
{field='other_versions' , id='fileinfotpl_ver' , tag='wm-license-information-other-versions'},
{field='image'}, -- (former: imgen) {{Igen/map}}
-- unused extras:
-- {field='imgen'}, -- deprecated 'image' alias
-- {field='help_warp'}, -- ignore deprecated relict, but don't show param error
-- {field='artist' , id='fileinfotpl_aut' , tag='artwork-artist', wrapper='<div class="fn value">\n%s</div>'},
-- {field='editor' , id='fileinfotpl_book_editor' , tag='book-editor', wrapper='<div class="fn value">\n%s</div>'},
-- {field='translator' , id='fileinfotpl_book_translator' , tag='book-translator', wrapper='<div class="fn value">\n%s</div>'},
-- {field='illustrator' , id='fileinfotpl_book_illustrator' , tag='book-illustrator', wrapper='<div class="fn value">\n%s</div>'},
-- {field='architect' , id='fileinfotpl_aut' , tag='Q42973', wrapper='<div class="fn value">\n%s</div>'},
-- {field='designer' , id='fileinfotpl_aut' , tag='Q5322166', wrapper='<div class="fn value">\n%s</div>'},
-- {field='photographer' , id='fileinfotpl_aut' , tag='Q33231', wrapper='<div class="fn value">\n%s</div>'},
-- {field='subtitle' , id='fileinfotpl_book_subtitle' , tag='book-subtitle'},
-- {field='series_title' , id='fileinfotpl_book_series-title' , tag='book-series-title'},
-- {field='edition' , id='fileinfotpl_edition' , tag='book-edition'},
-- {field='object_type' , id='fileinfotpl_art_object_type' , tag='object_type'},
-- {field='genre' , id='fileinfotpl_art_genre' , tag='Q483394'},
-- {field='original_description' , id='fileinfotpl_desc' , tag='original_description', wrapper='<div class="description">\n%s</div>'},
-- {field='pageoverview' , id='fileinfotpl_book-page-overview' , tag='book-page-overview'},
-- {field='depicted_people' , id='fileinfotpl_art_depicted_people' , tag='depicted_people'},
-- {field='depicted_place' , id='fileinfotpl_art_depicted_place' , tag='depicted_place'},
-- {field='depicted_part' , id='fileinfotpl_art_depicted_part' , tag='P5961'},
-- {field='department' , id='fileinfotpl_art_location' , tag='artwork-current-location', wrapper='<div class="locality">\n%s</div>'},
-- {field='coordinates' , id='fileinfo-paramfield' , tag='ObjectLocation'},
-- {field='place_of_creation' , id='fileinfotpl_art_creation_place' , tag='place_of_creation'},
-- {field='place_of_discovery' , id='fileinfotpl_art_discovery_place' , tag='place_of_discovery'},
-- {field='object_history' , id='fileinfotpl_art_object_history' , tag='artwork-object-history'},
-- {field='exhibition_history' , id='fileinfotpl_art_exhibition_history' , tag='exhibition_history'},
}
for _, param in ipairs(params) do
local field, tag, cell1, cell2, id
field = args[param.field]
if param.id then -- skip "other fields" parameter
id = mw.ustring.format('id="%s" ', param.id)
if field or (args.demo and param.tag and (param.field ~= 'source')) then -- skip the row if no field
tag = param.tag or 'bad'
if string.sub(tag,1,10) == 'wm-license' then -- translate using MediaWiki message
tag = mw.message.new( tag ):inLanguage(lang):plain() -- label message in args.lang language
elseif string.match(tag, "^[QP]%d+$") then -- translate based on Wikidata labels
tag = mw.language.new(lang):ucfirst(getBareLabel(tag, lang))
elseif labels[tag] then -- translate using LangSwitch and Module:I18n/map
tag = mw.language.new(lang):ucfirst(core.langSwitch(labels[tag], args.lang))
end
field = (param.wrapper and mw.ustring.format(param.wrapper, field or '')) or field -- apply wrapper if provided
cell1 = mw.ustring.format('<td %sclass="fileinfo-paramfield" lang="%s">%s%s</td>\n', id or '', lang, tag, param.tag2 or '')
cell2 = mw.ustring.format('<td>\n%s</td>', field or '')
field = mw.ustring.format('<tr style="vertical-align: top">\n%s%s\n</tr>\n\n', cell1, cell2)
end
elseif field and param.tag then -- do horizontal bar
tag = mw.language.new(lang):ucfirst(core.langSwitch(labels[param.tag], args.lang))
cell1 = mw.ustring.format('<td class="type fileinfo-paramfield" colspan="2" style="text-align:left;font-size:larger;"> %s</td>\n', tag)
field = mw.ustring.format('<tr style="vertical-align: top">\n%s\n</tr>\n\n', cell1)
end
table.insert(results, field)
end
-- add table and outer layers
local style = string.format('class="fileinfotpl-type-artwork toccolours vevent" dir="%s" style="width: 100%%" cellpadding="4"', dir)
results = string.format('<table %s>\n%s\n</table>\n', style, table.concat(results)) -- combine "results", an array of strings into a single string
results = string.format('<div class="hproduct commons-file-information-table">\n%s\n</div>\n', results)
return results
end
-- =================================================================
-- === Construct output fields from the input arguments
-- =================================================================
local function create_infobox(args)
local cats = ''
local frame = mw.getCurrentFrame()
if args.demo then
args.scale = '100000'
args.heading = 'N'
args.latitude = '0.0/0.0/0.0/0.0'
args.longitude = '0.0/0.0/0.0/0.0'
end
-- add formatting to the scale in accordance with current language preference
if args.scale and tonumber(args.scale) then
args.scale = string.format('1:%s', formatnum.formatNum(args.scale, args.lang))
end
-- compass image for heading
if args.heading then -- note : no input validation currently done
local img_link = frame:expandTemplate{ title = 'Compass rose file', args = { args.heading, style = 'north' } }
args.heading = string.format('[[%s|50px]]', img_link)
end
-- bounding box
if args.latitude and args.longitude then
args.bbox = frame:expandTemplate{ title = 'Map/bbox', args = { latitude = args.latitude, longitude = args.longitude } }
end
-- button with link for Map Warper or external georeferencing
local title = mw.title.getCurrentTitle()
local page_id_for_warper = ''
if 6 == title.namespace then
page_id_for_warper = title.id -- set pageID ready for warper link, but only if we are in the File: namespace
end
if ('warped' == args.warp_status) or ('1' == args.warp_status) then
local warp_msg = mw.language.new(args.lang):ucfirst(core.langSwitch(labels['view_warp'], args.lang)) -- msg from I18n/map
args.warp = frame:expandTemplate{
title = 'Clickable button',
args = {
target='//warper.wmflabs.org/wikimaps/new?pageid=' .. page_id_for_warper,
text= warp_msg,
external='yes',
class='mw-ui-progressive mw-ui-button ui-button-blue'
}
}
cats = cats .. '\n[[Category:Georeferenced maps in Wikimaps Warper]]'
elseif 'external' == args.warp_status then
local warp_msg = mw.language.new(args.lang):ucfirst(core.langSwitch(labels['external_warp'], args.lang)) -- msg from I18n/map
args.warp = frame:expandTemplate{
title = 'Clickable button 2',
args = {
link=args.warp_url,
text= warp_msg,
color='blue2',
}
}
elseif 'skip' == args.warp_status then
-- nothing
else
local warp_msg = mw.language.new(args.lang):ucfirst(core.langSwitch(labels['help_warp'], args.lang)) -- msg from I18n/map
args.warp = frame:expandTemplate{
title = 'Clickable button',
args = {
target='//warper.wmflabs.org/wikimaps/new?pageid=' .. page_id_for_warper,
text= warp_msg,
external='yes',
class='mw-ui-progressive mw-ui-button ui-button-blue'
}
}
if not ('unwarped' == args.warp_status) then
args.warp = mw.ustring.format('%s <small>%s</small>', args.warp, mw.language.new(args.lang):ucfirst(core.langSwitch(labels['skip_warp'], args.lang)))
end
end
-- try to internationalise language code
if args.language then
local language_i18n = mw.language.fetchLanguageName( args.language, args.lang )
if not ('' == language_i18n) then
args.language = language_i18n
end
end
-- internationalise ISO dates
if args.date then
-- apply ISODate to function to date string to convert date in ISO format to translated date string
args.date = ISOdate(args.date, args.lang, '', 'dtstart', '100-999')
end
if args.map_date then
-- apply ISODate to function to date string to convert date in ISO format to translated date string
args.map_date = ISOdate(args.map_date, args.lang, '', 'dtstart', '100-999')
end
if args.print_date then
-- apply ISODate to function to date string to convert date in ISO format to translated date string
args.print_date = ISOdate(args.print_date, args.lang, '', 'dtstart', '100-999')
end
if args.wikidata_title then
args.title = string.format('%s [[File:Wikidata-logo.svg|20px|wikidata:%s|link=wikidata:%s]]', args.title or '', args.wikidata_title, args.wikidata_title)
end
local results = build_html(args)
return results .. cats
end
-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}
-- ===========================================================================
-- === Version of the function to be called from other LUA codes
-- ===========================================================================
-------------------------------------------------------------------------------
-- _map function creates a wikicode for {{Map}} template based on
-- passed arguments (through "args") and data extracted from SDC.
-------------------------------------------------------------------------------
-- Dependencies: p._SDC_Description, p._SDC_Source, p._SDC_Author, p._SDC_Date,
-- Build_html, Module:ISOdate (_date)
-------------------------------------------------------------------------------
function p._map(args)
local cats = ''
-- ============================================================================================
-- === add [[Category:Pages using Map template with incorrect parameter]] if needed ===
-- ============================================================================================
local page = mw.title.getCurrentTitle()
local lang = args.lang
local namespace = page.namespace -- get page namespace
if namespace==6 or namespace==10 then
-- TODO add all allowed fields
local allowedFields = {'title', 'wikidata_title', 'description', 'legend', 'author', 'contributor', 'image', 'date', 'source', 'permission', 'map_date', 'location', 'wikidata_location', 'type', 'projection', 'centroid', 'scale', 'zoom', 'heading', 'latitude', 'longitude', 'warp_status', 'warp_url', 'set', 'wikidata_set', 'sheet', 'book_author', 'wd_book_author', 'book_title', 'wikidata_book', 'volume', 'page', 'language', 'publication_place', 'publisher', 'printer', 'print_date', 'ISBN', 'LCCN', 'OCLC', 'institution', 'id', 'dimensions', 'scan_resolution', 'medium', 'credit_line', 'inscriptions', 'notes', 'other_versions', 'references', 'other_fields', 'other_fields_1', 'other_fields_2', 'other_fields_3', 'other_fields_4', 'other_fields_5', 'demo', 'lang', 'resolution', 'other-versions', 'strict' }
local set, badField = {}, {}
for _, field in ipairs(allowedFields) do set[field] = true end
for field, _ in pairs( args ) do
if not set[field] then
table.insert(badField, field)
end
end
if #badField>0 then
cats = mw.ustring.format('\n;<span style="color:red">Error in [[Template:Map|{{Map}}'..
' template]]: unknown parameter "%s".</span>', table.concat(badField,'", "'))
cats = cats .. '\n[[Category:Pages using Map template with incorrect parameter]]'
end
end
args.pagename = page.text
return create_infobox(args) .. cats
end
-- ===========================================================================
-- === Version of the functions to be called from template namespace
-- ===========================================================================
-------------------------------------------------------------------------------
-- information function creates a wikicode for {{Map}} template based on
-- passed arguments (through "frame") and data extracted from SDC. All inputs do not
-- depend on capitalization and all "_" can be replaced with spaces.
-------------------------------------------------------------------------------
-- Dependencies: p._information
-------------------------------------------------------------------------------
function p.map(frame)
local args = core.getArgs(frame)
-- map aliases to a single variable (all parameters converted to lowercase with _ instead of spaces
args.id = args.id or args.accession_number
args.medium = args.medium or args.technique
args.dimensions = args.dimensions or args.size
args.permission = args.permission or args.license
args.location = args.depicted_place or args.location
args.resolution = args.scan or args.scan_resolution or args.resolution
args.warp_status = args.warp_status or args.warper or args.warped
if args.imgen then
if not args.image then
args.image = args.imgen
args.imgen = nil
end
end
if args.image and string.sub(args.image, 1, 1 ) ~= '{' then
args.image = frame:expandTemplate{ title = 'Igen/map', args = { args.image } }
end
-- remove aliases
args.accession_number = nil
args.technique = nil
args.size = nil
args.license = nil
args.help_warp = nil
args.depicted_place = nil
args.scan_resolution, args.scan = nil, nil
args.warper, args.warped = nil, nil
-- ensure the right format
args.strict = core.yesno(args.strict, true)
return p._map(args)
end
-------------------------------------------------------------------------------
-- List of exported functions
-------------------------------------------------------------------------------
-- map
--[[
Calculate coordinates of 4 corners of the map based on 3 georeferenced anchor
points and image dimensions.
INPUTS:
* anchorX - x map coordinate (pixel column) of 3 anchor points on the map
* anchorY - y map coordinate (pixel row ) of 3 anchor points on the map
* anchorDeg - latitude or longitude of 3 anchor points on the map
* nx - image width in pixels
* ny - image height in pixels
X = {7772, 330, 6679} -- x map coordinate of 4 cities on the map
Y = {553, 4122, 5248} -- y map coordinate of 4 cities on the map
lat = {52.516, 48.857, 48.133} -- latitude of 4 cities on the map
lon = {13.383, 2.351, 11.567} -- longitude of 4 cities on the map
nx = 8150 -- image width
ny = 6978 --image height
]]
function p.CalculateCornerLocations(frame)
-- process inputs
local anchorX = mw.text.split(frame.args.anchorX, '/')
local anchorY = mw.text.split(frame.args.anchorY, '/')
local anchorDeg = mw.text.split(frame.args.anchorDeg, '/')
local nx = tonumber(frame.args.nx)
local ny = tonumber(frame.args.ny)
local formatstr = tonumber(frame.args.formatstr) or '%8.6f'
if (#anchorX~=3 or #anchorY~=3 or #anchorDeg~=3) then
end
-- do matrix algebra
local matrix = require('Module:Matrix')
-- Calculate transformation matrix
-- MATLAB: M = [X, Y, ones(length(X),1)] \ anchorDeg;
C = matrix{{ anchorX[1], anchorY[1], 1, anchorDeg[1]},
{ anchorX[2], anchorY[2], 1, anchorDeg[2]},
{ anchorX[3], anchorY[3], 1, anchorDeg[3]}}
local done = matrix.dogauss( C )
if done then
M = matrix.subm( C, 1,4,3,4) -- remove identity matrix from first 3 columns
-- MATLAB: cornerDeg = [ 1, ny, 1; nx, ny, 1; nx, 1, 1; 1, 1, 1] * M
cornerPix = matrix{{ 1, ny, 1},{nx, ny, 1},{nx, 1, 1},{1, 1, 1}} -- corner points in pixels
cornerDeg = cornerPix * M
-- convert to a string
local tstr = {}
for i = 1,#cornerDeg do
tstr[i] = string.format(formatstr, cornerDeg[i][1])
end
str =table.concat(tstr,'/')
else
str = '0/0/0/0'
end
return str
end
return p