Module:Attached KML

-- Note: Originally written on English Wikipedia as w:en:Module:Attached_KML -- ##### Localisation (L10n) settings ##### local L10n = { -- Template parameter names -- (replace values in quotes with local parameter names) para = { display = "display", from = "from", header = "header", title = "title", wikidata = "wikidata", demo = "demo", },	-- Other configuration settings config = { -- controls the format used for inline display, can be set to "box" (default) or "line" -- "box" example: https://en.wikipedia.org/wiki/Template:Attached_KML -- "line" example: https://sv.wikipedia.org/wiki/Mall:KML inline_format = "box", },	-- Other strings str = { inline = "inline", -- used with display parameter: (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline) title = "title", -- (as above) dsep = ",", -- separator between inline and title (comma in the example above) kml_prefix = "Template:Attached KML/", -- local KML files are stored as subpages of this location default_title = "Route map", -- default title for links at top of page, when title parameter not used in transclusion default_header = "", -- default header for links in inline box, when header parameter not used in transclusion kml_file = "KML file", -- text to display for link to raw KML file edit = "edit", -- text to display for link to edit KML file help = "help", -- text to display for help page link help_location	= "Help:Attached KML", -- page to link to for help page link err_prepend	= "Attached KML", -- text to prepend to the error messages, when shown at top of page (display=title) cat	= { -- tracking categories: full wikimarkup required, or set to the empty string ("") to not to track the condition wikidata_kml = "", -- tracks mainspace articles using KML from Wikidata local_kml = "", -- tracks mainspace articles not using KML from Wikidata error_mqid = "", -- tracks malformed_qid error error_badqid = "", -- tracks bad_qid error error_noitem = "", -- tracks no_item error error_from = "", -- tracks bad_from error error_nokml = "", -- tracks no_kml error },		line = { -- these strings are only needed if using 'inline_format = "line"' configuration start = "", -- wikitext to display at start of line, may include image markup, should start with a space separator = "", -- text to display between links to external mapping providers, should include spaces },	} }

