<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://help.craftbot.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ANavigation</id>
	<title>Module:Navigation - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://help.craftbot.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3ANavigation"/>
	<link rel="alternate" type="text/html" href="https://help.craftbot.com/wiki/index.php?title=Module:Navigation&amp;action=history"/>
	<updated>2026-04-17T17:21:00Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.37.2</generator>
	<entry>
		<id>https://help.craftbot.com/wiki/index.php?title=Module:Navigation&amp;diff=239&amp;oldid=prev</id>
		<title>Cwproadmin: 1 revision imported</title>
		<link rel="alternate" type="text/html" href="https://help.craftbot.com/wiki/index.php?title=Module:Navigation&amp;diff=239&amp;oldid=prev"/>
		<updated>2022-09-01T08:13:43Z</updated>

		<summary type="html">&lt;p&gt;1 revision imported&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 10:13, 1 September 2022&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Cwproadmin</name></author>
	</entry>
	<entry>
		<id>https://help.craftbot.com/wiki/index.php?title=Module:Navigation&amp;diff=238&amp;oldid=prev</id>
		<title>cb&gt;Szabolcs at 07:34, 2 August 2022</title>
		<link rel="alternate" type="text/html" href="https://help.craftbot.com/wiki/index.php?title=Module:Navigation&amp;diff=238&amp;oldid=prev"/>
		<updated>2022-08-02T07:34:33Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local function trim(s)&lt;br /&gt;
    return s:match &amp;quot;^%s*(.-)%s*$&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Supported line format:   '  ## Page Title    '&lt;br /&gt;
