<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://dunedb.com/index.php?action=history&amp;feed=atom&amp;title=Module%3AJourneySystem</id>
	<title>Module:JourneySystem - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://dunedb.com/index.php?action=history&amp;feed=atom&amp;title=Module%3AJourneySystem"/>
	<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=Module:JourneySystem&amp;action=history"/>
	<updated>2026-05-23T16:17:16Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://dunedb.com/index.php?title=Module:JourneySystem&amp;diff=663&amp;oldid=prev</id>
		<title>Operator at 05:41, 26 May 2025</title>
		<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=Module:JourneySystem&amp;diff=663&amp;oldid=prev"/>
		<updated>2025-05-26T05:41:23Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://dunedb.com/index.php?title=Module:JourneySystem&amp;amp;diff=663&amp;amp;oldid=656&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Operator</name></author>
	</entry>
	<entry>
		<id>https://dunedb.com/index.php?title=Module:JourneySystem&amp;diff=656&amp;oldid=prev</id>
		<title>Operator at 04:56, 26 May 2025</title>
		<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=Module:JourneySystem&amp;diff=656&amp;oldid=prev"/>
		<updated>2025-05-26T04:56:40Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://dunedb.com/index.php?title=Module:JourneySystem&amp;amp;diff=656&amp;amp;oldid=653&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Operator</name></author>
	</entry>
	<entry>
		<id>https://dunedb.com/index.php?title=Module:JourneySystem&amp;diff=653&amp;oldid=prev</id>
		<title>Operator: Created page with &quot;-- Module:JourneySystem (Optimized for Template Data Fetching) -- Handles formatting and utility functions only -- Data fetching is done in templates for better caching  local p = {}  -- Default placeholder image local DEFAULT_JOURNEY_ICON = &quot;https://dunedb.com/images/3/39/WikiPlaceholder.jpg&quot;  -------------------------------------------------- -- Helper: Get journey icon with fallback -------------------------------------------------- local function getJourneyIcon(iconP...&quot;</title>
		<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=Module:JourneySystem&amp;diff=653&amp;oldid=prev"/>
		<updated>2025-05-25T19:48:41Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;-- Module:JourneySystem (Optimized for Template Data Fetching) -- Handles formatting and utility functions only -- Data fetching is done in templates for better caching  local p = {}  -- Default placeholder image local DEFAULT_JOURNEY_ICON = &amp;quot;https://dunedb.com/images/3/39/WikiPlaceholder.jpg&amp;quot;  -------------------------------------------------- -- Helper: Get journey icon with fallback -------------------------------------------------- local function getJourneyIcon(iconP...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Module:JourneySystem (Optimized for Template Data Fetching)&lt;br /&gt;
