Module:Chapters: Difference between revisions

From Candypedia
No edit summary
No edit summary
 
(18 intermediate revisions by 2 users not shown)
Line 1: Line 1:
-- Module:Chapters
-- Module:Chapters
local p = {}
local p = {}
function p.urlDecode(str)
    str = string.gsub(str, '%%(%x%x)', function(x) return string.char(tonumber(x, 16)) end)
    return str
end
function p.normalizeApostrophes(str)
    str = string.gsub(str, "’", "'")
    str = string.gsub(str, "'", "'")
    str = string.gsub(str, "%%27", "'")
    return str
end


function p.getChaptersList()
function p.getChaptersList()
Line 12: Line 24:
         return {}
         return {}
     end
     end
    -- Normalize apostrophes in content
    content = p.normalizeApostrophes(content)


     local chapters = {}
     local chapters = {}
     for number, title, date, pagecount in string.gmatch(content, "{{Chapter|number=(%d+)|title=([^|]+)|date=([^|]+)|pagecount=(%d+)}}") do
     for number, title, date, pagecount in string.gmatch(content, "{{Chapter|number=([%d%.]+)|title=([^|]+)|date=([^|]+)|pagecount=(%d+)}}") do
         table.insert(chapters, {number = tonumber(number), title = title, date = date, pagecount = tonumber(pagecount)})
         table.insert(chapters, {number = number, title = title, date = date, pagecount = tonumber(pagecount)})
     end
     end


     return chapters
     return chapters
end
function p.getMainChaptersCount()
    local chapters = p.getChaptersList()
    local count = 0
    for _, chapter in ipairs(chapters) do
        if not string.match(chapter.number, "%.") then
            count = count + 1
        end
    end
    return count
end
end


function p.getChapterDetails(chapterTitle, detail)
function p.getChapterDetails(chapterTitle, detail)
     local chapters = p.getChaptersList()
     local chapters = p.getChaptersList()
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
     for _, chapter in ipairs(chapters) do
     for _, chapter in ipairs(chapters) do
         if chapter.title == chapterTitle then
         if chapter.title == normalizedTitle then
             return chapter[detail]
             return chapter[detail]
         end
         end
Line 32: Line 60:


function p.getTotalChapters()
function p.getTotalChapters()
     local totalChapters = #p.getChaptersList()
     return p.getMainChaptersCount()
    return totalChapters
end
end


function p.getNextChapter(chapterTitle)
function p.getNextChapter(chapterTitle)
     local chapters = p.getChaptersList()
     local chapters = p.getChaptersList()
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
     for i, chapter in ipairs(chapters) do
     for i, chapter in ipairs(chapters) do
         if chapter.title == chapterTitle and i < #chapters then
         if chapter.title == normalizedTitle and i < #chapters then
             return chapters[i + 1].title
             return chapters[i + 1].title
         end
         end
Line 48: Line 77:
function p.getPreviousChapter(chapterTitle)
function p.getPreviousChapter(chapterTitle)
     local chapters = p.getChaptersList()
     local chapters = p.getChaptersList()
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
     for i, chapter in ipairs(chapters) do
     for i, chapter in ipairs(chapters) do
         if chapter.title == chapterTitle and i > 1 then
         if chapter.title == normalizedTitle and i > 1 then
             return chapters[i - 1].title
             return chapters[i - 1].title
         end
         end