L10n.str.err = { -- error messages malformed_qid	= "Error: malformed item id in  ",	-- item id doesn't match pattern (number with Q prefix) bad_qid		= "Error: item specified on Wikidata, or in, is not a KML file (P31→Q26267864 not found) ",	-- item doesn't have a P31→Q26267864 statement no_item		= "Error: item specified in  not found on Wikidata",	-- item not found on wikidata bad_from	= "Error: KML file not found, check ",	-- KML specified by from parameter doesn't exist no_kml		= "Error: KML file not found",	-- no KML file found }

-- Masks for external mapping providers, in the form: --  externalLinkMasks[index-number] = { short = "short-label", long = "long-label", link = "url" }' -- The short label is used for the title links; the long label is used for the inline links -- Links in the output will be ordered by index-number -- Instead of kml file's raw url or encoded raw url, use __KML_URL__  or  __KML_URL_E__ local externalLinks = {} --externalLinks[1] = { --	short = "Bing", --	long = "Display on Bing Maps", --	link = "http://www.bing.com/maps/?mapurl=__KML_URL__" --}

-- #### End of L10n settings ####

-- Table of available wikis, in the order that they are to be searched for kml files -- (once a kml file is found, further sites are not checked) local sites = { {		mw.ustring.match( mw.site.server, "%w+" ) .. mw.ustring.gsub( mw.ustring.lower(mw.site.siteName), "[mp]edia", ""), mw.ustring.sub(mw.site.server, 3), ""	}, -- local wiki (listed first so local files can override files on other wikis) { "commonswiki", "commons.wikimedia.org", "c:" }, -- Commons would be a logical central repository for KML files (but has no files as of August 2016) { "enwiki", "en.wikipedia.org", "w:en:" }, -- largest source of KML files (as of August 2016) { "bnwiki", "bn.wikipedia.org", "w:bn:" }, -- other sites with a KML template, listed in alphabetical order { "cswiki", "cs.wikipedia.org", "w:cs:" }, { "fawiki", "fa.wikipedia.org", "w:fa:" }, { "frwiki", "fr.wikipedia.org", "w:fr:" }, { "jawiki", "ja.wikipedia.org", "w:ja:" }, { "mlwiki", "ml.wikipedia.org", "w:ml:" }, { "svwiki", "sv.wikipedia.org", "w:sv:" }, { "zhwiki", "zh.wikipedia.org", "w:zh:" }, }

local p = {}

local function setCleanArgs(argsTable) local cleanArgs = {} for key, val in pairs(argsTable) do		if type(val) == 'string' then val = val:match('^%s*(.-)%s*$') if val ~= '' then cleanArgs[key] = val end else cleanArgs[key] = val end end return cleanArgs end

local function safeReplace(string, pattern, replacement) -- avoids "Lua error: invalid capture index" that occurs with string.gsub when the replacement contains one or more literal % character local nonpattern_parts = mw.text.split( string, pattern ) return table.concat(nonpattern_parts, replacement) end

local function makeTitleWikitext(titletext, err) if err and L10n.str.err_prepend then err = mw.ustring.gsub( err, ">", ">" .. L10n.str.err_prepend .. " ", 1 ) end

local titleLinks = {} for i, v in ipairs( externalLinks ) do		titleLinks[i] = mw.ustring.format( "[%s %s]", v.link, v.short) end return mw.getCurrentFrame:extensionTag{ name = 'indicator', args = { name = 'attached-kml' }, content = mw.ustring.format(					"\'\'\'%s\'\'\': %s ",					titletext,					err or table.concat(titleLinks, " / ")				) } end

local function makeInlineWikitext(headertext, url, err) local inlineLinks = {} for i, v in ipairs( externalLinks ) do		inlineLinks[i] = mw.ustring.format("[%s %s]", v.link, v.long) end local editUrl = mw.ustring.gsub( url, "action=raw", "action=edit" ) local wiki_link_class if mw.ustring.find( editUrl, mw.site.server, 1, true ) then wiki_link_class = "plainlinks" else wiki_link_class = "" end

if L10n.config.inline_format == "line" then return mw.ustring.format(			"%s%s%s ([%s %s] ([%s %s] • %s)  )",			headertext, L10n.str.line.start,			err or table.concat(inlineLinks, L10n.str.line.separator),			wiki_link_class, url, L10n.str.kml_file, editUrl, L10n.str.edit,			L10n.str.help_location, L10n.str.help		) end local text = mw.ustring.format(		'%s \'\'\'[%s %s]\'\'\' ([%s %s] • %s) ',		headertext, wiki_link_class, url, L10n.str.kml_file, editUrl,		L10n.str.edit, L10n.str.help_location, L10n.str.help	) if err or #inlineLinks > 0 then text = mw.ustring.format(			"%s%s",			text,			err or table.concat(inlineLinks, "")		) end return require('Module:Side box')._main({		class = 'attached-kml',		text = text	}) end

local function makeKmldataDiv(link, s_index) return mw.ustring.format(		' %s%s ',		sites[s_index][2], link, sites[s_index][3], link	) end

local function makeError(msg, cat) return mw.ustring.format(		'%s %s',		msg,		mw.title.getCurrentTitle:inNamespaces(0, 118) and cat or ''	) end

local function getUrlFromQid( kml_qid ) local pcall_result, kml_entity = pcall(mw.wikibase.getEntity, kml_qid) if not pcall_result then return nil, nil, nil, makeError(L10n.str.err.no_item, L10n.str.cat.error_noitem) end -- Error if entity doesn't exist

local p31_claim = kml_entity:getBestStatements("P31") -- P31 is property "instance of" local has_good_p31 for k, v in pairs( p31_claim ) do		if (p31_claim[k] and p31_claim[k].mainsnak.snaktype == "value" and			p31_claim[k].mainsnak.datavalue.type == "wikibase-entityid" and			p31_claim[k].mainsnak.datavalue.value["numeric-id"] == 26267864) then has_good_p31 = true end end if not (has_good_p31) then -- Error if item isn't a kml file return nil, nil, nil, makeError(L10n.str.err.bad_qid, L10n.str.cat.error_badqid) end

local kml_sitelink local kml_siteindex local kml_url for i, v in ipairs( sites ) do		kml_sitelink = kml_entity:getSitelink( v[1] ) if kml_sitelink then kml_url = "https://" .. v[2] .. "/w/index.php?title=" .. mw.uri.encode( kml_sitelink, "WIKI" ) .. "&action=raw" kml_siteindex = i		end if kml_url then break end end return kml_url or nil, kml_sitelink or nil, kml_siteindex or nil, nil end

-- Attempts to get url from linked wikidata items, will return nil if it can't local function getUrlFromWikidata local entity = mw.wikibase.getEntityObject if not entity then return nil end

local kml_claim = entity:getBestStatements("P3096")	-- P3096 is property "KML file" if kml_claim then -- get the QID of the first value of the property if (kml_claim[1] and kml_claim[1].mainsnak.snaktype == "value" and kml_claim[1].mainsnak.datavalue.type == "wikibase-entityid") then local kml_qid = "Q" .. kml_claim[1].mainsnak.datavalue.value["numeric-id"] return getUrlFromQid( kml_qid ) else return nil	-- TODO: error message end else return nil	-- TODO: error message end end

function p.main(frame) local parent = frame.getParent(frame) local Args = setCleanArgs(parent.args)

local qid = Args[L10n.para.wikidata] or nil

-- get KML file url local wikiUrl, wikiTitle, wikiLink, trackingWikitext, kmlError if not (Args[L10n.para.from]) then if not qid then wikiUrl, wikiLink, siteindex, kmlError = getUrlFromWikidata elseif mw.ustring.find( qid, "^Q%d+" ) then wikiUrl, wikiLink, siteindex, kmlError = getUrlFromQid(qid) else kmlError = makeError(L10n.str.err.malformed_qid, L10n.str.cat.error_mqid) end end if not (wikiUrl) then -- FIXME? this smells bad. shouldn't need to make a new title of a to_string -- from the current title and then turn it into text form wikiLink = Args[L10n.para.from] or mw.title.new(tostring(mw.title.getCurrentTitle)).text wikiLink = L10n.str.kml_prefix .. wikiLink wikiTitle = mw.title.new( wikiLink )

if not (wikiTitle.exists) and not (kmlError) then if Args[L10n.para.from] then kmlError = makeError(L10n.str.err.bad_from, L10n.str.cat.error_from) else kmlError = makeError(L10n.str.err.no_kml, L10n.str.cat.error_nokml) end end wikiUrl = wikiTitle:fullUrl("action=raw", "https") siteindex = 1 trackingWikitext = mw.ustring.format(			'KML is not from Wikidata %s',			mw.title.getCurrentTitle:inNamespace(0) and L10n.str.cat.local_kml or ''		) else trackingWikitext = mw.ustring.format(			'KML is from Wikidata %s',			mw.title.getCurrentTitle:inNamespace(0) and L10n.str.cat.wikidata_kml or ''		) end wikiTitle = mw.title.new( wikiLink ) if wikiTitle.exists then local transclusion = wikiTitle:getContent -- hack to register the template as transcluded. end -- replace __KML_URL__ or __KML_URL_E__ with actual values local encodedWikiUrl = mw.uri.encode(wikiUrl, "PATH") for i, v in ipairs( externalLinks ) do		local el1 = safeReplace( v.link, "__KML_URL__", wikiUrl ) local el2 = safeReplace( el1, "__KML_URL_E__", encodedWikiUrl ) externalLinks[i]["link"] = el2 end

-- suppress errors and categories if demo parameter is set if Args[L10n.para.demo] then kmlError = nil trackingWikitext = "" end

local wikitext = "" if Args[L10n.para.display] then local display = mw.text.split(Args[L10n.para.display], '%s*' .. L10n.str.dsep .. '%s*') if display[1] == L10n.str.title or display[2] == L10n.str.title then wikitext = makeTitleWikitext(Args[L10n.para.title] or L10n.str.default_title, kmlError) end if display[1] == L10n.str.inline or display[2] == L10n.str.inline or (display[1] ~= L10n.str.title and display[2] ~= L10n.str.title) then local inlineWikitext = makeInlineWikitext(Args[L10n.para.header] or L10n.str.default_header, wikiUrl, kmlError) wikitext = wikitext .. inlineWikitext end else wikitext = makeInlineWikitext(Args[L10n.para.header] or L10n.str.default_header, wikiUrl, kmlError) end wikitext = wikitext .. makeKmldataDiv(wikiLink, siteindex) .. trackingWikitext

return frame:extensionTag{ name = 'templatestyles', args = { src = 'Module:Attached KML/styles.css' } } .. frame:preprocess( wikitext )

end

return p