Module:NavboxMobile: Difference between revisions

No edit summary
Tag: Reverted
No edit summary
 
(86 intermediate revisions by the same user not shown)
Line 16: Line 16:
local listnums = {}
local listnums = {}


-- Helper Functions
-- Function to check if the given HTML class is a list class
local function has_list_class(htmlclass)
    local patterns = {
        '^' .. htmlclass .. '$',
        '%s' .. htmlclass .. '$',
        '^' .. htmlclass .. '%s',
        '%s' .. htmlclass .. '%s'
    }
   
    for arg, _ in pairs(args) do
        if type(arg) == 'string' and mw.ustring.find(arg, cfg.pattern.class) then
            for _, pattern in ipairs(patterns) do
                if mw.ustring.find(args[arg] or '', pattern) then
                    return true
                end
            end
        end
    end
    return false
end
 
-- Function to check if the navbar is enabled
local function has_navbar()
    return args[cfg.arg.navbar] ~= cfg.keyword.navbar_off
        and args[cfg.arg.navbar] ~= cfg.keyword.navbar_plain
        and (
            args[cfg.arg.name]
            or mw.getCurrentFrame():getParent():getTitle():gsub(cfg.pattern.sandbox, '')
                ~= cfg.pattern.navbox
        )
end
 
 
local function add_list_styles()
    local frame = mw.getCurrentFrame()
    local function add_list_templatestyles(htmlclass, templatestyles)
        if has_list_class(htmlclass) then
            return frame:extensionTag{
                name = 'templatestyles', args = { src = templatestyles }
            }
        else
            return ''
        end
    end
       
    local hlist_styles = add_list_templatestyles('hlist', cfg.hlist_templatestyles)
    local plainlist_styles = add_list_templatestyles('plainlist', cfg.plainlist_templatestyles)
   
    -- a second workaround for [[phab:T303378]]
    -- when that issue is fixed, we can actually use has_navbar not to emit the
    -- tag here if we want
    if has_navbar() and hlist_styles == '' then
        hlist_styles = frame:extensionTag{
            name = 'templatestyles', args = { src = cfg.hlist_templatestyles }
        }
    end
   
    -- hlist -> plainlist is best-effort to preserve old Common.css ordering.
    -- this ordering is not a guarantee because most navboxes will emit only
    -- one of these classes [hlist_note]
    return hlist_styles .. plainlist_styles
end
 
-- Analogous function to add_navbox_styles from Module:Navbox
local function add_navbox_mobile_styles(hiding_templatestyles)
    local frame = mw.getCurrentFrame()
   
    -- Function to add user-defined templatestyles
    local function add_user_styles(templatestyles)
        if templatestyles and templatestyles ~= '' then
            return frame:extensionTag{
                name = 'templatestyles',
                args = { src = templatestyles }
            }
        end
        return ''
    end
 
    -- Combine list styles with base and user styles
    local list_styles = add_list_styles()
    local base_templatestyles = cfg.templatestyles
    local templatestyles = add_user_styles(args[cfg.arg.templatestyles])
    local child_templatestyles = add_user_styles(args[cfg.arg.child_templatestyles])
 
    -- Combine all styles into a single <div>
    return mw.html.create('div')
        :addClass(cfg.class.navbox_styles)
        :wikitext(
            list_styles ..
            base_templatestyles ..
            templatestyles ..
            child_templatestyles ..
            table.concat(hiding_templatestyles)
        )
        :done()
end
 
-- Work around for style markers (similar to Navbox)
local function move_hiding_templatestyles(args)
    local gfind = string.gmatch
    local gsub = string.gsub
    local templatestyles_markers = {}
    local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
    for k, arg in pairs(args) do
        for marker in gfind(arg, strip_marker_pattern) do
            table.insert(templatestyles_markers, marker)
        end
        args[k] = gsub(arg, strip_marker_pattern, '')
    end
    return templatestyles_markers
end
 
-- Helper function to trim whitespace
local function trim(s)
local function trim(s)
     return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
     return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
end
end


-- Helper function to add newlines based on content
local function addNewline(s)
local function addNewline(s)
     if s:match('^[*:;#]') or s:match('^{|') then
     if s:match('^[*:;#]') or s:match('^{|') then
         return '\n' .. s .. '\n'
         return '\n' .. s ..'\n'
     else
     else
         return s
         return s
     end
     end
