Module:NavboxMobile: Difference between revisions

From Ikwipedia
No edit summary
No edit summary
Line 305: Line 305:
--  List rows
--  List rows
--
--
local function renderListRow(tbl, listnum)
local function renderListRow(tbl, index, listnum, listnums_size)
     local row = addTableRow(tbl)
     local row = addTableRow(tbl)


     -- Process group
     -- Process group (e.g., `group1`, `group2`)
     if args['group' .. listnum] then
    local group_and_num = format(cfg.arg.group_and_num, listnum)
    local groupstyle_and_num = format(cfg.arg.groupstyle_and_num, listnum)
     if args[group_and_num] then
         local groupCell = row:tag('th')
         local groupCell = row:tag('th')
        -- ID for aria-labelledby attribute if it's the first group with no title or above
        if listnum == 1 and not (args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group2]) then
            groupCell:attr('id', mw.uri.anchorEncode(args[cfg.arg.group1]))
        end
         groupCell
         groupCell
             :attr('scope', 'row')
             :attr('scope', 'row')
Line 316: Line 324:
             :cssText(args.basestyle)
             :cssText(args.basestyle)
             :cssText(args.groupstyle)
             :cssText(args.groupstyle)
             :cssText(args['group' .. listnum .. 'style'])
             :cssText(args[groupstyle_and_num])
             :wikitext(processItem(args['group' .. listnum]))
             :wikitext(processItem(args[group_and_num]))
     end
     end


     -- Add table row for the list
     -- Add list cell
    row = addTableRow(tbl)
     local listCell = row:tag('td')
     local listCell = row:tag('td')
    listCell:attr('colspan', 2)
    listCell:css('width', '100%')


     -- Apply dynamic styling
     -- If there's a group, add a class; otherwise, make the cell span both columns
     local oddEven = cfg.class.navbox_odd_part
     if args[group_and_num] then
     if args['list' .. listnum] and args['list' .. listnum]:sub(1, 12) == '</div><table' then
        listCell:addClass(cfg.class.navbox_list_with_group)
        oddEven = args['list' .. listnum]:find(cfg.pattern.navbox_title) and cfg.marker.restart or
     else
    cfg.class.navbox_odd_part
        listCell:attr('colspan', 2)
    end
 
    -- Set cell width if group width is not specified
    if not args[cfg.arg.groupwidth] then
        listCell:css('width', '100%')
     end
     end
    listCell:addClass(oddEven)


    -- Apply styles for odd/even rows
    local rowstyle = nil
    if index % 2 == 1 then
        rowstyle = args[cfg.arg.oddstyle]
    else
        rowstyle = args[cfg.arg.evenstyle]
    end


     listCell
     -- Handle the list itself
        :addClass('navboxMobile-list-content')
    local list_and_num = format(cfg.arg.list_and_num, listnum)
        :addClass(cfg.class.navbox_list) -- Add styling for lists
    local listText = args[list_and_num]
        :addClass(cfg.class.navbox_part .. ((listnum % 2 == 1) and 'odd' or 'even')) -- Ensure odd/even styles
        :addClass(args[cfg.arg.listclass]) -- Apply any additional classes from args
        :addClass(args['listclass_' .. listnum]) -- Apply list-specific classes
        :cssText(args.liststyle)
        :cssText(args['list' .. listnum .. 'style'])


     -- Check for nested subgroups dynamically
     -- Check for nested subgroups
     if inArray(cfg.keyword.subgroups, args['list' .. listnum]) then
     if inArray(cfg.keyword.subgroups, listText) then
         local childArgs = {
         local childArgs = {
             border = 'subgroup',
             [cfg.arg.border] = cfg.keyword.border_subgroup,
             navbar = 'plain'
             [cfg.arg.navbar] = cfg.keyword.navbar_plain
         }
         }
        local hasChildArgs = false
         for k, v in pairs(args) do
         for k, v in pairs(args) do
             local prefix = 'child' .. listnum .. '_'
             k = tostring(k)
            if k:sub(1, #prefix) == prefix then
            for _, w in ipairs(cfg.keyword.subgroups) do
                childArgs[k:sub(#prefix + 1)] = v
                w = w .. listnum .. "_"
                if (#k > #w) and (k:sub(1, #w) == w) then
                    childArgs[k:sub(#w + 1)] = v
                    hasChildArgs = true
                end
             end
             end
         end
         end
         args['list' .. listnum] = p._navboxMobile(childArgs)
         listText = hasChildArgs and p._navboxMobile(childArgs) or listText
     end
     end


     -- Check for nested lists (e.g., child1_groupX)
     -- Odd/even class and striping
     local nestedGroup = args['child' .. listnum .. '_group1']
     local oddEven = cfg.marker.oddeven
     local nestedList = args['child' .. listnum .. '_list1']
     if listText:sub(1, 12) == '</div><table' then
        -- If listText is for a subgroup navbox, no automatic striping for this row
        oddEven = listText:find(cfg.pattern.navbox_title) and cfg.marker.restart or cfg.class.navbox_odd_part
    end


     if nestedGroup or nestedList then
     -- Apply list-specific styles
        local nestedTbl = mw.html.create('table')
    local liststyle_and_num = format(cfg.arg.liststyle_and_num, listnum)
            :addClass('navboxMobile-subrendermaintabgroup')
    local listclass_and_num = format(cfg.arg.listclass_and_num, listnum)
             :css('width', '100%')
    listCell
        :css('padding', '0')
        :cssText(args[cfg.arg.liststyle])
        :cssText(rowstyle)
        :cssText(args[liststyle_and_num])
        :addClass(cfg.class.navbox_list)
        :addClass(cfg.class.navbox_part .. oddEven)
        :addClass(args[cfg.arg.listclass])
        :addClass(args[listclass_and_num])
        :tag('div')
             :css('padding', args[cfg.arg.list1padding] or args[cfg.arg.listpadding] or '0 0.25em')
            :wikitext(processItem(listText, args[cfg.arg.nowrapitems]))
end


        for i = 1, 10 do -- Assume a max of 10 nested groups/lists
            local nestedGroup = args['child' .. listnum .. '_group' .. i]
            local nestedList = args['child' .. listnum .. '_list' .. i]
            if not nestedGroup and not nestedList then break end
            local nestedRow = addTableRow(nestedTbl)
            if nestedGroup then
                nestedRow:tag('th')
                    :addClass('navboxMobile-group-content')
                    :cssText(args.basestyle)
                    :cssText(args['child' .. listnum .. '_group' .. i .. 'style'])
                    :wikitext(processItem(nestedGroup))
            end
            if nestedList then
                nestedRow:tag('td')
                    :addClass('navboxMobile-list-content hlist')
                    :cssText(args['child' .. listnum .. '_list' .. i .. 'style'])
                    :wikitext(processItem(nestedList))
            end
        end
        listCell:node(nestedTbl)
    else
        listCell
            :addClass('hlist') -- Add hlist for horizontal styling
            :tag('div') -- Wrap in a div to allow padding and better styling
                :css('padding', args[cfg.arg.listpadding] or '0 0.25em')
                :wikitext(processItem(args['list' .. listnum], args.nowrapitems))
    end
end





Revision as of 08:07, 24 November 2024

This module implements the {{Navbox}} template for mobile devices when Extension:MobileFrontend is installed. This mobile version differs from the desktop version as follows:

  • The table does not collapse.
  • The list cells, e.g. group1, list1, each display across the width of the screen
  • Images are not displayed, as it increases the complexity of the layout while reducing the area needed for content.

Original from wikipedia::Module:User:Lady G2016/NavboxMobile/doc

Overview

This approach works by utilizing CSS class rules. See: Hiding content on desktop devices

An onlymobile class in MediaWiki:Common.css will not display classes intended for mobile devices.

A nomobile class in MediaWiki:Mobile.css will not display classes intended for desktop devices.

Use these classes together inside the same template. The template will be rendered twice, but only display once depending on the view (desktop or mobile).

Module description

The module was copied from Module:Navbox and modified as follows:

  • All instances of navbox- were replaced with navboxMobile- to provide unique CSS identifiers that are independent of navbox.
  • All statements which processed images were removed. The statements remain as comments to show what was changed.

In function renderListRow(), the cell pair of (groupCell, listCell) appearing as a single row is broken into separate rows by adding local row = addTableRow(tbl) just before listCell.

Adding this row and removing the images are the only functional changes made to the existing navbox template. Except for removal of the images, the parameters used in the current navbox are supported.

Implementation

MediaWiki:Common.css

In MediaWiki:Common.css, add:

/* Only for mobile devices */
.onlymobile {
display:none;
}

MediaWiki:Mobile.css

In MediaWiki:Mobile.css, add:

/* Only for desktop devices */
.nomobile {
display:none;
}

MobileFrontend processes MediaWiki:Mobile.css. To provide an independent class that is not affected by the navbox rules, copy all of the navbox and hlist CSS styles from MediaWiki:Common.css to MediaWiki:Mobile.css.

Replace all navbox- with navboxMobile-. For example, navbox-title becomes navboxMobile-title. This will match the CSS properties in Module:NavboxMobile.

An example page can be found at User:Lady G2016/MediaWiki:Mobile.css.

Template:Navbox

Modify Template:Navbox to call both the desktop and mobile Lua modules as follows:

<div class="nomobile">{{#invoke:Navbox|navbox}}</div><div class="onlymobile">{{#invoke:NavboxMobile|navboxMobile}}</div><noinclude>
{{Documentation}}
</noinclude>

This will render both the desktop (navbox) and mobile (navboxMobile) versions. When displaying from a desktop view, MediaWiki:Common.css will not display the mobile template. When displaying from a mobile, only the mobile template will be displayed.

Constraints and limitations

This template was developed with MediaWiki 1.27.4 (Long Term Support) and MobileFrontEnd 1.0.0 (29 June 2016). No testing was performed with other versions.

The navbox class is explicitly disabled in /extensions/MobileFrontend/resources/skins.minerva.content.styles/hacks.less. Attempts to override navbox using $wgMFRemovableClasses do not display as intended when the navbox class is enabled.


-- Module:NavboxMobile
-- This module implements {{navbox}} for MobileFrontend

local p = {}

require('strict')
local cfg = mw.loadData('Module:NavboxMobile/configuration')
local navbar = require('Module:Navbar')._navbar
local getArgs -- Lazily initialized
local inArray = require('Module:TableTools').inArray
local format = string.format

local args
local tableRowAdded = false
local border
local listnums = {}

-- 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() -- Ensure this function is defined or required appropriately
    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)
    return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
end

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

local function processItem(item, nowrapitems)
    if not item then
        return '' -- Prevent nil errors
    end
    if item:sub(1, 2) == '{|' then
        -- 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.
        return '\n' .. item .. '\n'
    end
    if nowrapitems == cfg.keyword.nowrapitems_yes then
        local lines = {}
        for line in (item .. '\n'):gmatch('([^\n]*)\n') do
            local prefix, content = line:match('^([*:;#]+)%s*(.*)')
            if prefix and not content:match(cfg.pattern.nowrap) then
                line = format(cfg.nowrap_item, prefix, content)
            end
            table.insert(lines, line)
        end
        item = table.concat(lines, '\n')
    end
    if item:match('^[*:;#]') then
        return '\n' .. item .. '\n'
    end
    return item
end



-- Function to add a new table row with optional gutter
local function addTableRow(tbl)
    if tableRowAdded then
        tbl
            :tag('tr')
                :css('height', '2px')
                :tag('td')
                    :attr('colspan', 2)
        -- Note: You can add additional gutter styling here if needed
    end
    tableRowAdded = true
    return tbl:tag('tr')
end

-- Function to render the navigation bar
local function renderNavBar(titleCell)
    local spacerSide = nil

    if args.navbar == 'off' then
        if args.state == 'plain' then spacerSide = 'right' end
    elseif args.navbar == 'plain' or (not args.name and mw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$', '') == 'Template:navbox') then
        if args.state ~= 'plain' then spacerSide = 'left' end
    else
        if args.state == 'plain' then spacerSide = 'right' end

        titleCell:wikitext(navbar{
            args.name,
            mini = 1,
            fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
        })
    end

    if spacerSide then
        titleCell
            :tag('span')
                :css('float', spacerSide)
                :css('width', '6em')
                :wikitext('&nbsp;')
    end
end

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

    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')

    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(cfg.class.navbox_list) -- Add consistent list styling
        :addClass(args[cfg.arg.titleclass]) -- Additional title-specific class
        :attr('colspan', titleColspan)
        :cssText(args.basestyle)
        :cssText(args.titlestyle)

    renderNavBar(titleCell)

    titleCell
        :tag('div')
            :css('font-size', '114%')
            :css('padding', args[cfg.arg.list1padding] or args[cfg.arg.listpadding] or '0 0.25em')
            :wikitext(addNewline(args.title))
end


--
--   Above/Below rows
--

local function getAboveBelowColspan()
    return 2
end

local function renderAboveRow(tbl)
    if not args.above then return end

    addTableRow(tbl)
        :tag('td')
            :addClass('navboxMobile-abovebelow-content')
            :addClass(cfg.class.navbox_list) -- Add consistent list styling
            :addClass(args.aboveclass)
            :cssText(args.basestyle)
            :cssText(args.abovestyle)
            :css('padding', args[cfg.arg.abovepadding] or '0.5em') -- Optional padding
            :attr('colspan', getAboveBelowColspan())
            :tag('div')
                :wikitext(addNewline(args.above))
end


local function renderBelowRow(tbl)
    if not args.below then return end

    addTableRow(tbl)
        :tag('td')
            :addClass('navboxMobile-abovebelow-content')
            :addClass(cfg.class.navbox_list) -- Add consistent list styling
            :addClass(args.belowclass)
            :cssText(args.basestyle)
            :cssText(args.belowstyle)
            :css('padding', args[cfg.arg.belowpadding] or '0.5em') -- Optional padding
            :attr('colspan', getAboveBelowColspan())
            :tag('div')
                :wikitext(addNewline(args.below))
end


--
--   List rows
--
local function renderListRow(tbl, index, listnum, listnums_size)
    local row = addTableRow(tbl)

    -- Process group (e.g., `group1`, `group2`)
    local group_and_num = format(cfg.arg.group_and_num, listnum)
    local groupstyle_and_num = format(cfg.arg.groupstyle_and_num, listnum)
    if args[group_and_num] then
        local groupCell = row:tag('th')

        -- ID for aria-labelledby attribute if it's the first group with no title or above
        if listnum == 1 and not (args[cfg.arg.title] or args[cfg.arg.above] or args[cfg.arg.group2]) then
            groupCell:attr('id', mw.uri.anchorEncode(args[cfg.arg.group1]))
        end

        groupCell
            :attr('scope', 'row')
            :addClass('navboxMobile-group-content')
            :cssText(args.basestyle)
            :cssText(args.groupstyle)
            :cssText(args[groupstyle_and_num])
            :wikitext(processItem(args[group_and_num]))
    end

    -- Add list cell
    local listCell = row:tag('td')

    -- If there's a group, add a class; otherwise, make the cell span both columns
    if args[group_and_num] then
        listCell:addClass(cfg.class.navbox_list_with_group)
    else
        listCell:attr('colspan', 2)
    end

    -- Set cell width if group width is not specified
    if not args[cfg.arg.groupwidth] then
        listCell:css('width', '100%')
    end

    -- Apply styles for odd/even rows
    local rowstyle = nil
    if index % 2 == 1 then
        rowstyle = args[cfg.arg.oddstyle]
    else
        rowstyle = args[cfg.arg.evenstyle]
    end

    -- Handle the list itself
    local list_and_num = format(cfg.arg.list_and_num, listnum)
    local listText = args[list_and_num]

    -- Check for nested subgroups
    if inArray(cfg.keyword.subgroups, listText) then
        local childArgs = {
            [cfg.arg.border] = cfg.keyword.border_subgroup,
            [cfg.arg.navbar] = cfg.keyword.navbar_plain
        }
        local hasChildArgs = false
        for k, v in pairs(args) do
            k = tostring(k)
            for _, w in ipairs(cfg.keyword.subgroups) do
                w = w .. listnum .. "_"
                if (#k > #w) and (k:sub(1, #w) == w) then
                    childArgs[k:sub(#w + 1)] = v
                    hasChildArgs = true
                end
            end
        end
        listText = hasChildArgs and p._navboxMobile(childArgs) or listText
    end

    -- Odd/even class and striping
    local oddEven = cfg.marker.oddeven
    if listText:sub(1, 12) == '</div><table' then
        -- If listText is for a subgroup navbox, no automatic striping for this row
        oddEven = listText:find(cfg.pattern.navbox_title) and cfg.marker.restart or cfg.class.navbox_odd_part
    end

    -- Apply list-specific styles
    local liststyle_and_num = format(cfg.arg.liststyle_and_num, listnum)
    local listclass_and_num = format(cfg.arg.listclass_and_num, listnum)
    listCell
        :css('padding', '0')
        :cssText(args[cfg.arg.liststyle])
        :cssText(rowstyle)
        :cssText(args[liststyle_and_num])
        :addClass(cfg.class.navbox_list)
        :addClass(cfg.class.navbox_part .. oddEven)
        :addClass(args[cfg.arg.listclass])
        :addClass(args[listclass_and_num])
        :tag('div')
            :css('padding', args[cfg.arg.list1padding] or args[cfg.arg.listpadding] or '0 0.25em')
            :wikitext(processItem(listText, args[cfg.arg.nowrapitems]))
end





--
--   Tracking categories
--

local function needsHorizontalLists()
    if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end

    local listClasses = {'plainlist', 'hlist', 'hlist hnum', 'hlist hwrap', 'hlist vcard', 'vcard hlist', 'hlist vevent'}
    for _, cls in ipairs(listClasses) do
        if args.listclass == cls or args.bodyclass == cls then
            return false
        end
    end

    return true
end

local function hasBackgroundColors()
    return mw.ustring.match(args.titlestyle or '', 'background') 
        or mw.ustring.match(args.groupstyle or '', 'background') 
        or mw.ustring.match(args.basestyle or '', 'background')
end

local function isIllegible()
    local styleratio = require('Module:Color contrast')._styleratio

    for key, style in pairs(args) do
        if tostring(key):match("style$") then
            if styleratio{mw.text.unstripNoWiki(style)} < 4.5 then
                return true 
            end
        end
    end
    return false
end

local function getTrackingCategories()
    local cats = {}
    if needsHorizontalLists() then table.insert(cats, cfg.category.horizontal_lists) end
    if hasBackgroundColors() then table.insert(cats, cfg.category.background_colors) end
    if isIllegible() then table.insert(cats, cfg.category.illegible) end
    if border == 'subgroup' then table.insert(cats, cfg.category.subgroup) end
    if args.tracking == 'no' then table.insert(cats, cfg.category.no_tracking) end
    return cats
end

local function renderTrackingCategories(builder)
    local title = mw.title.getCurrentTitle()
    if title.namespace ~= 10 then return end -- Not in template space
    local subpage = title.subpageText
    if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end

    for _, cat in ipairs(getTrackingCategories()) do
        builder:wikitext('[[Category:' .. cat .. ']]')
    end
end

--
--   Main navboxMobile tables
--
local function renderMainTable()
    local tbl = mw.html.create('table')
        :addClass('nowraplinks')
        :addClass(cfg.class.navbox_list)
        :addClass(args.bodyclass)
        :cssText(args.bodystyle)
        :cssText(args.style)

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

    tbl:cssText(args.innerstyle)

    renderTitleRow(tbl)
    renderAboveRow(tbl)
    for _, listnum in ipairs(listnums) do
        renderListRow(tbl, listnum)
    end
    renderBelowRow(tbl)

    return tbl
end


function p._navboxMobile(navboxMobileArgs)
    args = navboxMobileArgs

    -- Reset state variables to prevent state leakage between invocations
    tableRowAdded = false
    listnums = {}

    -- Move and collect hiding templatestyles
    local hiding_templatestyles = move_hiding_templatestyles(args)

    -- Collect list numbers
    for k, v in pairs(args) do
        if type(k) == 'string' then
            local listnum = k:match('^list(%d+)$')
            if listnum then table.insert(listnums, tonumber(listnum)) end
        end
    end
    table.sort(listnums)

    border = trim(args.border or args[1] or '')
    if border == cfg.keyword.border_child then
        border = cfg.keyword.border_subgroup
    end

    -- Render the main body of the navboxMobile
    local tbl = renderMainTable()

    -- Create the final HTML with styles
    local res = mw.html.create()

    -- Inject styles analogous to Module:Navbox
    res:node(add_navbox_mobile_styles(hiding_templatestyles))

    -- 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')
        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
        res
            :wikitext('</div>') -- Close parent div
            :node(tbl)
            :wikitext('<div>') -- Reopen parent div
    else
        -- Wrap the table within a navigation div with additional classes and styles
        local navWrapper = mw.html.create('div')
            :attr('role', 'navigation')
            :addClass('navboxMobile') -- Add appropriate classes
            :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)
end

function p.navboxMobile(frame)
    if not getArgs then
        getArgs = require('Module:Arguments').getArgs
    end
    args = getArgs(frame, {wrappers = 'Template:Navbox'})

    -- Read the arguments in the order they'll be output in, to make references number in the right order.
    local _
    _ = args.title
    _ = args.above
    for i = 1, 20 do
        _ = args["group" .. tostring(i)]
        _ = args["list" .. tostring(i)]
    end
    _ = args.below

    return p._navboxMobile(args)
end

return p