--         or:    '  ### [[Page Link ]]  extra text '&lt;br /&gt;
function parse_line2(line)&lt;br /&gt;
	return line:match '^%s*(#+)%s*%[*%s*([^%]]*[^%s%]]+)%s*%]*%s*.*$'&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function read_tree_lines(lines)&lt;br /&gt;
    local res = {lines={}, cur=0}&lt;br /&gt;
    for nr=1,#lines do&lt;br /&gt;
        repeat&lt;br /&gt;
        	-- mw.log('line ' .. nr .. ': &amp;lt;' .. lines[nr] ..'&amp;gt;')&lt;br /&gt;
        	level, title = parse_line2(lines[nr])&lt;br /&gt;
        	if level == nil then&lt;br /&gt;
        		break&lt;br /&gt;
        	else&lt;br /&gt;
        		level = #level&lt;br /&gt;
        	end&lt;br /&gt;
            res.lines[#res.lines + 1] = {level=level, title=title}&lt;br /&gt;
        until true&lt;br /&gt;
    end&lt;br /&gt;
    return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function next(nodes)&lt;br /&gt;
    if #nodes.lines &amp;gt; nodes.cur then&lt;br /&gt;
        nodes.cur = nodes.cur + 1&lt;br /&gt;
        local pair = nodes.lines[nodes.cur]&lt;br /&gt;
        return pair.level, pair.title&lt;br /&gt;
    else&lt;br /&gt;
        return -1, ''&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function read_tree(tree, level, title, nodes)&lt;br /&gt;
    local cur_level = level&lt;br /&gt;
    while cur_level &amp;gt;= 0 and cur_level &amp;gt;= level do&lt;br /&gt;
        repeat&lt;br /&gt;
            if cur_level == level then&lt;br /&gt;
                tree.children[#tree.children + 1] = {content=title, children={}}&lt;br /&gt;
            else&lt;br /&gt;
                cur_level, title = read_tree(tree.children[#tree.children], level+1, title, nodes)&lt;br /&gt;
                break&lt;br /&gt;
            end&lt;br /&gt;
            cur_level, title = next(nodes)&lt;br /&gt;
        until true&lt;br /&gt;
    end&lt;br /&gt;
    return cur_level, title &lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function visit_tree(tree, visitor)&lt;br /&gt;
	if visitor.enter then&lt;br /&gt;
		visitor:enter(tree)&lt;br /&gt;
	end&lt;br /&gt;
    for i=1, #tree.children do&lt;br /&gt;
    	repeat&lt;br /&gt;
	        local child = tree.children[i]&lt;br /&gt;
	       	if visitor.filter and not visitor:filter(child) then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
	        visitor:visit(child)&lt;br /&gt;
	        if #child['children'] &amp;gt; 0 then&lt;br /&gt;
	            visit_tree(child, visitor)&lt;br /&gt;
	        end&lt;br /&gt;
	    until true&lt;br /&gt;
    end&lt;br /&gt;
    if visitor.leave then&lt;br /&gt;
	    visitor:leave(tree)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local Renderer = { parents={}, titles = {} }&lt;br /&gt;
&lt;br /&gt;
function Renderer:enter(tree)&lt;br /&gt;
	self.parents[#self.parents + 1] = self.parents[#self.parents]:tag 'ol'&lt;br /&gt;
	self.titles[#self.titles + 1] = tree.content&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Renderer:visit(tree)&lt;br /&gt;
	local li = self.parents[#self.parents]:tag 'li'&lt;br /&gt;
    li:wikitext('[['..tree.content..']]')&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function Renderer:leave(tree)&lt;br /&gt;
	self.parents[#self.parents] = nil&lt;br /&gt;
	self.titles[#self.titles] = nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local CurrentFinder = { titles={}, result = nil }&lt;br /&gt;
&lt;br /&gt;
function CurrentFinder:enter(tree)&lt;br /&gt;
	if tree.content then&lt;br /&gt;
		self.titles[#self.titles + 1] = tree.content&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function CurrentFinder:visit(tree)&lt;br /&gt;
	if tree.content == self.target then&lt;br /&gt;
		self.result = {}&lt;br /&gt;
		for i = 1,#self.titles do&lt;br /&gt;
			self.result[#self.result + 1] = self.titles[i]&lt;br /&gt;
		end&lt;br /&gt;
		self.result[#self.result + 1] = tree.content&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function CurrentFinder:leave(tree)&lt;br /&gt;
	self.titles[#self.titles] = nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function find_current_node(tree, title)&lt;br /&gt;
	CurrentFinder.parents = {}&lt;br /&gt;
	CurrentFinder.target = title&lt;br /&gt;
	CurrentFinder.result = nil&lt;br /&gt;
	visit_tree(tree, CurrentFinder)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function render_tree(tree, current_node)&lt;br /&gt;
	local div = mw.html.create('div')&lt;br /&gt;
	div:wikitext('Navigation')&lt;br /&gt;
	div:cssText('border: 1px solid blue; background-color: #f0f0f0')&lt;br /&gt;
	Renderer.parents = {div}&lt;br /&gt;
	Renderer.filter = function (self, tree)&lt;br /&gt;
		--[[&lt;br /&gt;
		mw.log('======\nrender filter: ')&lt;br /&gt;
		mw.log(&amp;quot;self titles:&amp;quot; ..mw.dumpObject(self.titles))&lt;br /&gt;
		mw.log(&amp;quot;current titles: &amp;quot; ..mw.dumpObject(current_node))&lt;br /&gt;
		mw.log(&amp;quot;tree: &amp;quot; ..mw.dumpObject(tree))&lt;br /&gt;
		]]&lt;br /&gt;
		if #self.titles &amp;gt; #current_node then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
		for i=1,#self.titles do&lt;br /&gt;
			if self.titles[i] ~= current_node[i] then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	visit_tree(tree, Renderer)&lt;br /&gt;
	return tostring(div)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function links_from_nodes(nodes, current_title)&lt;br /&gt;
    local level, title = next(nodes)&lt;br /&gt;
    local tree = {content='', children={}}&lt;br /&gt;
    read_tree(tree, level, title, nodes)&lt;br /&gt;
    &lt;br /&gt;
    find_current_node(tree, current_title)&lt;br /&gt;
    local current_node = CurrentFinder.result&lt;br /&gt;
    if current_node == nil then&lt;br /&gt;
    	current_node = {current_title}&lt;br /&gt;
    	mw.log(current_title .. ' not found in page')&lt;br /&gt;
    end&lt;br /&gt;
    return render_tree(tree, current_node)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Test&lt;br /&gt;
--[[&lt;br /&gt;
local tree = {content='', children={&lt;br /&gt;
 {content='a1', children={&lt;br /&gt;
     {content='a1-b1', children={}},&lt;br /&gt;
     {content='a1-b2', children={&lt;br /&gt;
         {content='a1-b2-c1', children= {&lt;br /&gt;
             {content='a2-b2-c1-d1', children={}}&lt;br /&gt;
         }}&lt;br /&gt;
     }}&lt;br /&gt;
 }},&lt;br /&gt;
 {content='a2', children= {&lt;br /&gt;
     {content='a2-b2', children={}},&lt;br /&gt;
     {content='a2-c2', children={}}&lt;br /&gt;
 }}&lt;br /&gt;
}}&lt;br /&gt;
]]--&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
function p.hello(frame)&lt;br /&gt;
	mw.log(mw.dumpObject(frame))&lt;br /&gt;
    return &amp;quot;Hello, world!&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.test(x)&lt;br /&gt;
	return x+1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function parse_contents(contents_page)&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
    local title = mw.title.new(contents_page)&lt;br /&gt;
    mw.log('fetch contents of title: ' .. title.text)&lt;br /&gt;
    local content = title:getContent()&lt;br /&gt;
    &lt;br /&gt;
    if content == nil or #content == 0 then&lt;br /&gt;
		return ''&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local function get_lines(text)&lt;br /&gt;
        if text:sub(-1)~=&amp;quot;\n&amp;quot; then&lt;br /&gt;
            text = text .. &amp;quot;\n&amp;quot;&lt;br /&gt;
        end&lt;br /&gt;
        return text:gmatch(&amp;quot;(.-)\n&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    local lines = {}&lt;br /&gt;
    --[[&lt;br /&gt;
    for line in get_lines(content) do&lt;br /&gt;
        lines[#lines+1] = frame:preprocess(line)&lt;br /&gt;
    end&lt;br /&gt;
    ]]&lt;br /&gt;
    for line in get_lines(frame:preprocess(content)) do&lt;br /&gt;
        lines[#lines+1] = line&lt;br /&gt;
    end&lt;br /&gt;
    &lt;br /&gt;
    return lines&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function get_params(frame)&lt;br /&gt;
    local current_title = frame.args['selfpage'] or frame:preprocess '{{PAGENAME}}'&lt;br /&gt;
    mw.log('Current title: ' .. current_title)&lt;br /&gt;
    &lt;br /&gt;
    -- mw.logObject(frame)&lt;br /&gt;
&lt;br /&gt;
   	local contents_page = frame.args[1] or nil&lt;br /&gt;
   	if not contents_page then&lt;br /&gt;
   		parent = frame:getParent()&lt;br /&gt;
   		contents_page = mw.title.new(parent:getTitle()).rootPageTitle.text .. &amp;quot;/Contents&amp;quot;&lt;br /&gt;
   	end&lt;br /&gt;
	mw.log('Contents page name: ' .. (contents_page or '&amp;lt;name missing&amp;gt;'))&lt;br /&gt;
	&lt;br /&gt;
	return current_title, contents_page&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
	&lt;br /&gt;
-- prev and next links&lt;br /&gt;
function p.create_prevnext(frame)&lt;br /&gt;
    local current_title, contents_page = get_params(frame)&lt;br /&gt;
	local lines = parse_contents(contents_page)&lt;br /&gt;
    local nodes = read_tree_lines(lines)&lt;br /&gt;
    local level, title = next(nodes)&lt;br /&gt;
    local tree = {content='', children={}}&lt;br /&gt;
    read_tree(tree, level, title, nodes)&lt;br /&gt;
    &lt;br /&gt;
    find_current_node(tree, current_title)&lt;br /&gt;
    local current_node = CurrentFinder.result&lt;br /&gt;
&lt;br /&gt;
	local tree_lines = nodes.lines&lt;br /&gt;
&lt;br /&gt;
	title_idx = nil&lt;br /&gt;
	mw.log(&amp;quot;# tree lines: &amp;quot; .. #tree_lines)&lt;br /&gt;
	for i = 1, #tree_lines do&lt;br /&gt;
		title = tree_lines[i].title&lt;br /&gt;
		if title == current_title then&lt;br /&gt;
			title_idx = i&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	mw.log(&amp;quot;Title index: &amp;quot; .. (title_idx or &amp;quot;&amp;lt;title not found&amp;gt;&amp;quot;))&lt;br /&gt;
	&lt;br /&gt;
	if title_idx == nil then&lt;br /&gt;
		return frame:preprocess('{{Note|Page title ' .. current_title .. ' missing from ' .. name .. '|error}}')&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local res = '{| class=&amp;quot;navcontrol&amp;quot; style=&amp;quot;margin-bottom:1em; padding:0.1em; 100%; width: 100%; text-align: left; background-color: #f0f0f0;&amp;quot;\n'&lt;br /&gt;
	&lt;br /&gt;
	if title_idx &amp;gt; 1 then&lt;br /&gt;
		res = res .. &amp;quot;|style='text-align:left'|'''&amp;amp;#9664;''' [[&amp;quot; .. tree_lines[title_idx-1].title .. &amp;quot;]]\n&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	res = res .. &amp;quot;|style='text-align:center'| [[&amp;quot; .. current_node[2] .. ']]'&lt;br /&gt;
	for i = 3, #current_node do&lt;br /&gt;
		res = res .. ' &amp;gt; [[' .. current_node[i] .. ']]'&lt;br /&gt;
	end&lt;br /&gt;
	res = res .. '\n'&lt;br /&gt;
	&lt;br /&gt;
	if title_idx &amp;lt; #tree_lines then&lt;br /&gt;
		res = res .. &amp;quot;|style='text-align:right'| [[&amp;quot; .. tree_lines[title_idx+1].title .. &amp;quot;]] '''&amp;amp;#9654;'''\n&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
--	if #CurrentFinder.result &amp;gt; 1 then&lt;br /&gt;
--		local parent = CurrentFinder.result[#CurrentFinder.result-1]&lt;br /&gt;
--		if #parent &amp;gt; 0 then&lt;br /&gt;
--			res = res ..&amp;quot;||'''&amp;amp;uarr; Up''' [[&amp;quot; .. parent ..&amp;quot;]] &amp;quot;&lt;br /&gt;
--		end&lt;br /&gt;
--	end&lt;br /&gt;
	&lt;br /&gt;
	res = res .. &amp;quot;\n|}\n&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	-- return log .. res&lt;br /&gt;
	return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.create_sidebar_tree(frame)&lt;br /&gt;
    local current_title, contents_page = get_params(frame)&lt;br /&gt;
&lt;br /&gt;
	local lines = parse_contents(contents_page)&lt;br /&gt;
	--mw.logObject(lines)&lt;br /&gt;
    local nodes = read_tree_lines(lines).lines&lt;br /&gt;
	--mw.logObject(nodes)&lt;br /&gt;
    &lt;br /&gt;
    local res = '{{#tree:\n'&lt;br /&gt;
	for i=1,#nodes do&lt;br /&gt;
		--mw.logObject(nodes[i])&lt;br /&gt;
		for i = 1, nodes[i].level do&lt;br /&gt;
			res = res .. '*'&lt;br /&gt;
		end&lt;br /&gt;
		res = res .. nodes[i].title .. '\n'&lt;br /&gt;
	end&lt;br /&gt;
	res = res .. '}}'&lt;br /&gt;
	--mw.log(res)&lt;br /&gt;
	return frame:preprocess(res)&lt;br /&gt;
	--return res&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.create_toc(frame)&lt;br /&gt;
    local current_title, contents_page = get_params(frame)&lt;br /&gt;
    mw.log(current_title)&lt;br /&gt;
	local lines = parse_contents(contents_page)&lt;br /&gt;
    local nodes = read_tree_lines(lines)&lt;br /&gt;
    return links_from_nodes(nodes, current_title)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[ How to test in Debug Console (no page saves required)&lt;br /&gt;
f = mw.getCurrentFrame():newChild{title=&amp;quot;Debug&amp;quot;, args={'Test toc', selfpage='Page3'}}&lt;br /&gt;
=p.create_links(f)&lt;br /&gt;
&lt;br /&gt;
f = mw.getCurrentFrame():newChild{title=&amp;quot;Manual/GettingStarted/Introduction&amp;quot;, args={&amp;quot;Manual/Contents&amp;quot;, selfpage=&amp;quot;Manual/GettingStarted/Introduction&amp;quot;}}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
p.create_links = p.create_prevnext&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>cb&gt;Szabolcs</name></author>
	</entry>
</feed>