Modul:Citation/CS1

Izvor: Hrvatska internetska enciklopedija
Prijeđi na navigaciju Prijeđi na pretraživanje
Dokumentacija modula
Ovaj modul i njegovi pod-moduli podržavaju CS1 i CS2 stil citiranja. Ovaj modul nije namijenjen za direktno pozivanje, već ga je potrebno pozvati iz predloška koji ga koristi.

<section begin=module_components_table /> Pod-moduli navedeni niže osiguravaju funkcionalnost predložaka za for CS1/2 stil citiranja:

CS1 / CS2 moduli
Pod-modul Opis
Gold padlock Modul:Citation/CS1 Odgovoran za prikazivanje i druge podržane funkcije
Modul:Citation/CS1/Configuration Tablice prijevoda; Rukovanje pogreškama i identifikatorima
Modul:Citation/CS1/Whitelist Popis aktivnih i zastarjelih parametara za citiranje
Modul:Citation/CS1/Date validation Rukovanje oblicima datuma i validacija njihove točnosti
Modul:Citation/CS1/Identifiers Funkcije za rukovanje imenovanim identifikatorima (ISBN, DOI, PMID, i sl.)
Modul:Citation/CS1/Utilities Često korištene tablice i funkcije
Modul:Citation/CS1/COinS Funkcije koje stvaraju meta-podatke o citiranom CS1/2 izvoru
Modul:Citation/CS1/styles.css CSS stilovi primijenjeni na predloške za citiranje
Silver padlock Modul:Citation/CS1/Suggestions Popias koji mapira česte netočno navedene parametre i dodjeljuje im ispravna imena
<section end=module_components_table />


-- Modul:Citation/CS1
-- Hrvatska internetska enciklopedija – profesionalno očišćena i proširena verzija CS1 sustava

require('strict')

local p = {}

local cfg        = require('Module:Citation/CS1/Configuration')
local util       = require('Module:Citation/CS1/Utilities')
local ids        = require('Module:Citation/CS1/Identifiers')
local whitelist  = require('Module:Citation/CS1/Whitelist')
local dateval    = require('Module:Citation/CS1/Date_validation')

--------------------------------------------------------------------------------
-- ISO 639-1 → puni nazivi jezika
--------------------------------------------------------------------------------

local iso639 = {
    en = "engleski",
    de = "njemacki",
    fr = "francuski",
    es = "spanjolski",
    it = "talijanski",
    hr = "hrvatski",
    sr = "srpski",
    bs = "bosanski",
    sl = "slovenski",
    ru = "ruski",
    pl = "poljski",
    cs = "ceski",
    da = "danski",
    sv = "svedski",
    fi = "finski",
    nl = "nizozemski",
}

--------------------------------------------------------------------------------
-- ISO 3166 → nazivi država
--------------------------------------------------------------------------------

local iso3166 = {
    DE = "Njemacka",
    HR = "Hrvatska",
    AT = "Austrija",
    CH = "Svicaraska",
    IT = "Italija",
    FR = "Francuska",
}

local function normalizeLanguage(lang)
    if not lang then return nil end
    local code = mw.ustring.lower(mw.text.trim(lang))
    return iso639[code] or lang
end

local function normalizeCountry(code)
    if not code then return nil end
    code = mw.ustring.upper(mw.text.trim(code))
    return iso3166[code] or code
end

--------------------------------------------------------------------------------
-- ISBN VALIDACIJA
--------------------------------------------------------------------------------

local function validateISBN(isbn)
    if not isbn then return nil end
    isbn = isbn:gsub("[^0-9Xx]", "")

    -- ISBN-10
    if #isbn == 10 then
        local sum = 0
        for i = 1, 9 do
            sum = sum + tonumber(isbn:sub(i,i)) * (11 - i)
        end
        local check = isbn:sub(10,10)
        check = (check == "X" or check == "x") and 10 or tonumber(check)
        if (sum + check) % 11 == 0 then
            return isbn
        end
        return isbn .. " (neispravan ISBN-10)"
    end

    -- ISBN-13
    if #isbn == 13 then
        local sum = 0
        for i = 1, 12 do
            local n = tonumber(isbn:sub(i,i))
            sum = sum + (i % 2 == 0 and n * 3 or n)
        end
        local check = tonumber(isbn:sub(13,13))
        if (10 - (sum % 10)) % 10 == check then
            return isbn
        end
        return isbn .. " (neispravan ISBN-13)"
    end

    return isbn .. " (neispravan format)"
