Module:PsalmFunctions

From Psalms: Layer by Layer
Jump to: navigation, search

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

local p = {}

function p.getPsalmNumber(frame)
    -- Get the current page name
    local pageName = mw.title.getCurrentTitle().text

    -- Check if "Psalm" exists in the page name
    if not pageName:find("Psalm") then
        return "19"  -- Return 1 if "Psalm" is not found
    end

    -- Extract the part of the page name after "Psalm "
    local psalmNumber = pageName:match("Psalm%s*(%d+)")

    return psalmNumber or "19"
end

function p.encode(frame)
    local text = frame.args[1] or ""
    text = mw.text.encode(text)  -- Converts <, >, &, etc. to HTML entities
    return text
end

function p.encode_brackets_pipes(frame)
	local text = frame.args[1] or ""

    -- Replace only brackets and pipes with URL encoding
    text = text:gsub("%[", "%%5B")  -- Encode '[' as '%5B'
           :gsub("%]", "%%5D")    -- Encode ']' as '%5D'
           :gsub("%|", "%%7C")     -- Encode '|' as '%7C'
           :gsub("%=", "%%3D")     -- Encode '=' as '%3D'
    return text
end
function p.decode_brackets_pipes(frame)
	local text = frame.args[1] or ""
    
    -- Replace only brackets and pipes with URL encoding
    text = text:gsub("%%5B","%[")
           :gsub("%%5D","%]")   
           :gsub("%%7C","|")
    	   :gsub("%%3C","<")
           :gsub("%%3E",">")
           :gsub("%%3D","=")
    return text
end

function p.escape_equals(frame)
	local text = frame.args[1] or ""
    
    -- Replace only brackets and pipes with URL encoding
    text = text:gsub("=", "{{=}}}}") 
    return text
end



function p.url_encode(frame)
	local text = frame.args[1] or ""
    
    text = text:gsub("\n", "\r\n")  -- Convert newlines to CRLF
    text = text:gsub("([^%w%-%.%_%~])", function(c)
        return string.format("%%%02X", string.byte(c))  -- Convert special characters to %XX format
    end)
    return text
end

function p.url_decode(frame)
    local text = frame.args[1] or ""
    
    text = text:gsub("%%(%x%x)", function(hex)
        return string.char(tonumber(hex, 16))  -- Convert hex code to character
    end)
    return text
end

function p.makeID(frame)
    local str = frame.args[1] or ""

    -- Ensure we only return the modified string, avoiding unintended second return values
    str = str:gsub("%s+", "-")   -- Replace spaces with hyphens
             :gsub("%.", "")     -- Remove periods
             :gsub(",", "-")     -- Replace commas with hyphens

    return str
end

function p.validPageName(frame)
    local str = frame.args[1] or ""

    -- Ensure we only return the modified string, avoiding unintended second return values
    str = str:gsub("%s+", "_")
             
    return str
end
function p.listSubpages(frame)
    local prefix = frame.args[1] or mw.title.getCurrentTitle().prefixedText
    local namespace = mw.title.getCurrentTitle().namespace
    local limit = tonumber(frame.args[2]) or 50  -- Set a reasonable limit (default: 50)

    -- Call the MediaWiki API to get subpages
    local api = mw.ext.data and mw.ext.data.getAllPageNames
    if not api then
        return "Error: API function not available. Check your MediaWiki configuration."
    end

    local pages = api({ namespace = namespace, prefix = prefix .. "/", limit = limit })
    if not pages or #pages == 0 then
        return "No subpages found for: " .. prefix
    end

    -- Format the list of subpages
    local result = {}
    for _, page in ipairs(pages) do
        table.insert(result, "[[" .. page .. "]]")
    end
    return table.concat(result, "<br>")
end

-- used for VxV Notes tables
local function splitLines(text)
    local lines = {}
    for line in mw.text.gsplit(text, "<br%s*/?>") do
        table.insert(lines, mw.text.trim(line))
    end
    return lines
end

function p.buildVerseTable(frame)
    local args = frame.args
    local verse = mw.text.trim(args[1] or "?")
	local hebrewText = args[2]
    local englishText = args[3]

    local hebrewLines = splitLines(hebrewText or "")
    local englishLines = splitLines(englishText or "")

    local output = {}
    table.insert(output, '{| class="wikitable"\n|-\n! v. !! Hebrew !! Close-but-clear')

    for i, heb in ipairs(hebrewLines) do
        local partLetter = string.char(96 + i) -- 1 = a, 2 = b, etc.
        local eng = englishLines[i] or ''
        table.insert(output, string.format('|-\n|%s%s ||%s ||%s', verse, partLetter, heb, eng))
    end

    table.insert(output, '|}')
    return table.concat(output, '\n')
end

function p.random(frame)
  local min = tonumber(frame.args[1]) or 1
  local max = tonumber(frame.args[2]) or 1000
  return math.random(min, max)
end

function p.TabbedContentHeaders(frame)
  local args = frame.args
  local names = mw.text.split(args[1] or "", ",")
  local parentID = args[2] or "parentID"
  local result = {}

 
  for i, name in ipairs(names) do
    table.insert(result, frame:expandTemplate{
      title = "TabbedContent/Header",
      args = {
        ParentID = parentID,
        ID = tostring(i),
        Title = mw.text.trim(name),
        Style = "header"
       
      }
    })
  end

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