end
end


local function processItem(item, nowrapitems)
local function processItem(item, nowrapitems)
Line 36: Line 150:
         -- Applying nowrap to lines in a table does not make sense.
         -- Applying nowrap to lines in a table does not make sense.
         -- Add newlines to compensate for trim of x in |parm=x in a template.
         -- Add newlines to compensate for trim of x in |parm=x in a template.
        item = item:gsub('|%s*width%s*=%s*"[%d%w]+"', '| width="100%"')
         return '\n' .. item .. '\n'
         return '\n' .. item .. '\n'
     end
     end
     if nowrapitems == cfg.keyword.nowrapitems_yes then
     if nowrapitems == cfg.keyword.nowrapitems_yes or true then
         local lines = {}
         local lines = {}
         for line in (item .. '\n'):gmatch('([^\n]*)\n') do
         for line in (item .. '\n'):gmatch('([^\n]*)\n') do
Line 52: Line 167:
         return '\n' .. item .. '\n'
         return '\n' .. item .. '\n'
     end
     end
    -- Ensure no excessive whitespace
    item = mw.ustring.gsub(item, "%s+", " ")
     return item
     return item
end
end


-- Function to add a new table row with optional gutter
-- Function to add a new table row with optional gutter
Line 69: Line 187:
     if tableRowAdded and not suppressSpacer then
     if tableRowAdded and not suppressSpacer then
         tbl:tag('tr')
         tbl:tag('tr')
             :css('height', '0.25em') -- Adjust spacer height as needed
             :css('height', '2px')
             :tag('td')
             :tag('td')
                 :attr('colspan', 2)
                 :attr('colspan', 2)
                 :css('background-color', 'transparent') -- Ensure spacer is invisible
                 :css('background-color', 'transparent') -- Ensure spacer is invisible
                :wikitext('&nbsp;')
     end
     end


     tableRowAdded = true
     tableRowAdded = true
     return tbl:tag('tr')
     return tbl:tag('tr')
end
-- Function to check if the navbar is enabled
local function has_navbar()
    return args[cfg.arg.navbar] ~= cfg.keyword.navbar_off
        and args[cfg.arg.navbar] ~= cfg.keyword.navbar_plain
        and (
            args[cfg.arg.name]
            or mw.getCurrentFrame():getParent():getTitle():gsub(cfg.pattern.sandbox, '')
                ~= cfg.pattern.navbox
        )
end
end


-- Function to render the navigation bar
-- Function to render the navigation bar
local function renderNavBar(titleCell)
local function renderNavBar(cell)
     if has_navbar() then
     if args.navbar == 'off' then
        titleCell:tag('div')
        return -- Don't render anything if Navbar is off
            :addClass('navbar-container') -- New container for navbar
            :node(navbar{
                args.name,
                mini = 1,
                fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
            })
     end
     end
    -- Render the Navbar
    cell:wikitext(navbar{
        args.name,
        mini = 1,
        fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') .. ';background:none transparent;border:none;'
    })
end
end


-- Function to render group rows
local function renderGroupRow(tbl, groupnum, level)
    local groupRow = addTableRow(tbl)
    local groupCell = groupRow:tag('th')
        :attr('scope', 'row')
        :addClass('navboxMobile-group-content')
        :addClass('navboxMobile-group-level' .. level)
        :cssText(args.basestyle)
        :cssText(args['group' .. groupnum .. 'style'])
        :wikitext(processItem(args['group' .. groupnum]))
   
    -- Center align group content
    groupCell:css('text-align', 'center')
   
    -- Add spacer below group row for consistent spacing
    tbl:tag('tr')
        :tag('td')
            :attr('colspan', 2)
            :css('height', '0.25em') -- Spacer height
            :wikitext('&nbsp;')
end


