Permanently protected module
From Wikipedia, the free encyclopedia


-- 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: /info/en/?search=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", -- 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 = "[[Category:Articles using KML from Wikidata]]", -- tracks mainspace articles using KML from Wikidata

			local_kml = "[[Category:Articles using KML not from Wikidata]]", -- tracks mainspace articles not using KML from Wikidata

			error_mqid = "[[Category:Attached KML errors|M]]", -- tracks malformed_qid error

			error_badqid = "[[Category:Attached KML errors|W]]", -- tracks bad_qid error

			error_noitem = "[[Category:Attached KML errors|N]]", -- tracks no_item error

			error_from = "[[Category:Attached KML errors|F]]", -- tracks bad_from error

			error_nokml = "[[Category:Attached KML errors|K]]", -- 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 <code><nowiki>|" .. L10n.para.wikidata .. "=</nowiki></code>",	-- item id doesn't match pattern (number with Q prefix)

	bad_qid		= "Error: item specified on Wikidata, or in <code><nowiki>|" .. L10n.para.wikidata .. "=</nowiki></code>, is not a KML file <small>(P31→Q26267864 not found)</small>",	-- item doesn't have a P31→Q26267864 statement

	no_item		= "Error: item specified in <code><nowiki>|" .. L10n.para.wikidata .. "=</nowiki></code> not found on Wikidata",	-- item not found on wikidata

	bad_from	= "Error: KML file not found, check <code><nowiki>|" .. L10n.para.from .. "=</nowiki></code>",	-- 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

				cleanArgskey = val

			end

		else

			cleanArgskey = 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

		titleLinksi =  mw.ustring.format( "[%s %s]", v.link , v.short)

	end

	return mw.getCurrentFrame():extensionTag{

				name = 'indicator',

				args = { name = 'attached-kml' },

				content = mw.ustring.format(

					"<span id=\"coordinates\">\'\'\'%s\'\'\': %s</span>",

					titletext,

					err or table.concat(titleLinks, " / ")

				)

			}

end



local function makeInlineWikitext(headertext, url, err)

	local inlineLinks = {}

	for i, v in ipairs( externalLinks ) do

		inlineLinksi =  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(

			"<li>%s%s%s (<span class=\"%s\">[%s %s] <span style=\"font-size:85%%;\">([%s %s] • [[%s|%s]])</span></span>)</li>",

			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.,

			L10n.str.help_location, L10n.str.help

		)

	end

	

	local text = mw.ustring.format(

		'%s<span class="%s">\'\'\'[%s %s]\'\'\' ([%s %s] • [[%s|%s]])</span>',

		headertext, wiki_link_class, url, L10n.str.kml_file, editUrl,

		L10n.str., L10n.str.help_location, L10n.str.help

	)

	

	if err or #inlineLinks > 0 then

		text = mw.ustring.format(

			"%s<ul><li>%s</li></ul>",

			text,

			err or table.concat(inlineLinks, "</li><li>")

		)

	end

	

	return require('Module:Side box')._main({

		class = 'attached-kml',

		text = text

	})

end



local function makeKmldataDiv(link, s_index)

	return mw.ustring.format(

		'<div class="kmldata load-gadget" data-server="%s" data-gadget="WikiMiniAtlas" title="%s">[[%s%s]]</div>',

		sitess_index][2], link, sitess_index][3], link

	)

end



local function makeError(msg, cat)

	return  mw.ustring.format(

		'<strong class="attached-kml-error">%s</strong>%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_claimk and p31_claimk].mainsnak.snaktype == "value" and

			p31_claimk].mainsnak.datavalue.type == "wikibase-entityid" and

			p31_claimk].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( v1 )

		if kml_sitelink then

			kml_url = "https://" .. v2 .. "/?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_claim1 and kml_claim1].mainsnak.snaktype == "value" and kml_claim1].mainsnak.datavalue.type == "wikibase-entityid") then

			local kml_qid = "Q" .. kml_claim1].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 = ArgsL10n.para.wikidata or nil



	-- get KML file url

	local wikiUrl, wikiTitle, wikiLink, trackingWikitext, kmlError

	if not (ArgsL10n.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 = ArgsL10n.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 ArgsL10n.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(

			'<div title="KML & Wikidata" class="attached-kml-wikidata">KML is not from Wikidata</div>%s',

			mw.title.getCurrentTitle():inNamespace(0) and L10n.str.cat.local_kml or ''

		)

	else

		trackingWikitext =  mw.ustring.format(

			'<div title="KML & Wikidata" class="attached-kml-wikidata">KML is from Wikidata</div>%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 )

		externalLinksi]["link" = el2

	end



	-- suppress errors and categories if demo parameter is set

	if ArgsL10n.para.demo then

		kmlError = nil

		trackingWikitext = ""

	end



	local wikitext = ""

	if ArgsL10n.para.display then

		local display = mw.text.split(ArgsL10n.para.display], '%s*' .. L10n.str.dsep .. '%s*')

		if display1 == L10n.str.title or display2 == L10n.str.title then

			wikitext = makeTitleWikitext(ArgsL10n.para.title or L10n.str.default_title, kmlError)

		end

		if display1 == L10n.str.inline or display2 == L10n.str.inline or (display1 ~= L10n.str.title and display2 ~= L10n.str.title) then

			local inlineWikitext = makeInlineWikitext(ArgsL10n.para.header or L10n.str.default_header, wikiUrl, kmlError)

			wikitext = wikitext .. inlineWikitext

		end

	else

		wikitext = makeInlineWikitext(ArgsL10n.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