このテンプレートは、以下のLuaモジュールを使用しています。 |
このモジュールは、モジュール:VCardで使用される関数を提供します。Wikivoyage:Marker utilities (ドイツ語版) も参照。
使用状況
このモジュールを使用しているモジュールは以下の通りです:
関数
メンテナンス関数
function mu.initMaintenance( name )
この関数は、エラーメッセージ出力のための変数を初期化します。name
には、名前空間名を除いた関連モジュールの名前が入ります。また、この関数は不正なパラメータとエラー・注釈のテーブルも初期化します。
function mu.addMaintenance( key, value )
この関数は、key
に与えられたコードから、エラーや注釈などのメッセージを取得してエラーと注釈のテーブルに入れます。value
はメッセージの引数として、%s
を置換します。上で紹介したいくつかの関数もこのテーブルに値を入れます。
function mu.getMaintenance()
この関数は、全てのエラーと注釈のメッセージを返します。
function mu.getCategories( formatStr )
使用されたすべてのウィキデータプロパティについて、そのプロパティのカテゴリへのリンクを返します。
補助関数
function mu.isSet( arg )
引数arg
がセットされているかどうかについて、true
またはfalse
を返します。arg
に空文字列以外の値が代入されている場合のみ、true
が返ります。
function mu.convertForSort( s )
ソート用に、文字列s
に含まれる特殊文字を置換します。置換される文字は、国際化ファイルのsubstitutes
テーブルに入っています。漢字は量が膨大であり列挙が不可能であるため、日本語版ウィキボヤージュではこの関数に意味がありません。
function mu.formatNumber( num )
数値の引数num
について、小数点を文字列として置換し、3桁ごとに桁の区切り文字を挿入します。
function mu.tableInsert( tab, value )
テーブルtab
が定義されており、空文字列でなければ、tab
にvalue
を挿入します。
function mu.textSplit( s, sep )
文字列s
を区切り文字sep
で分割し、空文字列を含まないテーブルに代入します。sep
は正確に1文字(1バイト)の長さを持ち、パターンマッチの構文は使用できません。この関数はmw.text.split()
よりも遥かに速いです。
function mu.split( s )
文字列s
をカンマで区切った連想配列を返します。部分文字列は小文字に変換され、スペースはアンダースコアで置換されます。
function mu.makeSpan( s, class, isBdi, attr, css )
s
を<span>
タグまたは<bdi>
タグで囲んだ文字列を返します。class
はCSSクラス、attr
は属性のテーブル、css
は要素に直接書かれるスタイルシートのテーブルです。
function mu.languageSpan( s, titleHint, args, country, addClass )
言語とテキストの方向が指定された<span>
タグにテキストs
を挿入します。titleHint
は<span>
タグのtitle
属性、args
はテンプレートのパラメータが入ったテーブル、country
は国の情報のテーブルです。
function mu.addWdClass( isFromWikidata )
isFromWikidata
がtrue
の場合、クラス識別子wikidata-content
を返し、そうでなければ空文字列を返します。
function mu.getAliases( tab, key )
テーブルtab
から、別名のキーと正式名称の値を持ったテーブルを作成します。
function mu.yesno( val )
val
が既知の値であればy
またはn
を返し、なければnil
を返します。モジュール:Yesnoと同じ機能です。
評価関数
function mu.checkArguments( templateArgs, validKeys )
テンプレートの呼び出し時に、未知のパラメータや別名によって重複したパラメータが使用されているか確認します。これらの不明または重複したパラメータは、無効なパラメータのテーブル(invalidParams
)または重複した別名のテーブル(duplicateAliases
)に入ります。templateArgs
は確認したいパラメータのテーブルで、validKeys
は既知のパラメータのテーブルです(モジュール:VCard/i18nなどを参照)。返り値は有効なパラメータのテーブルです。
function mu.checkCommonsCategory( args )
この関数は、コモンズのカテゴリargs.commonscat
から名前空間名を除去し、コモンズのカテゴリが設定されている場合はメンテナンス用のカテゴリを追加します。
function mu.checkCoordinates( lat, long )
lat
とlong
の値を確認します。エラーがある場合、latとlongは空文字列となります。エラーメッセージのテーブルにも対応する部分があります(下記参照)。
function mu.checkZoom( args )
args.zoom
の値が0~19の範囲の数字でない場合、args.zoom
を既定値に設定します。
function mu.checkImage( image, entity )
画像の値を確認し、エラーがあった場合には空文字列を代入します。エラーメッセージのテーブルにも対応する部分があります(下記参照)。
function mu.checkStatus( args )
status
パラメータの値を確認し、有効な値をargs.statusTable
に代入します。エラーが発生した場合、エラーメッセージのテーブルにも対応する部分があります(下記参照)。
function mu.checkTypeAndGroup( args )
args
のタイプとグループの値を確認し、正しい値を代入します。エラーが発生した場合、エラーメッセージのテーブルにも対応する部分があります(下記参照)。
function mu.checkUrl( args )
args
のURLの値を確認し、正しい値を代入します。エラーが発生した場合、エラーメッセージのテーブルにも対応する部分があります(下記参照)。
タイプとグループの関数
function mu.getTypeParams( aType )
aType
で指定されたタイプのテーブルを、モジュール:Marker utilities/Typesから取得して返します。該当するものがない場合、nil
が返ります。
function mu.getTypeLabel( id )
id
に対応するタイプの最初のラベルを返します。id
は、vCardのタイプかウィキデータの項目名です。エラーがある場合、空文字列かid
そのものが返ります。
function mu.typeExists( aType )
aType
がモジュール:Marker utilities/TypesにあればaTypeを、なければnil
を返します。別名は対応するタイプに変換されます。
function mu.groupWithEvents( group )
指定されたグループgroup
が、イベントのタイプを使用できるかどうかを返します。
function mu.getColor( args )
グループgroup
から引数args
にcolor
とinverse
を追加します。
function mu.idToType( id )
ウィキデータIDからタイプを検索し、見つかった場合はそのタイプを、そうでなければnil
を返します。
整形関数
function mu.getShow( default, args, validValues )
上書き可能な既定値を踏まえて、カンマ区切りでパラメータに渡されたshow
の値を持つ連想配列を返します。args
はパラメータのテーブルで、この関数内ではargs.show
のみが評価されます。
function mu.removeCtrls( s, onlyInline )
この関数は、文字列s
から制御文字や改行を削除します。onlyInline = false
の場合には改行は削除されません。この関数の返り値は2つあります:
- 整形された
s
<div>
タグのコンテナを持つ説明文descrDiv
クエリ関数
function mu.getCoordinatesFromWikidata( entity )
ウィキデータのデータセットにある座標をエンティティのインスタンスと共にに返します。まず P5140 プロパティから中心座標を取得しようと試み、次に P625 プロパティから座標の取得を試みます。
function mu.typeSearch( p31 )
いくつかの P31~P279 チェーンで、モジュール:Marker utilities/Typesのテーブルに値が含まれているかもしれないQIDを検索します。テーブル P31 には見つかったP31の値が含まれています。はじめにヒットした値が文字列で返されます。エラーの場合は、エラー文字列が返されます。上位レベルを検索する際の深さの最大数はmi.searchLimit
で設定でき、通常は4です。最初の P279 ID だけが評価され、ツリー構造全体は評価されません。
function mu.getCommonsCategory( args, entity )
この関数は、ウィキデータにあるエンティティのインスタンスからコモンズのカテゴリを取得しようと試みます。最初に接続されているコモンズへのリンクが調べられ、次に P373 プロパティ、最後に P910 プロパティを調べます。
function mu.getLangTable( wikiLang, localLang )
wikiLang
、localLang
(country.lang
)、モジュール:Marker utilities/i18nの言語langs
を使って言語コードの配列を作成します。
function mu.getNamesFromWikidata( args, fromWikidata, country, entity )
この関数は、ウィキデータの情報を用いて、ウィキの言語と現地語の名称でテーブルの引数を埋めます。fromWikidata
テーブルには、名称の情報をウィキデータから取得したかどうか(fromWikidata.name
、fromWikidata.nameLocal
)が格納されます。
function mu.getArticleLink( args, entity )
この記事でテンプレート呼び出しが行われない限り、この関数は関連する記事へのサイトリンクをargs.thisWiki
に渡します。
マーカー関数
function mu.getMaki( key )
Die Funktion liefert eine Tabelle für den angegebenen key
aus der Tabelle Module:Marker utilities/Maki icons zurück.
function mu.getMakiIconId( aType )
Die Funktion liefert den Namen eines MAKI-Symbols zum Type aType
oder nil
zurück, wenn es keinen gibt oder eine Abbildung für den Fließtext fehlt.
function mu.addIconToMarker( args )
fügt einen Text, der ein Symbol enthält, zur Parametertabelle args
.
function mu.makeMarkerSymbol( args, title, frame, show )
liefert r
: HTML-Quellcode des Marker-Symbols.
アイコン関数
function mu.makeStatusIcons( args )
args.statusTable
テーブルに従って画像の文字列を返します。
function mu.addLinkIcon( classes, link, title, text )
リンクされたアイコン画像を表示するためのHTMLを生成します。表示にはテンプレートのスタイルシートも必要です。listing-icon
に追加するCSSクラスclasses
と、リンクlink
(外部リンクでも内部リンクでも)、ツールチップtitle
、通常は表示されないリンクテキストtext
が必要です。
function mu.makeSisterIcons( icons, args, country, entity )
リンクされた姉妹プロジェクトのアイコンをテーブルに代入します。通常、情報はウィキデータ・エンティティのサイトリンクから取得します。args
は、テンプレートに渡されたパラメータのテーブルです。テーブルcountry
には言語をはじめとした国のデータが入っています。
function mu.makeSocial( icons, args, fromWikidata, name )
リンクされたソーシャルメディアサービスのアイコンをテーブルに代入します。args
は、テンプレートに渡されたパラメータのテーブルです。fromWikidata
はウィキデータから取得したパラメータのテーブル、name
はマーカーやvCardが紹介している場所の名称です。
出力関数
function mu.prepareNames( args )
name
パラメータとnameMap
から形成されるdisplayName
テーブルとgivenName
テーブルを引数テーブルに追加します。ウィキ構文内の有効なリンクから実際の名前を抽出することが主な目的です。どちらのテーブルも次の3つの要素で構成されます:
name
(string
):表示される名前all
(string
):テンプレートにリンク付きで渡された場合はリンクを含めたウィキ構文、そうでない場合は名前だけpageTitle
(string
):リンクの名前。name
と異なるかもしれません。
function mu.makeName( result, args, show, page, country, nameClass, localClass )
result
テーブルに名前と追加の名前を追加します。追加の名前には、別名、現地語での名前、コメント、空港コードが含まれ、括弧とspanタグに挟まれています。nameClass
とlocalClass
は、名前と現地語名の追加クラスです。
function mu.parentheses( s, trim )
この関数は、括弧内に文字列s
を挿入します。ブール値trim
がtrue
ならば、書式の文字列(通常は (%s)
)が切り抜かれます。
function mu.dmsCoordinates( lat, long, name, fromWD, extraParams, noBrackets )
文字列r
を返します。この文字列は、マップツールへのリンクを含む10進数の座標で、任意で括弧内に入れることもできます。name
は場所の名前で、fromWD = true
は座標がウィキデータ由来であることを意味します。また、extraParams
にはマップツールで使用される縮尺と領域のデータが入ります。
function mu.makeWrapper( result, args, country, show, list, aClass, frame )
マーカーやvCardの内容をタグ(<span>
、<div>
)で囲みます。
その他の関数
function mu.getPageData()
この関数は、ページに関連したデータを返します。
関連項目
この解説は、モジュール:Marker utilities/docから呼び出されています。 (編集 | 履歴) 編集者は、このモジュールをサンドボックス (作成 | 複製)とテストケース (作成)で試すことができます。(解説) このモジュールのサブページ一覧。 |
--[[ Functions library for Marker and vCard modules In non-Wikivoyage projects, sister-project links functions have to be adapted. ]]-- -- require( 'strict' ) local cd = require( 'Module:Coordinates' ) local mg = require( 'Module:Marker utilities/Groups' ) local mi = require( 'Module:Marker utilities/i18n' ) local mm -- MAKI icons local mt = require( 'Module:Marker utilities/Types' ) -- types to groups like drink, eat, go, see, sleep, ... local uc -- URL check local wu = require( 'Module:Wikidata utilities' ) -- module variable and administration local mu = { moduleInterface = { serial = '2025-02-14', item = 58187612 }, comma = mi.texts.comma, commaSeparator = mi.texts.commaSeparator } local colorAdjust = { ['-webkit-print-color-adjust'] = 'exact', ['color-adjust'] = 'exact', ['print-color-adjust'] = 'exact' } -- maintenance tools function mu.initMaintenance( name ) mu.invalidParams = {} -- table of unknown parameters mu.duplicateAliases = {} -- table of duplicate parameter aliases mu.maintenance = {} -- table of error strings mu.types = mt.types mu.groups = mg.groups mu.typeAliases = nil -- table for type aliases. Create on demand mu.groupAliases = nil -- table for group aliases end local function contains( new ) for i = 1, #mu.maintenance do if mu.maintenance[ i ] == new then return true end end return false end function mu.addMaintenance( key, value ) local s = key -- fallback local tab = mi.maintenance[ key ] if tab then s = mi.formats.category:format( tab.category ) .. ( tab.err and mi.formats.error:format( tab.err ) or '' ) .. ( tab.hint and mi.formats.hint:format( tab.hint ) or '' ) end s = value and mw.ustring.format( s, value ) or s if not contains( s ) then table.insert( mu.maintenance, s ) end end function mu.getCategories( formatStr ) return wu.getCategories( formatStr ) end local function getMaintenance() if #mu.invalidParams == 1 then mu.addMaintenance( 'unknownParam', mu.invalidParams[ 1 ] ) elseif #mu.invalidParams > 1 then mu.addMaintenance( 'unknownParams', table.concat( mu.invalidParams, mu.commaSeparator ) ) end if #mu.duplicateAliases > 0 then mu.addMaintenance( 'duplicateAliases', table.concat( mu.duplicateAliases, mu.commaSeparator ) ) end return table.concat( mu.maintenance, '' ) end function mu.makeMaintenance( page, modules ) if mi.nsNoMaintenance[ page.namespace ] then return '' end local r = getMaintenance() if mi.options.usePropertyCateg then local m = mi.maintenance.properties -- format string for i, aModule in ipairs( modules ) do if aModule then r = r .. aModule.getCategories( m ) end end end return r end -- general-use functions function mu.isSet( arg ) return arg and arg ~= '' end function mu.convertForSort( s ) s = s:ulower() for i, obj in ipairs( mi.substitutes ) do s = mw.ustring.gsub( s, obj.l, obj.as ) end return s end -- replacing decimal separator and inserting group separators function mu.formatNumber( num ) if mu.isSet( mi.texts.decimalPoint ) and mi.texts.decimalPoint ~= '.' then num = num:gsub( '%.', mi.texts.decimalPoint ) end if mu.isSet( mi.texts.groupSeparator ) then local count repeat num, count = num:gsub( '^([-+]?%d+)(%d%d%d)', '%1%' .. mi.texts.groupSeparator .. '%2' ) until count == 0 end return num end function mu.tableInsert( tab, value ) if mu.isSet( value ) then table.insert( tab, value ) end end -- splitting string s at sep, removing empty substrings -- sep is a single character separator but no magic pattern character function mu.textSplit( s, sep ) local result = {} for str in s:gmatch( '([^' .. sep .. ']+)' ) do mu.tableInsert( result, mw.text.trim( str ) ) end return result end local function encodeSpaces( s ) s = s:gsub( ' ', '_' ) return s end -- Splitting comma separated lists to a table and converting items function mu.split( s ) local arr = {} if not mu.isSet( s ) then return arr end for i, str in ipairs( mu.textSplit( s, ',' ) ) do arr[ encodeSpaces( str ) ] = 1 end return arr end function mu.makeSpan( s, class, isBdi, attr, css ) return tostring( mw.html.create( isBdi and 'bdi' or 'span' ) :addClass( class ) :attr( attr or {} ) :css( css or {} ) :wikitext( s ) ) 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, addClass ) if not mu.isSet( s ) then return '' end local bdi = mw.html.create( 'bdi' ) :addClass( addClass ) :wikitext( s ) local c = country.lang if c == '' or c == page.lang then return tostring( bdi ) end local dir local fStr = '%s' if country.isRTL and not page.isRTL then dir = 'rtl' fStr = '‏%s‎' elseif not country.isRTL and page.isRTL then dir = 'ltr' fStr = '‎%s‏' end return fStr:format( tostring( bdi :addClass( 'voy-lang voy-lang-' .. c ) :attr( { title = mw.ustring.format( titleHint , country.langName ), lang = c, dir = dir } ) ) ) end function mu.addWdClass( isFromWikidata ) return isFromWikidata and ' voy-wikidata-content' or '' end function mu.getAliases( tab, key ) local result = {} if not tab then return result end local v for k, tb in pairs( tab ) do v = tb[ key ] if v then if type( v ) == 'table' then for i = 1, #v do result[ v[ i ] ] = k end else result[ v ] = k end end end return result end function mu.yesno( val ) return mi.yesno[ val:ulower() ] end -- check functions local function normalizeValues( args ) for i, param in ipairs( mi.options.normalizeValues ) do if mu.isSet( args[ param ] ) then args[ param ] = args[ param ]:ulower():gsub( '[_%s]+', ' ' ) end end end local function emphasize( s ) return mw.ustring.format( mi.texts.emph, s ) 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( templateArgs, validKeys ) local args = {} if not templateArgs or not validKeys or not next( validKeys ) then return args end local keys = {} -- list of wiki-dependent parameter names for key, params in pairs( validKeys ) do if type( params ) == 'string' then keys[ params ] = key else for i = 1, #params do keys[ params[ i ] ] = key end end end local targetKey for key, arg in pairs( templateArgs ) do targetKey = keys[ key ] if targetKey then if args[ targetKey ] then -- prevents duplicates table.insert( mu.duplicateAliases, emphasize( key ) ) else args[ targetKey ] = arg end else table.insert( mu.invalidParams, emphasize( key ) ) end end normalizeValues( args ) return args end local function removeNS( s, nsTable ) if not s:find( ':', 1, true ) then return s end local t = s for i = 1, #nsTable do t = mw.ustring.gsub( t, '^' .. nsTable[ i ] .. ':', '' ) if s ~= t then return t end end return t end function mu.checkCommonsCategory( args ) -- remove namespace from category if mu.isSet( args.commonscat ) then args.commonscat = removeNS( args.commonscat, mi.texts.CategoryNS ) end end -- checking coordinates function mu.checkCoordinates( args ) local function clearCoordinates() args.lat, args.long = '', '' end local t if type( args.lat ) == 'boolean' or type( args.long ) == 'boolean' then clearCoordinates() 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 clearCoordinates() mu.addMaintenance( 'wrongCoord' ) return end local dms = false 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 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 end if args.lat == '' or args.long == '' then clearCoordinates() mu.addMaintenance( 'wrongCoord' ) elseif dms then mu.addMaintenance( 'dmsCoordinate' ) end end -- check zoom level function mu.checkZoom( args ) args.zoom = math.floor( tonumber( args.zoom ) or mi.map.defaultZoomLevel ) if args.zoom < 0 or args.zoom > mi.map.maxZoomLevel then args.zoom = mi.map.defaultZoomLevel end end -- image check function mu.checkImage( args, entity ) if type( args.image ) == 'boolean' or args.image == '' then return end -- formal checks if args.image:find( '^https?:' ) then args.image = '' else -- remove namespace args.image = removeNS( args.image, mi.texts.FileNS ) local extensionExists = false local im = args.image:lower() for i = 1, #mi.fileExtensions do if im:find( '%.' .. mi.fileExtensions[ i ] .. '$' ) then extensionExists = true break end end if not extensionExists then args.image = '' end end if args.image == '' then mu.addMaintenance( 'wrongImgName' ) return end local alreadyChecked = false if mi.options.mediaCheck and args.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 ) for i = 1, #imgs do if imgs[ i ] == args.image then alreadyChecked = true break end end end if not alreadyChecked then -- expensive function call local title = mw.title.new( 'Media:' .. args.image ) if not title or not title.exists then mu.addMaintenance( 'missingImg', args.image ) args.image = '' end end end end function mu.checkStatus( args ) args.statusTable = {} local hash = {} if mu.isSet( args.status ) then local statusAliases = mu.getAliases( mi.statuses, 'alias' ) for i, t in ipairs( mu.textSplit( args.status, ',' ) ) do t = encodeSpaces( t ) t = statusAliases[ t ] or t if mi.statuses[ t ] then if not hash[ t ] then table.insert( args.statusTable, t ) hash[ t ] = 'x' end else mu.addMaintenance( 'unknownStatus' ) end end if #args.statusTable > 1 then table.sort( args.statusTable, function( a, b ) local at = mi.statuses[ a ] local bt = mi.statuses[ b ] return ( at.g < bt.g ) or ( at.g == bt.g and a < b ) end ) end end end function mu.checkStyles( args ) if mu.isSet( args.styles ) then if mi.nameStyles[ args.styles:lower() ] then args.styles = args.styles:lower() args.styleClass = ' listing-name-style-' .. args.styles args.styles = mi.nameStyles[ args.styles ] end else args.styles = nil end end function mu.checkId( args ) if mu.isSet( args.id ) and mu.isSet( args.wikidata ) then mu.addMaintenance( 'wikidataWithId' ) args.id = '' end if mu.isSet( args.id ) and args.id:find( '[!-,.-/:-?[-^{-\127%z\1-\31]' ) then mu.addMaintenance( 'wrongId' ) args.id = '' end end -- groups translation for map legend into Wiki language local function translateGroup( group ) if not mu.isSet( group ) then group = mt.types.error.group end local t = mg.groups[ group ] if t then t = t.map or t.label or t.alias or group if type( t ) == 'table' then t = t[ 1 ] end return t end return group end local function getTypeFromTypeAliases( aType ) if not mu.typeAliases then mu.typeAliases = mu.getAliases( mt.types, 'alias' ) end return mu.typeAliases[ aType ] end local function getGroupFromGroupAliases( group ) if not mu.groupAliases then mu.groupAliases = mu.getAliases( mg.groups, 'alias' ) end return mu.groupAliases[ group ] end -- getting marker type and group function mu.checkTypeAndGroup( args ) local s, t args.typeTable = {} args.subtypeTable = {} -- check group if mu.isSet( args.group ) then mu.addMaintenance( 'parameterUsed', 'group' ) s = mg.groups[ args.group ] if not s then s = getGroupFromGroupAliases( args.group ) if s then args.group = s s = mg.groups[ args.group ] end end if not s then mu.addMaintenance( 'unknownGroup' ) args.group = '' elseif s.is and s.is == 'color' and mi.options.useTypeCateg then mu.addMaintenance( 'group', args.group ) end end -- check type if not mu.isSet( args.type ) then args.type = mt.types.error.group mu.addMaintenance( 'missingType' ) elseif args.type == mt.types.error.group then mu.addMaintenance( 'unknownType', args.type ) end if args.type == mt.types.error.group then args.group = mt.types.error.group else -- split seperate types and analyse them for i, t in ipairs( mu.textSplit( args.type, ',' ) ) do -- try to find the type t in types or groups t = encodeSpaces( t ) if not mt.types[ t ] then t = getTypeFromTypeAliases( t ) or getGroupFromGroupAliases( t ) or t end s = mg.groups[ t ] if s then -- type is a group itself if s.is and s.is == 'color' then if mi.options.excludeColorTypes then args.group = mt.types.error.group mu.addMaintenance( 'unknownType', t ) else mu.addMaintenance( 'typeIsColor' ) end elseif not mi.options.noTypeMsgs then mu.addMaintenance( 'typeIsGroup' ) end if args.group == '' then args.group = t end else s = mt.types[ t ] if s then if args.group == '' then args.group = s.group end if mu.isSet( s.subtype ) then table.insert( args.subtypeTable, t ) end else args.group = mt.types.error.group mu.addMaintenance( 'unknownType', t ) end end table.insert( args.typeTable, t ) if mi.options.useTypeCateg then mu.addMaintenance( 'type', t ) end end args.type = table.concat( args.typeTable, ',' ) end args.groupTranslated = translateGroup( args.group ) mu.getColor( args ) end local function isUrl( url ) uc = uc or require( 'Module:UrlCheck' ) return uc.isUrl( url, mi.options.skipPathCheck ) end -- url check in args function mu.checkUrl( args ) if not mu.isSet( args.url ) then return end local c = isUrl( args.url ) -- getting result code if c > 2 then mu.addMaintenance( 'wrongUrl' ) args.url = '' elseif c == 2 then -- URL contains IP address mu.addMaintenance( 'urlWithIP' ) else for i = 1, #mi.services do if args.url:find( mi.services[ i ].key .. '.com', 1, true ) then mu.addMaintenance( 'urlIsSocialMedia' ) args.url = '' end end end end -- type and group functions -- getting a set of parameters for a given type function mu.getTypeParams( aType ) return mt.types[ aType ] end function mu.idToType( id ) if not mu.typeIds then mu.typeIds = mu.getAliases( mt.types, 'wd' ) -- Q id to type table end return mu.typeIds[ id ] end function mu.getTypeLabel( id ) if not mu.isSet( id ) then return '' end if id:match( '^Q%d+$' ) then id = mu.idToType( id ) if not id then return '' end else id = id:gsub( '[_%s]+', '_' ) end local at, t t = mt.types[ id ] if not t then t = getTypeFromTypeAliases( id ) t = t and mt.types[ t ] end if t then t = t.label or id at = t:find( ',' ) if at then t = t:sub( 1, at - 1 ) end else t = id:gsub( '_', ' ' ) end return t end function mu.typeExists( aType ) return mt.types[ aType ] and aType or getTypeFromTypeAliases( aType ) end -- check if the specified group can have events function mu.groupWithEvents( group ) return mg.groups[ group ] and mg.groups[ group ].withEvents end -- see: https://www.w3.org/TR/WCAG20/#relativeluminancedef local function hexToLinear( hex ) hex = tonumber( hex, 16 ) / 255.0 if hex <= 0.03928 then return hex / 12.92 else return ( ( hex + 0.055 ) / 1.055 ) ^ 2.4 end end -- relative luminance of a color -- 6 digit hex color local function hexToLuminance( color ) local r = hexToLinear( color:sub( 1, 2 ) ) local g = hexToLinear( color:sub( 3, 4 ) ) local b = hexToLinear( color:sub( 5, 6 ) ) return 0.2126 * r + 0.7152 * g + 0.0722 * b end local function isInverse( backgroundColor ) -- magenta, error: 0.2848 -- the threshold should not be greater than 0.4 local luminanceThreshold = hexToLuminance( 'FF00FF' ) backgroundColor = backgroundColor:sub( 2 ) -- remove # :gsub( '^(%x)(%x)(%x)$', '%1%1%2%2%3%3' ) local luminance = hexToLuminance( backgroundColor ) return hexToLuminance( backgroundColor ) > luminanceThreshold end -- getting color from group in args function mu.getColor( args ) local c = mg.groups[ args.group ] or mg.groups[ 'error' ] args.color = c.color args.inverse = isInverse( c.color ) end -- Splitting comma separated lists to a table of key items -- checking items with allowed key values of validValues table local function splitAndCheck( s, validValues ) local values = {} if not validValues then return values, '' end local errors = {} for item, v in pairs( mu.split( s ) ) do -- value check if validValues[ item ] then values[ item ] = 1 else table.insert( errors, item ) end end return values, table.concat( errors, mu.commaSeparator ) end local function setCopyMarker( args, show ) if show.copy and ( mu.isSet( args.copyMarker ) or not mu.isSet( args.wikidata ) ) then show.copy = nil mu.addMaintenance( 'deleteShowCopy' ) end if show.copy then args.copyMarker = args.wikidata end if mu.isSet( args.copyMarker ) then show.symbol = nil end end -- treatment of social media services if Wikidata is available local function setSocialMedia( args, value ) for i, service in ipairs( mi.services ) do args[ service.key ] = value end end function mu.getShow( default, args, validValues ) local show = mu.split( default ) local add, err = splitAndCheck( args.show, validValues ) if err ~= '' then mu.addMaintenance( 'unknownShow', err ) end -- maintenance if add.inline then show.inlineSelected = true mu.addMaintenance( 'showInlineUsed' ) end if add.poi then mu.addMaintenance( 'showPoiUsed' ) -- is default end -- overwriting defaults if add.none or add.coord or add.poi or add.all then show.all, show.coord, show.poi = nil, nil, nil end -- merge show with add values for key, value in pairs( add ) do show[ key ] = value end if show.none then show.none, show.all, show.coord, show.poi = nil, nil, nil, nil end if show.all then show.all = nil show.coord, show.poi = 1, 1 end if show.noname then show.noname, show.name = nil, nil else show.name = 1 end setCopyMarker( args, show ) if args.wikidata ~= '' then if show.socialmedia then setSocialMedia( args, 'y' ) elseif show.nosocialmedia then setSocialMedia( args, 'n' ) end end if not show.nosocialmedia then show.socialmedia = 1 end return show end local function replaceWithSpace( s, pattern ) s = s:find( pattern ) and s:gsub( pattern, ' ' ) or s return s end -- removing line breaks and controls from parameter strings function mu.removeCtrls( s, onlyInline ) local descrDiv = false -- div tag instead of span tag for description needed? -- remove controls from tags before test s = s:gsub( '(<[^>]+>)', function( t ) return replaceWithSpace( t, '[%z\1-\31]' ) end ) local t = replaceWithSpace( s, '</br%s*>' ) if onlyInline then t = replaceWithSpace( t, '<br[^/>]*/*>' ) t = replaceWithSpace( t, '</*p[^/>]*/*>' ) t = replaceWithSpace( t, '[%z\1-\31]' ) -- not %c because \127 is used for Mediawiki tags (strip markers `UNIQ) else t = replaceWithSpace( t, '[%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( 'illegalCtrls' ) end -- remove LTR and RTL marks t = mw.ustring.gsub( t, '[]+', '' ) if descrDiv then -- unify line breaks to Linux mode t = t:gsub( '\13\10', '\10' ):gsub( '\13', '\10' ) -- replace line breaks by <br> in block mode t = t:gsub( '([^>%]\10])\10+([^<%[\10])', '%1<br class="listing-next-paragraph" />%2' ) end return replaceWithSpace( t, '%s%s+' ), descrDiv end -- fetch data from Wikidata 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, args.long = c.latitude, c.longitude fromWikidata.lat = true end end local function typeSearch( p31 ) -- p31: array of Wikidata values if not p31 or #p31 == 0 then return '' end local firstStep = true 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 = ( encodeSpaces( value ) ) if mt.types[ value ] then return value end end end return nil end local function compareIds( ar ) local id, t for i = 1, #ar do id = ar[ i ].id -- md: indexed array of q id - types relations t = mu.idToType( id ) if t then return t end -- checking English label and aliases t = compareLabels( mw.wikibase.getLabelByLang( id, 'en' ) ) or compareLabels( wu.getAliases( id, 'en' ) ) if t then if firstStep and not mi.options.noTypeMsgs then firstStep = false mu.addMaintenance( 'typeFromWDchain' ) end 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 firstStep = false for i = 1, #p31 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 if not mi.options.noTypeMsgs then mu.addMaintenance( 'typeFromWDchain' ) end return aType end id = ids[ 1 ].id end j = j + 1 -- limit: maximum levels to analyse until j >= mi.options.searchLimit or #ids == 0 end return '' end function mu.getTypeFromWikidata( args, entity ) if mu.isSet( args.type ) then return end local p31 = wu.getValues( entity, mi.properties.instanceOf ) if #p31 == 0 then p31 = wu.getValues( entity, mi.properties.subclassOf ) end args.type = typeSearch( p31 ) 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( '^[Cc]ategory:', '' ) 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( '^[Cc]ategory:', '' ) end end end if t ~= '' and args.commonscat ~= '' then mu.addMaintenance( 'commonscatWD' ) end if args.commonscat == '' then args.commonscat = t end end function mu.getLangTable( wikiLang, localLang ) local langs = { wikiLang } for i, lang in ipairs( mi.langs ) do table.insert( langs, lang ) end if mu.isSet( localLang ) and localLang ~= wikiLang then table.insert( langs, localLang ) end return langs 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 = '' local langs = mu.getLangTable( page.lang ) for i, lang in ipairs( langs ) do args.name = officialNames[ lang ] if args.name then break end end -- if failed then get labels if not mu.isSet( args.name ) then for i, lang in ipairs( langs ) do args.name = wu.getLabel( entity, lang, true ) -- no fallback if args.name then break end end args.name = args.name or '' end if args.name ~= '' then mu.addMaintenance( '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 type( args.nameLocal ) == 'string' and args.nameLocal ~= '' then -- keeping local name in any case for html data args.addNameLocal = args.nameLocal return end local nameLocal = officialNames[ country.lang ] or '' if nameLocal == '' then nameLocal = wu.getLabel( entity, country.lang, true ) or '' end if args.nameLocal == true then args.nameLocal = nameLocal if args.name == '' and args.nameLocal ~= '' then args.name = args.nameLocal args.nameLocal = '' mu.addMaintenance( 'nameFromWD' ) fromWikidata.name = true end if args.name:ulower() == args.nameLocal:ulower() then args.nameLocal = '' end fromWikidata.nameLocal = args.nameLocal ~= '' elseif page.lang ~= country.lang and args.name ~= nameLocal then args.addNameLocal = nameLocal end end -- getting link to Wikivoyage function mu.getArticleLink( args, entity, page ) local title, isRedirect = wu.getCheckedSitelink( entity, page.lang .. page.globalProject ) if title and title ~= page.text then args.wikiPage = title if isRedirect == true then args.linkIsRedirect = true end end end -- marker functions -- returns a single data set from Module:Marker utilities/Maki icons local function getMaki( key ) mm = mm or require( 'Module:Marker utilities/Maki icons' ) key = key:lower():gsub( '[_%s]+', '-' ) return mm.icons[ key ] end local function getMakiIconId( key ) if not mu.isSet( key ) then return nil end key = key:lower():gsub( '[_%s]+', '-' ) if getMaki( key ) then return key end key = mt.types[ key ] and mt.types[ key ].icon if key and getMaki( key ) then return key end return nil end local function addIconToMarker( args ) args.text = ( '[[File:Maki7-%s.svg|x14px|link=|class=noviewer]]' ):format( args.symbol ) args.isIcon = true end -- distinguishing marker symbols, default: number local function makeMarkerProperties( args, show ) args.symbol = args.symbol or '' local noSymbol = args.symbol == '' if args.symbol == '' and show.poi and show.symbol then args.symbol = getMakiIconId( args.typeTable[ 1 ] ) or '' end local isIcon = getMaki( args.symbol ) if args.symbol == '' or args.symbol == 'number' then args.symbol = '-number-' .. args.group elseif args.symbol == 'letter' then args.symbol = '-letter-' .. args.group elseif args.symbol:len() == 1 and args.symbol:match( '%w' ) then args.text = args.symbol:upper() mu.addMaintenance( 'numberUsed' ) elseif args.symbol ~= '' and args.text == '' and isIcon then addIconToMarker( args ) elseif args.symbol ~= '' and not isIcon then args.text = mi.texts.closeX args.isIcon = true args.group = 'error' mu.getColor( args ) mu.addMaintenance( noSymbol and 'unknownMAKI' or 'unknownIcon' ) end end -- making marker symbol function mu.makeMarkerSymbol( args, show, frame ) local extraClasses = args.inverse and ' listing-map-inverse' or ' listing-map-not-inverse' if args.group == 'error' then extraClasses = extraClasses .. ' listing-map-is-error' end local title = args.givenName.all if mu.isSet( args.copyMarker ) then local copyClass = 'listing-map plainlinks printNoLink voy-copy-marker' .. extraClasses return tostring( mw.html.create( 'span' ) :addClass( copyClass ) :css( colorAdjust ) -- display will be replaced by [[MediaWiki:Gadget-GeneralChanges.js]] script :css( { display = 'none' } ) :attr( { ['data-copy-marker-attribute'] = args.copyMarker:match( 'Q%d+' ) and 'data-wikidata' or 'data-name', title = mi.texts.tooltip, ['data-copy-marker-content'] = args.copyMarker } ) ) end makeMarkerProperties( args, show ) if args.isIcon then extraClasses = extraClasses .. ' listing-map-is-symbol' end local lon = tonumber( args.long ) local lat = tonumber( args.lat ) local tagArgs = { zoom = tonumber( args.zoom ), latitude = lat, longitude = lon, show = mg.showAll, } if mu.isSet( args.text ) then tagArgs.text = args.text tagArgs.class = 'no-icon' end if mu.isSet( args.mapGroup ) then tagArgs.group, tagArgs.show = args.mapGroup, args.mapGroup else tagArgs.group = args.groupTranslated end if mu.isSet( args.image ) then tagArgs.description = '[[File:' .. args.image .. '|100x100px|' .. 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' ) :addClass( 'listing-map plainlinks printNoLink' .. extraClasses ) :attr( 'title', mi.texts.tooltip ) :css( colorAdjust ) :css( { ['background-color'] = args.color, color = args.inverse and '#000' or '#fff' } ) -- frame:extensionTag is expensive :wikitext( frame:extensionTag( 'maplink', mw.text.jsonEncode( geoJson ), tagArgs ) ) ) end -- icon functions function mu.makeStatusIcons( args ) local result = '' for i, v in ipairs( args.statusTable ) do result = result .. mu.makeSpan( ' ', 'listing-status listing-status-' .. v, false, { title = mi.statuses[ v ].label }, colorAdjust ) if mi.statuses[ v ].category then result = result .. ( '[[Category:%s]]' ):format( mi.statuses[ v ].label ) end end return result end function mu.addLinkIcon( classes, link, title, text, addSpace ) local span = mu.makeSpan( ' ', nil, false, { title = title, ['data-icon'] = text }, colorAdjust ) -- space to keep the span tag local lFormat = ( link:find( '^https?://' ) or link:find( '^//' ) ) and '[%s %s]' or '[[%s|%s]]' local iconLink = mw.ustring.format( lFormat, link, span ) if addSpace then iconLink = mu.makeSpan( ' ', 'listing-icon-with-space', true ) .. iconLink end return mu.makeSpan( iconLink, 'listing-icon ' .. classes ) end -- adding linked sister icons local function addSisterIcons( icons, sisters, name, id ) local icon for i, key in ipairs( { 'wikivoyage', 'wikipedia', 'commons', 'wikidata' } ) do if mu.isSet( sisters[ key ] ) then icon = mu.addLinkIcon( 'listing-sister-icon listing-sister-' .. key, sisters[ key ], mw.ustring.format( mi.iconTitles[ key ], name, id ), key, key == 'wikidata' ) -- add leading space table.insert( icons, icon ) end end -- return true if only Wikidata icon return mu.isSet( sisters.wikidata ) and #icons == 1 end -- getting sister project links local function getWikiLink( langArray, wiki, entity, wikilang ) local prefix = wiki == 'wiki' and 'w:' or 'voy:' local link for i, lang in ipairs( langArray ) do if lang ~= '' then link = wu.getFilteredSitelink( entity, lang .. wiki ) if link then prefix = prefix .. ( lang ~= wikilang and ( lang .. ':' ) or '' ) return prefix .. link end end end return '' end -- adding Wikimedia sister project icons local function makeSisterIcons( icons, args, page, country, entity ) local sisters = { commons = '', -- link to Commons category wikidata = '', -- link to Wikidata wikipedia = '', -- link to Wikipedia wikivoyage = '' -- link to another branch, usually en, as a sister link } if mu.isSet( args.wikipedia ) then sisters.wikipedia = 'w:' .. args.wikipedia end if mu.isSet( args.wikidata ) then local langs = mu.getLangTable( page.lang, country.lang ) if sisters.wikipedia == '' then sisters.wikipedia = getWikiLink( langs, 'wiki', entity, page.lang ) end if args.wikiPage == '' then table.remove( langs, 1 ) -- exclude page.lang sisters.wikivoyage = getWikiLink( langs, page.globalProject, entity, page.lang ) if sisters.wikivoyage ~= '' then mu.addMaintenance( 'linkToOtherWV' ) end end sisters.wikidata = 'd:' .. args.wikidata end if args.commonscat ~= '' then sisters.commons = 'c:Category:' .. args.commonscat end return addSisterIcons( icons, sisters, args.givenName.name, args.wikidata ) end -- creating social media icons including value check local function makeSocial( icons, args, fromWikidata, name ) local domain, span, t, which for i, service in ipairs( mi.services ) do -- check values first t = args[ service.key ] or '' domain = type( service.url ) == 'string' and service.url or service.url[ 1 ] domain = domain:gsub( 'com/.*', 'com/' ) if t ~= '' then if t:match( '^http' ) then if not t:find( 'https', 1, true ) then t = t:gsub( '^http', 'https' ) mu.addMaintenance( 'wrongSocialUrl', service.key ) end if isUrl( t ) > 1 or not t:match( '^' .. domain .. '.+$' ) then t = '' mu.addMaintenance( 'wrongSocialUrl', service.key ) end if t ~= '' and not fromWikidata[ service.key ] then mu.addMaintenance( 'socialUrlUsed', service.key ) end else local match = false local sp = service.pattern if type( sp ) == 'string' then sp = { sp } end for i = 1, #sp do if mw.ustring.match( t, sp[ i ] ) then match = true which = i break end end if not match then t = '' mu.addMaintenance( 'wrongSocialId', service.key ) end end end args[ service.key ] = t -- create symbol link if t ~= '' then if not t:find( domain, 1, true ) then -- multiple service urls local formatStr = type( service.url ) == 'string' and service.url or service.url[ which ] t = mw.ustring.format( formatStr, t ) end span = mu.addLinkIcon( 'listing-social-media listing-social-media-' .. service.key .. mu.addWdClass( fromWikidata[ service.key ] ), t, mw.ustring.format( mi.iconTitles[ service.key ], name ), service.key ) table.insert( icons, span ) end end end function mu.makeIcons( args, page, country, entity, show, fromWikidata ) local icons = {} local onlyWikidata = mi.options.showSisters and not show.nositelinks and makeSisterIcons( icons, args, page, country, entity ) if show.socialmedia then makeSocial( icons, args, fromWikidata, args.givenName.name ) end if #icons > 0 then return ( onlyWikidata and '' or mi.texts.space ) .. table.concat( icons, '' ) else return '' end end -- output functions local function removeStars( args ) for i, param in ipairs( mi.options.noStarParams ) do if mu.isSet( args[ param ] ) and args[ param ]:find( '*', 1, true ) then args[ param ] = args[ param ]:gsub( '%*+', '' ) args[ param ] = mw.text.trim( args[ param ] ) mu.addMaintenance( 'nameWithStar' ) end end end local function makeAnchorId( name ) if name and not name:match( '^Q%d+$' ) then name = mw.uri.anchorEncode( name ) end return mw.ustring.format( mi.texts.anchor, name ) end -- getting name table with linked and unlinked names local function getName( name, pageTitle ) local r = { all = '', -- name or linked name name = '', -- only name pageTitle = '', -- if pageTitle ~= '' name is already linked } if type( name ) ~= 'string' or name == '' then return r end 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.ustring.gsub( t, '^(.*)|(.*)$', '%1' ) r.pageTitle = mw.text.trim( r.pageTitle ) else r.name = t r.pageTitle = t end else r.name = name r.all = name if mu.isSet( pageTitle ) then r.pageTitle = pageTitle r.all = '[[' .. pageTitle .. '|' .. name .. ']]' r.fromWD = true end end removeStars( r, { 'name', 'all' } ) return r end -- create givenName, displayName tables function mu.prepareNames( args ) local function simplifyString( s, length ) s = mw.ustring.sub( s, 1, length ) s = mw.ustring.gsub( s, "[%.'" .. '"“”„‟«»‘’‚‛‹›]', '' ) s = mw.ustring.gsub( s, '[-‐‑‒–—―]', ' ' ) return s:ulower():gsub( '%s%s+', ' ' ) end local function removeDuplicate( value1, key2 ) if not mu.isSet( value1 ) or not mu.isSet( args[ key2 ] ) then return end local minLen = math.min( mw.ustring.len( value1 ), mw.ustring.len( args[ key2 ] ) ) if simplifyString( value1, minLen ) == simplifyString( args[ key2 ], minLen ) then args[ key2 ] = '' end end -- use local name if name is not given if args.name == '' and args.nameLocal ~= '' then args.name = args.nameLocal args.nameLocal = '' end if args.name == args.nameMap then args.nameMap = '' end -- missing name if args.name == '' then args.name = mi.texts.missingName mu.addMaintenance( 'missingNameMsg' ) end -- names shall not contain tags or template calls if args.name:find( '<', 1, true ) or args.name:find( '{{', 1, true ) or args.nameMap:find( '<', 1, true ) or args.nameMap:find( '{{', 1, true ) or args.nameLocal:find( '<', 1, true ) or args.nameLocal:find( '{{', 1, true ) then mu.addMaintenance( 'malformedName' ) end removeStars( args ) -- handling linked names like [[article|text]] args.displayName = getName( args.name, args.wikiPage ) if mu.isSet( args.nameMap ) then args.givenName = getName( args.nameMap, args.wikiPage ) else -- real copy args.givenName = {} args.givenName.all = args.displayName.all args.givenName.name = args.displayName.name args.givenName.pageTitle = args.displayName.pageTitle end -- reset args.linkIsRedirect if Wikidata link is not used -- args.linkIsRedirect is set by mu.getArticleLink() if not args.displayName.fromWD then args.linkIsRedirect = nil end -- remove identical names removeDuplicate( args.givenName.name, 'nameLocal' ) removeDuplicate( args.givenName.name, 'alt' ) removeDuplicate( args.givenName.name, 'comment' ) removeDuplicate( args.nameLocal, 'alt' ) removeDuplicate( args.alt, 'comment' ) removeDuplicate( args.directions, 'directionsLocal' ) removeDuplicate( args.address, 'addressLocal' ) end local function _makeAirport( code, args ) local span = mu.makeSpan( args[ code ], 'listing-' .. code .. '-code' .. mu.addWdClass( true ) ) return mu.makeSpan( mw.ustring.format( mi.texts[ code ], span ), 'listing-airport listing-' .. code ) end local function makeAirport( args, show ) if show.noairport then return '' else local t = args.type:gsub( ',.*$', '' ) -- only first type if mt.types[ t ] and not mt.types[ t ].useIATA then return '' end end if mu.isSet( args.iata ) then return _makeAirport( 'iata', args ) elseif mu.isSet( args.icao ) then return _makeAirport( 'icao', args ) else return '' end end -- creating a list of nick names etc. local function makeNameAffix( args, page, country, addClass, show ) local result = {} if mi.options.showLocalData then if mu.isSet( args.nameLocal ) then table.insert( result, mu.languageSpan( args.nameLocal, mi.texts.hintName, page, country, 'listing-name-local' .. addClass ) ) end if mu.isSet( args.nameLatin ) then table.insert( result, mu.makeSpan( args.nameLatin, 'listing-name-latin', false, { title = mi.texts.hintLatin, lang = mu.isSet( country.lang ) and ( country.lang .. '-Latn' ) or nil } ) ) end end for i, key in ipairs( { 'alt', 'comment' } ) do if mu.isSet( args[ key ] ) then table.insert( result, mu.makeSpan( args[ key ], 'listing-' .. key ) ) end end mu.tableInsert( result, makeAirport( args, show ) ) if #result == 0 then return '' end return mu.makeSpan( mu.parentheses( table.concat( result, mu.comma ) ), 'p-nickname nickname listing-add-names' ) end -- replace brackets in names local function replaceBrackets( s ) s = s:gsub( '%[', '[' ):gsub( '%]', ']' ) return s end -- creating (linked) name and its affix function mu.makeName( result, args, show, page, country, nameClass, localClass ) local s = '' local r = {} nameClass = nameClass .. ( args.displayName.fromWD and ' listing-link-from-wd' or '' ) -- clear redirect wiki link if required if args.linkIsRedirect and not show.wikilink then args.displayName.pageTitle = '' args.displayName.all = args.displayName.name args.linkIsRedirect = nil nameClass = nameClass .. ' listing-unused-redirect' mu.addMaintenance( 'unusedRedirect' ) end if args.linkIsRedirect then nameClass = nameClass .. ' mw-redirect listing-link-is-redirect' mu.addMaintenance( 'linkIsRedirect' ) end if mu.isSet( args.url ) and args.displayName.pageTitle == '' then s = '[' .. args.url .. ' ' .. replaceBrackets( args.displayName.name ) .. ']' else s = args.displayName.all end if mu.isSet( args.nameExtra ) then s = s .. ' ' .. args.nameExtra end -- insert name if s ~= '' then local attr = { style = args.styles } s = mu.makeSpan( s, 'p-name fn org listing-name' .. nameClass .. ( args.styleClass and args.styleClass or '' ), true, attr ) if mu.isSet( args.metadata ) then s = s .. args.metadata end table.insert( r, s ) end -- insert separate url icon if mu.isSet( args.url ) and args.displayName.pageTitle ~= '' then -- both article and web links table.insert( r, mu.addLinkIcon( 'listing-url', args.url, mi.iconTitles.internet, 'internet' ) ) end -- insert name affix mu.tableInsert( r, makeNameAffix( args, page, country, localClass, show ) ) if #r > 0 then table.insert( result, table.concat( r, mi.texts.space ) ) end end function mu.parentheses( s, trim ) if not mu.isSet( s ) then return '' end local formatter = mi.texts.parentheses if trim then formatter = mw.text.trim( formatter ) end return mw.ustring.format( formatter, s ) end -- getting DMS coordinates function mu.dmsCoordinates( lat, long, name, fromWD, extraParams, noBrackets ) local function coordSpan( title, text ) return mu.makeSpan( text, 'coordStyle', false, { title = title } ) end local dec local latDMS, dec, latMs = cd.getDMSString( lat, 4, 'lat', '', '', mi.map.defaultDmsFormat ) local longDMS, dec, longMs = cd.getDMSString( long, 4, 'long', '', '', mi.map.defaultDmsFormat ) local r = '[' .. mi.map.coordURL .. latMs .. '_' .. longMs .. '_' .. mw.uri.encode( extraParams ) .. '&locname=' .. mw.uri.encode( name ) .. ' ' .. coordSpan( mi.texts.latitude, latDMS ) .. ' ' .. coordSpan( mi.texts.longitude, longDMS ) .. ']' r = noBrackets and r or mu.parentheses( r ) return mu.makeSpan( r, 'listing-dms-coordinates printNoLink plainlinks' .. mu.addWdClass( fromWD ) ) end -- prepare value s for data attribute and replace all entities by characters local function data( s ) return mu.isSet( s ) and mw.text.decode( s, true ) or nil end -- adding wrapper and microformats function mu.makeWrapper( result, args, page, country, show, list, frame ) if not mu.isSet( args.nameLocal ) and mu.isSet( args.addNameLocal ) then args.nameLocal = args.addNameLocal end if not mu.isSet( args.addressLocal ) and mu.isSet( args.addAddressLocal ) then args.addressLocal = args.addAddressLocal end local wrapper = mw.html.create( show.inline and 'span' or 'div' ) :addClass( 'vcard h-card ' .. args.template ) if args.noGpx then wrapper:addClass( 'listing-no-gpx' ) end if show.outdent and not show.inline then wrapper:addClass( 'listing-outdent' ) end if show.inlineSelected or args.template == 'Marker' then wrapper:addClass( 'listing-inline' ) end if mu.isSet( args.copyMarker ) or not show.poi then wrapper:addClass( 'voy-without-marker' ) end if #args.statusTable > 0 then wrapper:addClass( 'listing-with-status' ) end if args.givenName.name ~= mi.texts.missingName then wrapper:attr( 'data-name', data( args.givenName.name ) ) end if not ( mu.isSet( args.copyMarker ) and args.copyMarker == args.wikidata ) then local id = mu.isSet( args.wikidata ) and args.wikidata or args.id if mu.isSet( id ) then wrapper:attr( 'id', makeAnchorId( id ) ) end end local editClass = 'listing-edit' if mu.isSet( args.sectionFrom ) then args.sectionFrom = args.sectionFrom:gsub( '[_]+', ' ' ) if args.sectionFrom ~= page.text then editClass = 'listing-no-edit' end end wrapper:addClass( editClass ) wrapper:attr( 'data-location', data( page.subpageText ) ) :attr( 'data-location-qid', page.entityId ) :attr( 'data-wikilang', page.lang ) :attr( 'data-country', data( country.iso_3166 ) ) :attr( 'data-country-name', data( country.country ) ) :attr( 'data-lang', data( country.lang ) ) :attr( 'data-lang-name', data( country.langName ) ) :attr( 'data-country-calling-code', data( country.cc ) ) :attr( 'data-trunk-prefix', data( country.trunkPrefix ) ) :attr( 'data-dir', data( country.isRTL and 'rtl' or 'ltr' ) ) :attr( 'data-wiki-dir', data( page.isRTL and 'rtl' or 'ltr' ) ) :attr( 'data-currency', data( country.addCurrency ) ) local arg for key, value in pairs( list ) do if mu.isSet( args[ key ] ) then arg = args[ key ]:gsub( '<[^<>]*>', '' ) -- remove html tags wrapper:attr( value, data( arg ) ) end end if not show.name then wrapper:node( mw.html.create( 'span' ) :addClass( 'p-name fn org listing-name' ) :css( 'display', 'none' ) :wikitext( args.givenName.name ) ) end wrapper:wikitext( result ) if not show.noCoord then wrapper:node( mw.html.create( 'span' ) :addClass( 'p-geo geo listing-coordinates' ) :css( 'display', 'none' ) :node( mw.html.create( 'span' ) :addClass( 'p-latitude latitude' ) :wikitext( args.lat ) ) :node( mw.html.create( 'span' ) :addClass( 'p-longitude longitude' ) :wikitext( args.long ) ) ) end wrapper = tostring( wrapper ) -- 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 function mu.getPageData() local page = mw.title.getCurrentTitle() page.langObj = mw.getContentLanguage() page.lang = page.langObj:getCode() page.langName = mw.language.fetchLanguageName( page.lang, page.lang ) page.isRTL = page.langObj:isRTL() page.entityId = mw.wikibase.getEntityIdForCurrentPage() -- can be nil page.siteName = mw.site.siteName page.globalProject = page.siteName:lower() if page.globalProject == 'wikipedia' then page.globalProject = 'wiki' end return page end return mu