Line 67: Line 98:
function p.infoboxChapter(frame)
function p.infoboxChapter(frame)
     local chapterTitle = frame.args.chapter_title or mw.title.getCurrentTitle().text
     local chapterTitle = frame.args.chapter_title or mw.title.getCurrentTitle().text
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
     local image = frame.args.image
     local image = frame.args.image
     local caption = frame.args.caption or "Please supply caption"
     local caption = frame.args.caption
    local major_characters = frame.args.major_characters
    local minor_characters = frame.args.minor_characters
    local locations = frame.args.locations
    local collected_in = frame.args.collected_in


     local chapter_no = p.getChapterDetails(chapterTitle, "number") or "N/A"
    caption = caption and caption ~= "" and caption or nil
     local date = p.getChapterDetails(chapterTitle, "date") or "N/A"
 
     local pagecount = p.getChapterDetails(chapterTitle, "pagecount") or "N/A"
     local chapter_no = p.getChapterDetails(normalizedTitle, "number") or "N/A"
     local date = p.getChapterDetails(normalizedTitle, "date") or "N/A"
     local pagecount = p.getChapterDetails(normalizedTitle, "pagecount") or "N/A"
     local total_chapters = p.getTotalChapters() or "N/A"
     local total_chapters = p.getTotalChapters() or "N/A"
     local next_chapter = p.getNextChapter(chapterTitle) or "N/A"
     local next_chapter = p.getNextChapter(normalizedTitle) or "N/A"
     local prev_chapter = p.getPreviousChapter(chapterTitle) or "N/A"
     local prev_chapter = p.getPreviousChapter(normalizedTitle) or "N/A"
 
    local is_intermission = string.match(chapter_no, "%.") and true or false
    local chapter_no_for_url = chapter_no  -- Store the chapter number for the URL without quotation marks
 
    if is_intermission then
        chapter_no = '"' .. chapter_no .. '"'
    end


     local infobox = mw.html.create('table')
     local infobox = mw.html.create('table')
Line 91: Line 137:
         :done()
         :done()
      
      
     -- Optionally add image with standard size
     -- Add subtitle for intermission chapters
     if image and image ~= "" then
     if is_intermission then
         infobox:tag('tr')
         infobox:tag('tr')
             :tag('td')
             :tag('th')
                 :attr('colspan', '2')
                 :attr('colspan', '2')
                 :css('text-align', 'center')
                 :css('text-align', 'center')
                 :wikitext('[[File:' .. image .. '|250px]]')
                 :css('font-size', '110%')
                :css('padding', '2px')
                :css('background-color', '#f0f0f0')
                :css('font-style', 'italic')
                :wikitext('(Intermission)')
                 :done()
                 :done()
             :done()
             :done()
    end


        -- Add caption below image
    -- Optionally add image with standard size
    if image and image ~= "" then
         infobox:tag('tr')
         infobox:tag('tr')
             :tag('td')
             :tag('td')
                 :attr('colspan', '2')
                 :attr('colspan', '2')
                 :css('text-align', 'center')
                 :css('text-align', 'center')
                 :css('font-size', '90%')
                 :wikitext('[[File:' .. image .. '|250px]]')
                :css('padding', '5px')
                :wikitext(caption)
                 :done()
                 :done()
             :done()
             :done()
    else
 
         -- If no image is provided, still show the caption field
         -- Add caption below image if provided
        infobox:tag('tr')
        if caption then
            :tag('td')
            infobox:tag('tr')
                :attr('colspan', '2')
                :tag('td')
                :css('text-align', 'center')
                    :attr('colspan', '2')
                :css('font-size', '90%')
                    :css('text-align', 'center')
                :css('padding', '5px')
                    :css('font-size', '90%')
                :wikitext(caption)
                    :css('padding', '5px')
                    :wikitext(caption)
                    :done()
                 :done()
                 :done()
            :done()
        end
     end
     end


Line 132: Line 184:


     infobox:tag('tr')
     infobox:tag('tr')
         :tag('th'):wikitext('Date'):done()
         :tag('th'):wikitext('Published'):done()
         :tag('td'):wikitext(p.formatDate(date)):done()
         :tag('td'):wikitext(p.formatDate(date)):done()
         :done()
         :done()
Line 140: Line 192:
         :tag('td'):wikitext(pagecount):done()
         :tag('td'):wikitext(pagecount):done()
         :done()
         :done()
    -- Add additional manual entry parameters
    if major_characters and major_characters ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Major characters'):done()
            :tag('td'):wikitext(major_characters):done()
            :done()
    end
    if minor_characters and minor_characters ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Minor characters'):done()
            :tag('td'):wikitext(minor_characters):done()
            :done()
    end
    if locations and locations ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Locations'):done()
            :tag('td'):wikitext(locations):done()
            :done()
    end
    if collected_in and collected_in ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Collected in'):done()
            :tag('td'):wikitext(collected_in):done()
            :done()
    end


     -- Add chapter navigation heading
     -- Add chapter navigation heading
