Module:Cite
From Bahaipedia
						
						This module is used by Template:Cite to generate a citation based on a book title. See the template page for more documentation.
local p = {}
-- Helper: Get all labels from a list of claims
local function getLabelsFromClaims(claims)
    local labels = {}
    for _, claim in ipairs(claims or {}) do
        if claim.mainsnak and claim.mainsnak.datavalue then
            local id = claim.mainsnak.datavalue.value.id
            local label = mw.wikibase.getLabel(id)
            if label then table.insert(labels, label) end
        end
    end
    return labels
end
-- Helper: Format contributors, apply "et al." if needed
local function formatContributors(contributors)
    local n = #contributors
    if n == 0 then return "" end
    if n > 10 then
        local firstSeven = {}
        for i = 1, 7 do table.insert(firstSeven, contributors[i]) end
        return table.concat(firstSeven, ", ") .. ", et al."
    else
        return table.concat(contributors, ", ")
    end
end
-- Helper: Format secondary contributors (e.g., "ed.", "comp.", "trans.")
local function formatSecondaryContributors(contributors, label)
    local list = formatContributors(contributors)
    if list ~= "" then
        return ", " .. label .. " " .. list
    end
    return ""
end
-- Helper: Parse page range string into start and end pages
local function parsePageRange(pageRangeStr)
    local startPage, endPage
    if not pageRangeStr or pageRangeStr == "" then
        return nil, nil
    end
    pageRangeStr = mw.text.trim(pageRangeStr)
    if pageRangeStr:find("%-") then
        startPage, endPage = pageRangeStr:match("^(%d+)%s*%-%s*(%d+)$")
    else
        startPage = pageRangeStr:match("^(%d+)$")
        endPage = startPage
    end
    if startPage then
        startPage = tonumber(startPage)
        endPage = tonumber(endPage)
        return startPage, endPage
    else
        return nil, nil
    end
end
-- Helper: Check if two page ranges overlap
local function rangesOverlap(aStart, aEnd, bStart, bEnd)
    return aStart <= bEnd and bStart <= aEnd
