Modul:Marker utilities

![]() |
Dieses Modul wird auf vielen Seiten benutzt, und Änderungen werden projektweit sofort wahrgenommen. Bitte teste Änderungen vorher im /Sandkasten oder in deinem Benutzernamensraum. Die getestete Änderung sollte dann in einem einzigen Edit auf dieser Seite eingefügt werden. Bitte diskutiere Änderungen zuerst auf der Diskussionsseite bevor du sie implementierst. |
![]() |
Dieses Modul ist getestet und für den projektweiten Gebrauch geeignet. Es kann in Vorlagen benutzt und auf Hilfeseiten erläutert werden. Entwicklungen an dem Modul sollten auf Marker utilities/Test und die Anwendung auf der Spielwiese getestet werden, da wiederholte Trial-and-Error-Edits die Resourcen stark belasten können. |
![]() |
Dieses Modul benutzt eine oder mehrere Wikidata-Eigenschaften. |
Anwendung
Das Modul stellt gemeinsame Funktionen für das Modul:Marker und das Modul:vCard zur Verfügung.
Versionsbezeichnung auf WikiData: 2021-01-09
Benötigte weitere Module
Dieses Modul benötigt folgende weitere Module: Coordinates • Marker utilities/Groups • Marker utilities/i18n • Marker utilities/Maki icons • Marker utilities/Types • UrlCheck • Wikidata utilities • Wikidata2/POITypes
Verwendung in anderen Modulen
Dieses Modul ist notwendig für die Ausführung folgender Module. Bei Anpassungen sollte die Funktionstüchtigkeit der folgenden Module geprüft werden. Benutze dazu auch diese Tracking-Kategorie um Fehler zu finden, die sich dann auf Artikel auswirken:
- Marker • vCard • VCard/Params
- Modul benötigt das Modul Marker utilities – Wartungskategorie, in der nochmals alle Module gelistet sind, die von diesem Modul abhängig sind.
Wartungsfunktionen
function mu.initMaintenance( name )
Die Funktion initialisiert die Zeichenkettenverwaltung für die Ausgabe von Fehlermeldungen. name
ist der zugehörige Modulname ohne die Namensraumbezeichnung. Diese Funktion setzt auch die Tabellen fehlerhafter Paramter und der Fehlermeldungen/Hinweise zurück.
function mu.addWrongParameter( param )
Diese Funktion fügt den Parameter param
in die Tabelle fehlerhafter Parameter ein.
function mu.addDuplicateAlias( alias )
Diese Funktion fügt den Parameter alias
in die Tabelle doppelter Aliase ein.
function mu.addMaintenance( s )
Diese Funktion fügt die Fehlermeldung s
in die Tabelle der Fehlermeldungen und Hinweise ein. Ein Teil der oben genannten Funktionen befüllt ebenfalls diese Tabelle.
function mu.getMaintenance()
Dises Funktion liefert eine Zeichenkette mit allen Fehlermeldungen und Hinweisen zurück.
function mu.getCategories( formatStr )
- Liefert eine Zeichenkette mit den Kategorie-Links aller verwendeten Wikidata-Eigenschaften zurück.
function mu.getModuleInterface()
- liefert eine Tabelle mit der Moduldokumentation zurück (am Anfang des Moduls definiert).
function mu.failsafe( frame )
- liefert das Versionsdatum des Moduls zurück. Siehe auch Modul:Failsafe.
Funktionen
Im Projektnamensraum befindet sich die technische Dokumentation.
function mu.isSet( arg )
liefert true
oder false
, je nachdem, ob das Argument arg
gesetzt ist oder nicht. arg
muss existieren und einen Wert ungleich ''
enthalten.
function mu.checkArguments( args, validKeys )
prüft, ob im Vorlagenaufruf unbekannte Parameternamen verwendet werden. Diese unbekannten Parameter werden in die Tabelle fehlerhafter Parameter eingefügt. args
ist die Tabelle der Vorlagenparamter, validKeys
die Tabelle der erlaubten Parameter (siehe z. B. Modul:VCard/i18n).
function mu.getArgument( args, keys )
liest den Wert aus der Vorlagenparametertabelle args
mit dem Index/den Indices keys
. keys
kann eine Zeichenkette oder eine Tabelle mit Zeichenketten sein. Wenn ein Wert nicht existiert, wird nil
zurückgeliefert. Sollten im Fall, dass keys
eine Tabelle darstellt, mehrere Werte gefunden werden, wird der zuerst gefundene Wert zurückgeliefert, und der erste Parametername keys[ 1 ]
wird in die Liste doppelter Aliase eingetragen.
function mu.translateGroup( group )
liefert eine Zeichenkette mit group
in Übersetzung. Die Übersetzungen werden der Tabelle groups
im Modul Marker utilities/Types entnommen. Ist keine Übersetzung vorhanden, so wird group
unübersetzt zurückgeliefert.
function mu.addWdClass( isFromWikidata )
liefert den Klassenbezeichner wikidata-content
, wenn isFromWikidata
auf true
gesetzt ist, ansonsten eine leere Zeichenkette.
function mu.dmsCoordinates( lat, long, name, fromWD, extraParams, withBracket )
liefert die Zeichenkette r
, die eine zu den Kartenwerkzeugen verlinkte Dezimalkoordinate enthält, die wahlweise in Klammern gesetzt oder mit einem Komma eingeleitet werden kann. name
ist der Name der Einrichtung, fromWD = true
besagt, dass die Koordinate aus Wikidata stammt und extraParams
enthält zusätzliche Parameter wird Maßstab und Region, die in den kartenwerkzeugen ausgewertet werden.
function mu.removeCtrls( s, onlyInline )
Die Funktion entfernt Steuerzeichen und die HTML-Tags für den Zeilenumbruch und Zeilenwechsel aus der Zeichenkette s
. Wenn onlyInline = false
, dann bleiben Zeilenumbruch und Zeilenwechsel erhalten. Deren Vorkommen wird in der Variablen descrDiv
mitgeteilt. Die Funktion liefert zwei Werte zurück:
s
bereinigte Zeichenkette.descrDiv
Der Container für die Beschreibung muss ein<div>
-Tag sein.
function mu.addSisterIcons( sisters, name, id )
Die Funktion liefert die Zeichenkette mit Interwiki-verlinkten Symbolbildern wie Wikipedia und Wikimedia Commons zurück. sisters
ist eine Tabelle mit Link-Zeichenketten zu den Wikis, name
ist der Name einer Einrichtung und id
die zugehörige Wikidata-Id. Es werden zwei Zeichenketten zurückgeliefert:
s
vollständige Zeichenkette.t
Teilzeichenkette mit dem Wikidata-Link. Die Zeichenkette dient dazu, im Vergleich mit der ersten Zeichenkette festzustellen, ob die erste Zeichenkette nur aus dem Wikidata-Link besteht.
function mu.getWikiLink( langArray, wiki, entity )
liefert die vollständige Zeichenkette l
zu einem Artikel in Wikimedia-Projekten zurück. Die Angaben stammen aus den Sitelinks der Wikidata-Entity entity
. langArray
ist eine Tabelle der gewünschten Sprachen. wiki = "wiki"
steht für den Einsatz in der Wikipedia.
function mu.makeSisterIcons( args, country, entity )
liefert eine Zeichenkette mit den verlinkten Schwesterprojekt-Symbolen. Die Angaben stammen meist aus den Sitelinks der Wikidata-Entity entity
. args
ist die Tabelle der übergebenen Vorlagenparameter. Die Tabelle country
enthält länderspezifische Daten wie die Sprachangabe.
function mu.getName( name, pageTitle )
liefert die Tabelle array
, die den Namen einer Einrichtung name
in verschiedenen Formen enthält. Hauptaufgabe ist es, den eigentlichen Namen aus einem möglichen Link in Wikiyntax herauszulösen. pageTitle
ist der mögliche Titel des zugehörigen Artikels. Enthält der Name neben einem möglichen Link in Wikisyntax weitere Textteile, so werden diese verworfen. Folgende vier Tabellenelemente werden zurückgeliefert:
exists
:boolean
, Name liegt vor.name
:string
, nur der Name.all
:string
, verlinkter Name oder nur der Name, falls kein Link vorliegt.pageTitle
:string
, Artikel, auf den verlinkt wird. Der Titel kann vonname
verschieden sein.
function mu.checkCoordinates( lat, long )
liefert die überprüften Koordinaten lat, long
. Im Fehlerfall sind lat
und long
leere Zeichenketten. Die Fehlermeldungstabelle enthält zusätzlich einen entsprechenden Eintrag (siehe unten).
function mu.checkTypeAndGroup( aType, group )
liefert die überprüften Werte für aType, group
zurück. Im Fehlerfall enthält die Fehlermeldungstabelle zusätzlich einen entsprechenden Eintrag (siehe unten).
function mu.checkImage( image, entity )
liefert den überprüften Wert für das image
oder eine leere Zeichenkette zurück. Im Fehlerfall enthält die Fehlermeldungstabelle zusätzlich einen entsprechenden Eintrag (siehe unten). Die Variable mi.options.imageCheck
legt fest, ob überhaupt einen rechenzeitintensive Prüfung vorgenommen wird.
function mu.checkCategory( category, catArray )
liefert den überprüften Wert für das category
. Die Namenraumbezeichnung wird entfernt.
function mu.checkUrl( url )
liefert die überprüfte Internetaddresse url
zurück. Im Fehlerfall enthält die Fehlermeldungstabelle zusätzlich einen entsprechenden Eintrag (siehe unten).
function mu.makeMarkerSymbol( args, title, frame )
liefert r
: HTML-Quellcode des Marker-Symbols.
function mu.getColor( aType )
liefert color, aType
. Die Gruupe aType
wird durch error ersetzt, wenn sie nicht vorhanden ist. color
ist die zur Gruppe gehörende Farbe und wird aus der Tabelle Modul:Marker utilities/Groups bezogen.
function mu.replaceBrackets( s )
liefert eine Zeichenkette, in der eckige Klammern durch XML-Zeichenreferenz ersetzt wurden. Wird benötigt, wenn die Zeichenkette in einem Link verwendet werden soll.
function mu.convertForSort( s )
Wandelt die Zeichenkette s
so um, dass eine korrekte Sortierung ermöglicht wird. Die auszutauschenden Buchstaben sind in der sprachabhängigen Tabelle substitutes
im Modul Marker utilities/i18n enthalten.
function mu.generateTableTypeList( frame )
liefert eine sortierbare Tabelle aller für die Vorlagen {{Marker}} und {{vCard}} einsetzbaren Typen. Die Tabelle zeigt die deutsche Übersetzung, die zugehörige Gruppe und die englische Typbezeichnung an.
function mu.data( s )
liefert die Zeichenkette s
mit aufgelösten XML- und SGML-Enitäten, wenn sie existiert und nicht leer ist, ansonsten nil
.
function mu.makeWrapper( result, args, country, show, list, aClass, frame )
umgibt zum Inhalt eines Markers oder einer vCard mit einem umschließenden Tag (span, div).
function mu.languageSpan( s, titleHint, args, country )
fügt den Text in ein span-Tag, in dem die Sprache und Textrichtung des des Texts s
angegeben ist. titleHint
ist das title-Attribut des span-Tags, args
die Vorlagenparamtetertabelle und country
eine Tabelle mit landesspezifischen Angaben.
function mu.split( s, convert, toValue )
liefert eine Tabelle kommaseparierter Werte der Zeichenkette s
. Bei convert = true
wird die Zeichenkette in Kleinbuchstaben umgewandelt, und Leerräume werden durch den Unterstrich ersetzt. Bei toValue = false
, werden die Werte als Schlüssel einer assoziierten Tabelle übergeben.
function mu.splitAndCheck( s, validValues )
liefert eine Tabelle kommaseparierter Werte der Zeichenkette s
und überprüft, ob diese Werte in der Tabelle validValues
enthalten sind. Neben der Tabelle wird als zweiter Wert eine Zeichenkette mit den fehlerhaften Werten übergeben.
function mu.getShow( default, value, validValues )
liefert eine assoziierte Tabelle mit den übergebenen kommaseparierten show
-Attributen, wobei der überschreibbare Standardwert default
berücksichtigt wird. Die show
-Attribute werden auf Gültigkeit hin überprüft.
function mu.tableInsert( tab, value )
fügt den Wert value
zur Tabelle tab
hinzu, wenn er existiert und nicht leer ist.
function mu.getCoordinatesFromWikidata( entity )
liefert die im Wikidata-Datensatz mit der Einität entity
enthaltene Koordinate zurück. Zuerst wird versucht, die Zentrumskoordinate aus der Eigenbschaft P5140
zu erhalten, danach die Koordinate aus der Eigenschaft P625
.
function mu.makeSocial( args, fromWikidata, name, checkIt )
liefert die verlinkten Symbole von Social-Media-Diensten zurück. args
ist die Tabelle der Vorlagenparameter, fromWikidata
die Tabelle der Parameter, die aus Wikidata bezogen wurden, und name
die Bezeichnung der Einrichtung. checkIt
legt fest, ob eine Überprüfung der Werte erfolgen soll.
function mu.makeAirport( args, fromWikidata )
liefert den formatierten Flughafencode nach IATA oder, falls dieser fehlt, den nach ICAO. args
ist die Tabelle der Vorlagenparameter und fromWikidata
die Tabelle der Parameter, die aus Wikidata bezogen
function mu.typeSearch( p31 )
- Sucht in mehreren P31-P279-Ketten nach Q-ids, deren Werte in den Tabellen Module:Wikidata2/POITypes oder Module:Marker utilities/Types enthalten sein könnten. Die Tabelle
p31
enthält die vorgefunden P31-Werte. Der erste Treffer wird als Zeichenkette zurückgegeben, im Fehlerfall die Zeichenkette error. Die Maximalanzahl höherer Ebenen für die Suche ist mitmi.searchLimit
vorgegeben, dies sind üblicherweise 4. Es wird nur jeweils die erste P279-Id ausgewertet, also nicht die gesamte Baumstruktur.
function mu.getMakiIconName( aType )
Die Funktion liefert den Namen einer MAKI-Ikone zum Type aType
oder nil
zurück, wenn es keinen gibt oder eine Abbildung für den Fließtext fehlt.
function mu.checkCommonsCategory( args )
Die Funktion löscht eine evtl. vorhandene Namensraumangabe in der Commons-Kategorie args.commonscat
und fügt eine Wartungskategorie hinzu, wenn die Commons-Kategorie gesetzt wurde.
function mu.getCommonsCategory( args, entity )
Die Funktion versucht, eine Commons-Kategorie aus Wikidata über die Wikidata-Entität entity
zu beziehen. Zuerst wird der Commons-Site-Link analysiert, dann die Eigenschft P373 und zuletzt die Eigenschaft P910.
function mu.getNamesFromWikidata( args, fromWikidata, country, entity )
Die Funktion befüllt die Tabelle args
mit dem Namen der Einrichtung in der Wiki-Sprache und in der Landessprache mit den Angaben aus Wikidata. Die Tabelle fromWikidata
enthält die Information (fromWikidata.name
, fromWikidata.nameLocal
), ob der Name aus Wikidata stammt.
function mu.getArticleLink( args, entity )
Die Funktion übergibt den Sitelink zum zugehörigen Arikel an args.thisWiki
, außer der Vorlagenaufruf wurde in diesem Arikel vorgenommen.
function mu.formatNumber( num )
- Die obige Dokumentation wurde aus der Seite Modul:Marker utilities/Doku eingefügt. (bearbeiten | Versionsgeschichte) Die Kategorien für dieses Modul sollten in der Dokumentation eingetragen werden. Die Interwiki-Links sollten auf Wikidata eingepflegt werden.
- Liste der Unterseiten
-- documentation
local MarkerUtilities = {
suite = 'Marker utilities',
serial = '2021-01-09',
item = 58187612
}
-- Hint: In non-Wikivoyage projects, sister project links functions have to be
-- adapted.
-- module import
require( 'Module:No globals' )
local cd = require( 'Module:Coordinates' )
local mg = mw.loadData( 'Module:Marker utilities/Groups' )
local mi = require( 'Module:Marker utilities/i18n' )
local mm = require( 'Module:Marker utilities/Maki icons' )
local mt = mw.loadData( 'Module:Marker utilities/Types' ) -- types to groups like drink, eat, go, see, sleep, ...
local pt = mw.loadData( 'Module:Wikidata2/POITypes' ) -- WD types to vCard/Poi types
local uc = require( 'Module:UrlCheck' )
local wu = require( 'Module:Wikidata utilities' )
-- module variable
local mu = {}
-- maintenance tools
function mu.initMaintenance( name )
mu.name = name -- module name
mu.params = {} -- table of unknown parameters
mu.aliases = {} -- table of duplicate aliases
mu.maintenance = {} -- table of error strings
end
function mu.addWrongParameter( param )
table.insert( mu.params, "''" .. param .. "''" )
end
function mu.addDuplicateAlias( alias )
table.insert( mu.aliases, "''" .. alias .. "''" )
end
function mu.addMaintenance( s )
local function contains( new )
for _, value in ipairs( mu.maintenance ) do
if value == new then
return true
end
end
return false
end
if not contains( s ) then
table.insert( mu.maintenance, s )
end
end
function mu.getMaintenance()
local s = ''
if #mu.params > 0 then
if #mu.params == 1 then
s = mw.ustring.format( mi.maintenance.unknownParam, mu.params[ 1 ] )
else
s = mw.ustring.format( mi.maintenance.unknownParams,
table.concat( mu.params, ', ' ) )
end
s = s .. mw.ustring.format( mi.maintenance.wrongParam, mu.name )
end
if #mu.aliases > 0 then
s = s .. mw.ustring.format( mi.maintenance.duplicateAliases,
table.concat( mu.aliases, ', ' ) )
end
return s .. table.concat( mu.maintenance, ' ' )
end
function mu.getCategories( formatStr )
return wu.getCategories( formatStr )
end
function mu.isSet( arg )
return arg and arg ~= ''
end
-- args: template arguments consisting of argument name as key and a value
-- validKeys: table with argument name as key used by the script and
-- a string or a table of strings for argument names used by the local wiki
function mu.checkArguments( args, validKeys )
if type( args ) ~= 'table' or type( validKeys ) ~= 'table' or
not next( validKeys ) then
return
end
for key, _ in pairs( args ) do
local invalid = true
for _, validKey in pairs( validKeys ) do
if type( validKey ) == 'string' and validKey ~= '' then
validKey = { validKey }
end
if type( validKey ) == 'table' then
for _, vKey in ipairs( validKey ) do
if key == vKey then
invalid = false
break
end
end
end
end
if invalid then
mu.addWrongParameter( key )
end
end
return
end
-- returns an argument value from a set of keys
function mu.getArgument( args, keys )
local value = nil
if type( args ) ~= 'table' or not keys then
return value
end
if type( keys ) == 'string' and keys ~= '' then
keys = { keys }
end
if type( keys ) == 'table' then
for _, key in ipairs( keys ) do
if args[ key ] then
if not value then
value = args[ key ]
else
mu.addDuplicateAlias( keys[ 1 ] )
break
end
end
end
end
return value
end
-- groups translation for map legend into Wiki language
function mu.translateGroup( group )
if not mu.isSet( group ) then
group = mt.error.group
end
local t = mg[ group ]
if t then
if mu.isSet( t.map ) then
return t.map
elseif mu.isSet( t.label ) then
return t.label
end
end
return group
end
function mu.addWdClass( isFromWikidata )
return isFromWikidata and ' wikidata-content' or ''
end
-- getting DMS coordinates
function mu.dmsCoordinates( lat, long, name, fromWD, extraParams, withBracket )
-- local function outputCoordinates( lat, long, name )
local latDMS, _, latMs = cd.getDMSString( lat, 4, 'lat', '', '', mi.defaultDmsFormat )
local longDMS, _, longMs = cd.getDMSString( long, 4, 'long', '', '', mi.defaultDmsFormat )
local r = '[' .. mi.coordURL .. latMs .. '_' .. longMs .. '_'
.. mw.uri.encode( extraParams ) .. '&locname=' .. mw.uri.encode( name )
.. ' ' .. tostring( mw.html.create( 'span' )
:addClass( 'coordStyle' )
:attr( 'title', mi.texts.latitude )
:wikitext( latDMS )
)
.. ' ' .. tostring( mw.html.create( 'span' )
:addClass( 'coordStyle' )
:attr( 'title', mi.texts.longitude )
:wikitext( longDMS )
)
.. ']'
if withBracket then
r = '(' .. r .. ')'
end
return tostring( mw.html.create( 'span' )
:attr( 'class', 'listing-dms-coordinates printNoLink plainlinks'
.. mu.addWdClass( fromWD ) )
:wikitext( r ) )
end
-- removing breaks and controls from parameters
function mu.removeCtrls( s, onlyInline )
local t = s:gsub( '</br%s*>', ' ' )
local descrDiv = false
local withSpan = false
if onlyInline then
t = t:gsub( '<br[^/>]*/*>', ' ' )
:gsub( '</*p[^/>]*/*>', ' ' )
withSpan = t:find( '<span', 1, true )
if not withSpan then
-- keep some controls in span tag
t = t:gsub( '[%z\1-\31]', ' ' )
-- not %c because \127 is used for Mediawiki tags (strip markers `UNIQ)
end
else
t = t:gsub( '[%z\1-\9\11\12\14-\31]', ' ' )
descrDiv = t:find( '[\10\13]' ) or t:find( '<br[^/>]*/*>' ) or
t:find( '<p[^/>]*>' )
end
if t ~= s then
mu.addMaintenance( mi.maintenance.illegalCtrls )
end
if descrDiv then
mu.addMaintenance( mi.maintenance.descrDiv )
-- replacing newlines by <br> in block mode
t = t:gsub( '([^>%]\10\13])[\10\13]+([^<%[\10\13])', '%1<br class="next-paragraph" />%2' )
end
-- no maintenance message
t = t:gsub( '%s%s+', ' ' )
if withSpan then
t = t:gsub( '[%z\1-\31]', ' ' )
end
return t, descrDiv
end
-- adding linked sister icons
function mu.addSisterIcons( sisters, name, id )
local t = ''
for key, value in pairs( sisters ) do
if value ~= '' then
t = t .. ' ' .. tostring( mw.html.create( 'span' )
:attr( 'class', 'listing-sister-icon listing-sister-' .. key )
:wikitext( '[' .. value .. ' '
.. mw.ustring.format( mi.icons[ key ], name ) .. ']' )
)
end
end
local s = ''
if mu.isSet( id ) then
-- add Wikidata symbol
s = mw.html.create( 'span' )
:attr( 'class', 'listing-sister-icon listing-sister-wikidata' )
:addClass( t == '' and 'listing-only-wikidata' or nil )
:wikitext( '[' .. tostring( mw.uri.fullUrl( 'd:' .. id ) )
.. ' ' .. mw.ustring.format( mi.icons.wikidata, name, id ) .. ']' )
t = t .. tostring( s )
end
return t, s
end
-- getting sister project links
function mu.getWikiLink( langArray, wiki, entity )
local prefix = ''
if wiki == 'wiki' then
prefix = 'w:' -- empty in case of Wikivoyage
end
local link
for _, lang in ipairs( langArray ) do
if lang ~= '' then
link = wu.getSitelink( entity, lang .. wiki )
if link then
return tostring( mw.uri.fullUrl( prefix .. lang .. ':'
.. mw.uri.encode( link, 'WIKI' ) ) )
end
end
end
return ''
end
-- adding Wikimedia sister project icons
function mu.makeSisterIcons( args, page, country, entity )
local sisters = {
wikivoyage = '', -- link to another branch, usually en, as a sister link
commons = '', -- link to Commons category
wikipedia = '' -- link to Wikipedia
}
if args.wikidata ~= '' then
sisters.wikipedia = mu.getWikiLink(
{ page.lang, mi.langs.name, country.lang }, 'wiki', entity
)
if args.wikiPage == '' then
sisters.wikivoyage = mu.getWikiLink(
{ mi.langs.name, country.lang }, page.globalProject, entity
)
if sisters.wikivoyage ~= '' then
mu.addMaintenance( mi.maintenance.linkToOtherWV )
end
end
end
if args.commonscat ~= '' then
sisters.commons = tostring( mw.uri.fullUrl( 'c:Category:'
.. mw.uri.encode( args.commonscat, 'WIKI' ) ) )
end
return mu.addSisterIcons( sisters, args.givenName.name, args.wikidata )
end
-- getting name table with linked and unlinked names
function mu.getName( name, pageTitle )
local r = {
exists = false,
all = '', -- name or linked name
name = '', -- only name
pageTitle = '', -- if pageTitle ~= '' name is already linked
}
if not mu.isSet( name ) or type( name ) ~= 'string' then
return r
end
r.exists = true
local s
local t, c = mw.ustring.gsub( name, '^(.*)%[%[(.*)%]%](.*)$', '%2' )
if c > 0 then -- is / contains [[...]]
t = mw.text.trim( t )
r.all = '[[' .. t .. ']]'
s, c = mw.ustring.gsub( t, '^(.*)|(.*)$', '%2' )
if c > 0 then -- is [[...|...]]
r.name = mw.text.trim( s )
r.pageTitle = mw.text.trim( mw.ustring.gsub( t, '^(.*)|(.*)$', '%1' ) )
else
r.name = t
r.pageTitle = t
end
else
r.name = name
r.all = name
if pageTitle ~= '' then
r.pageTitle = pageTitle
r.all = '[[' .. pageTitle .. '|' .. name .. ']]'
end
end
return r
end
-- checking coordinates
function mu.checkCoordinates( args )
local dms = false
local t
if type( args.lat ) == 'boolean' then
args.lat = ''
end
if type( args.long ) == 'boolean' then
args.long = ''
end
if args.lat == '' and args.long == '' then
return
elseif args.lat ~= '' and args.long == '' then
t = args.lat:find( ',', 1, true )
if t then
args.long = mw.text.trim( args.lat:sub( t + 1, #args.lat ) )
args.lat = mw.text.trim( args.lat:sub( 1, t - 1 ) )
end
end
if args.lat == '' or args.long == '' then
args.lat = ''
args.long = ''
mu.addMaintenance( mi.maintenance.wrongCoord )
return
end
t = tonumber( args.lat )
if t then
args.lat = math.abs( t ) <= 90 and t or ''
else
t = cd.toDec( args.lat, 'lat', 6 )
args.lat = t.error == 0 and t.dec or ''
dms = args.lat ~= ''
end
if args.lat == '' then
args.long = ''
mu.addMaintenance( mi.maintenance.wrongCoord )
return
end
t = tonumber( args.long )
if t then
args.long = ( t > -180 and t <= 180 ) and t or ''
else
t = cd.toDec( args.long, 'long', 6 )
args.long = t.error == 0 and t.dec or ''
dms = dms or args.long ~= ''
end
if args.long == '' then
args.lat = ''
mu.addMaintenance( mi.maintenance.wrongCoord )
end
if dms then
mu.addMaintenance( mi.maintenance.dmsCoordinate )
end
return
end
-- getting marker type and group
function mu.checkTypeAndGroup( aType, group )
local s, t
if mu.isSet( group ) then
mu.addMaintenance( mi.maintenance.groupUsed )
s = mg[ group ]
if not s or s.alias then
mu.addMaintenance( mi.maintenance.unknownGroup )
group = ''
end
end
if not mu.isSet( aType ) then
aType = mt.error.group
if group == '' then
group = aType
end
mu.addMaintenance( mi.maintenance.missingType )
elseif aType == mt.error.group then
if group == '' then
group = aType
end
mu.addMaintenance( mi.maintenance.unknownType )
else
-- split seperate types and analyse them
local ar = {}
for t in mw.ustring.gmatch( aType .. ',', '([^,]+)' ) do
t = mw.text.trim( t:lower() )
t = t:gsub( ' ', '_' )
s = mg[ t ]
if s then -- type is a group itself
if s.is and s.is == 'color' then
mu.addMaintenance( mi.maintenance.typeIsColor )
if s.alias then
t = s.alias
end
else
mu.addMaintenance( mi.maintenance.typeIsGroup )
end
if group == '' then
group = t
end
else
s = mt[ t ]
if s then
if group == '' then
group = s.group
end
else
mu.addMaintenance( mi.maintenance.unknownType )
group = mt.error.group
end
end
table.insert( ar, t )
end
aType = table.concat( ar, ',' )
end
return aType, group
end
local function removeNS( s, nsTable )
s = s or ''
if not s:find( ':', 1, true ) then
return s
end
local t = s
for _, ns in ipairs( nsTable ) do
t = mw.ustring.gsub( t, '^' .. ns .. ':', '' )
if s ~= t then
break
end
end
return t
end
-- image check
function mu.checkImage( image, entity )
if type( image ) == 'boolean' or image == '' then
return image
end
-- delete namespace
image = removeNS( image, mi.texts.FileNS )
-- formal checks
if image:find( '^https?:' ) then
image = ''
else
local extExists = false
local im = image:lower()
for _, ext in ipairs( mi.fileExtensions ) do
if im:find( '%.' .. ext .. '$' ) then
extExists = true
break
end
end
if not extExists then
image = ''
end
end
if image == '' then
mu.addMaintenance( mi.maintenance.wrongImgName )
return image
end
local alreadyChecked = false
if mi.options.mediaCheck and image ~= '' then
if not mi.options.WDmediaCheck and entity then
-- check if image is stored in Wikidata
local imgs = wu.getValues( entity, mi.properties.image, nil )
if #imgs > 0 then
for i = 1, #imgs, 1 do
if imgs[ i ] == image then
alreadyChecked = true
break
end
end
end
end
if not alreadyChecked then
-- expensive function call
local title = mw.title.new( 'Media:' .. image )
if not title or not title.exists then
mu.addMaintenance( mw.ustring.format( mi.maintenance.missingImg, image ) )
image = ''
end
end
end
return image
end
-- remove namespace from category
function mu.checkCategory( category )
return removeNS( category, mi.texts.CategoryNS )
end
-- url check
function mu.checkUrl( url )
local domain
if mu.isSet( url ) then
local c = uc.isUrl( url, mi.options.skipPathCheck ) -- getting result code
if c > 2 then
mu.addMaintenance( mi.maintenance.wrongUrl )
url = ''
elseif c == 2 then -- URL contains IP address
mu.addMaintenance( mi.maintenance.UrlWithIP )
end
end
if mu.isSet( url ) then
for _, service in ipairs( mi.services ) do
domain = service.url:gsub( 'com/.*', 'com' )
:gsub( 'https://', '' ):gsub( 'www.', '' )
if url:find( domain, 1, true ) then
mu.addMaintenance( mi.maintenance.urlIsSocialMedia )
url = ''
end
end
end
return url
end
-- making marker symbol
function mu.makeMarkerSymbol( args, title, frame )
local lon = tonumber( args.long )
local lat = tonumber( args.lat )
local tagArgs = {
zoom = tonumber( args.zoom ),
latitude = lat,
longitude = lon,
show = mi.showAll,
}
if mu.isSet( args.text ) then
tagArgs.text = args.text
if not args.useIcon then
tagArgs.class = 'no-icon'
end
end
if mu.isSet( args.mapGroup ) then
tagArgs.group = args.mapGroup
tagArgs.show = args.mapGroup
else
tagArgs.group = args.groupTranslated
end
if mu.isSet( args.image ) then
tagArgs.description = '[[File:' .. args.image .. '|141px|' .. title .. ']]'
end
local geoJson = {
type = 'Feature',
geometry = {
type = 'Point',
coordinates = { lon, lat }
},
properties = {
title = title,
description = tagArgs.description,
['marker-symbol'] = args.symbol,
['marker-color'] = args.color,
['marker-size'] = 'medium',
}
}
return tostring( mw.html.create( 'span' )
:attr( 'class', 'plainlinks printNoLink poi listing-map' )
:attr( 'title', mi.texts.tooltip )
:css( {
[ 'background-color' ] = args.color,
[ 'border-color' ] = args.color
} )
-- frame:extensionTag is expensive
:wikitext( frame:extensionTag( 'maplink', mw.text.jsonEncode( geoJson ), tagArgs ) )
)
end
-- getting color from group type
function mu.getColor( aType )
local c = mg[ aType ]
if c then
return c.color, aType
else
return mg[ 'error' ].color, 'error'
end
end
-- replace brackets in names
function mu.replaceBrackets( s )
s, _ = s:gsub( '%[', '[' )
:gsub( '%]', ']' )
return s
end
function mu.convertForSort( s )
s = mw.ustring.lower( s )
for _, obj in ipairs( mi.substitutes ) do
s = mw.ustring.gsub( s, obj.l, obj.as )
end
return s
end
-- generates a table with type documentation
function mu.generateTableTypeList( frame )
local rows = {}
local typeList = '<table class="sortable multiline" cellspacing="0">'
.. '<tr><th>' .. mi.types.label .. '</th><th>'
.. mi.types.group .. '</th><th>' .. mi.types.type .. '</th></tr>'
for key, value in pairs( mt ) do
table.insert( rows, '<tr><td>' .. value.label .. '</td><td>' .. value.group
.. '</td><td>' .. key:gsub( '_', ' ' ) .. '</td></tr>' )
end
table.sort( rows,
function( a, b )
return mu.convertForSort( a ) < mu.convertForSort( b )
end
)
return typeList .. table.concat( rows, '' ) .. '</table>'
end
-- prepare value data parameter to a tag
function mu.data( s )
if not mu.isSet( s ) then
return nil
else
return mw.text.decode( s, true ) -- replacing all entities by characters
end
end
-- adding wrapper and microformats
function mu.makeWrapper( result, args, page, country, show, list, aClass, frame )
if type( result ) == 'table' then
result = table.concat( result, ' ' )
end
local wrapper = mw.html.create( show.inline and 'span' or 'div' )
:attr( 'class', 'h-card ' .. aClass )
if args.noGpx then
wrapper:addClass( 'vcard-nogpx' )
else
wrapper:addClass( 'vcard' )
end
if show.indent then
wrapper:addClass( 'listing-indent' )
end
if args.givenName.name ~= mi.maintenance.missingName then
wrapper:attr( 'data-name', mu.data( args.givenName.name ) )
end
wrapper:attr( 'data-location', mu.data( page.subpageText ) )
:attr( 'data-location-qid', page.entityId )
:attr( 'data-wikilang', page.lang )
:attr( 'data-country', mu.data( country.iso_3166 ) )
:attr( 'data-country-name', mu.data( country.country ) )
:attr( 'data-lang', mu.data( country.lang ) )
:attr( 'data-lang-name', mu.data( country.langName ) )
:attr( 'data-country-calling-code', mu.data( country.cc ) )
:attr( 'data-dir', mu.data( country.isRTL and 'rtl' or 'ltr' ) )
:attr( 'data-wiki-dir', mu.data( page.isRTL and 'rtl' or 'ltr' ) )
:attr( 'data-currency', mu.data( country.addCurrency ) )
local arg
for key, value in pairs( list ) do
arg = args[ key ]:gsub( '<[^<>]*>', '' ) -- remove html tags
wrapper:attr( value, mu.data( arg ) )
end
if not show.noCoord then
wrapper:node( mw.html.create( 'span' )
:attr( 'class', 'p-geo geo listing-coordinates' )
:css( 'display', 'none' )
:node( mw.html.create( 'span' )
:attr( 'class', 'p-latitude latitude' )
:wikitext( args.lat )
)
:node( mw.html.create( 'span' )
:attr( 'class', 'p-longitude longitude' )
:wikitext( args.long )
)
)
end
if mu.isSet( args.image ) then
wrapper:node( mw.html.create( 'span' )
:addClass( 'listing-image' )
:css( 'display', 'none' )
:wikitext( mw.ustring.format( '[[File:%s|350x240px|class=noviewer|%s]]',
args.image, args.givenName.name ) )
)
end
if not show.name then
wrapper:node( mw.html.create( 'span' )
:attr( 'class', 'p-name fn org listing-name' )
:css( 'display', 'none' )
:wikitext( args.givenName.name )
)
end
wrapper = tostring( wrapper:wikitext( result ) )
-- adding coordinates to Mediawiki database
-- frame:callParserFunction is expensive
if not show.noCoord and mi.options.secondaryCoords then
wrapper = wrapper .. frame:callParserFunction{ name = '#coordinates',
args = { args.lat, args.long, country.extra, name = args.givenName.name } }
end
return wrapper
end
-- bdi and bdo tags are not working properly on all browsers. Adding marks
-- (lrm, rlm) is maybe the only way for a correct output
function mu.languageSpan( s, titleHint, page, country )
if not mu.isSet( s ) then
return ''
end
local c = country.lang
if c == '' or c == page.lang then
return s
end
local dir
if country.isRTL then
dir = 'rtl'
elseif page.isRTL then
dir = 'ltr'
end
local t = tostring( mw.html.create( 'span' )
:attr( 'lang', c )
:attr( 'dir', dir )
:attr( 'title', mw.ustring.format( titleHint , country.langName ) )
:wikitext( s )
)
if country.isRTL and not page.isRTL then
t = '‏' .. t .. '‎'
end
if not country.isRTL and page.isRTL then
t = '‎' .. t .. '‏'
end
return t
end
-- Splitting comma separated lists to an array
-- convert = true: conversion to lowercase characters, spaces to low lines
-- toValue = true: list items handled as array values
-- toValue = false: list items handled as array keys
function mu.split( s, convert, toValue )
local arr = {}
if not mu.isSet( s ) then
return arr
end
local arr2 = mw.text.split( s, ',', true )
local t
for i = 1, #arr2, 1 do
t = mw.text.trim( arr2[ i ] )
if t ~= '' then
if convert then
t = t:lower():gsub( ' ', '_' )
end
if toValue then
table.insert( arr, t )
else
arr[ t ] = ''
end
end
end
return arr
end
-- Splitting comma separated lists to an array of key items
-- checking items with allowed key values of validValues array
function mu.splitAndCheck( s, validValues )
local arr = {}
local err = {}
local at, count, item, wrong
if not mu.isSet( s ) or not validValues then
return arr, ''
end
-- error check
for k, _ in pairs( mu.split( s, true ) ) do
wrong = false
count = ''
item = k
-- split subtype from count
at = k:find( ':', 1, true )
if at then
item = mw.text.trim( k:sub( 1, at - 1 ) )
count = tonumber( k:sub( at + 1, #k ) ) or ''
if count == '' then
wrong = true
else
count = math.floor( count )
if count < 2 then
count = ''
end
end
end
-- check subtype
if validValues[ item ] then
arr[ item ] = count
else
wrong = true
end
if wrong then
table.insert( err, k )
end
end
return arr, table.concat( err, ', ' )
end
function mu.getShow( default, value, validValues )
local show = mu.split( default, true )
local add, err = mu.splitAndCheck( value, validValues )
if err ~= '' then
mu.addMaintenance( mw.ustring.format( mi.maintenance.unknownShow, err ) )
end
if add.none or add.coord or add.poi or add.all then
show.all = nil -- overwriting defaults
show.coord = nil
show.poi = nil
end
for key, value in pairs( add ) do
show[ key ] = value
end
if show.none then
show.none = nil
show.all = nil
show.coord = nil
show.poi = nil
end
if show.all then
show.all = nil
show.coord = ''
show.poi = ''
end
return show
end
function mu.tableInsert( tab, value )
if type( tab ) == 'table' and mu.isSet( value ) then
table.insert( tab, value )
end
end
function mu.getCoordinatesFromWikidata( args, fromWikidata, entity )
if not entity or ( args.lat ~= '' and args.long ~= '' ) then
return
end
-- center coordinates from Wikidata
local c = wu.getValue( entity, mi.properties.centerCoordinates )
if c == '' then
-- coordinates from Wikidata
c = wu.getValue( entity, mi.properties.coordinates )
end
if c ~= '' then
args.lat = c.latitude
args.long = c.longitude
fromWikidata.lat = true
end
end
function mu.makeSocial( args, fromWikidata, name, checkIt )
local domain, span, t
local s = ''
for _, service in ipairs( mi.services ) do
-- check values first
t = args[ service.key ] or ''
domain = service.url:gsub( 'com/.*', 'com/' )
if t ~= '' and checkIt then
if t:match( '^http' ) then
if not t:match( '^https' ) then
t = t:gsub( '^http', 'https' )
mu.addMaintenance( mw.ustring.format(
mi.maintenance.wrongSocialUrl, service.key ) )
end
if uc.isUrl( t, mi.options.skipPathCheck ) > 1 or
not t:match( '^' .. domain .. '.+$' ) then
t = ''
mu.addMaintenance( mw.ustring.format(
mi.maintenance.wrongSocialUrl, service.key ) )
end
if t ~= '' and not fromWikidata[ service.key ] then
mu.addMaintenance( mw.ustring.format(
mi.maintenance.socialUrlUsed, service.key ) )
end
else
local match = false
if type( service.pattern ) == 'string' then
service.pattern = { service.pattern }
end
for _, pattern in ipairs( service.pattern ) do
if mw.ustring.match( t, pattern ) then
match = true
break
end
end
if not match then
t = ''
mu.addMaintenance( mw.ustring.format(
mi.maintenance.wrongSocialId, service.key ) )
end
end
end
args[ service.key ] = t
-- create symbol link
if t ~= '' then
if not t:find( domain, 1, true ) then
t = mw.ustring.format( service.url, t )
end
span = mw.html.create( 'span' )
:attr( 'class', 'listing-social-media '
.. 'listing-social-media-' .. service.key
.. mu.addWdClass( fromWikidata[ service.key ] ) )
:attr( 'style', mi.texts.socialStyle )
:wikitext( '[' .. t .. ' '
.. mw.ustring.format( mi.icons[ service.key ], name ) .. ']' )
s = s .. tostring( span )
end
end
return s
end
local function _makeAirport( code, args, fromWikidata )
local span = mw.html.create( 'span' )
:attr( 'class', 'listing-' .. code .. '-code'
.. mu.addWdClass( fromWikidata[ code ] ) )
:wikitext( args[ code ] )
return tostring( mw.html.create( 'span' )
:attr( 'class', 'listing-airport listing-' .. code )
:wikitext( mw.ustring.format( mi.texts[ code ], tostring( span ) ) )
)
end
function mu.makeAirport( args, fromWikidata )
local airport = ''
if mu.isSet( args.iata ) then
airport = _makeAirport( 'iata', args, fromWikidata )
elseif mu.isSet( args.icao ) then
airport = _makeAirport( 'icao', args, fromWikidata )
end
return airport
end
local function _typeSearch( p31 )
-- p31: array of Wikidata values
if not p31 or #p31 == 0 then
return 'error'
end
local function compareLabels( ar )
if not ar then
return nil
elseif type( ar ) == 'string' then
ar = { ar }
end
for i, value in ipairs( ar ) do
if mu.isSet( value ) then
value = mw.ustring.lower( value:gsub( ' ', '_' ) )
if mt[ value ] then
return value
end
end
end
return nil
end
local function compareIds( ar )
local id, t
for i = 1, #ar, 1 do
id = ar[ i ].id
-- pt: indexed array of q id - types relations
t = pt[ id ]
if t then
return t
end
-- checking English label and aliases
t = compareLabels( mw.wikibase.getLabelByLang( id, 'en' ) )
if t then
return t
end
t = compareLabels( wu.getAliases( id, 'en' ) )
if t then
return t
end
end
return nil
end
local aType = compareIds( p31 ) -- check p31 ids first, maybe step 2 is not nessary
if aType then
return aType
end
-- now functions becomes expensive because of multiple wu.getValues calls
local id, ids
for i = 1, #p31, 1 do -- step 2: analyse P279 chains of first ids
id = p31[ i ].id -- start id
local j = 0
repeat
ids = wu.getValues( id, mi.properties.subclassOf, nil )
if #ids > 0 then
aType = compareIds( ids )
if aType then
return aType
end
id = ids[ 1 ].id
end
j = j + 1
-- limit: maximum levels to analyse
until j >= mi.searchLimit or #ids == 0
end
return 'error'
end
function mu.typeSearch( p31, entity )
if p31 and #p31 == 0 then
p31 = wu.getValues( entity, mi.properties.subclassOf, mi.p31Limit )
end
local t = _typeSearch( p31 )
if t ~= 'error' then
mu.addMaintenance( mi.maintenance.typeFromWD )
end
return t
end
function mu.getMakiIconName( aType )
local mType
if mm[ aType ] then
mType = aType
elseif mt[ aType ] and mt[ aType ].icon then
mType = mt[ aType ].icon
end
if mType and mu.isSet( mm[ mType ].im ) then
return mType
end
return nil
end
function mu.checkCommonsCategory( args )
-- remove namespace from category
if mu.isSet( args.commonscat ) then
args.commonscat = mu.checkCategory( args.commonscat )
if args.commonscat ~= '' then
mu.addMaintenance( mi.maintenance.commonscat )
end
end
end
function mu.getCommonsCategory( args, entity )
-- getting commonscat from commonswiki sitelink before P373
-- because sitelink is checked by Wikidata
if type( args.commonscat ) == 'boolean' then
args.commonscat = ''
end
local t = wu.getSitelink( entity, 'commonswiki' ) or ''
if t:match( '^Category:.+$' ) then
t = t:gsub( '^Category:', '' )
else
t = wu.getValue( entity, mi.properties.commonsCategory )
if t == '' then
local id = wu.getId( entity, mi.properties.mainCategory )
if id ~= '' then
t = wu.getSitelink( id, 'commonswiki' ) or ''
t = t:gsub( '^Category:', '' )
end
end
end
if t ~= '' and args.commonscat ~= '' then
mu.addMaintenance( mi.maintenance.commonscatWD )
end
if args.commonscat == '' then
args.commonscat = t
end
end
-- getting names from Wikidata
function mu.getNamesFromWikidata( args, fromWikidata, page, country, entity )
-- getting official names
local officialNames =
wu.getMonolingualValues( entity, mi.properties.officialName )
if type( args.name ) == 'boolean' or args.name == '' then
args.name = officialNames[ page.lang ]
or mi.langs.name ~= '' and officialNames[ mi.langs.name ]
or ''
-- if failed then get labels
if args.name == '' then
if page.lang == mi.langs.name then
args.name = wu.getLabel( entity ) or ''
else
args.name = wu.getLabel( entity )
or mi.langs.name ~= '' and wu.getLabel( entity, mi.langs.name )
or ''
end
end
if args.name ~= '' then
mu.addMaintenance( mi.maintenance.nameFromWD )
fromWikidata.name = true
end
end
-- get local name if no name is available
if args.name == '' and
not ( type( args.nameLocal ) == 'string' and args.nameLocal ~= '' ) then
args.nameLocal = true
-- no local name if country and wiki language are identical
elseif args.nameLocal == true and page.lang == country.lang then
args.nameLocal = ''
end
if args.nameLocal == true then
args.nameLocal = officialNames[ country.lang ] or ''
if args.nameLocal == '' then
args.nameLocal = wu.getLabel( entity, country.lang ) or ''
end
if args.name == '' and args.nameLocal ~= '' then
args.name = args.nameLocal
args.nameLocal = ''
mu.addMaintenance( mi.maintenance.nameFromWD )
fromWikidata.name = true
end
fromWikidata.nameLocal = args.nameLocal ~= ''
-- for future use in Module:Marker
-- if fromWikidata.nameLocal then
-- mu.addMaintenance( mi.maintenance.localNameFromWD )
-- end
end
end
-- getting link to Wikivoyage
function mu.getArticleLink( args, entity, page )
local t = wu.getSitelinkTable( entity, page.lang .. page.globalProject )
if t and t.title ~= page.text then -- no link to the article itself
local isLink = false
for _, badge in ipairs( t.badges ) do
if badge == mi.qualifiers.intentionalSitelink or
badge == mi.qualifiers.redirectSitelink then
isLink = true
break
end
end
if not isLink then
args.wikiPage = t.title
end
end
end
-- replacing decimal separator and inserting group separators
function mu.formatNumber( num )
if mu.isSet( mi.formatnum.decimalPoint ) and mi.formatnum.decimalPoint ~= '.' then
num = num:gsub( '%.', mi.formatnum.decimalPoint )
end
if mu.isSet( mi.formatnum.groupSeparator ) then
local count
repeat
num, count = num:gsub( '^([-+]?%d+)(%d%d%d)',
'%1%' .. mi.formatnum.groupSeparator .. '%2' )
until count == 0
end
return num
end
-- module administration
function mu.getModuleInterface()
return MarkerUtilities
end
function mu.failsafe( version )
return wu._failsafe( version, MarkerUtilities ) or ''
end
return mu