Line 164: Line 245:
         :done()
         :done()
     nav_row:done()
     nav_row:done()
    -- Add link to read chapter on comic's website
    infobox:tag('tr')
        :tag('td')
            :attr('colspan', '2')
            :css('text-align', 'center')
            :wikitext(string.format("[https://bittersweetcandybowl.com/c%s Read chapter]", chapter_no_for_url))
            :done()
        :done()


     -- Return the complete wikitext
     -- Return the complete wikitext

Latest revision as of 06:50, 25 May 2024

Documentation for this module may be created at Module:Chapters/doc

-- Module:Chapters
local p = {}

function p.urlDecode(str)
    str = string.gsub(str, '%%(%x%x)', function(x) return string.char(tonumber(x, 16)) end)
    return str
end

function p.normalizeApostrophes(str)
    str = string.gsub(str, "’", "'")
    str = string.gsub(str, "&#39;", "'")
    str = string.gsub(str, "%%27", "'")
    return str
end

function p.getChaptersList()
    local listPage = mw.title.new('Template:ChapterList')
    if not listPage then
        return {}
    end

    local content = listPage:getContent()
    if not content then
        return {}
    end

    -- Normalize apostrophes in content
    content = p.normalizeApostrophes(content)

    local chapters = {}
    for number, title, date, pagecount in string.gmatch(content, "{{Chapter|number=([%d%.]+)|title=([^|]+)|date=([^|]+)|pagecount=(%d+)}}") do
        table.insert(chapters, {number = number, title = title, date = date, pagecount = tonumber(pagecount)})
    end

    return chapters
end

function p.getMainChaptersCount()
    local chapters = p.getChaptersList()
    local count = 0
    for _, chapter in ipairs(chapters) do
        if not string.match(chapter.number, "%.") then
            count = count + 1
        end
    end
    return count
end

function p.getChapterDetails(chapterTitle, detail)
    local chapters = p.getChaptersList()
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
    for _, chapter in ipairs(chapters) do
        if chapter.title == normalizedTitle then
            return chapter[detail]
        end
    end
    return nil
end

function p.getTotalChapters()
    return p.getMainChaptersCount()
end

function p.getNextChapter(chapterTitle)
    local chapters = p.getChaptersList()
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
    for i, chapter in ipairs(chapters) do
        if chapter.title == normalizedTitle and i < #chapters then
            return chapters[i + 1].title
        end
    end
    return nil
end

function p.getPreviousChapter(chapterTitle)
    local chapters = p.getChaptersList()
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
    for i, chapter in ipairs(chapters) do
        if chapter.title == normalizedTitle and i > 1 then
            return chapters[i - 1].title
        end
    end
    return nil
end

function p.formatDate(date)
    local year, month, day = string.match(date, "(%d+)%-(%d+)%-(%d+)")
    if year and month and day then
        return string.format("{{Start date|%s|%s|%s}}", year, month, day)
    else
        return date
    end
end