-- Function to render title row
--
--  Title row
--
local function renderTitleRow(tbl)
local function renderTitleRow(tbl)
     if not args.title then return end
     if not args.title then return end


     local titleRow = addTableRow(tbl)
     local titleRow = addTableRow(tbl)
    if args.titlegroup then
        titleRow
            :tag('th')
                :attr('scope', 'row')
                :addClass('navboxMobile-group-content')
                :addClass(args.titlegroupclass)
                :cssText(args.basestyle)
                :cssText(args.groupstyle)
                :cssText(args.titlegroupstyle)
                :wikitext(args.titlegroup)
    end
     local titleCell = titleRow:tag('th'):attr('scope', 'col')
     local titleCell = titleRow:tag('th'):attr('scope', 'col')
    if args.titlegroup then
        titleCell
            :css('border-left', '2px solid #fdfdfd')
            :css('width', '100%')
    end
    local titleColspan = 2
    if args.titlegroup then titleColspan = titleColspan - 1 end
    titleCell
         :addClass('navboxMobile-title')
         :addClass('navboxMobile-title')
         :attr('colspan', titleColspan)
        :addClass(cfg.class.navbox_list)
        :addClass(args[cfg.arg.titleclass])
        :attr('data-level', 1)
         :attr('colspan', 2)
         :cssText(args.basestyle)
         :cssText(args.basestyle)
         :cssText(args.titlestyle)
         :cssText(args.titlestyle)
         :addClass('navboxMobile-list') -- Consistent list styling
         :css('position', 'relative') -- Ensure relative positioning for absolute children
        :addClass(args.titleclass)
 
    renderNavBar(titleCell)


    -- Add the title content, centered across the full width
     titleCell
     titleCell
         :tag('div')
         :tag('div')
             :css('font-size', '114%')
             :css('margin', '0 auto')
             :css('margin', '0') -- Remove default margins
             :css('text-align', 'center')
             :wikitext(addNewline(args.title))
             :wikitext(addNewline(args.title))
    -- Add the navbar, positioned absolutely in the top-right corner
    if has_navbar() then
        titleCell
            :tag('div')
                :addClass('navboxMobile-navbar')
                :css('position', 'absolute')
                :css('top', '0')
                :css('right', '0')
                :css('padding', '0.2em')  -- Optional: Adjust padding for alignment
                :wikitext(navbar{
                    args.name,
                    mini = 1,
                    fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') .. ';background:none transparent;border:none;'
                })
    end
end
--
--  Above/Below rows
--
local function getAboveBelowColspan()
    return 2
end
end


-- Function to render above row
local function renderAboveRow(tbl)
local function renderAboveRow(tbl)
     if not args.above then return end
     if not args.above then return end
Line 181: Line 267:
         :tag('td')
         :tag('td')
             :addClass('navboxMobile-abovebelow-content')
             :addClass('navboxMobile-abovebelow-content')
            :addClass(cfg.class.navbox_list) -- Add consistent list styling
             :addClass(args.aboveclass)
             :addClass(args.aboveclass)
             :cssText(args.basestyle)
             :cssText(args.basestyle)
             :cssText(args.abovestyle)
             :cssText(args.abovestyle)
             :css('padding', args.abovepadding or '0.5em') -- Optional padding
             :css('padding', args[cfg.arg.abovepadding] or '0.5em') -- Optional padding
             :attr('colspan', 2)
             :attr('colspan', getAboveBelowColspan())
             :tag('div')
             :tag('div')
                 :wikitext(addNewline(args.above))
                 :wikitext(addNewline(args.above))
end
end


-- Function to render below row
 
 
local function renderBelowRow(tbl)
local function renderBelowRow(tbl)
     if not args.below then return end
     if not args.below then return end
Line 197: Line 285:
         :tag('td')
         :tag('td')
             :addClass('navboxMobile-abovebelow-content')
             :addClass('navboxMobile-abovebelow-content')
            :addClass(cfg.class.navbox_list) -- Add consistent list styling
             :addClass(args.belowclass)
             :addClass(args.belowclass)
             :cssText(args.basestyle)
             :cssText(args.basestyle)
             :cssText(args.belowstyle)
             :cssText(args.belowstyle)
             :css('padding', args.belowpadding or '0.5em') -- Optional padding
             :css('padding', args[cfg.arg.belowpadding] or '0.5em') -- Optional padding
             :attr('colspan', 2)
             :attr('colspan', getAboveBelowColspan())
             :tag('div')
             :tag('div')
                 :wikitext(addNewline(args.below))
                 :wikitext(addNewline(args.below))
