Jump to content

Module:Printable version

From Wikibooks, open books for an open world
-- Search and display the book pages from the TOC page, in order to create a printable version and a previous / next navigation.

debug = false
include_book_subpages_only = true
do_not_evaluate_each_chapter = false
local p = {}

ModuleTnt = require('Module:TNT')
Error = ModuleTnt.format('I18n/Module:Printable version', 'error_invalid_toc')
Beginning1 = ModuleTnt.format('I18n/Module:Printable version', 'header_notice')
Beginning2 = ModuleTnt.format('I18n/Module:Printable version', 'header_cover')
Break = ModuleTnt.format('I18n/Module:Printable version', 'page_break')
Ending1 = ModuleTnt.format('I18n/Module:Printable version', 'footer_license')
Ending2 = ModuleTnt.format('I18n/Module:Printable version', 'footer2')
templateLeft  = ModuleTnt.format('I18n/Module:Printable version', 'template_left')
templateRight = ModuleTnt.format('I18n/Module:Printable version', 'template_right')
TOC = ModuleTnt.format('I18n/Module:Printable version', 'TOC')
sep = ModuleTnt.format('I18n/Module:Printable version', 'subpage_separator')
page_before = ModuleTnt.format('I18n/Module:Printable version', 'page_before')
page_after = ModuleTnt.format('I18n/Module:Printable version', 'page_after')