function p.infoboxChapter(frame)
    local chapterTitle = frame.args.chapter_title or mw.title.getCurrentTitle().text
    local decodedTitle = p.urlDecode(chapterTitle)
    local normalizedTitle = p.normalizeApostrophes(decodedTitle)
    local image = frame.args.image
    local caption = frame.args.caption
    local major_characters = frame.args.major_characters
    local minor_characters = frame.args.minor_characters
    local locations = frame.args.locations
    local collected_in = frame.args.collected_in

    caption = caption and caption ~= "" and caption or nil

    local chapter_no = p.getChapterDetails(normalizedTitle, "number") or "N/A"
    local date = p.getChapterDetails(normalizedTitle, "date") or "N/A"
    local pagecount = p.getChapterDetails(normalizedTitle, "pagecount") or "N/A"
    local total_chapters = p.getTotalChapters() or "N/A"
    local next_chapter = p.getNextChapter(normalizedTitle) or "N/A"
    local prev_chapter = p.getPreviousChapter(normalizedTitle) or "N/A"

    local is_intermission = string.match(chapter_no, "%.") and true or false
    local chapter_no_for_url = chapter_no  -- Store the chapter number for the URL without quotation marks

    if is_intermission then
        chapter_no = '"' .. chapter_no .. '"'
    end

    local infobox = mw.html.create('table')
    infobox:addClass('infobox')

    -- Add title as heading
    infobox:tag('tr')
        :tag('th')
            :attr('colspan', '2')
            :css('text-align', 'center')
            :css('font-size', '125%')
            :css('padding', '5px')
            :wikitext(chapterTitle)
            :done()
        :done()
    
    -- Add subtitle for intermission chapters
    if is_intermission then
        infobox:tag('tr')
            :tag('th')
                :attr('colspan', '2')
                :css('text-align', 'center')
                :css('font-size', '110%')
                :css('padding', '2px')
                :css('background-color', '#f0f0f0')
                :css('font-style', 'italic')
                :wikitext('(Intermission)')
                :done()
            :done()
    end

    -- Optionally add image with standard size
    if image and image ~= "" then
        infobox:tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :css('text-align', 'center')
                :wikitext('[[File:' .. image .. '|250px]]')
                :done()
            :done()

        -- Add caption below image if provided
        if caption then
            infobox:tag('tr')
                :tag('td')
                    :attr('colspan', '2')
                    :css('text-align', 'center')
                    :css('font-size', '90%')
                    :css('padding', '5px')
                    :wikitext(caption)
                    :done()
                :done()
        end
    end

    -- Add chapter number and total chapters on the same line
    local chapter_info = string.format("%s of %s [[Template:ChapterList|(list of chapters)]]", chapter_no, total_chapters)
    infobox:tag('tr')
        :tag('th'):wikitext('Chapter'):done()
        :tag('td'):wikitext(chapter_info):done()
        :done()

    infobox:tag('tr')
        :tag('th'):wikitext('Published'):done()
        :tag('td'):wikitext(p.formatDate(date)):done()
        :done()

    infobox:tag('tr')
        :tag('th'):wikitext('Page count'):done()
        :tag('td'):wikitext(pagecount):done()
        :done()

    -- Add additional manual entry parameters
    if major_characters and major_characters ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Major characters'):done()
            :tag('td'):wikitext(major_characters):done()
            :done()
    end

    if minor_characters and minor_characters ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Minor characters'):done()
            :tag('td'):wikitext(minor_characters):done()
            :done()
    end

    if locations and locations ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Locations'):done()
            :tag('td'):wikitext(locations):done()
            :done()
    end

    if collected_in and collected_in ~= "" then
        infobox:tag('tr')
            :tag('th'):wikitext('Collected in'):done()
            :tag('td'):wikitext(collected_in):done()
            :done()
    end

    -- Add chapter navigation heading
    infobox:tag('tr')
        :tag('th')
            :attr('colspan', '2')
            :css('text-align', 'center')
            :css('font-size', '110%')
            :css('padding', '5px')
            :css('background-color', '#f0f0f0')
            :wikitext('Chapter navigation')
            :done()
        :done()

    -- Add chapter navigation links in separate columns
    local nav_row = infobox:tag('tr')
    nav_row:tag('td')
        :css('text-align', 'left')
        :wikitext(prev_chapter ~= "N/A" and string.format("[[%s:%s|← %s]]", mw.title.getCurrentTitle().nsText, prev_chapter, prev_chapter) or "← Previous")
        :done()
    nav_row:tag('td')
        :css('text-align', 'right')
        :wikitext(next_chapter ~= "N/A" and string.format("[[%s:%s|%s →]]", mw.title.getCurrentTitle().nsText, next_chapter, next_chapter) or "Next →")
        :done()
    nav_row:done()

    -- Add link to read chapter on comic's website
    infobox:tag('tr')
        :tag('td')
            :attr('colspan', '2')
            :css('text-align', 'center')
            :wikitext(string.format("[https://bittersweetcandybowl.com/c%s Read chapter]", chapter_no_for_url))
            :done()
        :done()

    -- Return the complete wikitext
    return frame:preprocess(tostring(infobox))
end

return p