Modul:Citation: Unterschied zwischen den Versionen

Aus skandinavien-wiki.net
K (Modifikation cleanup)
KKeine Bearbeitungszusammenfassung
Zeile 534: Zeile 534:
title = makeTitle( args.title, args.volume, args.articleUrl, '' )
title = makeTitle( args.title, args.volume, args.articleUrl, '' )
editor = makeAuthor( '', args.editor )
editor = makeAuthor( '', args.editor )
collection = makeTitle( args.collection, args.volume, args.articleUrl, '' )
collection = makeTitle( args.collection, args.volume, args.url, '' )


return author .. title .. formatters.tiIn .. editor .. collection
return author .. title .. formatters.tiIn .. editor .. collection

Version vom 23. März 2020, 20:13 Uhr

Die Dokumentation für dieses Modul kann unter Modul:Citation/doc erstellt werden

-- documentation
local scrollGallery = {
	suite  = 'Citation',
	serial = '2020-03-23',
}

-- module import
local cx = require( 'Module:Check isxn' )
local li = require( 'Module:LinkISBN' )
local uc = require( 'Module:UrlCheck' )
local yn = require( 'Module:Yesno' )

-- module variable
local ci = {}

-- global variables
local refTypes = {
	book       = { 'book', 'Buch' },
	map        = { 'map', 'Karte' },
	collection = { 'collection', 'Sammelwerk' },
	journal    = { 'journal', 'Zeitschrift' },
	newspaper  = { 'newspaper', 'Zeitung' }
}

local params = {
	type       = { 'type', 'Typ' },
	author     = { 'Autor', COinS = 'rft.au' },
	editor     = { 'Herausgeber', 'Hrsg' },
	title      = { 'Titel', COinS = 'rft.title' },
	chapter    = { 'Kapitel', types = 'book', COinS = 'rft.atitle' },
	collection = { 'Sammelwerk', types = 'collection' },
	journal    = { 'Zeitschrift', 'Sammelwerk', types = 'journal', COinS = 'rft.jtitle' },
	newspaper  = { 'Zeitung', 'Sammelwerk', types = 'newspaper', COinS = 'rft.jtitle' },
	abbr       = { 'Abk', types = { 'collection', 'journal', 'newspaper' } },
	url        = { 'Online', 'URL' },
	articleUrl = { 'Onlineaufsatz', 'Aufsatz-URL', types = { 'collection', 'journal', 'newspaper' } },
	jstor      = { 'JSTOR', types = { 'journal', 'newspaper' } },
	KBytes     = { 'KBytes', 'kBytes', 'kbytes' },
	accessDate = { 'Zugriff', 'Abruf' },
	scale      = { 'Maßstab', types = 'map' },
	place      = { 'Ort', COinS = 'rft.place' },
	publisher  = { 'Verlag', types = { 'book', 'map', 'collection' }, COinS = 'rft.pub' },
	date       = { 'Datum', 'Jahr', COinS = 'rft.date' },
	edition    = { 'Auflage', types = { 'book', 'map', 'collection' }, COinS = 'rft.edition' },
	volume     = { 'Band', COinS = 'rft.volume' },
	issue      = { 'Ausgabe', 'Nummer', 'Heft', types = { 'journal', 'newspaper' }, COinS = 'rft.issue' },
	pages      = { 'Seite', 'Seiten', types = { 'book', 'collection', 'journal', 'newspaper' }, COinS = 'rft.pages' },
	columns    = { 'Spalten', types = { 'book', 'collection', 'journal', 'newspaper' }, COinS = 'rft.pages' },
	extent     = { 'Umfang', 'Seitenanzahl', types = { 'book', 'collection', 'map' } },
	series     = { 'Serie', 'Reihe', types = { 'book', 'collection', 'map' }, COinS = 'rft.series' },
	series2    = { 'Serie2', 'Reihe2', types = { 'book', 'collection', 'map' } },
	series3    = { 'Serie3', 'Reihe3', types = { 'book', 'collection', 'map' } },
	isbn       = { 'ISBN', types = { 'book', 'collection', 'map', 'journal' }, COinS = 'rft.isbn' },
	dnb        = { 'DNB', types = { 'book', 'collection', 'map' } },
	oclc       = { 'OCLC', types = { 'book', 'collection', 'map' }, COinS_id = 'info:oclcnum' },
	issn       = { 'ISSN', COinS = 'rft.issn' },
	doi        = { 'DOI', COinS_id = 'info:doi' },
	language   = { 'Sprache' },
	comment    = { 'Kommentar' },
	noError    = { 'noError', 'noerror', 'keinFehler', 'kein Fehler' }
}

