local Serial = "2021-05-25"
--[=[
Zitation
]=]
Zitation = Zitation or { extern = false }
Zitation.serial = Serial
-- local globals
local Selbst = "Modul:Zitation"
local FehlerTypen = { Intern = { s = "Interner Fehler",
k = "Intern" },
Entfernen = { s = "Veraltet, bitte entfernen" },
Format = { s = "Parameterformat" },
Konflikt = { s = "Parameterkonflikt",
k = "Parameter" },
Modul = { s = "Modul-Seite fehlt",
k = "Intern" },
Name = { s = "Schreibweise falsch",
k = "Name" },
Pflicht = { s = "Pflichtparameter fehlt",
k = "Parameter" },
Problem = { s = "Parameterproblem" },
Abruf = { s = "Abrufdatum mangelhaft",
k = "Abruf" },
Vorlage = { s = "Vorlagen-Seite fehlt",
k = "Intern" },
Wert = { s = "Ungültig",
k = "Parameter" }
}
local KategorieBeginn = "Wikipedia:Vorlagenfehler"
local Kategorien = { Intern = { s = "/Interner Fehler" },
Name = { s = "/Parameterfehler" },
Parameter = { s = "/Parameterfehler" },
Abruf = { s = "/Abrufdatum" },
arXiv = { s = "Parameter:arXiv" },
bibcode = { s = "Parameter:bibcode" },
Datum = { s = "Parameter:Datum" },
DNB = { s = "Parameter:DNB" },
DOI = { s = "Parameter:DOI" },
ISBN = { s = "Parameter:ISBN" },
ISSN = { s = "Parameter:ISSN" },
JSTOR = { s = "Parameter:JSTOR" },
LCCN = { s = "Parameter:LCCN" },
OCLC = { s = "Parameter:OCLC" },
PMID = { s = "Parameter:PMID" },
Sprachcode = { s = "Parameter:Sprachcode" },
URN = { s = "Parameter:URN" },
ZDB = { s = "Parameter:ZDB" }
}
local DocTypes =
{ CSV = "[[CSV (Dateiformat)|CSV]]",
DJVU = "[[DjVu]]",
EPUB = "[[EPUB]]",
FLASH = "[[Adobe Flash|Flash]]",
GZIP = "[[gzip]]",
MIDI = "[[Musical Instrument Digital Interface]]",
MP3 = "MP3",
MPEG = "[[Moving Picture Experts Group|MPEG]]",
MPEG4 = "[[MPEG-4]]",
MSEXCEL = "[[Microsoft Excel|MS Excel]]",
MSPOWERPOINT = "[[Microsoft PowerPoint|MS PowerPoint]]",
MSWORD = "[[Microsoft Word|MS Word]]",
PDF = "PDF",
POSTSCRIPT = "[[PostScript]]",
RAR = "[[RAR (Dateiformat)|RAR]]",
REAL = "[[RealPlayer]]",
RTF = "[[Rich Text Format]]",
WINDOWSMV = "[[Windows Media Video|WMV]]",
ZIP = "[[ZIP-Dateiformat|ZIP]]" }
local URLunwanted = {
["//arxiv%.org/abs/"] = "arXiv",
["//adsabs%.harvard%.edu/"] = "bibcode",
["//portal%.dnb%.de/opac.+query=%d+X?$"] = "DNB",
["//doi%.org/10%."] = "DOI",
["//dx%.doi%.org/10%."] = "DOI",
["jstor%.org/pss/"] = "JSTOR",
["jstor%.org/stable/"] = "JSTOR",
["worldcat%.org/oclc"] = "OCLC",
["www%.worldcat%.org/oclc"] = "OCLC",
["ncbi%.nlm%.nih%.gov/pmc/articles/pmc%d"] = "PMC",
["ncbi%.nlm%.nih%.gov/pubmed/%d"] = "PMID",
["//nbn%-resolving%.de/urn:"] = "URN",
["//urn%.nb%.no/urn:nbn:"] = "URN",
["//urn%.kb%.se/resolve%?urn="] = "URN" }
local Fehler = false
local Fun = { }
local KBytesMax = 100
local Resultat
local Silent = false
local Spacer
-- Allgemeine Hilfsfunktionen ===========================================
local function faced( ahead, after )
-- Zwei Elemente durch schmalen Abstand verbinden
-- Parameter:
-- ahead -- string, mit erstem Element
-- after -- string, mit zweitem Element
-- Rückgabewert: string
local e
if not Spacer then
e = mw.html.create( "span" )
:css( { display = "inline-block",
width = ".2em" } )
:wikitext( " " )
Spacer = tostring( e )
end
return string.format( "%s%s%s", ahead, Spacer, after )
end -- faced()
local function facet( ahead, after )
-- Zwei Elemente durch schmalen umbruchgeschützten Abstand verbinden
-- Parameter:
-- ahead -- string, mit erstem Element
-- after -- string, mit zweitem Element
-- Rückgabewert: string
local e = mw.html.create( "span" )
:css( "white-space", "nowrap" )
:wikitext( faced( ahead, after ) )
return tostring( e )
end -- facet()
local function fading()
-- Ausblende-Modus feststellen
-- Rückgabewert: true, wenn im Ansicht-Modus (kein Bearbeitungsmodus)
if not Silent then
if not Zitation.frame then
Zitation.frame = mw.getCurrentFrame()
end
Silent = Zitation.frame:preprocess( "{{REVISIONID}}" )
end
return ( Silent ~= "" )
end -- fading()
local function fair( apply )
-- Turn any whitespace, even by HTML entity, into single ASCII space
-- Parameter:
-- apply -- string, with some text
-- Rückgabewert: string
local r = apply
if r:find( "&", 1, true ) then
r = r:gsub( " ", " " )
:gsub( " ", " " )
if r:find( "&#", 1, true ) then
r = r:gsub( " ", " " )
:gsub( " ", " " )
if r:find( "&#x", 1, true ) then
r = r:gsub( "�*[aA]0;", " " )
:gsub( "�*202[fF];", " " )
end
end
end
if r:len() > mw.ustring.len( r ) then
if not Zitation.patWhSp then
Zitation.patWhSp = mw.ustring.char( 91, 0xA0,
0x1680,
0x2000, 45, 0x200A,
0x202F,
0x205F,
93 )
end
r = mw.ustring.gsub( r, Zitation.patWhSp, " " )
end
return r:gsub( "%s%s+", " " )
end -- fair()
local function faraway( assign, alien )
-- Sprache zuweisen
-- Parameter:
-- assign -- mw.html-Element
-- alien -- string mit Sprachcode, oder nil
if alien and alien ~= "de" then
assign:addClass( "lang" )
:attr( { dir = "auto",
lang = alien } )
end
end -- faraway()
local function feed( area, access, about )
-- Zugriff auf Parameterkomponente
-- Parameter:
-- area -- string, mit Name der Parametergruppe
-- access -- string, mit Name der Komponente, oder nil
-- about -- true, for returning original parameter name
-- Rückgabewert: Parameterwert, oder nil
local e, r
if not Zitation.o then
Zitation.o = { }
end
e = Zitation.o[ area ]
if e then
if access then
r = e[ access ]
if type( r ) == "table" then
if about then
r = r.s or "???????"
else
r = r.v
end
end
else
r = e
end
end
return r
end -- feed()
local function fehler( art, anzeige )
-- Ein Fehler ist aufgetreten
-- Parameter:
-- art -- string mit Schlüsselwort zum Typ
-- anzeige -- string mit Einzelheiten, oder nil
local t
if not Fehler then
Fehler = FehlerTypen
end
t = Fehler[ art ]
if t then
if anzeige then
local s = mw.text.nowiki( anzeige )
if t.e then
t.e = string.format( "%s; %s", t.e, s )
else
t.e = s
end
end
if t.k then
local wk = Kategorien[ t.k ]
if wk then
wk.e = true
else
Fehler.Intern.e = "Wartungskat " .. wk
Kategorien.Intern.e = true
end
end
else
Fehler.Intern.e = string.format( "fehler(%s) %s",
art, anzeige )
Kategorien.Intern.e = true
end
end -- fehler()
local function fehlerliste()
-- Auflistung aller Fehlermeldungen und Kategorien
-- Rückgabewert: string mit formatiertem Ergebnis
local r = ""
local s
local t = mw.title.getCurrentTitle()
if Fehler then
local sep = ""
for k, v in pairs( Fehler ) do
if v.e then
if v.s then
s = v.s .. ":"
else
s = ""
end
s = string.format( "*** %s %s", s, v.e )
if not v.k and fading() then
local e = mw.html.create( "span" )
e:wikitext( s )
:addClass( "Zitationsfehler Zitationswartung" )
:css( "display", "none" )
s = tostring( e )
end
r = string.format( "%s%s%s", r, sep, s )
sep = " "
end
end -- for k, v
end
if t.namespace == 0 or
( t.namespace == 4 and
t.text:sub( 1, 4 ) == "Lua/" ) then
Selbst = feed( "leise", "Vorlage" ) or Selbst
for k, v in pairs( Kategorien ) do
if v.e then
if v.s:sub( 1, 1 ) == "/" then
s = Selbst
else
s = ""
end
r = string.format( "%s[[Kategorie:%s/%s%s]]",
r, KategorieBeginn, s, v.s )
end
end -- for k, v
end
return r
end -- fehlerliste()
local function fein( abtrennung, anhang )
-- Ergänze Resultat um fertig formatierten Block
-- Parameter:
-- abtrennung -- string mit vorangestelltem Separator
-- anhang -- string mit Textelement
if anhang then
Resultat = string.format( "%s%s%s",
Resultat, abtrennung, anhang )
end
end -- fein()
local function figure( a )
-- Ist das eine Zahl aus arabischen oder römischen Ziffern?
return a:match( "^[0-9./%-:IVX]+$" ) or
a:match( "^C*[LXVI]+$" ) or
not mw.ustring.find( a, "%a" )
end -- figure()
local function figures( a )
-- Formatierte Aufzählung von Zahlen
local i = true
local r = a
local j, k, s, suffix
while i do
i, j, suffix = r:match( "^(%d+)%-(%d+)(.*)$" )
if i then
s = ""
else
s, i, j, suffix = r:match( "^(.*[^0-9]?)(%d+)%-(%d+)(.*)$" )
end
if i then
if tonumber( i ) < tonumber( j ) then
k = 8211
else
k = 45
end
r = string.format( "%s%s&#%d;%s%s",
s, i, k, j, suffix )
end
end -- while
return fair( r ):gsub( "(%d)%s*(ff?)%.?", "%1 %2." )
:gsub( " ", " " )
:gsub( "(%d+) (ff?%.)", faced )
end -- figures()
local function findbar( assigned, about )
-- Unauffindbare Namen (Personen) melden
-- Parameter:
-- assigned -- string; zwei lateinische Buchstaben oder ein CJK
-- about -- string mit Parametername
if not mw.ustring.find( assigned, "%a.*%a" ) then
local Text = Zitation.fetch( "Text" )
if not Text.containsCJK then
fehler( "Wert", string.format( "'%s' zu kurz", about ) )
end
end
end -- findbar()
local function fire( art )
-- Melde Kategorie an
-- Parameter:
-- art -- string mit Schlagwort zum Typ
local t = Kategorien[ art ]
if t then
t.e = true
else
fehler( "Intern", "Kategorie:" .. art )
end
end -- fire()
local function flat( adjust, anzahl, ascii )
-- Komma-separierte Aufzählung begrenzen
-- Parameter:
-- adjust -- string, mit Aufzählung
-- anzahl -- number, mit Anzahl erlaubter Elemente
-- ascii -- true, für ASCII-Auslassung
-- Rückgabewert: string mit gleichem oder gekürztem Ergebnis
local i = 1
local n = 0
local r = adjust
while i do
i = r:find( ",", i, true )
if i then
n = n + 1
if n == anzahl then
r = r:sub( 1, i )
if ascii then
r = r .. " ..."
else
r = r .. " …" -- nbsp hellip
end
break -- while
end
i = i + 1
end
end -- while i
return r
end -- flat()
local function foreign( area, access )
-- Sprachcodes zuweisen
-- Parameter:
-- area -- string, mit Name der Parametergruppe
-- access -- string, mit Name der Komponente
local r = feed( area, access )
if r == "Undetermined" then
fehler( "Wert", "Sprache" )
fire( "Sprachcode" )
elseif r then
local Multilingual = Zitation.fetch( "Multilingual" )
local s = Multilingual.format( r, "-",
false, false, false,
Zitation.frame,
"[, ]", " " )
local parts = mw.text.split( s or "", " " )
local lapsus
for i = 1, #parts do
if not Multilingual.getName( parts[ i ] ) then
lapsus = true
break -- for i
end
end -- for i
if lapsus then
fehler( "Wert", "Sprachcode=" .. r )
fire( "Sprachcode" )
s = r:lower():match( "^(%l%l%l?)-" )
if s then
Zitation.fill( area, access, s )
end
elseif s ~= r then
local say = string.format( "%s: '%s' statt '%s' verwenden",
"Sprachcode", s, r )
r = s
Zitation.fill( area, access, r )
fehler( "Format", say )
end
end
return r
end -- foreign()
local function framedTemplate( access, args )
-- Vorlage einbinden
-- Parameter:
-- access -- Name der Vorlage
-- args -- table mit Parameterliste
-- Rückgabewert: string mit expandierter Vorlage
if not Zitation.frame then
Zitation.frame = mw.getCurrentFrame()
end
return Zitation.frame:expandTemplate{ title = access, args = args }
end -- framedTemplate()
local function future( ask )
-- Liegt Datum in der Zukunft?
-- Parameter:
-- ask -- table oder string, mit Datum
-- Rückgabewert: true, wenn ask ungültig oder in der Zukunft
local r = true
local DateTime, datum
if not Zitation.heute then
DateTime = Zitation.fetch( "DateTime" )
Zitation.heute = DateTime()
end
if type( ask ) == "string" then
DateTime = Zitation.fetch( "DateTime" )
datum = DateTime( ask )
else
datum = ask
end
if type( datum ) == "table" then
r = ( Zitation.heute < datum )
if r then
local karenz = Zitation.heute:future( "15 days" )
if karenz > datum then
r = false
end
end
end
return r
end -- future()
-- Spezielle Werte ======================================================
local function Abrufdatum( abruf )
-- Gib behauptetes Abrufdatum zurück
-- Parameter:
-- abruf -- table oder string, mit Datum
local o = abruf
local r
if type( o ) == "string" then
local DateTime = Zitation.fetch( "DateTime" )
o = DateTime( o )
end
if type( o ) == "table" then
if not future( o ) then
local s = o:format( "ISO" )
r = o:format( "T._Monat JJJJ", "de" )
if not o.dom or not o.month then
fehler( "Abruf", "Abrufdatum soll taggenau sein" )
elseif abruf ~= s then
fehler( "Format",
string.format( "'%s'=%s soll sein: %s",
feed( "www", "Abruf", true ),
abruf,
s ) )
fire( "Datum" )
end
end
end
if r then
local pub = feed( "bas", "Datum" )
if pub then
if type( pub ) == "string" then
local DateTime = Zitation.fetch( "DateTime" )
pub = DateTime( pub )
if type( pub ) == "table" then
Zitation.fill( "bas", "Datum", pub )
end
end
if type( pub ) == "table" and o < pub then
fehler( "Abruf", "Abrufdatum vor Publikationsdatum" )
end
end
else
r = abruf
fehler( "Wert",
string.format( "'%s'=%s",
feed( "www", "Abruf", true ),
abruf ) )
fire( "Datum" )
end
return "abgerufen am " .. r
end -- Abrufdatum()
local function Herausgeber( apply, above, ahead )
-- Analysiere Herausgeber und formatiere ihn, mit Klammerzusatz
-- Parameter:
-- access -- string mit Herausgeber
-- above -- true: innerhalb Klammerebene
-- ahead -- true: vorangestellt statt Klammerzusatz
-- Rückgabewerte: -- string
local pat = "^([^%(%[]+)[%(%[]((%w+)%.?)[%)%]](.*)$"
local scan = apply
local seek = "|hg|hsg|hrsg|hrsgg|herausgeber|ed|eds|editor|editors|"
local story = ""
local r, s, start, sub, suffix
while true do
start, sub, s, suffix = mw.ustring.match( scan, pat )
if s then
if seek:find( string.format( "|%s|", s:lower() ) ) then
story = story .. mw.text.trim( start )
elseif suffix:sub( 1, 1 ) == "|" and
sub:sub( 1, -1 ) == ")" then
story = string.format( "%s%s%s",
story, start, sub )
else
story = string.format( "%s%s[%s]",
story, start, s )
end
scan = suffix
else
break -- while
end
end -- while
r = story .. scan
sub, suffix = mw.ustring.match( r, "^(%w+%.?)%s*(.+)$" )
if sub == "Hg." then
-- (Verwechslungsgefahr bei abgekürztem Vornamen)
r = mw.text.trim( suffix )
elseif sub then
seek = "|hrsg|hrsgg|herausgegeben|"
if seek:find( string.format( "|%s|", sub:lower() ) ) then
r = mw.text.trim( suffix )
sub, suffix = mw.ustring.match( r, "^(vo?n?.?)%s*(.+)$" )
if sub == "von" or sub == "v." then
r = mw.text.trim( suffix )
end
end
end
if r ~= apply or r:match( "%)$" ) then
fehler( "Wert", "Herausgeber mit problematischem Zusatz" )
end
findbar( r, "Hrsg" )
if ahead then
r = "Hrsg.: " .. r
else
if above then
r = r .. " [Hrsg.]"
else
r = r .. " (Hrsg.)"
end
end
return r
end -- Herausgeber()
local function Ortsname( analyse, area, access )
-- Analysiere einen Ortsnamen
-- Parameter:
-- analyse -- string, mit Ortsname
-- area -- string, mit Name der Parametergruppe
-- access -- string, mit Name der Komponente
local s = analyse:gsub( "&#%x+;", "" )
if s:find( "%d%d%d%d" ) then
fehler( "Wert",
string.format( "'%s' %s (%s)",
feed( area, access, true ),
"mit verdächtiger Ziffernfolge",
"Jahreszahl, Postleitzahl" ) )
end
end -- Ortsname()
Fun.arXiv = function ( access )
-- Analysiere arXiv-ID und gib sie als formatierten Link zurück
local arXiv = Zitation.fetch( "arXiv", "Vorlage:arXiv" )
local details = arXiv.fair( access )
if not details.legal then
fehler( "Wert", "'arXiv'" )
fire( "arXiv" )
end
arXiv.features( { showArticle = "arXiv" } )
return arXiv.format( details )
end -- Fun.arXiv()
Fun.bibcode = function ( access )
-- Analysiere bibcode-ID und gib sie als formatierten Link zurück
local bibcode = Zitation.fetch( "bibcode", "Vorlage:bibcode" )
local r = bibcode.format{ access }
if not r:find( "//", 1, true ) then
fehler( "Wert", "'bibcode' =" .. access )
fire( "bibcode" )
end
return r
end -- Fun.bibcode()
Fun.DOI = function ( access )
-- Analysiere DOI und gib sie als formatierten Link zurück
local URIutil = Zitation.fetch( "URIutil" )
local r = URIutil.linkDOI( access )
local s = "Digital Object Identifier"
if r then
r = string.format( "[[%s|doi]]:%s", s, r )
else
r = string.format( "[[%s|DOI]]:%s%s",
s,
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
fehler( "Wert", "'DOI'" )
fire( "DOI" )
end
return r
end -- Fun.DOI()
Fun.DNB = function ( access )
-- Analysiere DNB und gib sie formatiert zurück
local URIutil = Zitation.fetch( "URIutil" )
local r
if URIutil.isDNBvalid( access ) then
r = URIutil.linkDNBopac( access, false, true, true )
else
local s = "Deutsche Nationalbibliothek"
fehler( "Wert", "'DNB'" )
fire( "DNB" )
r = string.format( "[[%s|DNB]] %s%s",
s,
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
end
return r
end -- Fun.DNB()
Fun.ISSN = function ( access, allow )
-- Analysiere ISSN und gib sie formatiert zurück
-- allow -- true: permit invalid check digit
local URIutil = Zitation.fetch( "URIutil" )
if allow or URIutil.isISSNvalid( access ) then
r = URIutil.linkISSN( access, allow, true, true )
else
local s = "International Standard Serial Number"
fehler( "Wert", "'ISSN'" )
fire( "ISSN" )
r = string.format( "[[%s|ISSN]] %s%s",
s,
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
end
return r
end -- Fun.ISSN()
Fun.ISSNfalsch = function ( access )
-- Analysiere formal falsche ISSN und gib sie formatiert zurück
return Fun.ISSN( access, true )
end -- Fun.ISSNfalsch()
Fun.JSTOR = function ( access )
-- Analysiere JSTOR (stable) und gib sie formatiert zurück
-- i: Volume
local JSTOR = Zitation.fetch( "JSTOR" )
local r, URIutil
if access:find( "/", 1, true ) then
URIutil = Zitation.fetch( "URIutil" )
end
r = JSTOR.feasible( access, "stable", URIutil )
if r then
r = JSTOR.format( r, "stable", false, URIutil )
else
fehler( "Wert", "'JSTOR'" )
fire( "JSTOR" )
r = string.format( "JSTOR:%s%s",
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
end
return r
end -- Fun.JSTOR()
Fun.LCCN = function ( access )
-- Analysiere LCCN und gib sie formatiert zurück
local URIutil = Zitation.fetch( "URIutil" )
local see = "Library of Congress Control Number"
local r = string.format( "[[%s|LCCN]] ", see )
if URIutil.isLCCN( access ) then
r = r .. URIutil.linkLCCN( access, "-" )
else
fehler( "Wert", "'LCCN'" )
fire( "LCCN" )
r = string.format( "%s%s%s",
r,
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
end
return r
end -- Fun.LCCN()
Fun.Lizenznummer = function ( access )
-- Gib DDR-Lizenznummer formatiert zurück
return "[[Lizenznummer]] " .. access
end -- Fun.Lizenznummer()
Fun.OCLC = function ( access )
-- Analysiere OCLC und gib sie formatiert zurück
local r
if access:match( "^[1-9][0-9]*$" ) then
r = framedTemplate( "OCLC", { access } )
else
fehler( "Wert", "'OCLC'" )
fire( "OCLC" )
r = string.format( "OCLC %s", access )
end
return r
end -- Fun.OCLC()
Fun.PMC = function ( access )
-- Analysiere PMC und gib sie formatiert zurück
local start, s = access:match( "^(%a%a%a)%s*(%d+)$" )
local r
if start and start:upper() == "PMC" then
fehler( "Wert", "'PMC' vor Nummer unerwünscht" )
else
s = access
end
if s:match( "^[1-9][0-9]*$" ) then
r = framedTemplate( "PMC", { s } )
else
fehler( "Wert", "'PMC'" )
fire( "PMID" ) -- Ja, PMID-Experte betreut auch PMC
r = string.format( "PMC %s", access )
end
return r
end -- Fun.PMC()
Fun.PMID = function ( access )
-- Analysiere PMID und gib sie formatiert zurück
if not access:match( "^[1-9][0-9]*$" ) then
fehler( "Wert", "'PMID'" )
fire( "PMID" )
end
return string.format( "PMID %s", access )
end -- Fun.PMID()
Fun.URN = function ( access )
-- Analysiere URN und gib sie formatiert zurück
local URIutil = Zitation.fetch( "URIutil" )
local r = URIutil.uriURN( "urn:" .. access )
if r:find( "class=\"[^\"]*error", 1, true ) or
not r:find( "//", 1, true ) then
fehler( "Wert", "'URN'=" .. access )
fire( "URN" )
end
return r
end -- Fun.URN()
Fun.ZDB = function ( access )
-- Analysiere ZDB und gib sie formatiert zurück
local URIutil = Zitation.fetch( "URIutil" )
if URIutil.isDNBvalid( access ) or
URIutil.isDNBvalid( access:gsub( "-", "" ) ) then
r = framedTemplate( "ZDB", { access:upper() } )
else
local s = "Zeitschriftendatenbank"
fehler( "Wert", "'ZDB'" )
fire( "ZDB" )
r = string.format( "[[%s|ZDB]] %s%s",
s,
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
end
return r
end -- Fun.ZDB()
local function doiCheck( analyse )
-- Prüfe Wikitext auf zulässige DOI-WikiLinks
-- Parameter:
-- analyse -- string (downcased)
local s = analyse
local f = function()
local skip, s = s:match( "^(.*%[%[%s*doi:)(.+)$" )
if s then
local seek
seek, s = s:match( "^(.*)%]%](.*)$" )
if seek then
local URIutil = Zitation.fetch( "URIutil" )
if URIutil.mayURI( seek ) then
fehler( "Wert", "doi:DOI ungültig" )
seek = false
end
else
fehler( "Wert", "doi: nicht geschlossen" )
end
if not seek then
fire( "DOI" )
s = false
end
end
return s
end
while f() do
end -- while
end -- doiCheck()
local function redundanz( analyse )
-- Prüfe Angabe auf Redundanz mit anderen Parametern
-- Parameter:
-- analyse -- string (downcased)
for k, v in pairs( URLunwanted ) do
if analyse:match( k ) then
if ( v == "DNB" or v == "LCCN" or v == "OCLC" ) and
( feed( "id", "ISBN" ) or
feed( "id", "ISBNfalsch" ) or
feed( "id", "ISBNdefekt" ) ) then
local s = string.format( "%s %s-URL redundant",
"ISBN vorhanden", v )
fehler( "Konflikt", s )
else
local s = string.format( "%s '%s=' %s",
"Statt URL sollte etwas wie",
v,
"angegeben werden" )
fehler( "Konflikt", s )
end
end
end -- for k, v
if analyse:find( "title=\"ctx_ver=Z39.88-2004", 1, true ) then
fehler( "Konflikt", "Verschachtelte Zitationsvorlagen" )
end
end -- redundanz()
local function bandNummer( area )
-- Formatiere Angaben von Band und/oder Nummer
-- Parameter:
-- area -- string, mit Name der Parametergruppe print/serie
-- Rückgabewert: string mit Inhalt, oder nil
local sB = feed( area, "Band" )
local sN = feed( area, "Nummer" )
local r
if sB then
local lead
sB = fair( sB ):gsub( "&#%x+;", " " )
:gsub( "%s%s+", " " )
if sB:sub( 1, 5 ) == "Band " then
sB = sB:sub( 6 )
lead = true
elseif sB:sub( 1, 3 ) == "Bd." then
sB = mw.text.trim( sB:sub( 4 ) )
lead = true
end
if figure( sB ) then
r = facet( "Band", sB )
else
if lead then
sB = "Band " .. sB
end
r = sB:gsub( "(Band) (%d+)", facet )
end
end
if sN then
local lead
sN = fair( sN ):gsub( "&#%x+;", " " )
:gsub( "%s%s+", " " )
if sN:sub( 1, 7 ) == "Nummer " then
sN = sN:sub( 8 )
lead = true
elseif sN:sub( 1, 3 ) == "Nr." then
sN = mw.text.trim( sN:sub( 4 ) )
lead = true
end
if figure( sN ) then
sN = facet( "Nr.", sN )
else
if lead then
sN = "Nr. " .. sN
end
sN = sN:gsub( "(Nr%.) (%d+)", facet )
end
if r then
r = string.format( "%s, %s", r, sN )
else
r = sN
end
end
return r
end -- bandNummer()
local function Kapitel( a )
-- Formatiere Kapitelangabe
local r = a
if a:match( "^%d+$" ) then
r = facet( "Kap.", a )
end
return r
end -- Kapitel()
local function ArtikelNr( aN, aS )
-- Analysiere ArtikelNr
if aS then
fehler( "Konflikt", "Seitenzahl redundant wenn ArtikelNr" )
end
if not aN:match( "^%d+$" ) then
fehler( "Wert", "'ArtikelNr'=" .. aN )
end
end -- ArtikelNr()
local function Seiten( a )
-- Analysiere Seitenzahl und formatiere
local s, seiten = a:match( "^(%w+%.?)%s*(.+)$" )
local r
if s then
local seek = "|s.|ss.|seite|seiten|page|pages|p.|pp.|"
if seek:find( string.format( "|%s|", s:lower() ) ) then
fehler( "Wert", "Seitenzahl mit unnötigem Zusatz" )
seiten = mw.text.trim( seiten )
else
seiten = a
end
else
seiten = a
end
if #seiten > 50 then
-- URL? Google-Buch?
local shrink = string.format( "[%%-0-9,;/ f%%.%s]",
mw.ustring.char( 8211 ) )
s = mw.ustring.gsub( seiten, shrink, "" )
if #s > 10 then
fehler( "Wert", "Seitenzahl unerklärlich lang" )
r = a
end
end
if not r then
r = facet( "S.", figures( seiten ) ):gsub( "%.</span>$",
"</span>." )
end
return r
end -- Seiten()
local function Spalten( a )
-- Analysiere Spaltenangabe und formatiere
local s, sp = a:match( "^(%w+%.?)%s*(.+)$" )
if s then
local seek = "|sp.|spalte|spalten|"
if seek:find( string.format( "|%s|", s:lower() ) ) then
fehler( "Wert", "Spaltenangabe mit unnötigem Zusatz" )
sp = mw.text.trim( sp )
else
sp = a
end
else
sp = a
end
return facet( "Sp.", figures( sp ) ):gsub( "%.</span>$",
"</span>." )
end -- Spalten()
local function Werktitel( a, amend, alien, abschluss )
-- Formatiere einen Werktitel, das Sammelwerk, ggf. Reihe
-- Parameter:
-- a -- string
-- amend -- string mit Ergänzung, oder nil
-- alien -- string mit Sprachcode, oder nil
-- abschluss -- true: Satzendezeichen sicherstellen
-- Rückgabewert: string mit formatiertem Werktitel
local Text = Zitation.fetch( "Text" )
local cite = mw.html.create( "cite" )
local sep
local r
cite:css( "font-style", "italic" )
:wikitext( Text.uprightNonlatin( a ) )
faraway( cite, alien )
r = tostring( cite )
if amend then
local s
if Text.sentenceTerminated( a ) then
sep = ""
else
sep = "."
end
r = string.format( "%s%s %s", r, sep, amend )
end
if abschluss and
( ( not amend and not Text.sentenceTerminated( a ) )
or ( amend and not Text.sentenceTerminated( amend ) ) ) then
r = r .. "."
end
return r
end -- Werktitel()
-- Einzelblöcke der Darstellung =========================================
local function resourceMeta( anfang )
-- Ergänze Resultat um für einen Online-Abruf wichtigen Informationen
-- anfang -- boolean
-- * true -- runde Klammern
-- um .Format und .KBytes gesetzt
-- * false -- eckige Klammern
-- um .Format und .KBytes und .Abruf
-- Rückgabewert: string mit führendem " " und Inhalt, oder ""
local r = ""
if feed( "www" ) then
local sURL = feed( "www", "URL" )
local sWeblink = feed( "www", "Weblink" )
local some = ( sURL or sWeblink )
local sAbruf = feed( "www", "Abruf" )
local sFormat = feed( "www", "Format" )
local sKBytes = feed( "www", "KBytes" )
if some then
local sep = ""
some = some:lower() .. " "
if sFormat then
local s = sFormat:upper()
if s ~= "HTML" then
if s:find( "PDF%-?" ) then
r = "pdf"
else
r = sFormat
end
end
elseif some:find( "%Wpdf%W" ) then
r = "pdf"
end
if r:lower() == "pdf" and
sWeblink and
some:find( " .*pdf" ) then
r = ""
end
if r == "" then
sKBytes = false
else
local docTypes = mw.text.split( r:upper(), " " )
local s
r = ""
sep = ""
for i = 1, #docTypes do
s = docTypes[ i ]
r = string.format( "%s%s%s",
r, sep, DocTypes[ s ] or s )
sep = " "
end -- for i
sep = "; "
end
if sKBytes then
local scan = "^(%d+[,%.]?%d*)%s*(%a*)$"
local large = sKBytes:find( "[sic!]", 3, true )
local lot, size, suffix
sKBytes = fair( sKBytes )
if large then
sKBytes = sKBytes:gsub( "%s*%[sic!%]%s*$", "" )
end
size, suffix = sKBytes:match( scan )
if size then
local n
size = size:gsub( "%.", "" )
if size:find( "," ) then
n = tonumber( size:gsub( ",", "." ), 10 )
size = string.format( "%1.1d", n )
else
n = tonumber( size )
end
if suffix then
if suffix == "" then
suffix = false
else
suffix = suffix:lower()
if suffix:match( "^mi?b%l*$" ) then
n = n * 1000
suffix = false
elseif suffix:match( "^ki?b%l*$" ) then
suffix = false
end
end
end
if suffix then
fehler( "Wert", "Byte-Einheit nicht erkannt" )
else
if n > 1000 then
n = math.ceil( n * 0.01 ) * 0.1
size = string.format( "%.1f", n )
suffix = "MB"
lot = ( n > KBytesMax )
else
suffix = "kB"
end
end
sKBytes = facet( size:gsub( "%.", "," ), suffix )
if lot then
sKBytes = string.format( "'''%s'''", sKBytes )
if not large then
fehler( "Wert", "zu viele MegaBytes" )
end
end
else
fehler( "Wert", "KiloByte-Zahl nicht erkannt" )
end
r = string.format( "%s%s%s", r, sep, sKBytes )
if large and not lot then
fehler( "Wert", "Fehlplatziertes [sic!]" )
end
sep = "; "
end
if not anfang and sAbruf and sWeblink then
r = string.format( "%s%s%s",
r, sep, Abrufdatum( sAbruf ) )
end
if r ~= "" then
if anfang then
sep = " (%s)"
else
sep = " [%s]"
end
r = string.format( sep, r )
end
redundanz( some )
elseif sFormat or sKBytes or sAbruf then
local s = feed( "bas", "Titel" )
if not s or not s:find( "//" ) then
fehler( "Problem",
"Dateiformat/Größe/Abruf nur wenn Weblink" )
end
end
end
return r
end -- resourceMeta()
local function autorHrsg()
-- Ergänze Resultat um Personen zu Beginn der Zitation
local sAutor = feed( "bas", "Autor" )
local sHrsg = feed( "bas", "Hrsg" )
local sTyp = feed( "leise", "Typ" )
local lead
if sTyp and sTyp ~= "wl" then
fehler( "Wert",
"'Typ' zurzeit nur 'Typ=wl' (Werkliste) unterstützt" )
r = "wl"
end
if sHrsg then
lead = ( not feed( "bas", "Werk" ) )
findbar( sHrsg, "Hrsg" )
end
if sAutor or lead then
local list = false
if sAutor then
sAutor = sAutor:gsub( "^#", "#" ) -- nick, hashtag
:gsub( "^%*", "*" )
if sTyp ~= "wl" then
fein( "", sAutor )
list = true
end
if type( sAutor ) == "table" then
sAutor = Zitation.citePerson( sAutor, false )
end
findbar( sAutor, "Autor" )
if sHrsg and not feed( "bas", "Titel" ) then
fehler( "Konflikt",
"Gleichzeitig 'Autor' und 'Hrsg' nur wenn auch 'Titel'" )
end
else
fein( "", Herausgeber( sHrsg ) )
list = true
end
if list then
fein( ": ", "" ) -- " news:" wäre eine Wiki-URL
end
end
end -- autorHrsg()
local function erstAusgabe()
-- Erstausgabe
-- Rückgabewert: string
local sJahr = feed( "ed1", "Jahr" )
local sOrt = feed( "ed1", "Ort" )
local sVerlag = feed( "ed1", "Verlag" )
local r = "Erstausgabe: "
local sep
if sVerlag then
r = r .. sVerlag
sep = ","
if feed( "bas", "Verlag" ) == sVerlag then
fehler( "Konflikt",
string.format( "'%s' hat gleichen Wert wie '%s'",
feed( "ed1", "Verlag", true ),
feed( "bas", "Verlag", true ) ) )
end
else
sep = ""
end
if sOrt then
r = string.format( "%s%s %s", r, sep, sOrt )
Ortsname( sOrt, "ed1", "Ort" )
sep = " "
-- bas.Verlag und ed1.Verlag dürfen in derselben Stadt sein
end
if sJahr then
local jahr
if sJahr:match( "^%d%d%d%d$" ) then
if not future( sJahr ) then
jahr = tonumber( sJahr )
end
end
if jahr then
local datum = feed( "bas", "Datum" )
r = string.format( "%s%s %s", r, sep, sJahr )
if type( datum ) == "table" and
datum.year and datum.year < jahr then
fehler( "Konflikt",
string.format( "'%s' nach Neuausgabe",
feed( "ed1", "Jahr", true ) ) )
end
else
fehler( "Wert",
string.format( "'%s'=%s",
feed( "ed1", "Jahr", true ),
sJahr ) )
fire( "Datum" )
end
end
return r
end -- erstAusgabe()
local function originalPublikation()
-- Originalpublikation; zulässige Parameterlogik noch unklar
-- Rückgabewert: string mit Inhalt, oder false
local r
if feed( "orig" ) then
local sTitel = feed( "orig", "Titel" )
local sTranslator = feed( "orig", "Translator" )
if sTitel then
local sprache = foreign( "orig", "Sprache" )
local sOrt = feed( "orig", "Ort" )
local sJahr = feed( "orig", "Jahr" )
r = Werktitel( sTitel, false, sprache, true )
if sOrt then
r = string.format( "%s %s", r, sOrt )
Ortsname( sOrt, "orig", "Ort" )
end
if sJahr then
r = string.format( "%s %s", r, sJahr )
if sJahr:match( "^%d%d%d%d$" ) then
if future( sJahr ) then
fehler( "Wert", "Originaljahr in der Zukunft" )
else
local jahr = tonumber( sJahr )
local datum = feed( "bas", "Datum" )
if type( datum ) == "table" and
datum.year and datum.year < jahr then
fehler( "Konflikt",
"Originaljahr nach Neuausgabe" )
end
end
else
fehler( "Wert", "Originaljahr ist keine Jahreszahl" )
end
end
if ( sOrt or sJahr ) and
( sJahr or not sOrt:match( "%.$" ) ) then
r = r .. "."
end
if sprache then
local Multilingual = Zitation.fetch( "Multilingual" )
local s = Multilingual.format( sprache, "de", "m",
false, false,
Zitation.frame,
" ", ", " )
if s then
sprache = s
elseif sprache:match( "^%l%l%l?$" ) then
fehler( "Wert",
"Unbekannter Sprachcode=" .. sprache )
fire( "Sprachcode" )
sprache = string.format( "<code>%s</code>", sprache )
-- elseif sprache:match( "^%l.+[ ,;/]" ) then
-- fehler( "Wert",
-- "Original-Sprachcode seltsam: " .. sprache )
end
else
sprache = "Originaltitel"
end
r = string.format( "%s: %s", sprache, r )
if sTranslator then
r = string.format( "%s Übersetzt von %s",
r, sTranslator )
end
elseif not sTranslator then
fehler( "Pflicht", "Originaltitel fehlt" )
end
end
return r
end -- originalPublikation()
local function titel()
-- Ergänze Resultat um Titel
local sTitel = feed( "bas", "Titel" )
local sWerk = feed( "bas", "Werk" )
if sTitel then
local stop = ""
local sReihe = feed( "serie", "Reihe" )
local sTitelErg = feed( "bas", "TitelErg" )
local sURL = feed( "www", "URL" )
local s = Werktitel( sTitel,
false,
feed( "bas", "Sprache" ),
sWerk or not sReihe or sTitelErg )
local Text
if sURL then
local URLutil = Zitation.fetch( "URLutil" )
if URLutil.isResourceURL( sURL ) then
s = s:gsub( "%[", "[" )
:gsub( "%]", "]" )
sURL = sURL:gsub( "%[", "%5B" )
:gsub( "%]", "%5D" )
s = string.format( "[%s %s]%s",
sURL, s, resourceMeta( true ) )
else
fehler( "Wert", "URL" )
end
end
if sTitelErg then
Text = Zitation.fetch( "Text" )
if ( sWerk or not sReihe ) and
not Text.sentenceTerminated( sTitelErg ) then
stop = "."
end
s = string.format( "%s %s%s", s, sTitelErg, stop )
end
fein( "", s )
if not sWerk then
local sAutor = feed( "bas", "Autor" )
local sHrsg = feed( "bas", "Hrsg" )
if sAutor and sHrsg then
Text = Zitation.fetch( "Text" )
if stop == "" then
local strip = Resultat:gsub( "</cite>$", "" )
if not Text.sentenceTerminated( strip ) then
stop = "."
end
elseif sTitelErg then
stop = ""
end
stop = stop .. " "
s = Herausgeber( sHrsg, false, true )
if not ( sReihe or
Text.sentenceTerminated( s ) ) then
s = s .. "."
end
fein( stop, s )
end
end
else
if sWerk then
fehler( "Pflicht", "Kein 'Titel'" )
else
fehler( "Pflicht", "Weder 'Titel' noch sonstiges Werk" )
end
end
end -- titel()
local function werk()
-- Ergänze Resultat um Sammelwerk usw.
local sWerk = feed( "bas", "Werk" )
if sWerk then
local start = " In: "
local sHrsg = feed( "bas", "Hrsg" )
local s = Werktitel( sWerk,
feed( "bas", "WerkErg" ),
feed( "bas", "Sprache" ),
not feed( "serie", "Reihe" ) )
if sHrsg then
s = string.format( "%s: %s", Herausgeber( sHrsg ), s )
end
if Resultat == "" then
start = "In: "
end
fein( start, s )
end
end -- werk()
local function auflage()
-- Ergänze Resultat um Auflage
local sAuflage = feed( "print", "Auflage" )
if sAuflage then
local s = sAuflage:gsub( "Aufla?g?e?%.?$", "" )
local lang = s:find( "d", 2, true )
if lang then
local sFR = mw.ustring.char( 233, 100, 46 )
s = mw.ustring.gsub( s, "[éÉ]d%.?$", sFR )
s = mw.ustring.gsub( s, "[éÉ]dition", sFR )
end
if s:match( "^%d+$" ) then
s = s .. "."
end
if not ( s:find( "Aufl", 1, true ) or
( lang and
( s:find( "ed.", 1, true ) or
mw.ustring.find( s, "éd.", 1, true ) ) ) ) then
s = s .. " Auflage"
end
if not s:match( "%.$" ) then
s = s .. "."
end
fein( " ", s )
end
end -- auflage()
local function reihe()
-- Ergänze Resultat um Angaben zur Reihe
if feed( "serie" ) then
local sReihe = feed( "serie", "Reihe" )
if sReihe then
local sBN = bandNummer( "serie" )
local sHrsg = feed( "serie", "Hrsg" )
local s = Werktitel( sReihe,
false,
feed( "bas", "Sprache" ),
sBN )
if sHrsg then
s = string.format( "%s: %s",
Herausgeber( sHrsg, true ), s )
end
if sBN then
s = string.format( "%s %s", s, sBN )
end
fein( " ", string.format( "(= %s).", s ) )
else
local scream
local flop = function ( au )
if feed( "serie", au ) then
local s = feed( "serie", au, true )
if scream then
scream = scream .. ", "
else
scream = ""
end
scream = string.format( "%s'%s'",
scream, s )
end
end -- flop()
flop( "Hrsg" )
flop( "Band" )
flop( "Nummer" )
if scream then
-- Muss in dieser Konstellation eigentlich immer sein
fehler( "Pflicht",
scream .. " nur wenn Reihe angegeben" )
end
end
end
end -- reihe()
local function bibliografischeAngaben()
-- Ermittle die Aufzählung bibliografische Angaben
-- Rückgabewert: string mit Inhalt, oder false
local r = ""
local sep = ""
local datum = feed( "bas", "Datum" )
local sVerlag = feed( "bas", "Verlag" )
local s, sOrt
if feed( "print" ) then
sOrt = feed( "print", "Ort" )
if sOrt and
( feed( "id", "ISSN" ) or feed( "id", "ZDB" ) ) then
sOrt = false
end
s = bandNummer( "print" )
if s then
r = s
if s:find( "%.$" ) then
sep = " "
elseif sVerlag or sOrt then
sep = ". "
else
sep = ", "
end
end
end
if sVerlag then
r = string.format( "%s%s%s", r, sep, sVerlag )
sep = ", "
end
if sOrt then
s = sOrt:gsub( "[,/; ]+$", "" )
r = string.format( "%s%s%s", r, sep, s )
if s ~= sOrt then
Zitation.fill( "print", "Ort", s )
end
Ortsname( sOrt, "print", "Ort" )
sep = ", "
end
if datum then
local o = datum
if type( datum ) == "string" then
local DateTime = Zitation.fetch( "DateTime" )
o = DateTime( datum )
end
if type( o ) == "table" and o.year then
Zitation.fill( "bas", "Datum", o )
if future( o ) or
( o.zone and not o.hour ) then
o = false
elseif feed( "id", "ISBN" ) then
s = tostring( o.year )
elseif feed( "www", "URL" ) then
s = o:format( "T._Monat JJJJ hh:mm:ss Zone" )
else
s = o:format( "T._Monat JJJJ" )
end
else
o = false
end
if not o then
if type( datum ) == "string" then
-- s = "Datum: " .. datum -- LEGACY
s = datum
else
s = "Datum??"
end
fehler( "Wert", s )
fire( "Datum" )
end
if sOrt then
sep = " "
end
r = string.format( "%s%s%s", r, sep, s )
sep = ", "
end
if feed( "id" ) then
local lazy = false -- gültige ISBN bekannt
local sID = feed( "id", "ID" )
local sISBN = feed( "id", "ISBN" )
local sISBNfalsch = feed( "id", "ISBNfalsch" )
local sISBNdefekt = feed( "id", "ISBNdefekt" )
local fiddler =
function( at )
local s = feed( "id", at )
if s then
if lazy and
not ( at == "ISSN" or
at == "ISSNfalsch" ) then
s = "redundant, da ISBN gegeben"
s = string.format( "'%s' %s",
feed( "id", at, true ),
s )
fehler( "Konflikt", s )
else
s = Fun[ at ]( s )
r = string.format( "%s%s%s",
r, sep, s )
sep = ", "
end
end
end
if sISBN and sISBNfalsch then
s = string.format( "'%s' und '%s' %s",
feed( "id", "ISBN", true ),
feed( "id", "ISBNfalsch", true ),
"nicht gleichzeitig angeben" )
fehler( "Konflikt", s )
elseif sISBN or sISBNfalsch then
local mode
if sISBNfalsch then
mode = -1
end
s, lazy = Zitation.ISBN( sISBN or sISBNfalsch, mode )
r = string.format( "%s%s%s", r, sep, s )
sep = ", "
end
if sISBNdefekt then
s = Zitation.ISBN( sISBNdefekt, #sISBNdefekt )
r = string.format( "%s%s%s", r, sep, s )
sep = ", "
end
fiddler( "ISSN" )
fiddler( "ISSNfalsch" )
fiddler( "DNB" )
fiddler( "LCCN" )
fiddler( "Lizenznummer" )
fiddler( "OCLC" )
fiddler( "ZDB" )
if sID then
r = string.format( "%s%s%s", r, sep, sID )
sep = ", "
redundanz( sID )
end
end
if feed( "fragment" ) then
local sArtikelNr = feed( "fragment", "ArtikelNr" )
local sFundstelle = feed( "fragment", "Fundstelle" )
local sKapitel = feed( "fragment", "Kapitel" )
local sSeiten = feed( "fragment", "Seiten" )
local sSpalten = feed( "fragment", "Spalten" )
if sKapitel then
r = string.format( "%s%s%s", r, sep, Kapitel( sKapitel ) )
sep = ", "
end
if sSeiten then
r = string.format( "%s%s%s", r, sep, Seiten( sSeiten ) )
sep = ", "
end
if sSpalten then
r = string.format( "%s%s%s", r, sep, Spalten( sSpalten ) )
sep = ", "
end
if sArtikelNr then
ArtikelNr( sArtikelNr, sSeiten )
r = string.format( "%s%s%s", r, sep, sArtikelNr )
sep = ", "
end
if sFundstelle then
r = string.format( "%s%s<span style='%s'>%s</span>",
r,
sep, "white-space:nowrap", sFundstelle )
sep = ", "
end
end
if feed( "id" ) then
local docCodes = { "DOI",
"PMID",
"PMC",
"arXiv",
"bibcode",
"JSTOR",
"URN" }
local sign
for i = 1, #docCodes do
s = docCodes[ i ]
sign = feed( "id", s )
if sign then
r = string.format( "%s%s%s", r, sep, Fun[ s ]( sign ) )
sep = ", "
end
end -- for i
end
if r == "" then
r = false
end
return r
end -- bibliografischeAngaben()
local function klammerInhalt()
-- Inhalt der Klammer am Ende der bibliografischen Angaben
-- Rückgabewert: string mit Inhalt, oder false
local r = ""
local sep = ""
local sKommentar = feed( "bas", "Kommentar" )
local sOrig = originalPublikation()
local sprache = feed( "bas", "Sprache" )
local sUmfang = feed( "print", "Umfang" )
if sprache and sprache ~= "de" then
local Multilingual = Zitation.fetch( "Multilingual" )
sprache = Multilingual.format( sprache, "de", "m",
false, false,
Zitation.frame,
" ", ", " )
r = string.format( "%s%s%s", r, sep, sprache )
sep = ", "
end
if sUmfang then
if not mw.ustring.find( sUmfang, "%a" ) then
-- "14, 234"
sUmfang = string.format( "%s S.", sUmfang )
end
r = string.format( "%s%s%s", r, sep, sUmfang )
sep = ", "
end
local sanitize = feed( "www", "Weblink" )
if sanitize and sanitize:find( "InternetArchiveBot", 1, true ) then
-- 2018-12-04
mw.addWarning( "<b>Unerlaubte Bot-Aktion</b><br /> " ..
sanitize )
fein( "", "[[Kategorie:Wikipedia:InternetArchiveBot-Fehler]]")
Zitation.o.www = false
-- Wiederholt ZR-widrig den Titel der Website u. a. 171587445/183321268
end
if feed( "www" ) then
local sWeblink = feed( "www", "Weblink" )
if sWeblink then
local WLink = Zitation.fetch( "WLink" )
local show = WLink.getWeblink( sWeblink )
local spec = resourceMeta( false )
show = show:gsub( " www%d*%.", " " )
r = string.format( "%s%s%s%s",
r, sep, show, spec )
if spec == "" then
sep = " – "
else
sep = " "
end
if ( r:find( "(", 1, true ) or
r:find( ")", 1, true ) ) and
not r:find( ">Memento</span>", 1, true ) then
fehler( "Wert",
"Unerlaubte Klammerung innerhalb Klammer" )
end
if sWeblink:find( "</cite>", 1, true ) or
sWeblink:find( "class=\"cite\"", 1, true ) then
fehler( "Konflikt",
"Zitationsvorlage rekursiv eingebunden" )
fire( "Parameter" )
-- Langfristig wirkungslos; greift nur vorübergehend
-- wenn IQ noch reine Vorlage,
-- oder cite als reine Vorlage.
-- Nach vollständiger Umsetzung
-- sperrt sich aber das System,
-- weil Modul:Zitation
-- dann rekursiv aufgerufen werden würde.
end
elseif feed( "www", "URL" ) then
local sAbruf = feed( "www", "Abruf" )
if sAbruf then
r = string.format( "%s%s%s",
r, sep, Abrufdatum( sAbruf ) )
sep = ", "
end
else
local s = feed( "bas", "Titel" )
if not s or not s:find( "//", 1, true ) then
fehler( "Problem",
"Dateiformat/Größe/Abruf nur bei externem Link" )
end
end
end
if sOrig then
r = string.format( "%s%s%s", r, sep, sOrig )
if feed( "orig", "Translator" ) then
sep = ", "
else
sep = " "
end
end
if feed( "ed1" ) then
r = string.format( "%s%s%s", r, sep, erstAusgabe() )
sep = ", "
end
if sKommentar then
r = string.format( "%s%s%s", r, sep, sKommentar )
sKommentar = mw.ustring.lower( sKommentar )
redundanz( sKommentar )
if sKommentar:find( "[[%s*doi:", 1, true ) then
doiCheck( sKommentar )
end
end
if r == "" then
r = false
end
return r
end -- klammerInhalt()
local function endBlock()
-- Ergänze Resultat um bibliografische Angaben, Klammer sowie Zitat.
-- Komma-getrennte Aufzählung, die mit Punkt abgeschlossen wird,
-- oder Zitat wird nachgestellt.
local sZitat = feed( "bas", "Zitat" )
local sep = ""
local s = bibliografischeAngaben()
if s then
fein( " ", s )
if not s:match( "%.$" ) then
sep = "."
end
end
s = klammerInhalt()
if s then
if Resultat:find( "%)$" ) then
-- Irgendwas zuvor endet auf eine runde Klammer.
sep = " – ("
else
sep = " ("
end
fein( sep, s .. ")" )
sep = "."
end
if sep ~= "" then
-- Aufzählung enthält zumindest ein Element
if sZitat then
fein( ":", "" )
elseif not Resultat:match( "%.$" ) then
fein( ".", "" )
end
end
if sZitat then
local sprache = feed( "bas", "Sprache" )
local Text = Zitation.fetch( "Text" )
local story = Text.quoteUnquoted( sZitat, sprache )
if sprache and sprache ~= "de" then
local q = mw.html.create( "span" )
faraway( q, sprache )
q:wikitext( story )
story = tostring( q )
end
fein( " ", story )
end
end -- endBlock()
local function coins()
-- Ergänze Resultat um COinS, wenn gewünscht
local COinS = feed( "coins" )
if COinS then
local std = "book"
local pars
if type( COinS ) == "table" then
pars = COinS
elseif feed( "bas" ) then
local datum = feed( "bas", "Datum" )
local sAutor = feed( "bas", "Autor" )
local sKapitel = feed( "fragment", "Kapitel" )
local sTitel = feed( "bas", "Titel" )
local sWerk = feed( "bas", "Werk" )
local stick
pars = { }
if sWerk then
if feed( "print", "Nummer" ) or
feed( "id", "ISSN" ) or
feed( "id", "ISSNfalsch" ) or
feed( "id", "ZDB" ) or
feed( "fragment", "ArtikelNr" ) then
pars.genre = "journal"
pars.jtitle = sWerk
std = "journal"
else
pars.genre = "book"
pars.btitle = sWerk
end
pars.atitle = sTitel
elseif sKapitel then
pars.genre = "bookitem"
pars.btitle = sTitel
pars.atitle = sKapitel
else
pars.genre = "book"
pars.btitle = sTitel
end
if type( datum ) == "table" then
pars.date = datum:format( "ISO" )
end
if sAutor then
if type( sAutor ) == "table" then
stick = Zitation.citePerson( sAutor, true )
else
pars.au = flat( sAutor, 3, true )
end
end
pars.pub = feed( "bas", "Verlag" )
pars.pages = feed( "fragment", "Seiten" )
if feed( "id" ) then
pars.isbn = feed( "id", "ISBN" ) or
feed( "id", "ISBNfalsch" ) or
feed( "id", "ISBNdefekt" )
pars.issn = feed( "id", "ISSN" ) or
feed( "id", "ISSNfalsch" )
pars.oclc = feed( "id", "OCLC" )
pars.doi = feed( "id", "DOI" )
pars.pmc = feed( "id", "PMC" )
pars.pmid = feed( "id", "PMID" )
end
if feed( "print" ) then
pars.edition = feed( "print", "Auflage" )
pars.issue = feed( "print", "Nummer" )
pars.place = feed( "print", "Ort" )
pars.volume = feed( "print", "Band" )
end
pars.series = feed( "serie", "Reihe" )
end
if pars then
fein( "", Zitation.COinS( pars, false, stick ), std )
end
end
end -- coins()
-- Exportierte Funktionen ===============================================
Zitation.failure = function ( alert, always )
-- Ausgabe von Fehlern mit class=error
-- Parameter:
-- alert -- string, mit Fehlerliste, oder nil
-- always -- do not hide: boolean, or nil
-- Rückgabewert: string, ggf. mit Fehlermeldung
local r
if alert then
local TemplUtl = Zitation.fetch( "TemplUtl" )
local light = feed( "leise", "leiser" ) and not always
local self = feed( "leise", "Vorlage" ) or Selbst
r = string.format( "'''Fehler in [[%s]]''' – %s",
self, alert )
r = TemplUtl.failure( r, not light, false, Zitation.frame )
else
r = ""
end
return r
end -- Zitation.failure()
Zitation.fault = function ( a, always, auxilary )
-- Formatiere Fehler als teils ausgeblendet
-- Parameter:
-- a -- string, mit Fehlermeldung
-- always -- true, wenn nicht zu unterdrücken
-- auxilary -- string oder nil, mit tooltip
-- Rückgabewert:
-- string, ggf. mit umschließendem HTML-Element
local r
if not always and
feed( "leise", "leiser" ) and
mw.site.server == "//de.wikipedia.org" then
if fading() then
local e = mw.html.create( "span" )
if auxilary then
e:attr( { title = auxilary } )
end
e:addClass( "Zitationsfehler Zitationswartung" )
:css( "display", "none" )
:wikitext( a )
r = tostring( e )
end
end
return r or a
end -- Zitation.fault()
Zitation.fetch = function ( assigned, acquire )
-- Binde Modul ein
-- Parameter:
-- assigned -- string mit Name
-- "arXiv"
-- "bibcode"
-- "DateTime"
-- "JSTOR"
-- "Multilingual"
-- "TemplUtl"
-- "Text"
-- "URIutil"
-- "URLutil"
-- "WLink"
-- acquire -- string mit abweichendem Modulnamen, oder false
-- Rückgabewert: table des Moduls
-- error: Modul nicht gefunden
local r
if Zitation.extern then
r = Zitation.extern[ assigned ]
else
Zitation.extern = { }
end
if not r then
local s = assigned
local lucky, g
if acquire then
s = acquire
end
lucky, g = pcall( require, "Module:" .. s )
if type( g ) == "table" then
r = g[ assigned ]()
Zitation.extern[ assigned ] = r
else
fehler( "Modul", g )
error( string.format( "Zitation.fetch(%s) %s", s, g ) )
end
end
return r
end -- Zitation.fetch()
Zitation.figure = function ( adjust )
-- Bilde Zahlenwert
-- Parameter:
-- adjust -- Wert beliebigen Typs
-- Rückgabewert:
-- Numerischer Wert, notfalls 0
local r
local s = type( adjust )
if s == "string" then
r = tonumber( adjust ) or 0
elseif s == "number" then
r = adjust
else
r = 0
end
return r
end -- Zitation.figure()
Zitation.fill = function ( area, access, assign, alias )
-- Parameterkomponente zuweisen
-- Parameter:
-- area -- string, mit Name der Parametergruppe
-- access -- string, mit Name der Komponente
-- assign -- Parameterwert
-- alias -- string, mit Name des Benutzerparameters, oder nil
if not Zitation.o then
Zitation.o = { }
end
if type( Zitation.o[ area ] ) ~= "table" then
Zitation.o[ area ] = { }
end
Zitation.o[ area ][ access ] = { s = alias or
string.format( "%s.%s",
area, access ),
v = assign }
end -- Zitation.fill()
Zitation.filler = function ( args, assign )
-- Parameterkomponenten zuweisen
-- Parameter:
-- args -- Zfilter.object,
-- mit Zuweisungen nach Vorlagenparametername
-- assign -- table, mit Transformation in neutrales Datenmodell
local g, r, value
if not Zitation.o then
Zitation.o = { }
end
for k, v in pairs( assign ) do
value = args{ k }
if value then
g = v[ 1 ]
if not Zitation.o[ g ] then
Zitation.o[ g ] = { }
end
Zitation.o[ g ][ v[ 2 ] ] = value
end
end -- for k, v
end -- Zitation.filler()
Zitation.filter = function ( args, allowed )
-- Analysiere Argumentenliste und gleiche mit erlaubten Namen ab
-- Parameter:
-- args -- table, mit aktuellen Werten
-- allowed -- table, mit erlaubten Namen, zugewiesen:
-- true -- Nur diese Namensvariante bekannt
-- table -- Namensvariationen
-- Jeder Wert:
-- true -- unerwünscht, Meldung
-- table -- Details
-- table -- low=true: Keine Meldung
-- Rückgabewerte:
-- table, mit gefilterten Werten, nach Parametername
-- Zfilter object
-- Jede Komponente:
-- index-Zugriff:
-- string, mit Parameterwert, kein leerer string
-- get-Zugriff:
-- table, mit
-- s=Orginal-Parametername
-- v=Parameterwert, nicht leer
local signatur = "__Zfilter"
local meta = { }
local r = { [ signatur ] = { } }
local discard = false
local doubled = false
local un = false
local d, lapsus
meta.__call = function ( self, arglist )
-- Antwort auf: Tabelle{ ... }
return self[ signatur ][ arglist[ 1 ] ]
end
meta.__index = function ( self, access )
-- Antwort auf: ... = Tabelle[x]
local e = self[ signatur ][ access ]
if type( e ) == "table" then
e = e.v
end
return e
end
meta.__newindex = function ( self, access, assign )
-- Antwort auf: Tabelle[x] = ...
local put = assign
if assign and
( type( assign ) ~= "table" or
not assign.v ) then
put = { s=access, v=assign }
end
self[ signatur ][ access ] = put
return
end
setmetatable( r, meta )
for s, v in pairs( args ) do
d = allowed[ s ]
if d then
lapsus = false
if type( d ) == "table" then
for dk, dv in pairs( d ) do
if args[ dk ] then
if not doubled then
doubled = { }
end
if not doubled[ dk ] then
doubled[ tostring( s ) ] = dk
end
end
end
else
d = false
end
elseif type( s ) == "string" then
if d == false then
if not discard then
discard = { }
end
table.insert( discard, s )
else
lapsus = true
end
else
lapsus = true
if v then
if mw.text.trim( v ) == "" then
fehler( "Format", "Pipe '|' zu viel" )
end
v = false
end
s = tostring( s )
end
if lapsus then
if not un then
un = { }
end
un[ s ] = true
end
if v == "" then
v = false
end
if v then
r[ s ] = v
if v:find( "'''", 1, true ) and
type( s ) == "string" then
fehler( "Wert",
string.format( "'%s' mit Wikisyntax", s ) )
r[ s ] = mw.text.encode( r[ s ] )
end
end
end -- for s, v
if un then
local down = { }
local scream = false
local undesired = false
local unknown = false
local light, s, sa
for k, v in pairs( allowed ) do
s = mw.ustring.lower( k )
down[ s ] = { standard=k }
if type( v ) == "table" then
for ka, va in pairs( v ) do
sa = mw.ustring.lower( ka )
if type( va ) == "table" then
va.standard = k
else
va = { standard=k }
end
down[ sa ] = va
end
end
end -- for k, v
for k, v in pairs( un ) do
if type( k ) == "string" then
s = mw.ustring.lower( k )
d = down[ s ]
else
d = false
end
if d then
if type( d ) == "table" then
light = d.low
s = d.standard
else
light = false
end
if r[ s ] then
if not doubled then
doubled = { }
end
if not doubled[ s ] then
doubled[ k ] = s
end
else
r[ s ] = r{ k }
r[ k ] = nil
if not light then
if not undesired then
undesired = { }
end
undesired[ k ] = s
end
end
else
if not unknown then
unknown = { }
end
unknown[ k ] = true
end
end -- for k, v
if unknown then
down = { }
for k, v in pairs( allowed ) do
if type( v ) == "table" then
sa = mw.ustring.lower( k )
for ka, va in pairs( v ) do
sa = mw.ustring.lower( ka )
if type( va ) == "table" then
va.standard = k
else
va = { standard=k }
end
down[ sa ] = va
end
end
end -- for k, v
for k, v in pairs( unknown ) do
if type( k ) == "string" then
s = mw.ustring.lower( k )
d = down[ s ]
if d then
if type( d ) == "table" then
light = d.low
else
light = false
end
s = d.standard
if r[ s ] then
if not doubled then
doubled = { }
end
doubled[ k ] = s
else
r[ s ] = r{ k }
r[ k ] = nil
if not light then
if not undesired then
undesired = { }
end
undesired[ k ] = d.standard
end
end
else
if scream then
scream = scream .. ", "
else
scream = "Unbekannte Parameter: "
end
scream = scream .. k
end
end
end -- for k, v
fehler( "Konflikt", scream )
scream = false
end
if undesired then
for k, v in pairs( undesired ) do
if scream then
scream = scream .. ", "
else
scream = ""
end
scream = string.format( "%s '%s' ist '%s'",
scream, k, v )
end -- for k, v
fehler( "Name", scream )
scream = false
end
end
if doubled then
for k, v in pairs( doubled ) do
if scream then
scream = scream .. ","
else
scream = "Parameterwerte gedoppelt: "
end
scream = string.format( "%s '%s' ./. '%s'",
scream, k, v )
end -- for k, v
fehler( "Konflikt", scream )
scream = false
end
if discard then
for k, v in pairs( discard ) do
fehler( "Entfernen", v .. "=" )
end -- for k, v
end
return r
end -- Zitation.filter()
Zitation.format = function ()
-- Generiere Zitation
-- Rückgabewert:
-- 1 -- string mit Vorlagenresultat
-- 2 -- string mit Fehlermeldung(en) und -kategorien, oder false
local s
Resultat = ""
foreign( "bas", "Sprache" )
autorHrsg()
titel() -- Schließt mit Punkt etc.
werk() -- Schließt mit Punkt etc.
reihe()
auflage() -- Schließt mit Punkt
endBlock() -- Schließt mit Punkt
coins()
s = fehlerliste()
if s == "" then
s = false
end
return Resultat, s
end -- Zitation.format()
Zitation.COinS = function ( args, assign, already )
-- Create string with COinS <span>
-- Parameter:
-- args -- table, with COinS components
-- assign -- optional string, with ID
-- already -- optional string, with preformatted &sequence
-- Returns HTML element string
local Text = Zitation.fetch( "Text" )
local WLink = Zitation.fetch( "WLink" )
local rft = { }
local site = mw.site.server:gsub( "^%l*:?//", "" )
local s, sub, v
if assign then
sub = assign
else
if args.genre then
sub = args.genre
else
sub = "book"
end
end
if args.isbn then
args.isbn = args.isbn:gsub( "-", "" ):upper()
end
s = string.format( "%s%s%s",
"ctx_ver=Z39.88-2004",
"&rft_val_fmt=info%3Aofi%2Ffmt%3Akev%3Amtx%3A",
sub )
if not args.genre then
s = s .. "&rft.genre=book"
end
if type( assign ) == "string" then
sub = assign
else
sub = mw.title.getCurrentTitle().fullText
end
s = string.format( "%s&rfr_id=info:sid/%s:%s",
s,
site,
mw.uri.encode( sub ) )
if already then
s = s .. already
end
for k, v in pairs( args ) do
table.insert( rft, k )
end -- for k, v
table.sort( rft )
for i = 1, #rft do
sub = rft[ i ]
v = args[ sub ]
if type( v ) == "table" then
if type( v.tostring ) == "function" then
v = v.tostring()
end
end
if type( v ) == "string" then
v = mw.text.killMarkers( v ) -- <math>
v = mw.uri.encode( WLink.getPlain( Text.getPlain( v ) ) )
:gsub( "%%E2%%80%%93", "-" )
s = string.format( "%s&rft.%s=%s", s, sub, v )
end
end -- for i
s = string.format( "<span class=\"Z3988\" title=\"%s\" %s>%s</span>",
s,
"style='display:none'",
" " )
return s
end -- Zitation.COinS()
Zitation.ISBN = function ( access, accept, alert )
-- Create string with formatted ISBN
-- Parameter:
-- access -- string, with presumable ISBN
-- accept -- optional number, whether invalid data is permitted
-- 0, nil -- require valid ISBN
-- -1 -- ignore invalid check digit
-- other -- other, e.g. number of digits
-- alert -- optional string, with maintenance category title
-- Returns:
-- 1 -- string, for display
-- 2 -- true, if conditions not matched
local URIutil = Zitation.fetch( "URIutil" )
local mode = accept or 0
local isbn, lapsus, legal, lethal, r
if mode == -1 then
legal, isbn = URIutil.isISBN( access )
if legal then
if URIutil.isISBNvalid( access ) then
fehler( "Wert", "'ISBN' ist nicht formal falsch" )
else
lapsus = true
end
end
elseif mode == 0 then
legal, isbn = URIutil.isISBNvalid( access )
else
legal, isbn = URIutil.isISBN( access )
if isbn == -1 then
lapsus = true
legal = true
lethal = true
end
end
if legal then
if lethal then
r = URIutil.linkISBN( access, true, true, true, alert )
else
r = "ISBN " .. URIutil.formatISBN( access, isbn )
end
if lapsus then
local plus = mw.html.create( "small" )
local show, story
if lethal then
show = "defekt"
story = "WP:ISBNdefekt"
else
show = "formal falsch"
story = "WP:ISBNformalFalsch"
end
if story then
show = string.format( "[[%s|%s]]", story, show )
end
show = string.format( "(%s)", show )
plus:addClass( "ISBN-bad-code" )
:css( "white-space", "nowrap" )
:wikitext( show )
r = string.format( "%s %s", r, tostring( plus ) )
end
else
r = string.format( "ISBN %s%s",
access,
Zitation.fault( "(?!)", true, "ungültig" ) )
fehler( "Wert", "'ISBN'" )
fire( "ISBN" )
end
return r, legal
end -- Zitation.ISBN()
-- Export ===============================================================
local p = { }
p.Endpunkt = function ( frame )
-- LEGACY für Vorlage:Internetquelle
local r = ""
local s = frame.args.titel
if s then
local Text = Zitation.fetch( "Text" )
if Text.sentenceTerminated( s ) then
r = ""
else
r = "."
end
end
return r
end -- p.Endpunkt
p.TitelFormat = function ( frame )
-- LEGACY für Vorlage:Internetquelle
local r = ""
local s = frame.args.titel
if s then
local Text = Zitation.fetch( "Text" )
if Text.sentenceTerminated( s ) then
r = s
else
r = s .. "."
end
r = string.format( "<i>%s</i>", r )
end
return r
end -- p.TitelFormat
p.COinS_Template = function ( frame )
local l, r = pcall( Zitation.COinS, frame:getParent().args )
return r
end -- p.COinS_Template
p.ISBN = function ( frame )
local mode = frame.args[ 2 ]
if mode then
mode = tonumber( mode )
end
if frame.args.template then
Selbst = frame.args.template
end
local l, r = pcall( Zitation.ISBN,
frame.args[ 1 ],
mode,
frame.args.link )
return r
end -- p.ISBN
function p.failsafe()
return Zitation.serial
end
p.Zitation = function ()
return Zitation
end -- p.Zitation
return p