end
function p.generateCitation(frame)
    local userInput = frame.args[1] or ""
    local pageNumbers = frame.args[2] or ""
    local itemNumber = nil
    local needsInput = false
    local category = "[[Category:Articles requiring Bahaidata input]]"
    -- Determine item number
    if mw.wikibase.isValidEntityId(userInput) then
        itemNumber = userInput
    else
        itemNumber = mw.wikibase.getEntityIdForTitle(userInput)
        if not itemNumber then
            local page = mw.title.new(userInput)
            if page then
                local rtarget = page.redirectTarget
                if rtarget then
                    itemNumber = mw.wikibase.getEntityIdForTitle(rtarget.fullText)
                end
            end
        end
    end
    if not itemNumber then
        return "''" .. userInput .. "''" .. (pageNumbers ~= "" and ", p." .. pageNumbers or "") .. " " .. category
    end
    -- Get entity and data
    local entity = mw.wikibase.getEntity(itemNumber)
    local titleValue = entity.claims['P47'] and entity.claims['P47'][1].mainsnak.datavalue.value.text or ""
    if titleValue == "" then
        return "''" .. userInput .. "''" .. (pageNumbers ~= "" and ", p." .. pageNumbers or "") .. " " .. category
    end
    local authors = getLabelsFromClaims(entity.claims['P10'])
    local editors = getLabelsFromClaims(entity.claims['P14'])
    local compilers = getLabelsFromClaims(entity.claims['P43'])
    local translators = getLabelsFromClaims(entity.claims['P32'])
    local authorValue = formatContributors(authors)
    local editorValue = formatContributors(editors)
    local compilerValue = formatContributors(compilers)
    local translatorValue = formatContributors(translators)
    local publicationDate = entity.claims['P29'] and mw.text.split(entity.claims['P29'][1].mainsnak.datavalue.value.time, '-')[1]:gsub('^%+', '') or ""
    local publisherValue = entity.claims['P26'] and mw.wikibase.getLabel(entity.claims['P26'][1].mainsnak.datavalue.value.id) or ""
    local countryValue = entity.claims['P48'] and mw.wikibase.getLabel(entity.claims['P48'][1].mainsnak.datavalue.value.id) or ""
    local isbn10Value = entity.claims['P31'] and entity.claims['P31'][1].mainsnak.datavalue.value or ""
    local isbn13Value = entity.claims['P49'] and entity.claims['P49'][1].mainsnak.datavalue.value or ""
    if authorValue == "" and compilerValue == "" and translatorValue == "" then
        needsInput = true
    end
    -- Page prefix logic
    local pagePrefix = "p."
    if pageNumbers:find(",") or pageNumbers:find("-") then
        pagePrefix = "pp."
    end
    -- Parse the page numbers passed in
    local citedStartPage, citedEndPage = parsePageRange(pageNumbers)
    if not citedStartPage then
        citedStartPage, citedEndPage = 1, math.huge  -- Default to all pages
    end
    -- Initialize variables for chapter data
    local chapterAuthorValue = ""
    local chapterTitleValue = ""
    local chapterTranslators = {}
    local chapterFound = false
    -- Check if the item has chapters (P59)
    if entity.claims['P59'] and citedStartPage then
        for _, chapterClaim in ipairs(entity.claims['P59']) do
            if chapterClaim.mainsnak and chapterClaim.mainsnak.datavalue then
                local chapterId = chapterClaim.mainsnak.datavalue.value.id
                local chapterEntity = mw.wikibase.getEntity(chapterId)
                if chapterEntity then
                    -- Get the chapter's pages (P6)
                    local chapterPagesValue = chapterEntity.claims['P6'] and chapterEntity.claims['P6'][1].mainsnak.datavalue.value or ""
                    if chapterPagesValue ~= "" then
                        local chapterStartPage, chapterEndPage = parsePageRange(chapterPagesValue)
                        if chapterStartPage and chapterEndPage then
                            -- Check if the cited pages overlap with chapter's pages
                            if rangesOverlap(citedStartPage, citedEndPage, chapterStartPage, chapterEndPage) then
                                -- We have found the chapter
                                chapterFound = true
                                -- Get chapter title from label
                                chapterTitleValue = mw.wikibase.getLabel(chapterId) or ""
                                -- Get chapter authors (P10)
                                local chapterAuthors = getLabelsFromClaims(chapterEntity.claims['P10'])
                                chapterAuthorValue = formatContributors(chapterAuthors)
                                -- Use the chapter's translators if available
                                chapterTranslators = getLabelsFromClaims(chapterEntity.claims['P32'])
                                -- Use the chapter's publication date if available
                                local chapterPublicationDate = chapterEntity.claims['P29'] and mw.text.split(chapterEntity.claims['P29'][1].mainsnak.datavalue.value.time, '-')[1]:gsub('^%+', '') or ""
                                if chapterPublicationDate ~= "" then
                                    publicationDate = chapterPublicationDate
                                end
                                break -- We found the matching chapter, exit the loop
                            end
                        end
                    end
                end
            end
        end
    end
    -- Build the citation
    local citation = ""
    if chapterFound then
        -- Chapter author
        if chapterAuthorValue ~= "" then
            citation = chapterAuthorValue
            if publicationDate ~= "" then
                citation = citation .. " (" .. publicationDate .. "). "
            else
                citation = citation .. ". "
            end
        elseif publicationDate ~= "" then
            citation = "(" .. publicationDate .. "). "
        end
        -- Chapter title
        if chapterTitleValue ~= "" then
            citation = citation .. "\"" .. chapterTitleValue .. ".\" "
        end
        -- 'In' main work
        citation = citation .. "In " .. "''" .. titleValue .. "''"
        -- Volume number (P50)
        local volumeNumber = entity.claims['P50'] and entity.claims['P50'][1].mainsnak.datavalue.value.amount or ""
        if volumeNumber ~= "" then
            citation = citation .. ", Vol. " .. volumeNumber
        end
        -- Secondary contributors (editors, compilers)
        if editorValue ~= "" then
            citation = citation .. ", edited by " .. editorValue
        elseif compilerValue ~= "" then
            citation = citation .. ", compiled by " .. compilerValue
        end
        -- Page numbers with prefix
        if pageNumbers ~= "" then
            citation = citation .. ", " .. pagePrefix .. " " .. pageNumbers
        end
        -- Location and publisher
        if countryValue ~= "" and publisherValue ~= "" then
            citation = citation .. ". " .. countryValue .. ": " .. publisherValue
        elseif publisherValue ~= "" then
            citation = citation .. ". " .. publisherValue
        end
        -- ISBN
        if isbn10Value ~= "" or isbn13Value ~= "" then
            citation = citation .. ". ISBN " .. (isbn10Value ~= "" and isbn10Value or isbn13Value)
        end
        -- Translators
        local combinedTranslators = formatContributors(chapterTranslators)
        if combinedTranslators ~= "" then
            citation = citation .. ". Translated by " .. combinedTranslators
        elseif translatorValue ~= "" then
            citation = citation .. ". Translated by " .. translatorValue
        end
        citation = citation .. "."
    else
        -- Existing logic when no chapter is found
        -- Primary contributor
        if authorValue ~= "" then
            citation = authorValue
            if publicationDate ~= "" then
                citation = citation .. " (" .. publicationDate .. "). "
            else
                citation = citation .. ". "
            end
        elseif compilerValue ~= "" then
            citation = compilerValue .. ", comp."
            if publicationDate ~= "" then
                citation = citation .. " (" .. publicationDate .. "). "
            else
                citation = citation .. ". "
            end
        elseif editorValue ~= "" then
            citation = editorValue .. ", ed."
            if publicationDate ~= "" then
                citation = citation .. " (" .. publicationDate .. "). "
            else
                citation = citation .. ". "
            end
        end
        -- Title
        citation = citation .. "''" .. titleValue .. "''"
        -- Secondary contributors
        if authorValue ~= "" then
            citation = citation .. formatSecondaryContributors(compilers, "comp.")
            citation = citation .. formatSecondaryContributors(editors, "ed.")
        end
        citation = citation .. formatSecondaryContributors(translators, "trans.")
        -- Location and publisher
        if countryValue ~= "" and publisherValue ~= "" then
            citation = citation .. ". " .. countryValue .. ": " .. publisherValue
        elseif publisherValue ~= "" then
            citation = citation .. ". " .. publisherValue
        end
        -- Fallback date if no author
        if publicationDate ~= "" and authorValue == "" then
            citation = citation .. ". " .. publicationDate
        end
        -- Page numbers with prefix
        if pageNumbers ~= "" then
            citation = citation .. ". " .. pagePrefix .. " " .. pageNumbers
        end
        -- ISBN
        if isbn10Value ~= "" or isbn13Value ~= "" then
            citation = citation .. ". ISBN " .. (isbn10Value ~= "" and isbn10Value or isbn13Value)
        end
        citation = citation .. "."
    end
    -- Add category if needed
    if needsInput then
        citation = citation .. " " .. category
    end
    return citation
end
return p