local formatters = {
	auAuthor = '%s: ',
	auEditor = '%s (Hrsg.)',
	auAuthorEditor = '%s ; %s',
	tiAll = "%s. ",
	tiTitle = "''%s''",
	tiVolume = "''%s''; Bd. %s",
	tiScale = 'Maßstab: %s. ',
	tiIn = 'In: ',
	tiChapter = "Kapitel ''%s''",
	puAll = '%s.',
	puPlaceDate = '%s, %s',
	puPlacePub = '%s: %s',
	puDateEdition = '%s (%d. Auflage)',
	addSeries = '(%s)',
	addPages = 'S. %s',
	addColumns = 'Sp. %s',
	addDelimiter1 = ', ',
	addDelimiter2 = '; ',
	addDoi = '[[w:Digital Object Identifier|doi]]:%s',
	addLanguage = ' (%s)',
	addComment = ' %s',
	prPlace = ' <%s>',
	prAbbr = ' (%s)',
	prVolume = 'Bd. %s',
	prIssue = 'Nr. %s',
	prVolIssue = '%s,%s',
	prVolYear = '%s (%s)',
	nsVolume = 'Jg. %s',
	nsNrOfDay = '%s vom %s',
	exPages = '%s Seiten',
	dbDnb = '[[w:Deutsche Nationalbibliothek|DNB]] [http://d-nb.info/%s %s]',
	dbOclc = '[[w:Online Computer Library Center|OCLC]] [https://worldcat.org/oclc/%s %s]',
	dbIssn = '[[w:Internationale Standardnummer für fortlaufende Sammelwerke|ISSN]] [http://zdb-katalog.de/list.xhtml?t=iss%3D%22xx1xx%22&key=cql xx1xx]',
	dbJstor = '[[w:JSTOR|JSTOR]] [https://www.jstor.org/stable/%s %s]',
	wbAccess = 'Internetabruf am %s',
	wbKBytes = 'Dateigröße %s KByte'
}

local texts = {
	noTitel       = '<span class="error">Fehlender Titel</span>',
	noURL         = '<span class="error">Ungültige URL</span>[[Category:Literatur: ungültige URL]]',
	unknownParam  = '<span class="error">Ungültiger Parameter: %s</span>[[Category:Literatur: ungültige Parameter]]',
	unknownParams = '<span class="error">Ungültige Parameter: %s</span>[[Category:Literatur: ungültige Parameter]]',
	unknownTitle  = '[[Category:Literatur: fehlender Titel]]',
	unknownPeriodical = '[[Category:Literatur: fehlender Titel eines Periodikums]]',
	wrongDate     = '<span class="error">Ungültiges Datum</span>[[Category:Literatur: ungültiges Datum]]',
	wrongIssn     = '<span class="error">Ungültige ISSN</span>[[Category:Seiten mit ISSN-Fehlern]]',
	wrongType     = '<span class="error">Ungültiger Typ</span>[[Category:Literatur: ungültiger Typ]]',
	wrongValue    = '<span class="error">Ungültiger Wert</span>[[Category:Literatur: ungültiger Wert]]'
}

local errorMsgs = {}
local dateFormat = ''

-- helper functions
local function isSet( param )
	return param and param ~= '';
end

local function addErrorMsg( msg )
	table.insert( errorMsgs, msg )
end

local function getFirst( s, delimiter )
	local at = s:find( delimiter )
	if at then
		s = mw.text.trim( s:sub( 1, at - 1 ) )
	end
	return s
