Module:Chapters: Difference between revisions
NeonWabbit (talk | contribs) No edit summary |
NeonWabbit (talk | contribs) No edit summary |
||
(36 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 = | table.insert(chapters, {number = number, title = title, date = date, pagecount = tonumber(pagecount)}) | ||
end | end | ||
return chapters | |||
end | |||
return | 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 == | if chapter.title == normalizedTitle then | ||
return chapter[detail] | return chapter[detail] | ||
end | end | ||
Line 35: | Line 60: | ||
function p.getTotalChapters() | function p.getTotalChapters() | ||
return p.getMainChaptersCount() | |||
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 == | if chapter.title == normalizedTitle and i < #chapters then | ||
return chapters[i + 1].title | return chapters[i + 1].title | ||
end | end | ||
Line 53: | 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 == | if chapter.title == normalizedTitle and i > 1 then | ||
return chapters[i - 1].title | return chapters[i - 1].title | ||
end | end | ||
end | end | ||
return nil | 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 | end | ||
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 | |||
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( | local chapter_no = p.getChapterDetails(normalizedTitle, "number") or "N/A" | ||
local date = p.getChapterDetails( | local date = p.getChapterDetails(normalizedTitle, "date") or "N/A" | ||
local pagecount = p.getChapterDetails( | 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( | local next_chapter = p.getNextChapter(normalizedTitle) or "N/A" | ||
local prev_chapter = p.getPreviousChapter( | 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 81: | Line 131: | ||
:attr('colspan', '2') | :attr('colspan', '2') | ||
:css('text-align', 'center') | :css('text-align', 'center') | ||
:css('font-size', ' | :css('font-size', '125%') | ||
:css('padding', ' | :css('padding', '5px') | ||
:wikitext(chapterTitle) | :wikitext(chapterTitle) | ||
:done() | :done() | ||
:done() | :done() | ||
-- Optionally add image | -- 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 | if image and image ~= "" then | ||
infobox:tag('tr') | infobox:tag('tr') | ||
Line 93: | Line 158: | ||
:attr('colspan', '2') | :attr('colspan', '2') | ||
:css('text-align', 'center') | :css('text-align', 'center') | ||
:wikitext('[[File:' .. image .. ']]') | :wikitext('[[File:' .. image .. '|250px]]') | ||
:done() | :done() | ||
: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 | end | ||
-- Add chapter number and total chapters on the same line | -- Add chapter number and total chapters on the same line | ||
local chapter_info = string.format("%s of %s [[Template:ChapterList|( | local chapter_info = string.format("%s of %s [[Template:ChapterList|(list of chapters)]]", chapter_no, total_chapters) | ||
infobox:tag('tr') | infobox:tag('tr') | ||
:tag('th'):wikitext('Chapter'):done() | :tag('th'):wikitext('Chapter'):done() | ||
Line 106: | Line 184: | ||
infobox:tag('tr') | infobox:tag('tr') | ||
:tag('th'):wikitext(' | :tag('th'):wikitext('Published'):done() | ||
:tag('td'):wikitext(date):done() | :tag('td'):wikitext(p.formatDate(date)):done() | ||
:done() | :done() | ||
infobox:tag('tr') | infobox:tag('tr') | ||
:tag('th'):wikitext(' | :tag('th'):wikitext('Page count'):done() | ||
: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 | |||
infobox:tag('tr') | infobox:tag('tr') | ||
:tag('th'): | :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() | :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') | infobox:tag('tr') | ||
:tag(' | :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() | :done() | ||
return infobox | -- Return the complete wikitext | ||
return frame:preprocess(tostring(infobox)) | |||
end | end | ||
return p | return p |
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, "'", "'")
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