Modul:Citation

Aus Wikivoyage
Zur Navigation springen Zur Suche springen
Template-info.png Dokumentation für das Modul Citation[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]

Anwendung

Das Modul wird direkt von den Vorlagen {{Buch}}, {{Karte}}, {{Sammelwerk}}, {{Zeitschrift}} und {{Zeitung}} aufgerufen. Parameterbeschreibung siehe dort.

Benötigte weitere Module

Dieses Modul benötigt folgende weitere Module: Check isxn • Citation/COinS • Citation/i18n • Citation/utilities • LinkISBN • UrlCheck • Yesno
Hinweise
-- documentation
local citation = {
	suite  = 'Citation',
	serial = '2020-05-16',
}

-- module import
local cu = require( 'Module:Citation/utilities' )
local cc = require( 'Module:Citation/COinS' )
local ci = require( 'Module:Citation/i18n' )
local cx = require( 'Module:Check isxn' )
local li = require( 'Module:LinkISBN' )
local uc = require( 'Module:UrlCheck' )
local yn = require( 'Module:Yesno' )

-- module variable
local ct = {}

-- check for valid arguments against params table
local function getValidArgs( frameArgs )
	local args = {}
	local complete = {}
	local wrongParams = {}
	local aType = frameArgs.type

	for key, value in pairs( ci.params ) do
		if not value.types or cu.inArray( value.types, aType ) then
			for key2, value2 in ipairs( value ) do
				complete[ value2 ] = key
				args[ key ] = args[ key ] or
					cu.parameterCleanup( frameArgs[ value2 ] )
			end
			args[ key ] = args[ key ] or ''
		end
	end
	-- no missing items
	for key, value in pairs( ci.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
		cu.addErrorMsg( cu.formatItem( wrongParams[ 1 ], ci.texts.unknownParam ) )
	elseif #wrongParams > 0 then
		cu.addErrorMsg( cu.formatItem( table.concat( wrongParams, ', ' ), ci.texts.unknownParams ) )
	end
	return args
end

-- check parameter values
local function checkValues( args )
	local wrong = {}
	local aType = args.type
	local i

	if aType == 'web' and not cu.isSet( args.title ) and not cu.isSet( args.url ) then
		title = ci.texts.noTitle
		cu.addErrorMsg( ci.texts.noTitleUrl )
	elseif not cu.isSet( args.title ) then
		title = ci.texts.noTitle
		cu.addErrorMsg( ci.texts.unknownTitle )
	end

	args.pages = cu.cleanupPageNumbers( args.pages )
	args.columns = cu.cleanupPageNumbers( args.columns )

	if ( cu.getNumber( args.KBytes ) / 1024 > 100 ) or
		( cu.getNumber( args.MBytes ) > 100 ) then
		cu.addErrorMsg( ci.texts.moreThan100 )
	end
	if cu.isSet( args.KBytes ) then
		args.KBytes = args.KBytes:gsub( '%s*%[sic!%]', '' )
	end
	if cu.isSet( args.MBytes ) then
		args.MBytes = args.MBytes:gsub( '%s*%[sic!%]', '' )
	end
	if cu.isSet( args.KBytes ) and cu.isSet( args.MBytes ) then
		args.MBytes = ''
		cu.addErrorMsg( ci.texts.KBytesMBytes )
	end

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

	-- containing date format detected from args.date
	args.dateFormat = ''
	if cu.isSet( args.date ) then
		if args.date:match( '^[12]%d%d%d%-[01]?%d%-[0123]?%d$' ) then
			args.dateFormat = 'j. F Y'
		elseif args.date:match( '^[12]%d%d%d%-[01]?%d$' ) then
			args.dateFormat = 'M Y'
		elseif args.date:match( '^[12]%d%d%d$' ) then
			args.dateFormat = 'Y'
		else
			args.date = args.date:match( '%d+' ) or ''
			if cu.isSet( args.date ) then
				i = tonumber( args.date )
				if i >= 1000 and i < 2100 then
					args.dateFormat = 'Y'
				else
					args.date = ''
					cu.addErrorMsg( ci.texts.wrongDate )
				end
			end
		end
	end
	for key, value in ipairs( { 'accessDate', 'archiveDate' } ) do
		if cu.isSet( args[ value ] ) and
			not args[ value ]:match( '^20%d%d%-[01]?%d%-[0123]?%d$' ) then
			args[ value ] = ''
			cu.addErrorMsg( ci.texts.wrongDate )
		end
	end

	for key, value in ipairs( { 'url', 'archiveUrl' } ) do
		if cu.isSet( args[ value ] ) and
			uc.isUrl( args[ value ], ci.skipPathCheck ) > 2 then
			args[ value ] = ''
			cu.addErrorMsg( ci.texts.noURL )
		end
	end
	args.urlStatus = cu.getKey( args.urlStatus, ci.urlStatusTable )
	if not cu.isSet( args.urlStatus ) and cu.isSet( args.archiveUrl ) then
		args.urlStatus = 'dead'
	elseif not cu.isSet( args.urlStatus ) then
		args.urlStatus = 'live'
	end
	args.isArchived = cu.isSet( args.archiveUrl )
	if args.urlStatus == 'dead' or args.urlStatus == 'usurped' then
		args.originalUrl = args.url
		args.url = args.archiveUrl
		args.archiveUrl = ''
	end

	for key, value in ipairs( { 'dnb', 'oclc', 'jstor', 'KBytes' } ) do
		if cu.isSet( args[ value ] ) and not args[ value ]:match( '^%d+$' ) then
			args[ value ] = ''
			table.insert( wrong, value )
		end
	end

	if cu.isSet( args.doi ) and not mw.ustring.match( args.doi, '^10%.%d+/.+$' ) then
		args.doi = ''
		table.insert( wrong, 'doi' )
	end

	if cu.isSet( args.edition ) and args.edition:match( '^%d+%.*$' ) then
		args.edition = args.edition:gsub( '%.', '' )
		if args.edition == '1' then
			args.edition = ''
		end
	end

	if cu.isSet( args.type ) and args.type ~= 'map' then
		args.scale = ''
	end

	if cu.isSet( args.access ) then
		args.access = cu.getKey( args.access, ci.accessTypes )
		if args.access == '' then
			cu.addErrorMsg( ci.texts.accesswrong )
		elseif not cu.isSet( args.url ) and not cu.isSet( args.archiveUrl ) then
			cu.addErrorMsg( ci.texts.accessNoUrl )
		end
	end

	if #wrong == 1 then
		cu.addErrorMsg( cu.formatItem( wrong[ 1 ], ci.texts.wrongValue ) )
	elseif #wrong > 1 then
		cu.addErrorMsg( cu.formatItem( table.concat( wrong, ', ' ), ci.texts.wrongValues ) )
	end
end

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

-- make author part
local function makeAuthor( author, editor )
	editor = cu.formatItem( editor, ci.formatters.auEditor )
	if cu.isSet( author ) and cu.isSet( editor ) then
		author = cu.formatItem2( author, editor, ci.formatters.auAuthorEditor )
	elseif not cu.isSet( author ) and cu.isSet( editor ) then
		author = editor
	end
	return cu.formatItem( author, ci.formatters.auAuthor )
end

-- make title part
local function makeTitle( title, volume, addition, url, scale )
	if not cu.isSet( title ) then
		title = ci.texts.noTitle
		cu.addErrorMsg( ci.texts.unknownTitle )
	else
		title = title:gsub( "''+", '' ) -- remove multiple apostrophes
	end
	if cu.isSet( url ) then
		title = cu.makeLink( url, title:gsub( '[%[%]]', '' ) )
	end

	if cu.isSet( volume ) then
		title = cu.formatItem2( title, volume, ci.formatters.tiVolume )
	else
		title = cu.formatItem( title, ci.formatters.tiTitle )
	end
	if cu.isSet( addition ) then
		title = cu.formatItem2( title, addition, ci.formatters.tiAddition )
	end
	return cu.formatItem( title, ci.formatters.tiAll )
		.. cu.formatItem( scale, ci.formatters.tiScale )
end

-- make publisher part for books
local function makePublisher( args, tab )
	local theDate = ''
	if cu.isSet( args.date ) then
		if cu.isSet( args.dateFormat ) and args.dateFormat ~= 'Y' then
			args.dateFormat = 'M Y'
		end
		theDate = cu.getDate( args.date, args.dateFormat, ci.texts.wrongDate )
	end

	local published = ''

	if cu.isSet( args.edition ) then
		if args.edition:match( '^%d+$' ) then
			theDate = cu.formatItem2( theDate, args.edition, ci.formatters.puDateEditionNum )
		else
			theDate = cu.formatItem2( theDate, args.edition, ci.formatters.puDateEdition )
		end
	end

	if cu.isSet( args.place ) and cu.isSet( args.publisher ) then
		published = cu.formatItem2( args.place, args.publisher, ci.formatters.puPlacePub )
	elseif cu.isSet( args.place ) then
		published = args.place
	elseif cu.isSet( args.publisher ) then
		published = args.publisher
	end
	if not cu.isSet( published ) then
		published = theDate
	elseif cu.isSet( theDate ) then
		published = cu.formatItem2( published, theDate, ci.formatters.puPlaceDate )
	end
	cu.insertItem( tab, published )
end

local function makeIsbn( args, tab )
	if cu.isSet( args.isbn ) then
		table.insert( tab,
			li._linkISBNSet( { isbn = args.isbn, ignoreError = args.ignoreError } ) )
	elseif cu.isSet( args.dnb ) then
		cu.insertItem2( tab, args.dnb, args.dnb, ci.formatters.dbDnb )
	elseif cu.isSet( args.oclc ) then
		cu.insertItem2( tab, args.oclc, args.oclc, ci.formatters.dbOclc )
	end
	if cu.isSet( args.issn ) then
		table.insert( tab, makeIssnLink( args.issn, args.ignoreError ) )
	end
	if cu.isSet( args.eissn ) then
		table.insert( tab, makeIssnLink( args.eissn, args.ignoreError ) )
	end
end

local function formatPages( s )
	s = mw.ustring.gsub( s, '-', '–' )
	return mw.ustring.gsub( s, ci.formatters.addPagesSeq, '&nbsp;%1' )
end

local function makePages( args, tab )
	cu.insertItem( tab, formatPages( args.pages ), ci.formatters.addPages )
	cu.insertItem( tab, formatPages( args.columns), ci.formatters.addColumns )
end

local function makeDoi( args, tab )
	if cu.isSet( args.extent ) then
		if args.extent:match( '^%d+$' ) then
			args.extent = cu.formatItem( args.extent, ci.formatters.addExtent )
		end
		table.insert( tab, args.extent )
	end
	if cu.isSet( args.doi ) then
		cu.insertItem( tab, cu.makeDoiLink( args.doi ), ci.formatters.dbDoi )
	end
	cu.insertItem2( tab, args.jstor, args.jstor, ci.formatters.dbJstor )
end

local function makeWebInfo( args, tab )
	local kb
	if cu.isSet( args.url ) or cu.isSet( args.originalUrl ) or cu.isSet( args.archiveUrl ) then
		if cu.isSet( args.accessDate ) then
			args.accessDate = cu.getDate( args.accessDate, 'j. F Y', ci.texts.wrongDate )
			cu.insertItem( tab, args.accessDate, ci.formatters.wbAccess )
		end
		if cu.isSet( args.format ) then
			table.insert( tab, args.format:upper() )
		else
			for index, value in ipairs( { 'PDF', 'DOC', 'DOCX', 'RTF', 'ODT',
				'PPT', 'PPTX', 'XLS', 'XLSX' } ) do
				if cu.hasExtension( args.url, value ) then
					table.insert( tab, value )
					break
				end
				if cu.hasExtension( args.archiveUrl, value ) then
					table.insert( tab, value )
					break
				end
			end
		end
		if cu.isSet( args.KBytes ) then
			kb = tonumber( args.KBytes ) or 0
			if kb >= 1024 then
				cu.insertItem( tab,
					tostring( cu.round( kb / 1024, 3 ) ):gsub( '%.', ci.texts.decimalPoint ),
					ci.formatters.wbMBytes )
			else
				cu.insertItem( tab, args.KBytes, ci.formatters.wbKBytes )
			end
		elseif cu.isSet( args.MBytes ) then
			cu.insertItem( tab, args.MBytes, ci.formatters.wbMBytes )
		end
	end
end

local function makeArchived( args )
	local archived = ci.formatters.arArchived
	local original = ci.formatters.arOriginal
	local result = ''

	if cu.isSet( args.archiveUrl ) then
		archived = cu.makeLink( args.archiveUrl, archived )
	end
	if cu.isSet( args.originalUrl ) then
		original = cu.makeLink( args.originalUrl, original )
	end
	
	local archiveDay = '', result
	if cu.isSet( args.archiveDate ) then
		archiveDay = cu.getDate( args.archiveDate, 'l, j. F Y', ci.texts.wrongDate )
	end

	if archiveDay ~= '' then
		if args.isArchived then
			result = mw.ustring.format( ci.formatters.arArchiveDate, archived, original, archiveDay )
		else
			result = cu.formatItem( original, ci.formatters.arOffline )
		end
	else
		if cu.isSet( args.archiveDate ) then
			cu.addErrorMsg( ci.texts.wrongDate )
		end
		if args.isArchived then
			result = cu.formatItem2( archived, original, ci.formatters.arArchive )
		else
			result = cu.formatItem( original, ci.formatters.arOffline )
		end
	end
	return result
end

local function makeLanguageComment( args, result )
	local ok = true
	if cu.isSet( args.language ) then
		local parts = mw.text.split( args.language, ' ' )
		for i = 1, #parts, 1 do
			parts[ i ] = mw.text.trim( parts[ i ]:gsub( ',', '' ) )
			if parts[ i ]:match( '^%a%a%a?$' ) then
				parts[ i ] = mw.language.fetchLanguageName( parts[ i ],
					mw.language.getContentLanguage():getCode() )
				if parts[ i ] == '' then
					ok = false
					break
				end
			else
				ok = false
				break
			end
		end
		if ok and #parts > 0 then
			args.language = table.concat( parts, ', ' )
			args.language = cu.formatItem( args.language, ci.formatters.addInLanguage )
		end
	end
	result = result .. cu.formatItem( args.language, ci.formatters.addLanguage )
	result = cu.formatItem( result, ci.formatters.puAll )
	if cu.isSet( args.archiveUrl ) or cu.isSet( args.originalUrl ) 
		or args.urlStatus == 'usurped' then
		result = result .. makeArchived( args )
	end
	return result .. cu.formatItem( args.quote, ci.formatters.addQuote )
		.. cu.formatItem( args.comment, ci.formatters.addComment )
end

local function makePublished( args )
	local result = {}
	makePublisher( args, result )
	cu.insertItem( result, args.series, ci.formatters.tiSeries )
	makeIsbn( args, result )
	cu.insertItem( result, args.chapter, ci.formatters.tiChapter )
	makePages( args, result )
	if #result > 0 then
		result = { table.concat( result, ci.formatters.addDelimiter1 ) }
	end

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

	return makeLanguageComment( args, result )
end

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

local function makeCollection( args )
	local author = makeAuthor( args.author, '' )
	local title = makeTitle( args.title, '', '', args.url, '' )
	local editor = makeAuthor( '', args.editor )
	local collection = makeTitle( args.collection, args.volume, args.titleAddition, args.siteUrl, '' )

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

local function makeJournalTitle( args )
	if args.type == 'journal' then
		title = args.journal
	elseif args.type == 'newspaper' then
		title = args.newspaper
	else
		title = args.website
	end
	if not cu.isSet( title ) then
		if args.type ~= 'web' then
			title = ci.texts.noTitle
			cu.addErrorMsg( ci.texts.unknownPeriodical )
		end
	else
		title = title:gsub( "''+", '' ) -- remove multiple apostrophes
		title = cu.formatItem( title, ci.formatters.tiTitle )
		if cu.isSet( args.siteUrl ) then
			title = cu.makeLink( args.siteUrl, title:gsub( '[%[%]]', '' ) )
		end
		title = ci.formatters.tiIn .. title
			.. cu.formatItem( args.place, ci.formatters.prPlace )
			.. cu.formatItem( args.abbr, ci.formatters.prAbbr)
	end
	return title
end

local function makeJournalInfo( args, tab )
	local year = ''
	if cu.isSet( args.date ) then
		year = cu.getDate( args.date, args.dateFormat, ci.texts.wrongDate )
	end
	local volume = ''
	if cu.isSet( args.volume ) then
		volume = cu.formatItem( args.volume, ci.formatters.prVolume )
		if cu.isSet( args.issue ) then
			volume = cu.formatItem2( volume, args.issue, ci.formatters.prVolIssue )
		end
		if year ~= '' then
			volume = cu.formatItem2( volume, year, ci.formatters.prVolYear )
		end
	else
		if cu.isSet( args.issue ) then
			volume = cu.formatItem( args.issue, ci.formatters.prIssue )
			if year ~= '' then
				volume = cu.formatItem2( volume, year, ci.formatters.prVolYear )
			end
		else
			volume = year
		end
	end
	cu.insertItem( tab, volume )
end

local function makeNewspaperInfo( args, tab )
	local day = ''
	if cu.isSet( args.date ) then
		if args.dateFormat == 'j. F Y' then
			-- following result can be ''
			day = cu.getDate( args.date, 'l, j. F Y', ci.texts.wrongDate )
		else
			cu.addErrorMsg( ci.texts.wrongDate )
		end
	end

	cu.insertItem( tab, args.publisher )
	cu.insertItem( tab, args.volume, ci.formatters.nsVolume )
	cu.insertItem( tab, args.issue, ci.formatters.prIssue )
	cu.insertItem( tab, day )
end

local function makePeriodical( args )
	local author = makeAuthor( args.author, '' )
		.. makeTitle( args.title, '', args.titleAddition, args.url, '' )

	local result = {}
	local jTitle = makeJournalTitle( args )
	cu.insertItem( result, jTitle )
	
	makeIsbn( args, result )
	if args.type == 'journal' then
		makeJournalInfo( args, result )
	else -- newspaper and web
		makeNewspaperInfo( args, result )
	end
	makePages( args, result )
	makeDoi( args, result )
	makeWebInfo( args, result )
	if #result > 0 then
		result[ 1 ] = mw.ustring.gsub( result[ 1 ], '^%l', mw.ustring.upper )
	end
	result = table.concat( result, ci.formatters.addDelimiter1 )

	return author .. makeLanguageComment( args, result )
end

local function makeCitation( frameArgs )
	local args = getValidArgs( frameArgs )
	checkValues( args )

	local citation
	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'
		or args.type == 'web' then
		citation = makePeriodical( args )
	else
		args.type = 'book'
		citation = ci.texts.wrongType .. makeBook( args )
	end

	citation = cu.finalCleanup( citation )
	if cu.isSet( args.access ) then
		citation = citation
			.. '&nbsp;<span style="position:relative; top: -2px;">'
			.. ci.accessTypes[ args.access ].file .. '</span>'
	end
	cc.prepareForCOinS( args )

	return cu.getErrorMsgs()
		.. tostring( mw.html.create( 'cite' )
			:attr( 'class', 'citation printNoLink ' .. args.type )
			:css( 'font-style', 'normal' )
			:wikitext( citation )
		)
		.. cc.makeCOinS( args )
end

function ct.citation( frame )
	local fType = frame.args.type
	local args = frame:getParent().args

	if cu.isSet( fType ) then
		args.type = fType
	else
		args.type = cu.getKey( cu.getArgValue( ci.params, 'type', args ), ci.refTypes )
	end
	if not cu.isSet( args.type ) then
		if cu.getArgValue( ci.params, 'scale', args ) ~= '' then
			args.type = 'map'
		elseif cu.getArgValue( ci.params, 'collection', args ) ~= '' then
			args.type = 'collection'
		elseif cu.getArgValue( ci.params, 'journal', args ) ~= '' then
			args.type = 'journal'
		elseif cu.getArgValue( ci.params, 'newspaper', args ) ~= '' then
			args.type = 'newspaper'
		elseif cu.getArgValue( ci.params, 'website', args ) ~= '' then
			args.type = 'web'
		else
			args.type = 'book'
		end
	end
	return makeCitation( args )
end

return ct