end

--------------------------------------------------------------------------------
-- FORMATIRANJE UREDNIKA I PREVODITELJA
--------------------------------------------------------------------------------

local function formatEditors(args)
    local list = {}

    if util.is_set(args.editor) then
        table.insert(list, args.editor)
    end
    for i = 1, 9 do
        local e = args["editor" .. i]
        if util.is_set(e) then
            table.insert(list, e)
        end
    end

    if #list == 0 then return nil end
    if #list == 1 then return "Uredio: " .. list[1] end
    if #list == 2 then return "Uredili: " .. list[1] .. " i " .. list[2] end

    local last = table.remove(list)
    return "Uredili: " .. table.concat(list, ", ") .. " i " .. last
end

local function formatTranslators(args)
    local list = {}

    if util.is_set(args.translator) then
        table.insert(list, args.translator)
    end
    for i = 1, 9 do
        local t = args["translator" .. i]
        if util.is_set(t) then
            table.insert(list, t)
        end
    end

    if #list == 0 then return nil end
    if #list == 1 then return "Preveo: " .. list[1] end
    if #list == 2 then return "Preveli: " .. list[1] .. " i " .. list[2] end

    local last = table.remove(list)
    return "Preveli: " .. table.concat(list, ", ") .. " i " .. last
end

--------------------------------------------------------------------------------
-- POMOĆNE FUNKCIJE
--------------------------------------------------------------------------------

local function clean(s)
    if not s then return nil end
    return mw.text.trim(s):gsub('[%.,;:]+$', '')
end

local function italic(s)
    if not util.is_set(s) then return nil end
    return "''" .. clean(s) .. "''"
end

local function quoted(s)
    if not util.is_set(s) then return nil end
    return '„' .. clean(s) .. '“'
end

local function sentence(parts)
    local line = util.join(parts, ' ')
    if not line or line == '' then return nil end
    if not line:match('[%.%!%?]$') then
        line = line .. '.'
    end
    return line
end

--------------------------------------------------------------------------------
-- NORMALIZACIJA KLASE (OMOGUĆENE SVE TVOJE KLASE)
--------------------------------------------------------------------------------

local function normalizeClass(args, frame)
    local cls = args.CitationClass or args.type
    if cls then
        return mw.text.trim(cls):lower()
    end

    -- ako postoji URL, a klasa nije zadana → web
    if util.is_set(args.url) then
        return 'web'
    end

    local title = frame:getTitle() or (frame:getParent() and frame:getParent():getTitle()) or ''
    title = mw.ustring.lower(title)

    if title:find('citiranje knjige', 1, true)        then return 'book' end
    if title:find('citiranje weba', 1, true)          then return 'web' end
    if title:find('citiranje casopisa', 1, true)      then return 'journal' end
    if title:find('citiranje novina', 1, true)        then return 'newspaper' end
    if title:find('citiranje enciklopedije', 1, true) then return 'encyclopedia' end
    if title:find('citiranje zakona', 1, true)        then return 'law' end
    if title:find('citiranje arhive', 1, true)        then return 'archive' end
    if title:find('citiranje intervjua', 1, true)     then return 'interview' end

    return 'web'
end
--------------------------------------------------------------------------------
-- HRVATSKI ALIAS PARAMETRI
--------------------------------------------------------------------------------

local hr_aliases = {
    autor      = "author",
    autor1     = "author1",
    autor2     = "author2",
    autor3     = "author3",

    naslov     = "title",

    izdavac    = "publisher",
    mjesto     = "location",
    place      = "location",

    godina     = "year",

    stranica   = "pages",
    stranice   = "pages",

    urednik    = "editor",
    izdanje    = "edition",

    novine     = "newspaper",
    enciklopedija = "encyclopedia",
    zakon      = "law",
    arhiva     = "archive",
    intervju   = "interview",
}