function p._escapePattern(pattern)
    return mw.ustring.gsub(pattern, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1");
end


function p.displays_book(frame)
    if not debug then Error = '' end
    if frame == nil then return '' end
    if frame.args == nil then return '' end
    if frame.args[1] == nil then return '' end
    local BookName = frame.args[1]
    if (BookName ~= nil and mw.text.trim(BookName) ~= '') then
        title = mw.title.new(BookName)
        if frame.args[2] ~= nil and frame.args[2] ~= '' then
            BookName = frame.args[2]
        else
            if mw.ustring.find(BookName, sep .. TOC, 1, true) ~= nil then BookName = mw.ustring.gsub(BookName, "^(.*)" .. sep .. TOC .. "$", "%1") end
        end
        if frame.args[3] ~= nil then include_book_subpages_only = false end
    else
        return Error
    end
    if frame.args[4] ~= nil and frame.args[4] ~= '' then do_not_evaluate_each_chapter = true end

    if (title == nil or title == '') then return Error end
    text = title.getContent(title)
    if (text == nil or text == '') then return Error end

    -- Book subpages titles normalization to absolute names
    local lines_ = mw.text.split(text, "\n")
    local fullPageName
    local PrintVersion = {}

    if (page_before ~= '') then
        -- Add book header
        fullPageName = BookName .. sep .. page_before
        ChapterTitle = mw.title.new(fullPageName)
        if (ChapterTitle ~= nil and ChapterTitle.exists) then
            -- Title should be defined in the page itself
            table.insert(PrintVersion, frame:expandTemplate{ title = ':' .. fullPageName } .. '\n\n')
        end
    end

    -- Add book chapters
    for i,v in ipairs(lines_) do
        if mw.text.trim(v) ~= '' then
            fullPageName = p.getFullPageName(BookName, v)
            if fullPageName ~= nil then
                ChapterTitle = mw.title.new(fullPageName)
                if (ChapterTitle ~= nil and (do_not_evaluate_each_chapter or ChapterTitle.exists)) then
                    PageName = p.getSubpageName(BookName, fullPageName)
                    if (PageName ~= nil and PageName ~= '') then
                        if Break ~= "" then table.insert(PrintVersion, frame:expandTemplate{title = Break}) end
                            table.insert(PrintVersion, '\n<div style="clear:both;page-break-before:always;"></div>\n=' .. PageName .. '=\n')
                    end
                    table.insert(PrintVersion, frame:expandTemplate{ title = ':' .. fullPageName } .. '\n\n')
                else
                    if debug then table.insert(PrintVersion, '<span class="error">Missing subpage "' .. fullPageName .. '" on line "' .. v .. '" for the book:</span> ' .. BookName .. '\n\n') end
                end
            end
        end
    end
 
    if (page_after ~= '') then
        -- Add book footer
        fullPageName = BookName .. sep .. page_after
        ChapterTitle = mw.title.new(fullPageName)
        if (ChapterTitle ~= nil and ChapterTitle.exists) then
            -- Title should be defined in the page itself
            table.insert(PrintVersion, frame:expandTemplate{ title = ':' .. fullPageName } .. '\n\n')
        end
    end

    Templates1 = ""
    if Beginning1 ~= "" then Templates1 = Templates1 .. frame:expandTemplate{title = Beginning1} .. '\n' end
    if Beginning2 ~= "" then Templates1 = Templates1 .. frame:expandTemplate{title = Beginning2} .. '\n' end
    Templates2 = ""
    if Ending1 ~= "" then Templates2 = Templates2 .. frame:expandTemplate{title = Ending1} .. '\n' end
    if Ending2 ~= "" then Templates2 = Templates2 .. frame:expandTemplate{title = Ending2} .. '\n' end

    return Templates1 .. table.concat(PrintVersion, "\r\n") .. Templates2
end


function p.extract_fullPageName(frame)
    if frame == nil then return '' end
    if frame.args == nil then return '' end
    if frame.args[1] == nil then return '' end
    if frame.args[2] == nil then return '' end
    return p.getFullPageName(frame.args[1], frame.args[2])
end


function p.getFullPageName(BookName, chapter)
    if (BookName ~= nil and mw.text.trim(BookName) ~= '') or (chapter ~= nil and mw.text.trim(chapter) ~= '') then
        BookName = mw.text.trim(BookName)
        chapter = mw.text.trim(chapter)
        BookName = mw.ustring.gsub(BookName, "_", " ")
        chapter = mw.ustring.gsub(chapter, "_", " ")
    else
        if debug then chapter = '<span class="error">Incorrect book or chapter name</span>' else chapter = '' end
    end

    chapter = mw.ustring.gsub(chapter, "{{BOOKNAME}}", BookName)
    chapter = mw.ustring.gsub(chapter, "{{[Mm]odulo%|([^}]+)}}", "[[%1]]")
    chapter = mw.ustring.gsub(chapter, " *%| *[0-9]*.*{{[Cc]%|([^}]+)%|[0-9]}}", "[[" .. BookName .. sep .. "%1]]")
    chapter = mw.ustring.gsub(chapter, " *%| *[0-9]*.*{{[Cc]%|([^}]+)}}", "[[" .. BookName .. sep .. "%1]]")
    chapter = mw.ustring.gsub(chapter, " *%[%[Image:[^%]]+%]%]", "")
    chapter = mw.ustring.gsub(chapter, "{{[^}]*}}", "")
    chapter = mw.ustring.gsub(chapter, "^[%#%*:; ]*", "")
    chapter = mw.ustring.gsub(chapter, "%[%[%.%.?/", "[[" .. BookName .. sep)
    chapter = mw.ustring.gsub(chapter, "%[%[/", "[[" .. BookName .. sep)
    chapter = mw.ustring.gsub(chapter, "%/%]%]", "]]")
    chapter = mw.ustring.gsub(chapter, "%/$", "")
    if mw.ustring.find(chapter, "%[%[") ~= nil then
        -- Pages titles extraction from the TOC
        if mw.ustring.find(chapter, "%|") == nil or (mw.ustring.find(chapter, "%]") ~= nil and mw.ustring.find(chapter, "%|") > mw.ustring.find(chapter, "%]")) then
                Ending = "%]"
        else
                if mw.ustring.find(chapter, "%/%|") == nil or mw.ustring.find(chapter, "%/%|") > mw.ustring.find(chapter, "%|") then
                    Ending = "%|"
            else
                    Ending = "%/%|"
            end
        end
        chapter = mw.text.split(chapter, Ending)[1]   -- extraction of the line beginning
        --chapter = mw.text.split(chapter, "%[%[")[2]
        chapter = mw.ustring.gsub(chapter, "[^%[]*%[%[(.*)", "%1") -- brackets and pipes removal

        if chapter == BookName or chapter == BookName .. sep or mw.ustring.find(chapter, "%#") ~= nil then
            if debug then chapter = '<span class="error">Chapter = ' .. chapter .. ' => book name or another subpage name</span> with Ending = ' .. Ending else chapter = '' end
        else
            if include_book_subpages_only then
                -- Book subpages only (and ignoring the other links like "see also")
                if mw.ustring.find(chapter, BookName .. sep, 1, true) == nil then
                    if debug then chapter = "<span class=\"error\">No book subpage into the internal link:</span> '" .. chapter .. "' doesn't include '" .. BookName .. sep .. "'" else chapter = '' end
                end
            end
        end
    else
        if debug then chapter = "<span class=\"error\">No internal link</span> for: " .. chapter .. "\n" else chapter = '' end
    end
    return chapter
end


function p.getSubpageName(bookName, fullPageName)
    k, v = mw.ustring.gsub(fullPageName, '^' .. p._escapePattern(bookName .. sep), '')
    return k
end


function p.extract_subpageName(frame)
    if frame == nil then return '' end
    if frame.args == nil then return '' end
    if frame.args[1] == nil then return '' end
    if frame.args[2] == nil then return '' end
    return p.getSubpageName(frame.args[1], frame.args[2])
end


function p.displays_footer(frame)
    if not debug then Error = '' end
    if frame == nil then return "" end
    if frame.args == nil then return "" end
    if frame.args[1] == nil then return "" end
    local footer = {}

    local BookName = frame.args[1]
    if (BookName ~= nil and mw.text.trim(BookName) ~= "") then
        title = mw.title.new(BookName)
        if mw.ustring.find(BookName, sep .. TOC, 1, true) ~= nil then BookName = mw.ustring.gsub(BookName, "^(.*)" .. sep .. TOC .. "$", "%1") end
    else
        return Error
    end

    local currentPageName
    if frame.args[2] ~= nil and frame.args[2] ~= '' then
        currentPageName = frame.args[2]
    else
        currentPageName = p.getSubpageName(BookName, mw.title.getCurrentTitle().fullText)
    end
    if (currentPageName ~= nil and mw.text.trim(currentPageName) ~= "") then 
        currentPageName = mw.text.trim(currentPageName)
    else
        return Error
    end
    if debug then table.insert(footer, " currentPageName = " .. currentPageName .. "\n") end

    if (title == nil or title == "") then return Error end
    text = title.getContent(title)
    if (text == nil or text == "") then return Error end

    if frame.args[3] ~= nil and frame.args[3] ~= '' then
        if frame.args[3] == 'programming' then
            if debug then table.insert(footer, " skin=programming\n\n") end
            templateLeft = '{| style="width:100%; border:solid 1px #71c837; background:#c6e9af; color:#2d5016;" class="navlinks noprint"\n| style="text-align:left; width:33%; font-size:90%;" class="navprevious" |[[Image:Navigation_Left_Arrow.svg|18px|link=printf|alt=]] [[printf]]\n'
            templateRight = '| style="text-align:center; width:34%;" class="navtitle" | [['..mw.title.getCurrentTitle().rootText..']]<br><b>'..mw.title.getCurrentTitle().subpageText..'</b>\n| style="text-align:right; width:33%; font-size:90%;" class="navnext" | [[printf]] [[Image:Navigation_Right_Arrow.svg|18px|link=printf|alt=]]\n|}'
        end
    end

    -- Book subpages titles normalization to absolute names
    local lines_ = mw.text.split(text, "\n")
    local previousChapter = ""
    local found = false
    local fullPageName
    local homepage = false
    local subpageName
    local rawFullPageName

    if (currentPageName == BookName) then
        if debug then table.insert(footer, " homepage\n") end
        homepage = true
    end

    for i, v in ipairs(lines_) do
        rawFullPageName = mw.text.trim(v)
        if rawFullPageName ~= '' then
            fullPageName = p.getFullPageName(BookName, rawFullPageName)
            if debug then
                if mw.ustring.find(fullPageName, "<span class=\"error\">No internal link</span>") ~= nil then
                    fullPageName = nil
                else
                    table.insert(footer, " research into: " .. rawFullPageName .. "\n")
                    table.insert(footer, " extraction of: " .. fullPageName .. "\n")
                end
            end
            if fullPageName ~= nil then
                if mw.ustring.find(fullPageName, BookName .. sep, 1, true) == nil then
                    if debug then table.insert(footer, " replacement of " .. fullPageName .. " by " .. BookName .. sep .. fullPageName .. "\n") end
                    fullPageName = BookName .. sep .. fullPageName
                end
                ChapterTitle = mw.title.new(fullPageName)
                if (ChapterTitle ~= nil and ChapterTitle.exists) then
                    subpageName = p.getSubpageName(BookName, fullPageName)
                    if debug then table.insert(footer, " cut subpage: " .. subpageName .. "\n") end
                    if (subpageName ~= nil and subpageName ~= "") then
                        if found == true or homepage == true then
                            if debug then table.insert(footer, "<span class=\"error\">Previous & next chapter insertion</span>\n") end

                            if homepage == false then
                                if previousChapter == "" then
                                    theTemplateLeft, nb = mw.ustring.gsub(templateLeft, "printf", BookName .. "|" .. TOC)
                                else
                                    theTemplateLeft, nb = mw.ustring.gsub(templateLeft, "printf", BookName .. sep .. previousChapter .. "|" .. previousChapter)
                                end
                                table.insert(footer, theTemplateLeft)
                            end

                            theTemplateRight, nb = mw.ustring.gsub(templateRight, "printf", BookName .. sep .. subpageName .. "|" .. subpageName)
                            table.insert(footer, theTemplateRight)
                            break
                        elseif subpageName == currentPageName then
                            if debug then table.insert(footer, "<span class=\"error\">Page</span> '" .. currentPageName .. "' found\n\n") end
                            found = true
                        elseif fullPageName ~= "" then
                            if debug then table.insert(footer, " " .. subpageName .. " is different from " .. currentPageName .. "\n") end
                            previousChapter = subpageName
                        else
                            if debug then table.insert(footer, "<span class=\"error\">The current page</span> '" .. subpageName .. "' is not '" .. currentPageName .. "'") end
                        end
                    end
                else
                    if debug then table.insert(footer, "<span class=\"error\">The page</span> '" .. fullPageName .. "' doesn't exist, for '" .. currentPageName .. "'\n\n") end
                end
            end
        end
    end

    if found == true and table.getn(footer) == 0 then
        if debug then table.insert(footer, "<span class=\"error\">No next chapter</span>\n") end
        theTemplateLeft, nb = mw.ustring.gsub(templateLeft, "printf", BookName .. sep .. previousChapter .. "|" .. previousChapter)
        table.insert(footer, theTemplateLeft)
        theTemplateRight, nb = mw.ustring.gsub(templateRight, "printf", BookName .. "|" .. TOC)
        table.insert(footer, theTemplateRight)
    end

    return table.concat(footer, "")
end


return p