end

-- check if table contains the value
local function inArray( tab, val )
	if type( tab ) == 'string' then
		return tab == val
	end

	local index, value
	for index, value in ipairs( tab ) do
		if value == val then
			return true
		end
	end

	return false
end

-- convert type values if translated
-- local function getRefType( t )
local function getRefType( t )
    local key, tab
    for key, tab in pairs( refTypes ) do
        if inArray( tab, t ) then
            t = key
            break
        end
    end
    return t
end

-- returns a single value from frame argument table
local function getArgValue( param, args )
	value = '', k, v
	if params[ param ] then
		for k, v in ipairs( params[ param ] ) do
			if isSet( args[ v ] ) then
				value = args[ v ]
				break
			end
		end
	end
	return value
end

-- string cleanup
local function cleanupParameters( s, all )
	if not s or s == '' then
		return s
	end
	s = s:gsub( '[\009\010\013]', ' ' ) -- horizontal tab, line feed, carriage return
	s = s:gsub( '[%z%c]', '' ) -- control characters
	s = s:gsub( '&nbsp;', ' ' );
	s = s:gsub( '\226\128\138', ' ' ); -- hair space
	s = mw.ustring.gsub( s, '[\226\128\141\226\128\139\194\173]', '' ); -- zero-width joiner, zero-width space, soft hyphen
	s = mw.ustring.gsub( s, '%.%.%.', '…' )
	s = mw.ustring.gsub( s, '%.%.', '‥' )
	s = mw.ustring.gsub( s, '<br%s*/*>', '' )
	s = mw.ustring.gsub( s, '</*p%s*/*>', '' )
	if all then
		s = mw.ustring.gsub( s, '%[%[[^%[%]]*|([^%[%]]*)%]%]', '%1' ) -- MediaWiki links
		s = mw.ustring.gsub( s, '%[%[([^%[%]]*)%]%]', '%1' )
	end
	return mw.ustring.gsub( s, '</*span%s*/*>', '' )
end

-- check for possible arguments against params table
local function checkParams( frameArgs )
	local args = {}, key, key2, ok, value, value2
	local complete = {}
	local wrongParams = {}
	local aType = getRefType( getArgValue( 'type', frameArgs ) )

	for key, value in pairs( params ) do
		if not value.types or inArray( value.types, aType ) then
			for key2, value2 in ipairs( value ) do
				complete[ value2 ] = key
				args[ key ] = args[ key ] or
					cleanupParameters( frameArgs[ value2 ], key ~= 'comment' )
			end
			args[ key ] = args[ key ] or ''
		end
	end
	-- no missing items
	for key, value in pairs( params ) do
		if not args[ key ] then
			args[ key ] = ''
		end
	end

	for key, value in pairs( frameArgs ) do
		if not complete[ key ] then
			table.insert( wrongParams, key )
		end
	end
	if #wrongParams == 1 then
		addErrorMsg( mw.ustring.format( texts.unknownParam, table.concat( wrongParams, ', ' ) ) )
	elseif #wrongParams > 0 then
		addErrorMsg( mw.ustring.format( texts.unknownParams, table.concat( wrongParams, ', ' ) ) )
	end
	return args
end

local function getPageNumbers( pages )
	if not pages then
		return ''
	end
	pages = ( '' .. pages ):gsub( '–', '-' ); -- replace endashes with hyphens
	return pages:gsub( '&%w+;', '-' ); -- replace html entities with hyphens
end