--------------------------------------------------------------------------------
-- getArgs() S MAPIRANJEM HR PARAMETARA
--------------------------------------------------------------------------------

local function getArgs(frame)
    local args = require('Module:Arguments').getArgs(frame)

    for hr, en in pairs(hr_aliases) do
        if args[hr] and not args[en] then
            args[en] = args[hr]
        end
    end

    if args.page and not args.pages then
        args.pages = args.page
    end

    return args
end

--------------------------------------------------------------------------------
-- VALIDACIJA PARAMETARA
--------------------------------------------------------------------------------

local function validateParams(args, cls)
    local errors = {}

    -- Nepoznati parametri
    for k, v in pairs(args) do
        if type(k) == 'string' and not whitelist.params[k] then
            table.insert(errors, "Nepoznat parametar: <code>" .. k .. "</code>")
        end
    end

    -- Obavezni parametri
    for _, req in ipairs(cfg.required_params[cls] or {}) do
        if not util.is_set(args[req]) then
            table.insert(errors, "Nedostaje obavezni parametar: <code>" .. req .. "</code>")
        end
    end

    -- Parametri koji nisu dopušteni u klasi
    local allowed = {}
    for _, p in ipairs(cfg.class_params[cls] or {}) do
        allowed[p] = true
    end

    for k, v in pairs(args) do
        if type(k) == 'string' and whitelist.params[k] and not allowed[k] then
            table.insert(errors, "Parametar <code>" .. k .. "</code> nije dopušten u klasi <code>" .. cls .. "</code>")
        end
    end

    -- Bare URL
    if util.is_set(args.url) and not util.is_set(args.title) then
        table.insert(errors, "Bare URL: nedostaje parametar <code>title</code>")
    end

    -- Prazni parametri
    for k, v in pairs(args) do
        if type(k) == 'string' and type(v) == 'string' and mw.text.trim(v) == '' then
            table.insert(errors, "Prazan parametar: <code>" .. k .. "</code>")
        end
    end

    return errors
end

--------------------------------------------------------------------------------
-- FORMATIRANJE IDENTIFIKATORA
--------------------------------------------------------------------------------

local function formatIds(args)
    local out = {}
    for id, _ in pairs(cfg.id_handlers or {}) do
        local val = args[id:lower()] or args[id]
        if util.is_set(val) then
            table.insert(out, ids.format(id, val))
        end
    end
    return util.join(out, ' · ')
end

--------------------------------------------------------------------------------
-- FORMATIRANJE AUTORA
--------------------------------------------------------------------------------

local function formatAuthors(args)
    local list = {}

    if util.is_set(args.author) then
        table.insert(list, args.author)
    end

    for i = 1, 9 do
        local a = args["author" .. i]
        if util.is_set(a) then
            table.insert(list, a)
        end
    end

    if #list == 0 then return nil end
    if #list == 1 then return list[1] end
    if #list == 2 then return list[1] .. " i " .. list[2] end

    local last = table.remove(list)
    return table.concat(list, ", ") .. " i " .. last
end

--------------------------------------------------------------------------------
-- CITATION: BOOK
--------------------------------------------------------------------------------