end
end


-- Function to render list rows
local function renderListRow(tbl, listnum)
    -- Determine level (2 for main groups, 3 for subgroups)
    local level = 2
    if border == 'subgroup' then
        level = 3
    end
   
    -- Render group row
    renderGroupRow(tbl, listnum, level)
   
    -- Continue with rendering the list
    local listRow = addTableRow(tbl)
    local listCell = listRow:tag('td')
        :addClass('navboxMobile-list-content')
        :addClass('navboxMobile-' .. ((listnum % 2 == 1) and 'odd' or 'even'))
        :attr('colspan', 2)
        :css('padding', '0 0.25em')
        :css('width', '100%')
        :cssText(args.liststyle)
        :cssText(args['list' .. listnum .. 'style'])
   
    if args['list' .. listnum] == 'child' then
        -- Render nested subgroup as a separate table
        for i = 1, 10 do
            local nestedGroup = args['child' .. listnum .. '_group' .. i]
            local nestedList = args['child' .. listnum .. '_list' .. i]


            if not nestedGroup and not nestedList then break end


            renderGroupRow(tbl, i, 3) -- Level 3 for subgroups
local function renderListRow(tbl, path, parentLevel)
            local nestedListRow = addTableRow(tbl)
    -- Initialize path and parentLevel
            local nestedListCell = nestedListRow:tag('td')
    path = path or ""
                :addClass('navboxMobile-list-content')
    parentLevel = parentLevel or 2 -- Start at level 2 for child groups
                :addClass('navboxMobile-' .. ((i % 2 == 1) and 'odd' or 'even'))
 
                :attr('colspan', 2)
    -- Keep track of rendered children to avoid duplicates
                 :css('padding', '0 0.25em')
    local renderedChildren = {}
                 :cssText(args['child' .. listnum .. '_list' .. i .. 'style'])
 
                 :wikitext(processItem(nestedList))
    for i = 1, 10 do
        end
        local groupKey = (path ~= "" and "child" .. path .. "_" or "") .. "group" .. i
    else
        local listKey = (path ~= "" and "child" .. path .. "_" or "") .. "list" .. i
        -- Render flat list
 
        listCell:tag('div')
        -- Skip if this group has already been rendered
            :css('padding', args.listpadding or '0 0.25em')
        if not renderedChildren[listKey] and args[listKey] then
            :wikitext(processItem(args['list' .. listnum], args.nowrapitems))
            renderedChildren[listKey] = true -- Track rendered lists
    end
 
end
            -- Render the group (heading)
            local groupRow = addTableRow(tbl)
            local groupCell = groupRow:tag('th')
                 :attr('scope', 'row')
                 :addClass('navboxMobile-group-content')
                 :addClass('navboxMobile-group-level' .. parentLevel) -- Correct level
                :attr('data-level', parentLevel) -- Optional attribute for CSS targeting
                :wikitext(processItem(args[groupKey]))


            -- Check if the list is non-empty before rendering content
            if args[listKey] and args[listKey] ~= "" then
                if args[listKey] == "child" then
                    -- Check if the child contains valid groups or lists
                    local childHasContent = false
                    for j = 1, 10 do
                        local childGroupKey = "child" .. (path ~= "" and path .. "_" or "") .. i .. "_group" .. j
                        local childListKey = "child" .. (path ~= "" and path .. "_" or "") .. i .. "_list" .. j
                        if args[childGroupKey] or args[childListKey] then
                            childHasContent = true
                            break
                        end
                    end


-- Function to add list styles
                    if childHasContent then