local function checkValues( args )
	local i, key, value

	args.pages = getPageNumbers( args.pages )
	args.columns = getPageNumbers( args.columns )

	args.noError = yn( args.noError, false )
	if args.noError then
		args.noError = 'true'
	else
		args.noError = 'false'
	end

	if isSet( args.date ) then
		if args.date:match( '^[12]%d%d%d%-[01]?%d%-[0123]?%d$' ) then
			dateFormat = 'j. F Y'
		elseif args.date:match( '^[12]%d%d%d%-[01]?%d$' ) then
			dateFormat = 'M Y'
		elseif args.date:match( '^[12]%d%d%d$' ) then
			dateFormat = 'Y'
		else
			args.date = args.date:match( '%d+' ) or ''
			if isSet( args.date ) then
				i = tonumber( args.date )
				if i >= 1000 and i < 2100 then
					dateFormat = 'Y'
				else
					args.date = ''
					addErrorMsg( texts.wrongDate )
				end
			end
		end
	end
	if isSet( args.accessDate ) and
		not args.accessDate:match( '^20%d%d%-[01]?%d%-[0123]?%d$' ) then
		args.accessDate = ''
		addErrorMsg( texts.wrongDate )
	end

	i = 0
	for key, value in ipairs( { 'url', 'articleUrl' } ) do
		if isSet( args[ value ] ) and uc.isUrl( args[ value ] ) > 2 then
			args[ value ] = ''
			i = i + 1
		end
	end
	if i > 0 then
		addErrorMsg( texts.noURL )
	end

	i = 0
	for key, value in ipairs( { 'dnb', 'oclc', 'jstor', 'KBytes' } ) do
		if isSet( args[ value ] ) and not args[ value ]:match( '^%d+$' ) then
			args[ value ] = ''
			i = i + 1
		end
	end
	if i > 0 then
		addErrorMsg( texts.wrongValue )
	end

	args.edition = args.edition:match( '%d+' ) or ''
	if args.edition == '1' then
		args.edition = ''
	end

	if args.type ~= 'map' then
		args.scale = ''
	end
end

local function makeAuthor( author, editor )
	if isSet( editor ) then
		editor = mw.ustring.format( formatters.auEditor, editor )
	end
	if isSet( author ) and isSet( editor ) then
		author = mw.ustring.format( formatters.auAuthorEditor, author, editor )
	elseif not isSet( author ) and isSet( editor ) then
		author = editor
	end
	if isSet( author ) then
		return mw.ustring.format( formatters.auAuthor, author )
	else
		return ''
	end
end

local function makeTitle( title, volume, url, scale )
	if not isSet( title ) then
		title = texts.noTitle
		addErrorMsg( texts.unknownTitle )
	end
	if isSet( url ) then
		title = '[' .. url .. ' ' .. title .. ']'
	end
	
	if isSet( volume ) then
		title = mw.ustring.format( formatters.tiVolume, title, volume )
	else
		title = mw.ustring.format( formatters.tiTitle, title )
	end
	title = mw.ustring.format( formatters.tiAll, title )
	if isSet( scale ) then
		title = title .. mw.ustring.format( formatters.tiScale, scale )
	end
	return title
end

local function makeDoiLink( doi )
	doi = mw.ustring.gsub( doi, 'https?://doi.org/', '' )
	return '[' .. 'https://doi.org/' .. mw.uri.encode( doi )
		.. ' ' .. doi .. ']'
end

local function makeIssnLink( issn, noError )
	local text = ''
	if noError ~= 'true' then
		text = texts.wrongIssn
	end
	return formatters.dbIssn:gsub( 'xx1xx', issn )
		.. cx.check_issn( { args = { [ 1 ] = issn, error = text } } )
end

local function getDate( aDate, aFormat )
	local function formatDate( aDate, aFormat )
		return mw.getContentLanguage():formatDate( aFormat, aDate, true )
	end

	if aDate ~='' then
		local success, t;
		success, t = pcall( formatDate, aDate, aFormat )
		if success then
			return t
		else
			addErrorMsg( texts.wrongDate )
			return ''
		end
	else
		return ''
	end
end

local function makePublisher( args, tab )
	local theDate = ''
	if isSet( args.date ) then
		if isSet( dateFormat ) and dateFormat ~= 'Y' then
			dateFormat = 'M Y'
		end
		theDate = getDate( args.date, dateFormat )
	end

	local published = ''

	if isSet( theDate ) and isSet( args.edition ) then
		theDate = mw.ustring.format( formatters.puDateEdition, theDate, args.edition )
	end
	if isSet( args.place ) and isSet( args.publisher ) then
		published = mw.ustring.format( formatters.puPlacePub, args.place, args.publisher )
	elseif isSet( args.place ) then
		published = args.place
	elseif isSet( args.publisher ) then
		published = args.publisher
	end
	if not isSet( published ) then
		published = theDate
	elseif isSet( theDate ) then
		published = mw.ustring.format( formatters.puPlaceDate, published, theDate )
	end
	if isSet( published ) then
		table.insert( tab, published )
	end