-- Handles formatting and utility functions only&lt;br /&gt;
-- Data fetching is done in templates for better caching&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- Default placeholder image&lt;br /&gt;
local DEFAULT_JOURNEY_ICON = &amp;quot;https://dunedb.com/images/3/39/WikiPlaceholder.jpg&amp;quot;&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Helper: Get journey icon with fallback&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
local function getJourneyIcon(iconPath, size)&lt;br /&gt;
    size = size or &amp;quot;48px&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    -- Check for null, empty string, or &amp;quot;NULL&amp;quot; string&lt;br /&gt;
    if not iconPath or iconPath == &amp;quot;&amp;quot; or iconPath == &amp;quot;NULL&amp;quot; or iconPath == &amp;quot;null&amp;quot; then&lt;br /&gt;
        return string.format(&amp;#039;&amp;lt;img src=&amp;quot;%s&amp;quot; width=&amp;quot;%s&amp;quot; height=&amp;quot;%s&amp;quot; alt=&amp;quot;Journey Icon&amp;quot;&amp;gt;&amp;#039;,&lt;br /&gt;
            DEFAULT_JOURNEY_ICON, size:match(&amp;quot;(%d+)&amp;quot;) or &amp;quot;48&amp;quot;, size:match(&amp;quot;(%d+)&amp;quot;) or &amp;quot;48&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Check if it&amp;#039;s already a full URL&lt;br /&gt;
    if iconPath:match(&amp;quot;^https?://&amp;quot;) then&lt;br /&gt;
        return string.format(&amp;#039;&amp;lt;img src=&amp;quot;%s&amp;quot; width=&amp;quot;%s&amp;quot; height=&amp;quot;%s&amp;quot; alt=&amp;quot;Journey Icon&amp;quot;&amp;gt;&amp;#039;,&lt;br /&gt;
            iconPath, size:match(&amp;quot;(%d+)&amp;quot;) or &amp;quot;48&amp;quot;, size:match(&amp;quot;(%d+)&amp;quot;) or &amp;quot;48&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Check if it&amp;#039;s already a full File: reference&lt;br /&gt;
    if iconPath:match(&amp;quot;^File:&amp;quot;) then&lt;br /&gt;
        return string.format(&amp;#039;[[%s|%s|link=]]&amp;#039;, iconPath, size)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    -- Check if it&amp;#039;s a filename&lt;br /&gt;
    local fileTitle = mw.title.new(&amp;quot;File:&amp;quot; .. iconPath)&lt;br /&gt;
    if fileTitle and fileTitle.exists then&lt;br /&gt;
        return string.format(&amp;#039;[[File:%s|%s|link=]]&amp;#039;, iconPath, size)&lt;br /&gt;
    else&lt;br /&gt;
        -- Fallback to placeholder&lt;br /&gt;
        return string.format(&amp;#039;&amp;lt;img src=&amp;quot;%s&amp;quot; width=&amp;quot;%s&amp;quot; height=&amp;quot;%s&amp;quot; alt=&amp;quot;Journey Icon&amp;quot;&amp;gt;&amp;#039;,&lt;br /&gt;
            DEFAULT_JOURNEY_ICON, size:match(&amp;quot;(%d+)&amp;quot;) or &amp;quot;48&amp;quot;, size:match(&amp;quot;(%d+)&amp;quot;) or &amp;quot;48&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: getIcon&lt;br /&gt;
-- Public function to get journey icon&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.getIcon(frame)&lt;br /&gt;
    local iconPath = frame.args[1] or &amp;quot;&amp;quot;&lt;br /&gt;
    local groupName = frame.args[2] or &amp;quot;&amp;quot;&lt;br /&gt;
    local size = frame.args[3] or &amp;quot;48px&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if iconPath ~= &amp;quot;&amp;quot; then&lt;br /&gt;
        return getJourneyIcon(iconPath, size)&lt;br /&gt;
    else&lt;br /&gt;
        -- Use group-based fallback&lt;br /&gt;
        local groupIcons = {&lt;br /&gt;
            [&amp;#039;A New Beginning&amp;#039;]          = &amp;#039;Icon_Zone_NewBeginning.png&amp;#039;,&lt;br /&gt;
            [&amp;#039;Vermillius Gap&amp;#039;]           = &amp;#039;Icon_Zone_Vermillius.png&amp;#039;,&lt;br /&gt;
            [&amp;#039;Jabal Eifrit &amp;amp; Hagga Rift&amp;#039;] = &amp;#039;Icon_Zone_Jabal.png&amp;#039;,&lt;br /&gt;
            [&amp;#039;Find The Fremen&amp;#039;]          = &amp;#039;Icon_Trial_Fremen.png&amp;#039;,&lt;br /&gt;
            [&amp;#039;Miscellaneous&amp;#039;]            = &amp;#039;Icon_Category_Standard.png&amp;#039;,&lt;br /&gt;
            [&amp;#039;Factions&amp;#039;]                 = &amp;#039;Icon_Category_Faction.png&amp;#039;&lt;br /&gt;
        }&lt;br /&gt;
        return getJourneyIcon(groupIcons[groupName], size)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: getGroupIcon&lt;br /&gt;
-- Get icon for journey group&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.getGroupIcon(frame)&lt;br /&gt;
    local groupName = frame.args[1] or &amp;quot;&amp;quot;&lt;br /&gt;
    local size      = frame.args[2] or &amp;quot;24px&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    local groupIcons = {&lt;br /&gt;
        [&amp;#039;A New Beginning&amp;#039;]          = &amp;#039;Icon_Zone_NewBeginning.png&amp;#039;,&lt;br /&gt;
        [&amp;#039;Vermillius Gap&amp;#039;]           = &amp;#039;Icon_Zone_Vermillius.png&amp;#039;,&lt;br /&gt;
        [&amp;#039;Jabal Eifrit &amp;amp; Hagga Rift&amp;#039;] = &amp;#039;Icon_Zone_Jabal.png&amp;#039;,&lt;br /&gt;
        [&amp;#039;Find The Fremen&amp;#039;]          = &amp;#039;Icon_Trial_Fremen.png&amp;#039;,&lt;br /&gt;
        [&amp;#039;Miscellaneous&amp;#039;]            = &amp;#039;Icon_Category_Standard.png&amp;#039;,&lt;br /&gt;
        [&amp;#039;Factions&amp;#039;]                 = &amp;#039;Icon_Category_Faction.png&amp;#039;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return getJourneyIcon(groupIcons[groupName], size)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: buildJourneyJSON&lt;br /&gt;
-- Builds JSON from template data&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.buildJourneyJSON(frame)&lt;br /&gt;
    -- Data is supplied by template; just return placeholder for now&lt;br /&gt;
    return &amp;#039;{}&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: escapeJson&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.escapeJson(frame)&lt;br /&gt;
    local text = frame.args[1] or &amp;quot;&amp;quot;&lt;br /&gt;
    text = text:gsub(&amp;#039;&amp;quot;&amp;#039;,  &amp;#039;\\&amp;quot;&amp;#039;)&lt;br /&gt;
               :gsub(&amp;#039;\n&amp;#039;, &amp;#039;\\n&amp;#039;)&lt;br /&gt;
               :gsub(&amp;#039;\r&amp;#039;, &amp;#039;&amp;#039;)&lt;br /&gt;
    return &amp;#039;&amp;quot;&amp;#039; .. text .. &amp;#039;&amp;quot;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: escapeHtml&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.escapeHtml(frame)&lt;br /&gt;
    local text = frame.args[1] or &amp;quot;&amp;quot;&lt;br /&gt;
    text = text:gsub(&amp;#039;&amp;amp;&amp;#039;, &amp;#039;&amp;amp;amp;&amp;#039;)  -- Must be first&lt;br /&gt;
               :gsub(&amp;#039;&amp;quot;&amp;#039;, &amp;#039;&amp;amp;quot;&amp;#039;)&lt;br /&gt;
               :gsub(&amp;quot;&amp;#039;&amp;quot;, &amp;#039;&amp;amp;#39;&amp;#039;)&lt;br /&gt;
               :gsub(&amp;#039;&amp;lt;&amp;#039;, &amp;#039;&amp;amp;lt;&amp;#039;)&lt;br /&gt;
               :gsub(&amp;#039;&amp;gt;&amp;#039;, &amp;#039;&amp;amp;gt;&amp;#039;)&lt;br /&gt;
    return text&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: formatObjectives&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.formatObjectives(frame)&lt;br /&gt;
    local output, index = &amp;quot;&amp;quot;, 1&lt;br /&gt;
&lt;br /&gt;
    while frame.args[&amp;quot;obj_id_&amp;quot; .. index] do&lt;br /&gt;
        local objId    = frame.args[&amp;quot;obj_id_&amp;quot; .. index]&lt;br /&gt;
        local objTitle = frame.args[&amp;quot;obj_title_&amp;quot; .. index] or &amp;quot;&amp;quot;&lt;br /&gt;
        local objSeq   = frame.args[&amp;quot;obj_seq_&amp;quot; .. index]   or index&lt;br /&gt;
        local collapsedClass = index &amp;gt; 1 and &amp;quot; collapsed&amp;quot; or &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        output = output .. string.format([[&lt;br /&gt;
&amp;lt;div class=&amp;quot;objective-item%s&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;objective-header&amp;quot; data-objective-id=&amp;quot;%s&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;objective-icon&amp;quot;&amp;gt;%s&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;objective-title&amp;quot;&amp;gt;%s&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;objective-progress&amp;quot;&amp;gt;0/0&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;objective-tasks&amp;quot;&amp;gt;]], collapsedClass, objId, objSeq, objTitle)&lt;br /&gt;
&lt;br /&gt;
        -- Tasks&lt;br /&gt;
        local taskIndex = 1&lt;br /&gt;
        while frame.args[&amp;quot;task_&amp;quot; .. index .. &amp;quot;_&amp;quot; .. taskIndex] do&lt;br /&gt;
            local taskDesc = frame.args[&amp;quot;task_&amp;quot; .. index .. &amp;quot;_&amp;quot; .. taskIndex]&lt;br /&gt;
            local taskQty  = frame.args[&amp;quot;task_qty_&amp;quot; .. index .. &amp;quot;_&amp;quot; .. taskIndex]&lt;br /&gt;
&lt;br /&gt;
            output = output .. string.format([[&lt;br /&gt;
        &amp;lt;div class=&amp;quot;task-item&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;task-checkbox&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;task-description&amp;quot;&amp;gt;%s&amp;lt;/div&amp;gt;]], taskDesc)&lt;br /&gt;
&lt;br /&gt;
            if taskQty and taskQty ~= &amp;quot;&amp;quot; then&lt;br /&gt;
                output = output .. string.format(&amp;#039;&amp;lt;div class=&amp;quot;task-qty&amp;quot;&amp;gt;%s pcs&amp;lt;/div&amp;gt;&amp;#039;, taskQty)&lt;br /&gt;
            end&lt;br /&gt;
&lt;br /&gt;
            output = output .. &amp;#039;&amp;lt;/div&amp;gt;\n&amp;#039;&lt;br /&gt;
            taskIndex = taskIndex + 1&lt;br /&gt;
        end&lt;br /&gt;
&lt;br /&gt;
        output = output .. [[&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;]]&lt;br /&gt;
        index = index + 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    return output&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
-- Function: formatMaterials&lt;br /&gt;
--------------------------------------------------&lt;br /&gt;
function p.formatMaterials(frame)&lt;br /&gt;
    local output, totalCount, idx = &amp;quot;&amp;quot;, 0, 0&lt;br /&gt;
&lt;br /&gt;
    -- Count materials&lt;br /&gt;
    while frame.args[&amp;quot;mat_name_&amp;quot; .. (idx + 1)] do&lt;br /&gt;
        totalCount = totalCount + 1&lt;br /&gt;
        idx        = idx + 1&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    output = string.format([[&lt;br /&gt;
&amp;lt;div class=&amp;quot;materials-progress&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;span class=&amp;quot;materials-progress-text&amp;quot;&amp;gt;Materials Collected&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;span class=&amp;quot;materials-progress-count&amp;quot;&amp;gt;0/%d&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;materials-list&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;material-category&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;material-category-title&amp;quot;&amp;gt;Required Materials&amp;lt;/div&amp;gt;]], totalCount)&lt;br /&gt;
&lt;br /&gt;
    -- Render each material&lt;br /&gt;
    for i = 1, totalCount do&lt;br /&gt;
        local matName = frame.args[&amp;quot;mat_name_&amp;quot; .. i] or &amp;quot;&amp;quot;&lt;br /&gt;
        local matQty  = frame.args[&amp;quot;mat_qty_&amp;quot; .. i] or &amp;quot;1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        -- Icon lookup&lt;br /&gt;
        local iconFile = matName:gsub(&amp;quot;%s+&amp;quot;, &amp;quot;_&amp;quot;) .. &amp;quot;_-_Icon.png&amp;quot;&lt;br /&gt;
        local fileTitle = mw.title.new(&amp;quot;File:&amp;quot; .. iconFile)&lt;br /&gt;
        local iconHtml  = fileTitle and fileTitle.exists&lt;br /&gt;
                          and string.format(&amp;#039;[[File:%s|20px|link=]]&amp;#039;, iconFile)&lt;br /&gt;
                          or &amp;#039;⚙️&amp;#039;&lt;br /&gt;
&lt;br /&gt;
        -- *** fixed delimiter here ***&lt;br /&gt;
        output = output .. string.format([=[&lt;br /&gt;
        &amp;lt;div class=&amp;quot;material-item&amp;quot; data-material-index=&amp;quot;%d&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;material-checkbox&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;material-icon&amp;quot;&amp;gt;%s&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;material-name&amp;quot;&amp;gt;[[%s]]&amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;material-qty&amp;quot;&amp;gt;%s&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;]=], i - 1, iconHtml, matName, matQty)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    output = output .. [[&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
    return output&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Operator</name></author>
	</entry>
</feed>