Sari la conținut

Modul:RefQ

De la Wikipedia, enciclopedia liberă

-- Modul:RefQ
-- Layer between Modul:Wikidata and Modul:Citat Q.
-- Passes its parameters to Modul:Citat Q, names the result automatically
-- (hash of the citation text) and renders it as a complete <ref> footnote.
-- References made only of P248 plus locator properties are rendered as
-- sub-references: the cited work as content and the locators in |details=.

local p = {}

local getArgs = require('Module:Arguments').getArgs
local CitatQ = require('Modul:Citat Q')
local DateUtils = require('Modul:DateUtils')

local function snakValues(snaks)
	local values = {}
	for _, snak in ipairs(snaks or {}) do
		if snak.snaktype == 'value' and snak.datavalue then
			table.insert(values, snak)
		end
	end
	return values
end

local function joinValues(snaks, toText)
	local parts = {}
	for _, snak in ipairs(snakValues(snaks)) do
		local text = toText(snak)
		if text and text ~= '' then table.insert(parts, text) end
	end
	return (#parts > 0) and table.concat(parts, ', ') or nil
end

local function stringValue(snak)
	local v = snak.datavalue.value
	return type(v) == 'string' and mw.text.trim(v) or nil
end

local function wikidataDate(snak)
	return DateUtils.formatDate(DateUtils.extractDateFromWikidataSnak(snak), false, true)
end

-- Free-text dates (template parameters) are reformatted when recognised.
local function textDate(text)
	local ok, d = pcall(DateUtils.parseDate, text)
	local formatted = ok and d and DateUtils.formatDate(d, false, true)
	return formatted or text
end

local function isPageRange(pages)
	local _, numberCount = mw.ustring.gsub(pages, '%d+', '')
	return numberCount > 1 or mw.ustring.find(pages, '[-–—,;/]') ~= nil
end

-- Builds the |details= text from plain values:
-- { chapter, section, pages, plural (true/false/nil = detect), accessDate, extra }
local function buildDetails(v)
	local parts = {}
	if v.chapter then table.insert(parts, 'cap. „' .. v.chapter .. '”') end
	if v.section then table.insert(parts, 'secțiunea „' .. v.section .. '”') end
	if v.pages then
		local plural = v.plural
		if plural == nil then plural = isPageRange(v.pages) end
		table.insert(parts, (plural and 'pp. ' or 'p. ') .. v.pages)
	end
	if v.accessDate then table.insert(parts, 'accesat la ' .. v.accessDate) end
	if v.extra then table.insert(parts, v.extra) end
	return (#parts > 0) and table.concat(parts, ', ') or nil
end

-- Wikidata reference properties allowed in |details=
local DETAIL_PROPS = { P792 = true, P958 = true, P304 = true, P813 = true }

-- If the reference has exactly P248, optionally with some DETAIL_PROPS (and
-- nothing else), returns the stated-in QID and the details text.
local function splitSnakDetails(snaks)
	local statedIn = snakValues(snaks['P248'])[1]
	if not statedIn or statedIn.datavalue.type ~= 'wikibase-entityid' then return nil end

	for propId, _ in pairs(snaks) do
		if propId ~= 'P248' and not DETAIL_PROPS[propId] then return nil end
	end

	return statedIn.datavalue.value.id, buildDetails{
		chapter = joinValues(snaks['P792'], stringValue),
		section = joinValues(snaks['P958'], stringValue),
		pages = joinValues(snaks['P304'], stringValue),
		accessDate = joinValues(snaks['P813'], wikidataDate),
	}
end

-- Template parameters that go into |details= instead of the citation.
-- p= / pp= force the singular / plural page prefix.
local DETAIL_ARGS = {
	chapter = { 'capitol', 'cap', 'chapter' },
	section = { 'secțiune', 'secțiunea', 'section', 'at' },
	pages = { 'pagini', 'pagina', 'pages', 'page' },
	singularPage = { 'p' },
	pluralPages = { 'pp' },
	accessDate = { 'access-date', 'accessdate', 'accesat', 'data accesării' },
	extra = { 'details' },
}

-- Separates the details parameters from the arguments passed to Citat Q.
local function splitArgDetails(args)
	local rest, found = {}, {}
	local detailArgName = {}
	for key, names in pairs(DETAIL_ARGS) do
		for _, name in ipairs(names) do detailArgName[name] = key end
	end
	for name, value in pairs(args) do
		local key = detailArgName[name]
		if key then
			found[key] = found[key] or value
		else
			rest[name] = value
		end
	end

	local plural = nil
	local pages = found.pages
	if found.pluralPages then pages, plural = found.pluralPages, true
	elseif found.singularPage then pages, plural = found.singularPage, false
	end
	return rest, buildDetails{
		chapter = found.chapter,
		section = found.section,
		pages = pages,
		plural = plural,
		accessDate = found.accessDate and textDate(found.accessDate),
		extra = found.extra,
	}
end

-- Returns the unexpanded citation wikitext for a Wikidata reference
-- (reference structure + options, as for Modul:Citat Q's cite_ref) and,
-- for sub-referenceable references, a second value with the details text.
function p.cite(reference, options)
	if reference and reference.snaks then
		local statedInId, details = splitSnakDetails(reference.snaks)
		if statedInId then
			return CitatQ.cite_item_lua(statedInId, {}), details
		end
	end
	return CitatQ.cite_ref(reference, options)
end

-- Wraps citation text in a <ref> whose name is derived from the text.
-- The optional details become the ref's |details= attribute; they are not
-- part of the name, so all sub-references of a work share the main reference.
function p.wrap(content, frame, details)
	if not content or content == '' then return '' end
	frame = frame or mw.getCurrentFrame()
	local args = { name = 'wdref-' .. mw.hash.hashValue('md5', content) }
	if details and details ~= '' then args.details = details end
	return frame:extensionTag{
		name = 'ref',
		content = content,
		args = args,
	}
end

-- Lua entry point: parameters -> Modul:Citat Q -> named <ref>.
function p.build(frame, ...)
	local content, details = p.cite(...)
	return p.wrap(content, frame, details)
end

-- Template entry point: {{#invoke:RefQ|ref|Q136354833|...}} (or through {{RefQ}})
-- Takes what {{Citat Q}} takes: the QID in |1= (or |q=) plus optional overrides.
-- Locator parameters (pages, chapter, section, access date, details) go into
-- the ref's |details= attribute, in the same form as for Wikidata references;
-- all other parameters are passed to Modul:Citat Q's cite_item_lua, which
-- returns the same kind of unexpanded text as cite_ref, so equal citations
-- get equal names whether they come from a template or from Wikidata.
function p.ref(frame)
	local args = getArgs(frame)
	local qid = args.q or args[1]
	if not qid or qid == '' then
		return '<span class="error">RefQ: lipsă QID</span>'
	end
	local rest, details = splitArgDetails(args)
	rest.q = nil
	rest[1] = nil
	return p.wrap(CitatQ.cite_item_lua(qid, rest), frame, details)
end

return p