local function add_list_styles()
                        -- Recursively render child lists
    local frame = mw.getCurrentFrame()
                        local newPath = (path ~= "" and path .. "_" or "") .. i
    local function add_list_templatestyles(htmlclass, templatestyles)
                        renderListRow(tbl, tostring(newPath), parentLevel + 1)
        if has_list_class(htmlclass) then
                    end
            return frame:extensionTag{
                else
                name = 'templatestyles', args = { src = templatestyles }
                    -- Render flat lists
            }
                    local listRow = addTableRow(tbl)
        else
                    local listCell = listRow:tag('td')
             return ''
                        :attr('colspan', 2)
                        :addClass('navboxMobile-list-content') -- Base content class
                        :addClass('navboxMobile-list-level' .. parentLevel) -- Correct level
                        :addClass((i % 2 == 1) and 'navboxMobile-odd' or 'navboxMobile-even') -- Odd/even class
                        :addClass(args.listclass or '') -- Apply `listclass` if defined in the template
                        :wikitext(processItem(args[listKey], args.nowrapitems))
                end
             end
         end
         end
     end
     end
       
    local hlist_styles = add_list_templatestyles('hlist', cfg.hlist_templatestyles)
    local plainlist_styles = add_list_templatestyles('plainlist', cfg.plainlist_templatestyles)
   
    -- Workaround for [[phab:T303378]]
    if has_navbar() and hlist_styles == '' then
        hlist_styles = frame:extensionTag{
            name = 'templatestyles', args = { src = cfg.hlist_templatestyles }
        }
    end
   
    -- hlist -> plainlist is best-effort to preserve old Common.css ordering.
    return hlist_styles .. plainlist_styles
end
end


-- Function to add styles
local function add_navbox_mobile_styles(hiding_templatestyles)
    local frame = mw.getCurrentFrame()
   
    -- Function to add user-defined templatestyles
    local function add_user_styles(templatestyles)
        if templatestyles and templatestyles ~= '' then
            return frame:extensionTag{
                name = 'templatestyles',
                args = { src = templatestyles }
            }
        end
        return ''
    end


    -- Combine list styles with base and user styles
    local list_styles = add_list_styles()
    local base_templatestyles = cfg.templatestyles
    local templatestyles = add_user_styles(args[cfg.arg.templatestyles])
    local child_templatestyles = add_user_styles(args[cfg.arg.child_templatestyles])


    -- Combine all styles into a single <div>
    return mw.html.create('div')
        :addClass('navboxMobile-styles')
        :wikitext(
            list_styles ..
            base_templatestyles ..
            templatestyles ..
            child_templatestyles ..
            table.concat(hiding_templatestyles)
        )
        :done()
end


-- Function to move and collect hiding templatestyles
local function move_hiding_templatestyles(args)
    local gfind = string.gmatch
    local gsub = string.gsub
    local templatestyles_markers = {}
    local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
    for k, arg in pairs(args) do
        for marker in gfind(arg, strip_marker_pattern) do
            table.insert(templatestyles_markers, marker)
        end
        args[k] = gsub(arg, strip_marker_pattern, '')
    end
    return templatestyles_markers
end


-- Function to render tracking categories
--
--  Tracking categories
--
 
local function needsHorizontalLists()
local function needsHorizontalLists()
     if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end
     if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end
Line 385: Line 418:
end
end


-- Function to render main table
--
--  Main navboxMobile tables
--
local function renderMainTable()
local function renderMainTable()
     local tbl = mw.html.create('table')
     local tbl = mw.html.create('table')
         :addClass('nowraplinks')
         :addClass('nowraplinks')
         :addClass('navboxMobile-list')
         :addClass(cfg.class.navbox)
         :addClass(args.bodyclass)
         :addClass(args.bodyclass)
        :addClass(args.listclass or '') -- Apply the `listclass` argument globally if applicable
         :cssText(args.bodystyle)
         :cssText(args.bodystyle)
         :cssText(args.style)
         :cssText(args.style)
         :css('margin-top', '0')
         :css('margin-top', '0')
         :css('margin-bottom', '0')
         :css('margin-bottom', '0')
        :css('border-spacing', '0')


     if border == 'subgroup' or border == 'child' or border == 'none' then
     -- Add the title row
        tbl
    renderTitleRow(tbl)
            :addClass('navboxMobile-subgroup')
            :css('width', '100%')
    else
        tbl
            :addClass('navboxMobile-inner')
            :css('background', 'transparent')
            :css('color', 'inherit')
    end


     tbl:cssText(args.innerstyle)
     -- Add the above row
    renderAboveRow(tbl)


     renderTitleRow(tbl)
     -- Render all group and list rows
    renderAboveRow(tbl)
     for _, listnum in ipairs(listnums) do
     for _, listnum in ipairs(listnums) do
         renderListRow(tbl, listnum)
         local listKey = "list" .. listnum
        local groupKey = "group" .. listnum
 
        if args[listKey] then
            -- Render group row
            local groupRow = addTableRow(tbl)
            local groupCell = groupRow:tag('th')
                :attr('scope', 'row')
                :addClass('navboxMobile-group-content')
                :addClass('navboxMobile-group-level1')
                :addClass(args.listclass or '') -- Apply `listclass` for group rows
                :wikitext(processItem(args[groupKey]))
 
            -- Render list row
            if args[listKey] == 'child' then
                renderListRow(tbl, tostring(listnum), 2)
            else
                local listRow = addTableRow(tbl)
                listRow:tag('td')
                    :attr('colspan', 2)
                    :addClass('navboxMobile-list-content')
                    :addClass((listnum % 2 == 1) and 'navboxMobile-odd' or 'navboxMobile-even')
                    :addClass(args.listclass or '') -- Apply `listclass` to flat rows
                    :wikitext(processItem(args[listKey]))
            end
        end
     end
     end
    -- Add the below row
     renderBelowRow(tbl)
     renderBelowRow(tbl)


