Module:Listing: Difference between revisions

From Zelda Dungeon Wiki
Jump to navigation Jump to search
Want an adless experience? Log in or Create an account.
(instead of parsing raw content and then expanding some templates within the content, just expand the whole content as a template)
(support single arg ("The Legend of Zelda Characters" instead of "The Legend of Zelda|Characters"), and parse categories from the listing page)
Line 53: Line 53:
   until not contentBackfillSection
   until not contentBackfillSection


   return currentSection
  -- determine if line is a category
  local cat = string.match( line, '^%s*%[%[Category:(.-)]]%s*$' )
  cat = cat and mw.text.split( cat, '|' )[1]
 
   return currentSection, cat
end
end


Line 61: Line 65:


function Navbox.new( args )
function Navbox.new( args )
   local subject = args[1] .. ' ' .. args[2]
   local subject = args[2] and (args[1] .. ' ' .. args[2]) or args[1]
   args.class = 'navbox'
   args.class = 'navbox'
   args.title = '[[' .. subject .. ']]'
   args.title = '[[' .. subject .. ']]'
Line 68: Line 72:
   local obj = Box.new( 'light', args )
   local obj = Box.new( 'light', args )
   obj.subject = subject
   obj.subject = subject
   obj.categories = { args[1], subject, args[2] }
   obj.categories = args[2] and { args[1], subject, args[2] } or {} -- will be set later when parsing the page
   return setmetatable( obj, Navbox )
   return setmetatable( obj, Navbox )
end
end
Line 84: Line 88:
     summary = "",
     summary = "",
     sections = {},
     sections = {},
    categories = {},
     topLevelLeaves = {}, -- i.e. L2 sections with no children
     topLevelLeaves = {}, -- i.e. L2 sections with no children
     groups = {} -- i.e. L2 sections that have children
     groups = {} -- i.e. L2 sections that have children
   }
   }
   local currentSection = root
   local currentSection = root
  local cat = nil


   -- can't think of a regex to split sections so go line by line
   -- can't think of a regex to split sections so go line by line
   for line in gsplit( pageContent, '\n' ) do
   for line in gsplit( pageContent, '\n' ) do
     currentSection = handleLine( line, currentSection )
     currentSection, cat = handleLine( line, currentSection )
    if cat and cat ~= "Listings" then root.categories[#root.categories + 1] = cat end
   end
   end



Revision as of 19:13, August 12, 2020

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

local Args = require( 'Module:Args' )
local Box = require( 'Module:Box' ).Box

-- got this from http://lua-users.org/wiki/SplitJoin
-- idk how it works but it's 100x more performant than mw.text.gsplit
function gsplit(s,sep)
   local lasti, done, g = 1, false, s:gmatch('(.-)'..sep..'()')
   return function()
      if done then
         return
      end
      local v,i = g()
      if s == '' or sep == '' then
         done = true
         return s
      end
      if v == nil then
         done = true
         return s:sub(lasti)
      end
      lasti = i
      return v
   end
end

function handleLine( line, currentSection )
  local headingLevel, headingText = string.match( line, '^%s*(=+)%s*(.-)%s*=+$' )
  if headingLevel then -- line is a heading
    local newSection = {
      level = #headingLevel,
      name = headingText,
      content = "",
      summary = "",
      sections = {}
    }

    -- find the right parent and insert
    while currentSection.level >= #headingLevel do
      currentSection = currentSection.parent
    end
    newSection.parent = currentSection
    currentSection.sections[#currentSection.sections + 1] = newSection
    currentSection = newSection
  elseif #currentSection.sections == 0 then -- no child headings yet so this is part of the summary of the current section
    currentSection.summary = currentSection.summary .. line .. '\n'
  end

  -- add to content of all parent sections, plus current section if line isn't a heading
  local contentBackfillSection = headingLevel and currentSection.parent or currentSection
  repeat
    contentBackfillSection.content = contentBackfillSection.content .. line .. '\n'
    contentBackfillSection = contentBackfillSection.parent
  until not contentBackfillSection

  -- determine if line is a category
  local cat = string.match( line, '^%s*%[%[Category:(.-)]]%s*$' )
  cat = cat and mw.text.split( cat, '|' )[1]

  return currentSection, cat
end

local Navbox = Box.new()
Navbox.__index = Navbox
setmetatable( Navbox, Box )

function Navbox.new( args )
  local subject = args[2] and (args[1] .. ' ' .. args[2]) or args[1]
  args.class = 'navbox'
  args.title = '[[' .. subject .. ']]'
  args.edit = subject
  args.hide = args.hide or 'show'
  local obj = Box.new( 'light', args )
  obj.subject = subject
  obj.categories = args[2] and { args[1], subject, args[2] } or {} -- will be set later when parsing the page
  return setmetatable( obj, Navbox )
end

local p = {}

p.Navbox = Navbox

function p._parseListing( pageName, pageContent )
  local pageContent = pageContent or mw.text.killMarkers( mw.getCurrentFrame():expandTemplate{ title = ':' .. pageName, args = {} } )
  local root = {
    level = 1,
    name = pageName,
    content = "",
    summary = "",
    sections = {},
    categories = {},
    topLevelLeaves = {}, -- i.e. L2 sections with no children
    groups = {} -- i.e. L2 sections that have children
  }
  local currentSection = root
  local cat = nil

  -- can't think of a regex to split sections so go line by line
  for line in gsplit( pageContent, '\n' ) do
    currentSection, cat = handleLine( line, currentSection )
    if cat and cat ~= "Listings" then root.categories[#root.categories + 1] = cat end
  end

  -- split sections into top-level items and groups with second-level items
  for _, section in ipairs( root.sections ) do
    if #section.sections > 0 then
      root.groups[#root.groups + 1] = section
    else
      root.topLevelLeaves[#root.topLevelLeaves + 1] = section
    end
  end

  return root
end

function p.bullets( frame )
  local listing = p._parseListing( frame.args[1] )
  local bullets = mw.html.create( 'ul' )
  for _, section in ipairs( listing.sections ) do
    local sublist = bullets:tag( 'li' )
      :wikitext( section.name )
      :tag( 'ul' )
    for _, subsection in ipairs( section.sections ) do
      sublist:tag( 'li' ):wikitext( subsection.name )
    end
  end
  return tostring( bullets )
end

p.debugFrame = {
  args = {
    [1] = 'The Legend of Zelda Locations'
  }
}

p.debugContent = [[
Summary {{Infobox|thing=value}}

== First Section ==
Section 1 summary {{Template|prop=val}}

=== Subsection of First Section ===
Subsection 1 content {{Template|prop=val}}

== Second Section ==
Section 2 summary {{Template|prop=val}}

=== Subsection of Second Section ===
Subsection 2 content {{Template|prop=val}}

{{Cat}}
]]

return p