function p.TabbedContentSubPages(frame)
  local args = frame.args
  local names = mw.text.split(args[1] or "", ",")
  local parentID = mw.text.trim(args[2] or "parentID"):gsub("_$", "")
  local currentPage = mw.title.getCurrentTitle().fullText
  local result = {}

  for i, name in ipairs(names) do


    local subpageName = mw.text.trim(name)
    local fullPageName = currentPage .. "/" .. subpageName
    local transclusion = frame:preprocess('{{:' .. fullPageName .. '}}')
    local divEnd = '</div>'
	
	table.insert(result, frame:expandTemplate{
	      title = "TabbedContent/Header",
	      args = {
	        ParentID = parentID,
	        ID = tostring(i),
	        Title = mw.text.trim(name),
	        Style = "body"
	      }
    })

    table.insert(result, transclusion)
    table.insert(result, divEnd)
  end

  return table.concat(result, "\n")
end
function p.TabbedContentAnnotations(frame)
  local args = frame.args
  local names = mw.text.split(args[1] or "", ",")
  local parentID = mw.text.trim(args[2] or "parentID"):gsub("_$", "")
  local chapter = mw.text.trim(args[3] or "19")
  local result = {}

  for i, name in ipairs(names) do
    local subpageName = mw.text.trim(name)
    local divID = parentID .. "-" .. tostring(i)
    local divClass = "tab-pane fade" .. (i == 1 and " show active" or "")
    local labelFor = divID .. "Label"

    -- Build the full page title of the rendered subpage
    local renderedTitle = string.format("Psalm %s/Overlays/%s/Rendered", chapter, subpageName)
    local titleObj = mw.title.new(renderedTitle)
    local bodyContent = ""

    if titleObj and titleObj.exists then
      -- Transclude the rendered page
      bodyContent = string.format("{{:%s}}", renderedTitle)
    else
      -- Fall back to rendering it dynamically
      bodyContent = string.format("{{Psalm/Table |Chapter=%s|annotations=%s|speakerbars=no|sections=no}}", chapter, subpageName)
    end

    table.insert(result, string.format(
      '<div id="%s" class="%s" role="tabpanel" aria-labelledby="%s">%s</div>',
      divID, divClass, labelFor, bodyContent
    ))
  end

  return frame:preprocess(table.concat(result, "\n"))
end



function p.setPropertiesFromArgs(frame)
  local args = frame:getParent().args
  local out = {}

  for name, value in pairs(args) do
    name = mw.text.trim(name)
    value = mw.text.trim(value)

    if name ~= "" and value ~= "" then
      table.insert(out, string.format('%s: [[%s::%s]]', name, name, value))
      table.insert(out, "<br/>")
    end
  end

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

function p.setSubobjectFromArgs(frame)
  local args = frame:getParent().args
  local category = frame.args[1] or "subobject"
  local out = {}

    local subobject = {}
      table.insert(subobject, '{{#subobject:')
      table.insert(subobject, string.format('|IsCategory=%s', category))

      table.insert(subobject, string.format('|Chapter=%s', p.getPsalmNumber(frame)))

  for name, value in pairs(args) do
    name = mw.text.trim(name)
    value = mw.text.trim(value)

    if name ~= "" and value ~= "" then
      table.insert(subobject, string.format('|%s=%s', name, value))
    end
  end

      table.insert(subobject, "}}")
      table.insert(out, frame:preprocess(table.concat(subobject, "\n")))

  return ""
end

function p.setVersePropertiesFromArgs(frame)
  local args = frame:getParent().args
  local category = frame.args[1] or "HebrewText"
  local out = {}

  for name, value in pairs(args) do
    name = mw.text.trim(name)
    value = mw.text.trim(value)
    local subobject = {}

    if name ~= "" and value ~= "" then
      local number, part = string.match(name, "^(%d+)([a-z]?)$")

      table.insert(subobject, '{{#subobject:')
      table.insert(subobject, string.format('|IsCategory=%s', category))
      table.insert(subobject, "|Chapter={{CurrentChapter}}")
      table.insert(subobject, string.format('|Reference=Psalm {{CurrentChapter}}/%s', name))
      table.insert(subobject, string.format('|VersePortion=%s', name))
      if number then
        table.insert(subobject, string.format('|Verse=%s', number))
      end
      if part and part ~= "" then
        table.insert(subobject, string.format('|VersePart=%s', part))
      end
      table.insert(subobject, string.format('|Text=%s', value))

      table.insert(subobject, "}}")
      table.insert(out, frame:preprocess(table.concat(subobject, "\n")))
    end
  end

  return ""
end



function p.psalmImages(frame)
  local output = {}
  local total = tonumber(frame.args[1]) or 150 -- default to 150 Psalms
  local perRow = tonumber(frame.args[2]) or 5

  for i = 1, total do
    table.insert(output, frame:preprocess(string.format("{{PsalmImage|%d|%d}}", i, perRow)))
  end

  return table.concat(output, " ")
end

function p.GenerateDiagramID(frame)
    local str = frame.args[1] or ""

    -- Ensure we only return the modified string, avoiding unintended second return values
    str = str:gsub("%s+", "-")   -- Replace spaces with hyphens
             :gsub("%.", "")     -- Remove periods
             :gsub(",", "-")     -- Replace commas with hyphens
			 :gsub("[%s/\\]+", "-")          -- turn spaces/slashes into dashes
			 :gsub("[^%w%-]+", "")           -- remove non-word characters except dashes
			 :gsub("%-+", "-")               -- collapse multiple dashes into one
			 :gsub("^%-+", "")               -- trim leading dashes
			 :gsub("%-+$", "")               -- trim trailing dashes

  return str
end

function p.renderWikitext(frame)
    local input = frame.args[1] or ''
    return frame:preprocess(input)
end

return p