Jump to content
Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Dice: Difference between revisions

From Teriock
// via Wikitext Extension for VSCode
Tags: Manual revert Reverted
// via Wikitext Extension for VSCode
Tag: Reverted
Line 1: Line 1:
-- Module:Dice
-- Module:Dice
-- Processes dice input strings and outputs HTML spans with roll links, templates, and data attributes
-- Processes dice input strings and outputs HTML spans with roll links, templates, and data attributes
-- Now uses mw.text.preprocess to ensure generated wikitext is fully expanded


local p = {}
local p = {}
Line 92: Line 93:
   local typ = frame.args[2] or "none"
   local typ = frame.args[2] or "none"
   local parts = splitParts(fullRoll)
   local parts = splitParts(fullRoll)
   local quickParts = {}
   local quickParts, content = {}, {}
  local content = {}


   for _, part in ipairs(parts) do
   for _, part in ipairs(parts) do
Line 101: Line 101:
     else
     else
       local prefixCount, prefixFlag, diceCount, diceFaces, qualifiers = parsePart(part)
       local prefixCount, prefixFlag, diceCount, diceFaces, qualifiers = parsePart(part)
       -- Build quick-roll sequence (ignore flags)
       -- Build quick-roll
       if diceCount then
       if diceCount then
         table.insert(quickParts, diceCount .. "d" .. diceFaces)
         table.insert(quickParts, diceCount .. "d" .. diceFaces)
       end
       end
       -- Prefix template for non-'none' types
       -- Prefix template for non-'none' types
       if prefixFlag and typ ~= "none" and diceCount then
       if prefixFlag and typ ~= "none" and diceCount then
         local tpl = "{{" .. string.upper(prefixFlag)
         local tpl = string.format("{{%s%s}}",
        if prefixCount and prefixCount ~= 1 then tpl = tpl .. "|" .. prefixCount end
          string.upper(prefixFlag), prefixCount and prefixCount ~= 1 and "|"..prefixCount or "")
        tpl = tpl .. "}}"
         table.insert(content, tpl)
         table.insert(content, tpl)
       end
       end
 
       -- Dice link or standalone prefix
       -- Build dice link
       if diceCount then
       if diceCount then
         local displayDice = (diceCount == 1) and ("d" .. diceFaces) or (diceCount .. "d" .. diceFaces)
         local display = diceCount == 1 and ("d"..diceFaces) or (diceCount.."d"..diceFaces)
         local linkLabel = displayDice
         local label = display
        -- Embed prefix in label when type='none' and no qualifiers
         if prefixFlag and typ == "none" and #qualifiers == 0 then
         if prefixFlag and typ == "none" and #qualifiers == 0 then
           linkLabel = (prefixCount or 1) .. string.upper(prefixFlag) .. displayDice
           label = (prefixCount or 1) .. string.upper(prefixFlag) .. display
         end
         end
         local link = string.format("[https://dice.run/#/d/%dd%s %s]", diceCount, diceFaces, linkLabel)
         table.insert(content,
         table.insert(content, link)
          string.format("[https://dice.run/#/d/%dd%s %s]", diceCount, diceFaces, label)
       elseif prefixFlag and not diceCount and typ ~= "none" then
         )
        -- Standalone prefix (no dice)
       elseif prefixFlag and typ ~= "none" then
         table.insert(content, "{{" .. string.upper(prefixFlag) .. "}}")
         table.insert(content, string.format("{{%s}}", string.upper(prefixFlag)))
       end
       end
       -- Qualifier labels
       -- Qualifier labels
       for _, q in ipairs(qualifiers) do
       for _, q in ipairs(qualifiers) do
         table.insert(content, "{{L|" .. capitalize(typ) .. "|" .. capitalize(q) .. "}}")
         table.insert(content, string.format("{{L|%s|%s}}", capitalize(typ), capitalize(q)))
       end
       end
     end
     end
   end
   end


  -- Combine quick-roll and inner wikitext
  local quickRoll = table.concat(quickParts, " ")
   local inner = table.concat(content)
   local inner = table.concat(content)
  local quick = table.concat(quickParts, " ")


   -- Construct span via mw.html for proper parsing
   -- Build span and preprocess
   local span = html.create('span')
   local raw = html.create('span')
     :addClass('dice')
     :addClass('dice')
     :attr('data-full-roll', fullRoll)
     :attr('data-full-roll', fullRoll)
     :attr('data-quick-roll', quickRoll)
     :attr('data-quick-roll', quick)
     :attr('data-type', typ)
     :attr('data-type', typ)
     :wikitext(inner)
     :wikitext(inner)
    :allDone()


  -- Preprocess the generated HTML+wikitext so MediaWiki parses templates correctly
   return text.preprocess(raw)
  local output = span:allDone()
   return frame:preprocess(output)