end

local function makeSeries( args, tab )
	local key, value
	for key, value in ipairs( { 'series', 'series2', 'series3' } ) do
		if isSet( args[ value ] ) then
			table.insert( tab, mw.ustring.format( formatters.addSeries, args[ value ] ) )
		end
	end
end

local function makeIsbn( args, tab )
	if isSet( args.isbn ) then
		table.insert( tab,
			li._linkISBNSet( { isbn = args.isbn, noerror = args.noError } ) )
	elseif isSet( args.dnb ) then
		table.insert( tab, mw.ustring.format( formatters.dbDnb, args.dnb, args.dnb ) )
	elseif isSet( args.oclc ) then
		table.insert( tab, mw.ustring.format( formatters.dbOclc, args.oclc, args.oclc ) )
	end
	if isSet( args.issn ) then
		table.insert( tab, makeIssnLink( args.issn, args.noError ) )
	end
end

local function makePages( args, tab )
	if isSet( args.pages ) then
		table.insert( tab,
			mw.ustring.format( formatters.addPages, args.pages:gsub( '-', '–' ) ) )
	end
	if isSet( args.columns ) then
		table.insert( tab,
			mw.ustring.format( formatters.addColumns, args.columns:gsub( '-', '–' ) ) )
	end
end

local function makeDoi( args, tab )
	if isSet( args.extent ) then
		if args.extent:match( '^%d+$' ) then
			args.extent = mw.ustring.format( formatters.exPages, args.extent )
		end
		table.insert( tab, args.extent )
	end
	if isSet( args.doi ) then
		table.insert( tab,
			mw.ustring.format( formatters.addDoi, makeDoiLink( args.doi ) ) )
	end
	if isSet( args.jstor ) then
		table.insert( tab,
			mw.ustring.format( formatters.dbJstor, args.jstor, args.jstor ) )
	end
end

local function makeWebInfo( args, tab )
	if isSet( args.url ) or isSet( args.articleUrl ) then
		if isSet( args.accessDate ) then
			args.accessDate = getDate( args.accessDate, 'j. F Y' )
			if isSet( args.accessDate ) then
				table.insert( tab,
					mw.ustring.format( formatters.wbAccess, args.accessDate ) )
			end
		end
		if isSet( args.KBytes ) then
			table.insert( tab,
				mw.ustring.format( formatters.wbKBytes, args.KBytes ) )
		end
	end
end

local function makeLanguageComment( args, result )
	if isSet( args.language ) then
		result = result .. mw.ustring.format( formatters.addLanguage, args.language )
	end
	if result ~= '' then
		result = mw.ustring.format( formatters.puAll, result )
	end
	if isSet( args.comment ) then
		result = result .. mw.ustring.format( formatters.addComment, args.comment )
	end
	return result
end

local function makePublished( args )
	result = {}
	makePublisher( args, result )
	makeSeries( args, result )
	makeIsbn( args, result )
	if isSet( args.chapter ) then
		table.insert( result, mw.ustring.format( formatters.tiChapter, args.chapter ) )
	end
	makePages( args, result )
	if #result > 0 then
		result = { table.concat( result, formatters.addDelimiter1 ) }
	end

	makeDoi( args, result )
	makeWebInfo( args, result )
	result = table.concat( result, formatters.addDelimiter2 )

	return makeLanguageComment( args, result )
end

local function makeBook( args )
	local author, title
	
	if args.type == 'map' or args.type == 'book' then
		author = makeAuthor( args.author, args.editor )
		title = makeTitle( args.title, args.volume, args.url, args.scale )
	else
		author = makeAuthor( '', args.editor )
		title = makeTitle( args.collection, args.volume, args.url, args.scale )
	end
	return author .. title .. makePublished( args )