local function citeBook(args)
    local parts = {}

    local lang_full = normalizeLanguage(args.language)
    local isbn      = args.isbn and validateISBN(args.isbn) or nil
    local country   = normalizeCountry(args.country)

    table.insert(parts, sentence({
        formatAuthors(args),
        args.year and "(" .. args.year .. ")" or nil,
        italic(args.title),
        args.subtitle and italic(args.subtitle) or nil,
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        formatEditors(args),
        formatTranslators(args),
        args.edition and (args.edition .. ". izd.") or nil,
        args.series and ("Serija: " .. args.series) or nil,
        args.volume and ("Svezak " .. args.volume) or nil,
        util.join({args.location, args.publisher}, ": "),
        country and ("(" .. country .. ")") or nil,
        formatIds(args)
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.quote) then
        table.insert(parts, sentence({quoted(args.quote)}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- HR FORMAT DATUMA (jednostavna verzija za YYYY-MM-DD)
--------------------------------------------------------------------------------

local function formatDateHR(datestr)
    if not util.is_set(datestr) then
        return nil
    end

    local y, m, d = datestr:match('^(%d%d%d%d)%-(%d%d)%-(%d%d)$')
    if not (y and m and d) then
        -- ako nije ISO format, vrati original (već očišćen)
        return clean(datestr)
    end

    -- mapiranje mjeseca na hrvatski naziv (koristi cfg.date_names ako želiš)
    local month_names = {
        ['01'] = 'siječnja',
        ['02'] = 'veljače',
        ['03'] = 'ožujka',
        ['04'] = 'travnja',
        ['05'] = 'svibnja',
        ['06'] = 'lipnja',
        ['07'] = 'srpnja',
        ['08'] = 'kolovoza',
        ['09'] = 'rujna',
        ['10'] = 'listopada',
        ['11'] = 'studenoga',
        ['12'] = 'prosinca',
    }

    local month = month_names[m] or m
    return string.format('%s. %s %s.', tonumber(d), month, y)
end


--------------------------------------------------------------------------------
-- CITATION: WEB
--------------------------------------------------------------------------------


local function citeWeb(args)
    local parts = {}

    -- 1. Naslov (kao link, ali prikazuje se samo naslov)
    if util.is_set(args.url) and util.is_set(args.title) then
        table.insert(parts, sentence({
            "[" .. args.url .. " " .. clean(args.title) .. "]"
        }))
    elseif util.is_set(args.title) then
        table.insert(parts, sentence({
            clean(args.title)
        }))
    end

    -- 2. Website / izdavač
    local site = args.website or args.work or args.publisher
    if util.is_set(site) then
        table.insert(parts, sentence({
            clean(site)
        }))
    end

    -- 3. Datum objave (hr format ako je moguće)
    if util.is_set(args.date) then
        table.insert(parts, sentence({
            formatDateHR(args.date)
        }))
    elseif util.is_set(args.year) then
        table.insert(parts, sentence({
            clean(args.year)
        }))
    end

    -- 4. Pristupljeno
    if util.is_set(args["access-date"]) then
        table.insert(parts, sentence({
            "Pristupljeno " .. clean(args["access-date"])
        }))
    end

    return util.join(parts, " ")
end


--------------------------------------------------------------------------------
-- CITATION: JOURNAL
--------------------------------------------------------------------------------

local function citeJournal(args)
    local parts = {}
    local lang_full = normalizeLanguage(args.language)

    table.insert(parts, sentence({
        formatAuthors(args),
        args.year and "(" .. args.year .. ")" or nil,
        quoted(args.title),
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        italic(args.journal),
        util.join({args.volume, args.issue and "(" .. args.issue .. ")" or nil}, " "),
        args.pages and ("str. " .. args.pages) or nil,
        formatIds(args)
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.quote) then
        table.insert(parts, sentence({quoted(args.quote)}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- CITATION: NEWSPAPER
--------------------------------------------------------------------------------

local function citeNewspaper(args)
    local parts = {}
    local lang_full = normalizeLanguage(args.language)

    table.insert(parts, sentence({
        formatAuthors(args),
        args.date and formatDateHR(args.date) or args.year,
        quoted(args.title),
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        italic(args.newspaper or args.work),
        util.join({args.location, args.publisher}, ": "),
        args.pages and ("str. " .. args.pages) or nil,
        formatIds(args)
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.quote) then
        table.insert(parts, sentence({quoted(args.quote)}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- CITATION: ENCYCLOPEDIA
--------------------------------------------------------------------------------

local function citeEncyclopedia(args)
    local parts = {}
    local lang_full = normalizeLanguage(args.language)

    table.insert(parts, sentence({
        formatAuthors(args),
        italic(args.title),
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        italic(args.encyclopedia or args.work),
        args.volume and ("Svezak " .. args.volume) or nil,
        args.edition and (args.edition .. ". izd.") or nil,
        util.join({args.location, args.publisher}, ": "),
        args.year,
        args.pages and ("str. " .. args.pages) or nil,
        formatIds(args)
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.quote) then
        table.insert(parts, sentence({quoted(args.quote)}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- CITATION: LAW
--------------------------------------------------------------------------------

local function citeLaw(args)
    local parts = {}
    local lang_full = normalizeLanguage(args.language)

    table.insert(parts, sentence({
        italic(args.title or args.law),
        args.jurisdiction,
        args.year or args.date,
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        args.article and ("cl. " .. args.article) or nil,
        args.section and ("§ " .. args.section) or nil,
        args.chapter and ("pog. " .. args.chapter) or nil,
        args.publisher
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.notes) then
        table.insert(parts, sentence({args.notes}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- CITATION: ARCHIVE
--------------------------------------------------------------------------------

local function citeArchive(args)
    local parts = {}
    local lang_full = normalizeLanguage(args.language)

    table.insert(parts, sentence({
        formatAuthors(args),
        italic(args.title),
        args.year or args.date,
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        args.archive,
        args.collection,
        args.identifier,
        util.join({args.location}, ", "),
        args.pages and ("str. " .. args.pages) or nil
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.quote) then
        table.insert(parts, sentence({quoted(args.quote)}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- CITATION: INTERVIEW
--------------------------------------------------------------------------------

local function citeInterview(args)
    local parts = {}
    local lang_full = normalizeLanguage(args.language)

    table.insert(parts, sentence({
        args.interviewer and ("Intervju: " .. args.interviewer) or nil,
        formatAuthors(args),
        quoted(args.title),
        lang_full and ("[jezik: " .. lang_full .. "]") or nil
    }))

    table.insert(parts, sentence({
        italic(args.program or args.work),
        args.publisher,
        args.location,
        args.date or args.year
    }))

    if util.is_set(args.url) then
        local url = "[" .. args.url .. " " .. args.url .. "]"
        if util.is_set(args["access-date"]) then
            url = url .. " (pristupljeno " .. args["access-date"] .. ")"
        end
        table.insert(parts, sentence({url}))
    end

    if util.is_set(args.quote) then
        table.insert(parts, sentence({quoted(args.quote)}))
    end

    return util.join(parts, " ")
end

--------------------------------------------------------------------------------
-- GLAVNA FUNKCIJA
--------------------------------------------------------------------------------

function p.citation(frame)
    local args = getArgs(frame)
    local cls  = normalizeClass(args, frame)

    -- Validacija
    local errors = validateParams(args, cls)
    if #errors > 0 then
        local out = '<div class="citation-errors" style="color:#b00; font-size:90%;">'
        for _, e in ipairs(errors) do
            out = out .. '• ' .. e .. '<br>'
        end
        out = out .. '</div>'
        return out
    end

    -- Dispatch prema klasi
    if cls == 'book' then
        return citeBook(args)
    elseif cls == 'journal' then
        return citeJournal(args)
    elseif cls == 'newspaper' then
        return citeNewspaper(args)
    elseif cls == 'encyclopedia' then
        return citeEncyclopedia(args)
    elseif cls == 'law' then
        return citeLaw(args)
    elseif cls == 'archive' then
        return citeArchive(args)
    elseif cls == 'interview' then
        return citeInterview(args)
    else
        return citeWeb(args)
    end
end

--------------------------------------------------------------------------------
-- ALIAS ZA #invoke: ... |main
--------------------------------------------------------------------------------

p.main = p.citation

--------------------------------------------------------------------------------
-- BIBLIOGRAFIJA
--------------------------------------------------------------------------------

function p.bibliography(frame)
    local args = frame.args
    local out  = {}

    local index = 1
    while args[tostring(index)] do
        table.insert(out, "* " .. args[tostring(index)])
        index = index + 1
    end

    return table.concat(out, "\n")
end

--------------------------------------------------------------------------------
-- POVRAT MODULA
--------------------------------------------------------------------------------

return p