Line 420: Line 474:
end
end


-- Main function to render navboxMobile
 
 
--
--  Main NavboxMobile Function
--
-- In the main navboxMobile function
function p._navboxMobile(navboxMobileArgs)
function p._navboxMobile(navboxMobileArgs)
     args = navboxMobileArgs
     args = navboxMobileArgs
Line 431: Line 490:
     local hiding_templatestyles = move_hiding_templatestyles(args)
     local hiding_templatestyles = move_hiding_templatestyles(args)


     -- Collect list numbers
     -- Collect top-level list numbers (list1, list2, etc.)
     for k, v in pairs(args) do
     for k, v in pairs(args) do
         if type(k) == 'string' then
         if type(k) == 'string' then
Line 450: Line 509:
     -- Create the final HTML with styles
     -- Create the final HTML with styles
     local res = mw.html.create()
     local res = mw.html.create()
    -- Inject styles analogous to Module:Navbox
     res:node(add_navbox_mobile_styles(hiding_templatestyles))
     res:node(add_navbox_mobile_styles(hiding_templatestyles))
 
     res:node(tbl)
     -- Handle wrapping based on border parameter
    if border == 'none' then
        -- Wrap the table within a navigation div with ARIA attributes
        local navWrapper = mw.html.create('div')
            :attr('role', 'navigation')
            :addClass('navboxMobile')
        if args.title or args.above or (args.group1 and not args.group2) then
            navWrapper:attr(
                'aria-labelledby',
                mw.uri.anchorEncode(args.title or args.above or args.group1)
            )
        else
            navWrapper:attr('aria-label', cfg.aria_label)
        end
        navWrapper:node(tbl)
        res:node(navWrapper)
    elseif border == 'subgroup' or border == 'child' then
        -- Assume this navboxMobile is inside a parent navboxMobile's list cell
        -- Insert closing and opening divs to manage padding
        local subgroupWrapper = mw.html.create('div')
            :addClass('navboxMobile-container') -- Consistent wrapping container
            :node(tbl) -- Add the table as a child
 
        res:node(subgroupWrapper)
    else
        -- Wrap the table within a navigation div with additional classes and styles
        local navWrapper = mw.html.create('div')
            :addClass('navboxMobile') -- Add consistent container
            :attr('role', 'navigation')
            :cssText(args.bodystyle)
            :cssText(args.style)
            :css('padding', '2px') -- Adjust padding as needed
        if args.title or args.above or (args.group1 and not args.group2) then
            navWrapper:attr(
                'aria-labelledby',
                mw.uri.anchorEncode(args.title or args.above or args.group1)
            )
        else
            navWrapper:attr('aria-label', cfg.aria_label)
        end
        navWrapper:node(tbl)
        res:node(navWrapper)
    end
 
    -- Render tracking categories
    renderTrackingCategories(res)


     return tostring(res)
     return tostring(res)
end
end


-- Public function to invoke navboxMobile
 
--
--  Main NavboxMobile Function
--
function p.navboxMobile(frame)
function p.navboxMobile(frame)
     if not getArgs then
     if not getArgs then