end

local function makeCollection( args )
	local author, collection, editor, title

	author = makeAuthor( args.author, '' )
	title = makeTitle( args.title, args.volume, args.articleUrl, '' )
	editor = makeAuthor( '', args.editor )
	collection = makeTitle( args.collection, args.volume, args.url, '' )

	return author .. title .. formatters.tiIn .. editor .. collection
		.. makePublished( args )
end

local function makeJournalTitle( args )
	local title
	if args.type == 'journal' then
		title = args.journal
	else
		title = args.newspaper
	end
	if title == '' then
		title = texts.noTitel
		addErrorMsg( texts.unknownPeriodical )
	else
		title = mw.ustring.format( formatters.tiTitle, title )
	end
	if isSet( args.url ) then
		title = '[' .. args.url .. ' ' .. title .. ']'
	end
	if isSet( args.place ) then
		title = title .. mw.ustring.format( formatters.prPlace, args.place )
	end
	if isSet( args.abbr ) then
		title = title .. mw.ustring.format( formatters.prAbbr, args.abbr )
	end
	return title
end

local function makeJournalInfo( args, tab )
	local year = ''
	if isSet( args.date ) then
		year = getDate( args.date, dateFormat )
	end
	local volume = ''
	if isSet( args.volume ) then
		volume = mw.ustring.format( formatters.prVolume, args.volume )
		if isSet( args.issue ) then
			volume = mw.ustring.format( formatters.prVolIssue, volume, args.issue )
		end
		if year ~= '' then
			volume = mw.ustring.format( formatters.prVolYear, volume, year )
		end
	else
		if isSet( args.issue ) then
			volume = mw.ustring.format( formatters.prIssue, args.issue )
			if year ~= '' then
				volume = mw.ustring.format( formatters.prVolYear, volume, year )
			end
		else
			volume = year
		end
	end
	if volume ~= '' then
		table.insert( tab, volume )
	end
end

local function makeNewspaperInfo( args, tab )
	if isSet( args.volume ) then
		table.insert( tab,
			mw.ustring.format( formatters.nsVolume, args.volume ) )
	end

	day = ''
	if isSet( args.date ) then
		if dateFormat == 'j. F Y' then
			day = getDate( args.date, 'l, j. F Y' )
		else
			addErrorMsg( texts.wrongDate )
		end
	end

	local issue = ''
	if isSet( args.issue ) then
		issue = mw.ustring.format( formatters.prIssue, args.issue )
		if day ~= '' then
			issue = mw.ustring.format( formatters.nsNrOfDay, issue, day )
		end
	else
		issue = day
	end
	if issue ~= '' then
		table.insert( tab, issue )
	end
end

local function makePeriodical( args )
	local result = { makeAuthor( args.author, '' )
		.. makeTitle( args.title, '', args.articleUrl, '' ) .. formatters.tiIn
		.. makeJournalTitle( args ) }

	makeIsbn( args, result )
	if args.type == 'journal' then
		makeJournalInfo( args, result )
	else
		makeNewspaperInfo( args, result )
	end
	makePages( args, result )
	makeDoi( args, result )
	makeWebInfo( args, result )
	result = table.concat( result, formatters.addDelimiter1 )

	return makeLanguageComment( args, result )
end

local function prepareForCOinS( args )
	args.pages = args.pages:match( '%d+%s*%-%s*%d+' )
		or args.pages:match( '%d+' ) or ''
	args.pages = args.pages:gsub( ' ', '' )
	args.columns = args.columns:match( '%d+%s*%-%s*%d+' )
		or args.columns:match( '%d+' ) or ''
	args.columns = args.columns:gsub( ' ', '' )
	if isSet( args.pages ) and isSet( args.columns ) then
		args.columns = ''
	end

	-- only first author
	args.author = getFirst( args.author, ';' )
	local count
	_,count = args.author:gsub( ',', ',' )
	if count > 1 then
		args.author = getFirst( args.author, ',' )
	end

	args.isbn = getFirst( args.isbn, ',' )
