Module:R: Difference between revisions

From Cool Wiki
Jump to navigation Jump to search
m spelling
 
m 1 revision imported
 
(No difference)

Latest revision as of 13:25, 20 October 2026

Documentation for this module may be created at Module:R/doc

local rp = {}
local r = {}
local hyphen2dash = require('Module:String2').hyphen_to_dash
local lang = require('Module:Lang')
local trim_quotes = require('Module:trim quotes')._trim
local getArgs = require('Module:Arguments').getArgs
local plainText = require('Module:Plain text')._main
local mt = {__call = function (t, v) t[#t+1] = v end}

local notblank = function(v) return (v or '') ~= '' end
local isblank = function(v) return (v or '') == '' end

local pageTest = {pages = 1, pp = 1, page = 1, p = 1}
local quoteTest = {quote = 1, q = 1}
local wrapTest = {yes = 1, y = 1, forced = 1, f = 1}

-- get first non-empty argument from a list of names
local function firstArg(args, ...)
	for i = 1, select('#', ...) do
		local n = select(i, ...)
		local v = args[n]
		if notblank(v) then return v end
	end
	return nil
end

local function firstArgN(s, args, ...)
	for i = 1, select('#', ...) do
		local n = select(i, ...)
		local v = args[n .. s]
		if notblank(v) then return v end
	end
	return nil
end

-- Implements [[Template:page_needed]]
-- may replace with lua implementation at some point
local function page_needed(frame, date, reason)
	return frame:expandTemplate{title='Page needed', args = {date = date, reason = reason}}
end

-- Formats quotes
-- takes params{language=value, translation=value}
local function make_quote(params, contentId, qcli, quote)
	local out = setmetatable({}, mt)
	local langcode = ""
	out("<q ")
	if notblank(contentId) then
		out('id="' .. contentId .. '" ')
	end
	if notblank(qcli) then
		out('cite="#' .. (mw.uri.anchorEncode(qcli)) .. '" ')
	end
	if notblank(params.language) then
		langcode = r._langcode(params.language)
		out('lang="' .. langcode .. '">')
		out('<bdi lang="' .. langcode .. '">')
	else
		out('><bdi>')
	end
	out(quote .. '</bdi></q>')
	if notblank(params.translation) then
		out('&#32;&#91;<bdi ')
		if notblank(params.language) then
			out('lang="' .. langcode .. '"')
		end
		out('>' .. trim_quotes(params.translation .. '</bdi>&#93;'))
	end
	
	return table.concat(out)
end
	
-- Implements [[Template:R/langcode]]
-- Only for template/module use: |language=code/name
function r._langcode(language)
	language = language or ''
	local tag, result = lang._tag_from_name{language}
	if result then
		return tag
	elseif lang._is_ietf_tag(language) then
		return language
	end
	return 'mis' -- use language code "mis" for any unrecognized language
end
function r.langcode(frame)
	local args = getArgs(frame)
	return r._langcode(args.language)
end


-- Implements [[Template:R/where]] sub-template
-- Only for template/module use: |plural=pages |singular=page |location=in-source-location |spacing=character
-- |pluralleadin=pp |singularleadin=p |leadin=
function r._where(params)
	local out = setmetatable({}, mt)

	if notblank(params.plural) then
		if notblank(params.pluralleadin) and notblank(params.singularleadin) then
			out(tonumber(params.plural) and (params.singularleadin) or (params.pluralleadin))
			out("." .. (params.spacing or ""))
		end
		out(params.plural)
		if notblank(params.singular) then
			out("," .. (params.spacing or "") .. "[" .. params.singular .. "]")
		end
	elseif notblank(params.singular) then
		if notblank(params.singularleadin) then
			out(params.singularleadin)
			out("." .. (params.spacing or ""))
		end
		out(params.singular)
	end

	if notblank(params.location) then
		if notblank(params.plural) or notblank(params.singular) then
			out("," .. (params.spacing or ""))
		end
		if(params.leadin) then
			out(params.leadin .. (params.spacing or ""))
		end
		out(params.location)
	end

	return table.concat(out)
end
function r.where(frame)
	return r._where(getArgs(frame))
end


-- Implements [[Template:R/superscript]]
-- Only for template/module use: |wrap=n[o]/y[es]/f[orced] |leadin=value |prefix=value |pp=value |where=value |sup-where=value |quote-where=value |quote=value |language=value |translation=value |suffix=value
function r._superscript(params)
	if not params or isblank(params.where) then
		return ""
	end

	local out = setmetatable({}, mt)
	
	-- "wrap" if wrap is "yes", "y", "f" or "forced", else "nowrap"
	local wrap = wrapTest[string.ulower(params.wrap or '')]
	out('<sup class="reference ' .. (wrap and "" or "no") .. 'wrap">')

	--prefix, if there's a quote
	if notblank(params.quote) and notblank(params.prefix) then
		out(params.prefix)
	end
	
	-- open tooltip span
	out('<span title="')
	
	-- Lead-in text (escaped)
	local whereText = notblank(params["quote-where"]) and params["quote-where"]
		or (params["where"] or "")
	local tooltipText = plainText((params.leadin or "") .. ": " .. whereText, false)
	out(mw.text.encode(tooltipText, '<>"'))

	-- Quotation block if present
	if notblank(params.quote) then
		local quoteTab = setmetatable({}, mt)
		if notblank(params.language) then
			local langText = lang._is_ietf_tag(params.language) and lang._name_from_tag{params.language} or params.language
			quoteTab("&#32;(" .. langText .. ")")
		end
		
		quoteTab("&#58; &quot;" .. trim_quotes(params.quote) ..
			"&quot;")

		if notblank(params.translation) then
			quoteTab("&#10;Translation: &quot;" ..
				trim_quotes(params.translation) .. "&quot;")
		end
		
		local quoteText = plainText(table.concat(quoteTab), false)
		out("&#10;Quotation" .. mw.text.encode(quoteText, '<>"') ..
			'" class="tooltip tooltip-dashed" style="border-bottom: 1px dashed;')
	end
	
	-- close tooltip span
	out('">')
	
	-- prefix, if not inserted above
	if (isblank(params.quote)) and notblank(params.prefix) then
		out(params.prefix)
	end
	
	--pp and sup-where
	out(params.pp or '')
	out(params['sup-where'] or '')
	
	-- suffix
	if notblank(params.quote) then
		out("</span>" .. (params.suffix or ""))
	else
		out((params.suffix or "") .. "</span>")
	end

	out("</sup>")

	return table.concat(out)
end
function r.superscript(frame)
	return r._superscript(getArgs(frame))
end

-- Implements [[Template:R/details]] formatting for the details= field
-- Only for template/module use: |where=value |quote-where=value |quote=value |language=value |translation=value |annotation=value |contentId=value |qcli = firstArg(params, 'quote-cite', 'link-id')
function r._details(params)
	if not params or (
			isblank(params["where"]) and
			isblank(params["quote-where"]) and
			isblank(params["quote"]) and
			isblank(params["annotation"])
	) then
		return ""
	end

	local out = setmetatable({}, mt)

	-- process language
	local langText = ""
	local langName = ""
	if notblank(params.language) then
		langName = lang._is_ietf_tag(params.language) and lang._name_from_tag{params.language} or params.language
		langText = "&#32;(in " .. langName .. ")"
	end

	-- process location
	local whereText = isblank(params["where"]) and (params["quote-where"] or "")
		or (params["where"] or "")
	if isblank(params.annotation) and isblank(params.quote) and notblank(whereText) then
		out(whereText)
	end

	local stripError=false

	-- Annotation block if present
	local annotation = mw.text.killMarkers(params.annotation or '')
	if notblank(annotation) then
		if annotation ~= params.annotation then stripError=true end
		annotation = mw.ustring.gsub(mw.text.trim(annotation), "^:", "")
		if notblank(whereText) then
			annotation = mw.ustring.gsub(annotation, "^" .. mw.text.decode(whereText) .. ": *", "")
			out(whereText .. (isblank(params.quote) and langText or "") .. "&#58;&#32;")
		end
		out(annotation)
		if mw.ustring.sub(annotation, -1) ~= "." then
			out(".")
		end
		out("&#32;")
	end
	
	-- Quotation block if present
	local quote = mw.text.killMarkers(trim_quotes(params.quote or ''))
	if notblank(quote) then
		if quote ~= trim_quotes(params.quote or '') then stripError = true end
		if notblank(params["quote-where"]) then
			if params["quote-where"] ~= whereText or isblank(annotation) then
				if params["quote-where"] ~= whereText and isblank(annotation) then
					out(whereText .. ".&#32;")
				end
				out(params["quote-where"] .. langText .. "&#58;&#32;")
			elseif notblank(langName) then
				out("In " .. langName .. "&#58;&#32;")
			end
		elseif isblank(annotation) and notblank(whereText) then
			out(whereText .. langText .. "&#58;&#32;")
		elseif notblank(whereText) and table.concat(out) == whereText then
			out(langText .. "&#58;&#32;")
		elseif notblank(langName) then
			out("In " .. langName .. "&#58;&#32;")
		end

		out(make_quote(params, params.contentId, params.qcli, quote))
	elseif table.concat(out) == whereText then
		out(langText .. ".&#32;")
	end

	if stripError == true then
		local errorMsg = ' Nested references and other parser functions that produce [[:mw:Strip_marker|strip markers]] are not supported in quotes or annotations when using sub-referencing.'
		mw.addWarning('<span style="color:#d33">Error in citation using {{tl|R}}:</span>' .. errorMsg)
		out('<span class="cs1-visible-error citation-comment template-r-error">' .. errorMsg .. '</span>')
	end

	return table.concat(out)
end
function r.details(frame)
	return r._details(getArgs(frame))
end

-- Implements [[Template:R/ref]]
function r._ref(params, frame)
	frame = frame or mw.getCurrentFrame()
	local out = setmetatable({}, mt)
	
	local contextSectionName = mw.uri.anchorEncode(
			'cite_sect-' ..
			trim_quotes(params[1] or '') ..	'-' ..
			trim_quotes(params[2] or '') .. '-' .. 
			trim_quotes(
				(notblank(params.page) and params.page or hyphen2dash(params.pages or '', ' ')) ..
				(params.location or '')
			)
		)
	local contentId = notblank(params['content-id']) and mw.uri.anchorEncode(params['content-id']) or nil
	local whereArgs = {
		plural = hyphen2dash(params.pages, ' '),
		singular = params.page,
		location = params.location,
		spacing = '&#32;'
	}
	local quoteWhereArgs = {
		plural = hyphen2dash(params['quote-pages'], ' '),
		singular = params['quote-page'],
		location = params['quote-location'],
		spacing = '&#32;'
	}
	local refArgs = {name = params[1] or '', group = params[2] or ''}

	local leadin = params.leadin or ''
	local quote = trim_quotes(params.quote or '')
	local quotePage = firstArg(params, 'quote-pages', 'quote-page', 'quote-location')
	local qcli = firstArg(params, 'quote-cite', 'link-id')

	-- Whether or not to use subreferencing. Set to default for now, but this should changed when moved to enwiki
	local subreferencing = ({sub = 1, subreference = 1, ['sub-reference']=1})[string.ulower(params.style or '')] == 1
	
	-- Debug facility
	if notblank(params.debug) then
		out("DEBUG: ")
		for k, v in pairs(params) do
			out(k .. "=" .. (v or '') .. ", ")
		end
		out(". Potential context-section-name:")
		out(contextSectionName .. '".')
	end
	
	-- Opening "support context" span
	local lst
	if notblank(params.section) then
		local section = (params.section == 'yes' or params.section == 'y') and
			contextSectionName or params.section
		lst = frame:callParserFunction('#lst', {
			mw.title.getCurrentTitle().fullText,
			section
		})
		if notblank(lst) then
			out(frame:extensionTag('templatestyles', '', {src='Template:Tooltip/styles.css'}))
			out('<span class="rt-commentedText tooltip tooltip-dotted"' ..
				'title="Context: &quot;' .. mw.text.encode(plainText(lst, false), '<>"') ..
				'&quot;">')
		end
	end
	
	--First call to create reference link (variants identical except for dir):
	if notblank(params['link-id']) then
		out('<span id="' .. mw.uri.anchorEncode(params['link-id']) ..
			'class="citation">')
	end

	local refContent = setmetatable({}, mt)
	if (isblank(params.annotation)) then
		if contentId then
			refContent('<span id="' .. contentId .. '" class="citation">')
			refContent(params.reference or '')
			refContent('</span>')
		else
			refContent(params.reference or '')
		end
		refContent(params.postscript or '')
	end

	if notblank(params.direction) then
		refArgs.dir = params.direction
	end

	-- Generate details for subreferencing, if enabled
	if subreferencing and firstArg(params, 'annotation', 'quote', 'page', 'pages', 'location') then
		local detailsWhereArgs = mw.clone(whereArgs)
		detailsWhereArgs.singularleadin = "p"
		detailsWhereArgs.pluralleadin = "pp"
		local detailsQuoteWhereArgs = mw.clone(quoteWhereArgs)
		detailsQuoteWhereArgs.singularleadin = "p"
		detailsQuoteWhereArgs.pluralleadin = "pp"
		local details=r._details{
			where = r._where(detailsWhereArgs), -- where must not include qp params
			annotation = quoteTest[params.annotation] and '' or (leadin .. (params.annotation or '')),
			['quote-where'] = r._where( -- quote-where must not contain normal in-source-location params
				pageTest[quotePage] and detailsWhereArgs or detailsQuoteWhereArgs
			),
			quote = quote,
			language = params.language,
			translation = params.translation,
			contentId=contentId,
			qcli = qcli
		}
		if notblank(details) then
			refArgs.details = details
		end
	end
	
	out(frame:extensionTag('ref', table.concat(refContent), refArgs))
	
	if notblank(params['link-id']) then
		out('</span>')
	end

	if not subreferencing then
		--Optional second call to append data to reference (variants identical except for dir):
		if notblank(params.annotation) then
			refContent = setmetatable({}, mt)
			if pageTest[params.annotation] then
				if notblank(firstArg(params, 'pages', 'page', 'location')) then
					--refContent('&#8204;')
					if contentId then
						refContent('<span id="' .. contentId .. '">')
					end
					refContent(leadin)
					refContent(r._where(whereArgs))
					if contentId then
						refContent('</span>')
					end
	
				end
			elseif quoteTest[params.annotation] then
				--refContent('&#8204;')
				if pageTest[quotePage] then
					if notblank(firstArg(params, 'pages', 'page', 'location')) then
						refContent(leadin)
						refContent(r._where(whereArgs) .. ':&#32;')
					end
				elseif notblank(quotePage) then
					refContent(leadin)
					refContent(r._where(quoteWhereArgs) .. ':&#32;')
				end

				refContent(make_quote(params, contentId, qcli, quote))
			elseif contentId then
				refContent('<span id="' .. contentId ..
					' class="citation">' .. leadin ..
					params.annotation .. '</span>')
			else
				refContent(leadin .. params.annotation)
			end
			refContent(params.postscript or '')
			refArgs = {follow = params[1] or '', group = params[2] or ''}
			if notblank(params.direction) then
				refArgs.dir = params.direction
			end

			
			if notblank(params.annotation) and params.annotation:sub(1,1) == "#" then
				local errorMsg = ' Automatic numbering by preceeding the annotation ' ..
					'with <code>&num;</code> will not work with the new [[:mw:Parsoid|Parsoid]] ' ..
					'parser, and therefore its use is discouraged'
				mw.addWarning('<span style="color:#085">Maintenance messages for citation using {{tl|R}}:</span>' ..
					errorMsg ..
					'; messages may be hidden ([[Help:CS1_errors#Controlling_error_message_display|help]]).')
				refContent('<span class="cs1-maint citation-comment template-r-error">' .. errorMsg .. '.</span>')
			end
			
			out(frame:extensionTag('ref', table.concat(refContent), refArgs))
		end
	
		--Superscript pages and tooltip for help, pages, quotes:
		local ssAma = string.ulower(params.style or '') == 'ama'
		-- p/pp is only used in superscript label, therefore it does not contain any qp params
		local ssPp = ''
		if ssAma and (isblank(params['no-pp'])) then
			if notblank(params.pages) then
				ssPp = 'pp'
			elseif notblank(params.page) then
				ssPp = 'p'
			end
		end
		-- leadin is only used in tooltip
		local ssLeadin = 'Page&nbsp;/ location'
		if pageTest[quotePage] then
			if notblank(params.pages) then
				ssLeadin = 'Pages'
			elseif notblank(params.page) then
				ssLeadin = 'Page'
			elseif notblank(params.location) then
				ssLeadin = 'Location'
			end
		elseif notblank(params['quote-pages']) then
			ssLeadin = 'Pages'
		elseif notblank(params['quote-page']) then
			ssLeadin = 'Page'
		elseif notblank(params['quote-location']) then
			ssLeadin = 'Location'
		end
		
		out(r._superscript{
			prefix = ssAma and '(' or '&#58;&hairsp;',
			suffix = ssAma and ')' or '&hairsp;',
			pp = ssPp,
			leadin = ssLeadin,
			where = r._where(whereArgs), -- where must not include qp params
			['sup-where'] = r._where{ -- sup-where same as where, but with improved list spacing for superscript
				plural = hyphen2dash(params.pages, '&hairsp;'),
				singular = params.page,
				location = params.location,
				spacing='&hairsp;'
			},
			['quote-where'] = r._where(pageTest[quotePage] and whereArgs or quoteWhereArgs),
			quote = quote,
			language = params.language,
			translation = params.translation,
			['wrap'] = params['wrap']
		})
	end
	
	-- Closing "support context" span:
	if notblank(params.section) and notblank(lst) then
		out('</span>')
	end
	
	-- Page needed functionality:
	if notblank(params['needed-reason']) then
		local pnReason = ({yes = 1, y = 1})[params['needed-reason']] and
			'No reason given' or params['needed-reason']
		out(page_needed(frame, params['needed-date'], pnReason))
	end
	
	-- Line wrapping functionality:
	if wrapTest[string.ulower(params.wrap or '')] then
		out("&#8203;") --zero-width space
	end

	-- Tracking category for nested references
	if (notblank(params.quote) and params.quote ~= mw.text.killMarkers(params.quote or '')) or
		(notblank(params.annotation) and params.annotation ~= mw.text.killMarkers(params.annotation or '')) then
		out('[[Category:Pages using Template:R with nested references]]')
	end
	
	--End of code
	return table.concat(out)
end
function r.ref(frame)
	return r._ref(getArgs(frame), frame)
end

function r._r(args, frame)
	frame = frame or mw.getCurrentFrame()
	local output = setmetatable({}, mt)
	output(frame:extensionTag('templatestyles', '', {src='Module:Citation/CS1/styles.css'}))
	-- ### 1 ###
	output(r._ref({
		[1]				= firstArg(args, 'name1', 'name', 'n1', 'n', 1),
		[2]				= firstArg(args, 'group', 'grp', 'g'),
		direction		= firstArg(args, 'direction1', 'direction', 'dir1', 'dir'),
		page			= firstArg(args, 'page1', 'page', 'p1', '1p', 'p'),
		pages			= firstArg(args, 'pages1', 'pages', 'pp1', '1pp', 'pp'),
		location		= firstArg(args, 'location1', 'location', 'loc1', '1loc', 'loc', 'at1', 'at'),
		['quote-page']	= firstArg(args, 'quotation-page1', 'quotation-page', 'quote-page1', 'quote-page', 'qp1', 'qp'),
		['quote-pages']	= firstArg(args, 'quotation-pages1', 'quotation-pages', 'quote-pages1', 'quote-pages', 'qpp1', 'qpp'),
		['quote-location'] = firstArg(args,
			'quotation-location1', 'quotation-location', 'quote-location1', 'quote-location', 'quote-loc1', 'quote-loc',
			'quote-at1', 'quote-at'
		),
		quote			= firstArg(args, 'quotation1', 'quotation', 'quote1', 'quote', 'q1', 'q'),
		language		= firstArg(args, 
			'quotation-language1', 'quotation-language', 'quote-language1', 'quote-language', 'quotation-lang1',
			'quotation-lang', 'quote-lang1', 'quote-lang', 'ql1', 'ql', 'language1', 'language', 'lang1', 'language', 'l1', 'l'
		),
		translation		= firstArg(args,
			'translation-quotation1', 'translation-quotation', 'trans-quotation1', 'trans-quotation', 'translation-quote1',
			'translation-quote', 'trans-quote1', 'trans-quote', 'tq1', 'tq', 'translation1', 'translation', 'trans1', 'trans',
			't1', 't', 'xlat1', 'xlat'
		),
		['quote-cite']	= firstArg(args, 'quotation-cite1', 'quotation-cite', 'quote-cite1', 'quote-cite', 'qc1', 'qc'),
		reference		= firstArg(args,
			'reference1', 'references', 'reference', 'notes', 'note', 'content', 'text', 'refn1', 'refn', 'refs', 'r1', 'r'
		),
		annotation		= firstArg(args, 'annotation1', 'annotation', 'annot1', 'annot', 'a1', 'a'),
		leadin			= args.leadin,
		postscript		= firstArg(args, 'postscript', 'postscript1', 'ps', 'ps1', '1ps'),
		section			= firstArg(args, 'section1', 'section', 'sec1', 'sec', 's1', 's'),
		['needed-reason'] = firstArg(args, 'needed-reason1', 'needed-reason', 'needed1', 'needed', 'reason'),
		['needed-date']	= firstArg(args, 'needed-date', 'date'),
		wrap			= args.wrap,
		['no-pp']		= firstArg(args, 'no-pp', 'nopp'),
		style			= args.style,
		['content-id']	= firstArg(args, 'ref1', '1ref', 'ref', 'id1', 'id'),
		['link-id']		= firstArg(args, 'link-id1', 'link-id'),
		['debug']		= args['debug']
	}, frame))

	-- ### 2+ ###
	local n = 2
	while firstArg(args, "name" .. n, "n" .. n, n) ~= nil do
		output(r._ref({
			[1]				= firstArg(args, 'name' .. n, 'n' .. n, n),
			[2]				= firstArg(args, 'group', 'grp', 'g'),
			direction		= firstArgN(n, args, 'direction', 'dir'),
			page			= firstArg(args, 'page' .. n, 'p' .. n, n .. 'p'),
			pages			= firstArg(args, 'pages' .. n, 'pp' .. n, n .. 'pp'),
			location		= firstArg(args, 'location' .. n, 'loc' .. n, n .. 'loc', 'at' .. n),
			['quote-page']	= firstArgN(n, args, 'quotation-page', 'quote-page', 'qp'),
			['quote-pages']	= firstArgN(n, args, 'quotation-pages', 'quote-pages', 'qpp'),
			['quote-location'] = firstArgN(n, args, 'quotation-location', 'quote-location', 'quote-loc', 'quote-at'),
			quote			= firstArgN(n, args, 'quotation', 'quote', 'q'),
			language		= firstArgN(n, args,
				'quotation-language', 'quote-language',	'quotation-lang', 'quote-lang', 'ql', 'language', 'lang', 'l'
			),
			translation		= firstArgN(n, args,
				'translation-quotation', 'trans-quotation', 'translation-quote', 'trans-quote', 'tq', 'translation', 'trans', 't',
				'xlat'
			),
			['quote-cite']	= firstArgN(n, args, 'quotation-cite', 'quote-cite', 'qc'),
			reference		= firstArgN(n, args, 'reference', 'refn', 'r'),
			annotation		= firstArgN(n, args, 'annotation', 'annot', 'a'),
			leadin			= args.leadin,
			postscript		= firstArg(args, 'postscript' .. n, 'ps' .. n, n .. 'ps', 'postscript', 'ps'),
			section			= firstArgN(n, args, 'section', 'sec', 's'),
			['needed-reason'] = firstArgN(n, args, 'needed-reason', 'needed'),
			['needed-date']	= firstArg(args, 'needed-date', 'date'),
			['wrap']		= args['wrap'],
			['no-pp']		= firstArg(args, 'no-pp', 'nopp'),
			style			= args.style,
			['content-id']	= firstArg(args, 'ref' .. n, n .. 'ref', 'id' .. n),
			['link-id']		= args['link-id' .. n],
			['debug']		= args['debug'],
		}, frame))
		n = n + 1
	end
	local outputText = table.concat(output)
	local errorText = outputText:find('template-r-error', 1, true) and
		'[[Category:Pages with errors in Template:R]]' or ''
	return (outputText .. errorText)
end
function r.r(frame)
	return r._r(getArgs(frame), frame)
end

-- Implements [[Template:Rp]]
function rp._rp(args, frame)
	frame = frame or mw.getCurrentFrame()
	-- If needed param is present and non-empty, show {{page needed}}
	if notblank(args.needed) then
		return page_needed(frame, args.date, args.reason)
	end

	-- prefix/suffix depending on style
	local ama = string.ulower(args.style or "") == "ama"
	local prefix = ama and "(" or "&#58;&hairsp;"
	local suffix = ama and ")" or "&hairsp;"

	-- p/pp is only used in superscript label, therefore it does not contain any qp params
	local pp = ""
	if ama and isblank(args["no-pp"]) and isblank(args.nopp) then
		if notblank(args.pages) or notblank(args.pp) then
			pp = "pp"
		elseif notblank(args.page) or notblank(args.p) then
			pp = "p"
		end
	end
	
	-- leadin is only used in tooltip
	local leadin
	local quote_switch = firstArg(args, "quotation-pages", "quote-pages", "qpp",
		"quotation-page", "quote-page", "qp",
		"quotation-location", "quote-location", "quote-loc", "quote-at")

	if not pageTest[quote_switch] then
		if notblank(firstArg(args, "quotation-pages", "quote-pages", "qpp")) then
			leadin = "Pages"
		elseif notblank(firstArg(args, "quotation-page", "quote-page", "qp")) then
			leadin = "Page"
		elseif notblank(firstArg(args, "quotation-location", "quote-location", "quote-loc", "quote-at")) then
			leadin = "Location"
		end
	end
	if not leadin then
		--either the quote_switch wasn't 'pages', 'pp', 'page',
		-- or 'p', or the 'quotation' params were all blank/nil
		if notblank(firstArg(args, "pages", "pp")) then
			leadin = "Pages"
		elseif notblank(firstArg(args, "page", "p")) then
			leadin = "Page"
		elseif notblank(firstArg(args, "location", "loc", "at")) then
			leadin = "Location"
		else
			leadin = "Page&nbsp;/ location"
		end
	end

	-- where must not include qp params
	local where = r._where{
		plural = hyphen2dash(firstArg(args, "pages", "pp", "1"), '&#32;'),
		singular = firstArg(args, "page", "p"),
		location = firstArg(args, "location", "loc", "at"),
		spacing = "&#32;"
	}

	-- sup-where same as where, but with improved list spacing for superscript
	local sup_where = r._where{
		plural = hyphen2dash(firstArg(args, "pages", "pp", "1"), '&hairsp;'),
		singular = firstArg(args, "page", "p"),
		location = firstArg(args, "location", "loc", "at"),
		spacing = "&hairsp;"
	}

	-- quote-where must not contain normal in-source-location params
	local quote_where
	if pageTest[quote_switch] then
		quote_where = r._where{
			plural = hyphen2dash(firstArg(args, "pages", "pp", 1), ' '),
			singular = firstArg(args, "page", "p"),
			location = firstArg(args, "location", "loc", "at"),
			spacing = "&#32;"
		}
	else
		quote_where = r._where{
			plural = hyphen2dash(firstArg(args, "quotation-pages", "quote-pages", "qpp"), ' '),
			singular = firstArg(args, "quotation-page", "quote-page", "qp"),
			location = firstArg(args, "quotation-location", "quote-location", "quote-loc", "quote-at"),
			spacing = "&#32;"
		}
	end

	local zws = ""
	if wrapTest[string.ulower(args.wrap or '')] then
		zws = "&#8203;" --zero-width space
	end

	return r._superscript{
		prefix = prefix,
		suffix = suffix,
		pp = pp,
		leadin = leadin,
		["where"] = where,
		["sup-where"] = sup_where,
		["quote-where"] = quote_where,
		quote = firstArg(args, "quotation", "quote", "q"),
		language = firstArg(args, "quotation-language", "quote-language",
			"quotation-lang", "quote-lang", "ql", "language", "lang", "l"),
		translation = firstArg(args, "translation-quotation", "trans-quotation",
			"translation-quote", "trans-quote", "tq", "translation", "trans",
			"t", "xlat"),
		["wrap"] = args.wrap
	} .. zws
end
function rp.rp(frame)
	return rp._rp(getArgs(frame), frame)
end

return {
	[''] = r.r,
	r = r.r,
	_r = r._r,
	rp = rp.rp,
	_rp = rp._rp,
	ref = r.ref,
	_ref = r._ref,
	where = r.where,
	_where = r._where,
	details = r.details,
	_details = r._details,
	langcode = r.langcode,
	_langcode = r._langcode,
	superscript = r.superscript,
	_superscript = r._superscript
}