end
end


return p
return p

Revision as of 23:25, 19 June 2025

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

-- Module:Dice
-- Processes dice input strings and outputs HTML spans with roll links, templates, and data attributes
-- Now uses mw.text.preprocess to ensure generated wikitext is fully expanded

local p = {}
local html = mw.html
local text = mw.text

-- Trim whitespace from both ends
local function trim(s)
  return (s:gsub("^%s*(.-)%s*$", "%1"))
end

-- Split the full roll string into parts and operators (+, -)
local function splitParts(s)
  local parts = {}
  local i = 1
  while i <= #s do
    local c = s:sub(i,i)
    if c == "+" or c == "-" then
      table.insert(parts, c)
      i = i + 1
    elseif c == " " then
      i = i + 1
    else
      local j = s:find("[%+%-]", i)
      if j then
        table.insert(parts, trim(s:sub(i, j-1)))
        i = j
      else
        table.insert(parts, trim(s:sub(i)))
        break
      end
    end
  end
  return parts
end

-- Capitalize first letter
local function capitalize(s)
  return (s:gsub("^%l", string.upper))
end

-- Parse an individual part into prefix, dice, and qualifiers
local function parsePart(part)
  local s = trim(part)
  local prefixCount, prefixFlag
  local diceCount, diceFaces
  local qualifiers = {}

  -- Extract qualifiers in [brackets]
  local main, qualStr = s:match("^(.-)%[([^%]]+)%]$")
  if qualStr then
    s = trim(main)
    for q in qualStr:gmatch("([^ ]+)") do
      table.insert(qualifiers, q)
    end
  end

  -- Extract parenthesized prefix, e.g. (2@p) or (@f)
  local pref = s:match("^%(([%d]*@%a+)%)")
  if pref then
    local num, flag = pref:match("^(%d*)@(%a+)")
    prefixCount = tonumber(num) or 1
    prefixFlag = flag
    s = s:gsub("^%b()", "", 1)
  else
    -- Pure prefix without dice
    local pure = s:match("^@(%a+)$")
    if pure then
      prefixCount = 1
      prefixFlag = pure
      s = ""
    end
  end

  -- Extract dice, e.g. 2d6 or d8
  if s:match("^d%d+") then
    diceCount = 1
    diceFaces = s:match("^d(%d+)")
  elseif s:match("^%d+d%d+") then
    local cnt, faces = s:match("^(%d+)d(%d+)")
    diceCount = tonumber(cnt)
    diceFaces = faces
  end

  return prefixCount, prefixFlag, diceCount, diceFaces, qualifiers
end

-- Main entry for #invoke:Dice|d|<roll>|<type>
function p.d(frame)
  local fullRoll = frame.args[1] or ""
  local typ = frame.args[2] or "none"
  local parts = splitParts(fullRoll)
  local quickParts, content = {}, {}

  for _, part in ipairs(parts) do
    if part == "+" or part == "-" then
      table.insert(quickParts, part)
      table.insert(content, " " .. part .. " ")
    else
      local prefixCount, prefixFlag, diceCount, diceFaces, qualifiers = parsePart(part)
      -- Build quick-roll
      if diceCount then
        table.insert(quickParts, diceCount .. "d" .. diceFaces)
      end
      -- Prefix template for non-'none' types
      if prefixFlag and typ ~= "none" and diceCount then
        local tpl = string.format("{{%s%s}}",
          string.upper(prefixFlag), prefixCount and prefixCount ~= 1 and "|"..prefixCount or "")
        table.insert(content, tpl)
      end
      -- Dice link or standalone prefix
      if diceCount then
        local display = diceCount == 1 and ("d"..diceFaces) or (diceCount.."d"..diceFaces)
        local label = display
        if prefixFlag and typ == "none" and #qualifiers == 0 then
          label = (prefixCount or 1) .. string.upper(prefixFlag) .. display
        end
        table.insert(content,
          string.format("[https://dice.run/#/d/%dd%s %s]", diceCount, diceFaces, label)
        )
      elseif prefixFlag and typ ~= "none" then
        table.insert(content, string.format("{{%s}}", string.upper(prefixFlag)))
      end
      -- Qualifier labels
      for _, q in ipairs(qualifiers) do
        table.insert(content, string.format("{{L|%s|%s}}", capitalize(typ), capitalize(q)))
      end
    end
  end

  local inner = table.concat(content)
  local quick = table.concat(quickParts, " ")

  -- Build span and preprocess
  local raw = html.create('span')
    :addClass('dice')
    :attr('data-full-roll', fullRoll)
    :attr('data-quick-roll', quick)
    :attr('data-type', typ)
    :wikitext(inner)
    :allDone()

  return text.preprocess(raw)
end

return p