Module:Official website/sandbox

From blackwiki
< Module:Official website
Revision as of 16:22, 12 August 2018 by blackwiki>Zyxw (In renderUrl, remove unnecessary leading space in string. Changes related to Wikidata edit link were implemented at Module:Official website, so a diff with sandbox will now show only the changes related to displaying language name and adding language categories.)
Jump to navigation Jump to search

Documentation for this module may be created at Module:Official website/sandbox/doc

local makeUrl = require('Module:URL')._url

local p = {}

-- Wrapper for pcall which returns nil on failure.
local function quickPcall(func)
	local success, result = pcall(func)
	if success then
		return result
	end
end

-- Gets the rank for a Wikidata property table. Returns 1, 0 or -1, in
-- order of rank.
local function getRank(prop)
	local rank = prop.rank
	if rank == 'preferred' then
		return 1
	elseif rank == 'normal' then
		return 0
	elseif rank == 'deprecated' then
		return -1
	else
		-- No rank or undefined rank is treated as "normal".
		return 0
	end
end

-- Finds whether a Wikidata property is qualified as being in English.
local function isEnglish(prop)
	local ret = quickPcall(function ()
		for i, lang in ipairs(prop.qualifiers.P407) do
			if lang.datavalue.value['numeric-id'] == 1860 then
				return true
			end
		end
		return false
	end)
	return ret == true
end

-- Retrieves the name of a language from a Wikipedia template
local function fetchLabelForLangCode(code)
	return quickPcall(function ()
		return mw.getCurrentFrame():expandTemplate{
			title = 'ISO 639 name ' .. code
		}
	end)
end

-- Fetches the official website data from Wikidata
local fetchWikidata
fetchWikidata = function()
	-- Get objects for all official sites on Wikidata.
	local websites = quickPcall(function ()
		return mw.wikibase.getEntityObject().claims.P856
	end)

	-- Clone the objects in case other code needs them in their original order.
	websites = websites and mw.clone(websites) or {}

	-- Add the table index to the objects in case it is needed in the sort.
	for i, website in ipairs(websites) do
		website._index = i
	end

	-- Sort the websites, first by highest rank, and then by websites in the
	-- English language, then by the website's original position in the
	-- property list. When we are done, get the URL from the highest-sorted
	-- object.
	table.sort(websites, function(ws1, ws2)
		local r1 = getRank(ws1)
		local r2 = getRank(ws2)
		if r1 ~= r2 then
			return r1 > r2
		end
		local e1 = isEnglish(ws1)
		local e2 = isEnglish(ws2)
		if e1 ~= e2 then
			return e1
		end
		return ws1._index < ws2._index
	end)

	-- Cache the result so that we only do the heavy lifting once per #invoke.
	fetchWikidata = function ()
		return websites[1]
	end

	return websites[1]
end

-- Retrieves the URL of the website
local function fetchWikidataUrl()
	return quickPcall(function ()
		return fetchWikidata().mainsnak.datavalue.value
	end)
end

-- Retrieves the name of the language for the website
local function fetchWikidataLang()
	return quickPcall(function ()
		local website = fetchWikidata()
		if not isEnglish(website) then
			local id = website.qualifiers.P407[1].datavalue.value.id
			local lang = mw.wikibase.getEntity(id)
			local iso639_3 = quickPcall(function ()
				return lang:getBestStatements('P220')[1].mainsnak.datavalue.value
			end)
			local ietf = quickPcall(function ()
				return lang:getBestStatements('P305')[1].mainsnak.datavalue.value
			end)

			local name = fetchLabelForLangCode(iso639_3)
			name = name or fetchLabelForLangCode(ietf)
			local label = name or lang:getLabel('en')

			return {
				label = label,
				name = name,
				iso639 = iso639_3,
				ietf = ietf
			}
		end
	end)
end

-- Render the URL link, plus other visible output.
local function renderUrl(options)
	if not options.url and not options.wikidataurl then
		return '<strong class="error">' ..
			'No URL found. Please specify a URL here or add one to Wikidata.' ..
			'</strong>'
	end
	local ret = {}
	ret[#ret + 1] = string.format(
		'<span class="official-website">%s</span>',
		makeUrl(options.url or options.wikidataurl, options.display)
	)
	if options.wikidataurl and not options.url then
		local entity = mw.wikibase.getEntityObject() or {}
		local qid = entity.id
		if qid then
			ret[#ret + 1] = '[[File:Blue pencil.svg |frameless |text-top |10px |alt=Edit this at Wikidata |link=https://www.wikidata.org/wiki/' .. qid .. '#P856|Edit this at Wikidata]]'
		end
	end
	if options.format == 'flash' then
		ret[#ret + 1] = mw.getCurrentFrame():expandTemplate{
			title = 'Link note',
			args = {note = 'Requires [[Adobe Flash Player]]'}
		}
	end
	if options.mobile then
		ret[#ret + 1] = '(' .. makeUrl(options.mobile, 'Mobile') .. ')'
	end
	if options.lang then
		if options.lang.label then
			ret[#ret + 1] = string.format(
				'<span class="languageicon">(in %s)</span>',
				options.lang.label
			)
		else
			ret[#ret + 1] = '<strong class="error">Invalid language code.</strong>'
		end
	end
	return table.concat(ret, ' ')
end

-- Render the tracking categories
local function renderTrackingCategories(url, wikidataurl, lang)
	if mw.title.getCurrentTitle().namespace ~= 0 then
		return ''
	end
	local cats = {}

	-- Official website categories
	if not url and not wikidataurl then
		cats[#cats + 1] = 'Official website missing URL'
	elseif url and not wikidataurl then
		cats[#cats + 1] = 'Official website not in Wikidata'
	elseif url and wikidataurl then
		if url:gsub('/%s*$', '') ~= wikidataurl:gsub('/%s*$', '') then
			cats[#cats + 1] = 'Official website different in Wikidata and Wikipedia'
		end
	end

	-- Foreign language categories
	if lang and lang.name and lang.iso639 ~= "en" and lang.iso639 ~= "eng" and (url or wikidataurl) then
		cats[#cats + 1] = string.format(
			"Articles with %s-language external links",
			lang.name
		)
	end

	for i, cat in ipairs(cats) do
		cats[i] = string.format('[[Category:%s]]', cat)
	end
	return table.concat(cats)
end

function p._main(args)
	local url = args[1] or args.URL or args.url
	local lang = args.lang

	local wikidataurl = fetchWikidataUrl()
	if not url then
		lang = lang or fetchWikidataLang()
	end
	if type(lang) == "string" then
		lang = {
			name = fetchLabelForLangCode(lang),
			iso639 = lang
		}
		lang.label = lang.name
	end

	local formattedUrl = renderUrl{
		url = url,
		wikidataurl = wikidataurl,
		display = args[2] or args.name or 'Official website',
		format = args.format,
		mobile = args.mobile,
		lang = lang
	}
	return formattedUrl .. renderTrackingCategories(url, wikidataurl, lang)
end

function p.main(frame)
	local args = require('Module:Arguments').getArgs(frame, {
		wrappers = 'Template:Official website'
	})
	return p._main(args)
end

return p