end

local function makeCOinS( args )
	local rft = {}, key, value

	local function insertCOinS( key, value )
		table.insert( rft, key .. '=' .. mw.uri.encode( '' .. value ) )
	end

	for key, value in pairs( params ) do
		if isSet( args[ key ] ) then
			if value.COinS  then
				insertCOinS( value.COinS, args[ key ] )
			elseif value.COinS_id then
				-- ...
			end
		end
	end

	if next( rft ) then
		if args.type == 'book' or args.type == 'map' or args.type == 'collection' then
			if args.type == 'collection' then
				insertCOinS( 'rft.atitle=', args.title )
				insertCOinS( 'rft.btitle=', args.collection )
				table.insert( rft, 1, 'rft.genre=bookitem' )
			else
				insertCOinS( 'rft.btitle=', args.title )
				table.insert( rft, 1, 'rft.genre=book' )
			end
			table.insert( rft, 1, 'rft_val_fmt=' .. mw.uri.encode( 'info:ofi/fmt:kev:mtx:book' ) )
		else
			table.insert( rft, 1, 'rft.genre=journal' )
			table.insert( rft, 1, 'rft_val_fmt=' .. mw.uri.encode( 'info:ofi/fmt:kev:mtx:journal' ) )
			if args.type == 'journal' then
				insertCOinS( 'rft.jtitle=', args.journal )
			else
				insertCOinS( 'rft.jtitle=', args.newspaper )
			end
			insertCOinS( 'rft.atitle=', args.title )
		end
		table.insert( rft, 1, 'ctx_ver=Z39.88-2004' )
		rft = table.concat( rft, '&' )
		return '<span title="' .. rft .. '" class="Z3988"></span>'
	end
	return ''
end

-- remove adjoining punctuation marks
local function finalCleanup( s )
	s = mw.ustring.gsub( s, '%.+%.', '.' )
	s = mw.ustring.gsub( s, '([!%?])(%s%.+)', '%1' )
	return mw.ustring.gsub( s, '([,;:])(%s%.+)', '.' )
end

local function makeCitation( frameArgs )
	local args, citation
	args = checkParams( frameArgs )
	checkValues( args )

	if args.type == 'map' or args.type == 'book' then
		citation = makeBook( args )
	elseif args.type == 'collection' then
		citation = makeCollection( args )
	elseif args.type == 'journal' or args.type == 'newspaper' then
		citation = makePeriodical( args )
	else
		citation = texts.wrongType
	end

	citation = finalCleanup( citation )
	prepareForCOinS( args )

	return table.concat( errorMsgs, ' ' )
		.. '<cite style="font-style: normal;" class="citation ' .. args.type
		.. ' printNoLink">' .. citation .. '</cite>' .. makeCOinS( args )
end

function ci.book( frame )
	local args = frame:getParent().args, ok
	args.type = 'book'
	return makeCitation( args )
end

function ci.map( frame )
	local args = frame:getParent().args
	args.type = 'map'
	return makeCitation( args )
end

function ci.collection( frame )
	local args = frame:getParent().args
	args.type = 'collection'
	return makeCitation( args )
end

function ci.journal( frame )
	local args = frame:getParent().args
	args.type = 'journal'
	return makeCitation( args )
end

function ci.newspaper( frame )
	local args = frame:getParent().args
	args.type = 'newspaper'
	return makeCitation( args )
end

function ci.citation( frame )
	local args = frame:getParent().args

	args.type = getRefType( getArgValue( 'type', args ) )
	if not isSet( aType ) then
		if getArgValue( 'scale', args ) ~= '' then
			args.type = 'map'
		elseif getArgValue( 'collection', args ) ~= '' then
			args.type = 'collection'
		elseif getArgValue( 'journal', args ) ~= '' then
			args.type = 'journal'
		elseif getArgValue( 'newspaper', args ) ~= '' then
			args.type = 'newspaper'
		else
			args.type = 'book'
		end
	end
	return makeCitation( args )
end

return ci