Modul:Zitation
Die Dokumentation für dieses Modul kann unter Modul:Zitation/Doku erstellt werden
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( "90 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 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