Hey everyone (again),

I have updated the Navigation macro to include some new things,
including a Tree navigation.

Features of this new macro:
  Will work just like the old Navigation macro
  [[Navigation(help)]] will print a help table
  new types, tree navigation, both children, siblings, and root
  new format bulleted list (only applies to siblings and children)
  can show full name of page
  can pass in a rootpage
  can turn off the table around the output

Feel free to include it in MoinMoin.

Newest Stuff:
I added the roottree type since the last update. Several people asked me
why [[Navigation(childtree, rootpage=/)]] or [[Navigation(tree,
rootpage=FrontPage]] didn't work.  That is because / is not really a
page in the wiki internals, merely a pointer to somewhere else.

Thanks,
Eric


The Help:
[[Navigation(args)]]: navigate slides or children and sibling pages

Arg Number and/or keyword       Argument Definition
---------------------------------------------------
0 \ type        the type of navigation valid types are: children,       
                siblings, tree, roottree, childtree, slideshow,
                slides (default: children)

1 \ maxdepth    the maximum depth to search (default: No limit)

format          the format of the list (only for siblings, children),
                valid: bullet, string (default: string)

fullname        flag to show the full name of the page, True of False   
                (default: False)

navtable        flag to wrap the output in the navtable, True or False
                (default: True)

rootpage        the root page to start from, (default: current page)

showsys         flag to show system pages, only for roottree, True or
                False (default: False)



# -*- coding: iso-8859-1 -*-
"""
    MoinMoin - Navigation Macro

    @copyright: 2003 by J�rgen Hermann <[EMAIL PROTECTED]>
    @license: GNU GPL, see COPYING for details.
"""

import re
from MoinMoin import config
from MoinMoin.Page import Page
from MoinMoin import wikiutil

Dependencies = ["namespace"]

# helpers
#!!! refactor these to an util module?
def _getParent(pagename):
    """ Return parent of pagename.
    """
    pos = pagename.rfind('/')
    if pos >= 0:
        return pagename[:pos]
    return None


def _getPages(request, filter_regex=None):
    """ Return a (filtered) list of pages names.
    """
    filter = None
    if filter_regex:
        filter = re.compile(filter_regex).match
    pages = request.rootpage.getPageList(filter=filter)
    pages.sort()
    return pages


def _getLinks(request, pagename, filter_regex=None):
    """ Return pagename for up, first, prev, next, last; each can be None.
    """
    pos, size, first, prev, next, last = 0, 0, None, None, None, None

    all_pages = _getPages(request, filter_regex)
    size = len(all_pages)

    if all_pages:
        try:
            pos = all_pages.index(pagename)
        except ValueError:
            # this should never happen in theory, but let's be sure
            pass
        else:
            if pos > 0:
                first = all_pages[0]
                prev = all_pages[pos-1]
            if pos+1 < len(all_pages):
                next = all_pages[pos+1]
                last = all_pages[-1]

    return pos, size, (first, prev, next, last)


class Navigation:
    """ Dispatcher class implementing the navigation schemes.
    """

    # querystring for slideshow links
    PROJECTION = 'action=print&media=projection'

    def __init__(self, macro, args):
        """ Prepare common values used during processing.
        """
        self.keywordhelp = {}
        self.keywordhelp['0 \ type'] = """the type of navigation
                valid types are: children, siblings, tree, roottree, childtree,
                slideshow, slides (default: children)
                """
        self.keywordhelp['1 \ maxdepth'] = """the maximum depth to search
                                    (default: No limit) """
        self.keywordhelp['format'] = """the format of the list (only for
                                    children, siblings), valid:
                                    bullet, string (default: string)"""
        self.keywordhelp['navtable'] = """flag to wrap the output in the
                                    navtable, True or False
                                    (default: True)"""
        self.keywordhelp['rootpage'] = """the root page to start from,
                                    (default: current page)"""
        self.keywordhelp['fullname'] = """flag to show the full name of the
                                    page, True of False
                                    (default: False)"""
        self.keywordhelp['showsys'] = """flag to show system pages, only for
                                    roottree, True or False
                                    (default: False)"""
        self.macro = macro
        self.args = {}
        self.maxdepth = None
        self.ntype = None
        self.fullname = None
        self.navtable = None
        self.showsys = None
        self.rootpage = None
        self.parse_args(args)
        self._ = self.macro.request.getText

        self.pagename = self.macro.formatter.page.page_name
        self.print_mode = self.macro.request.form.has_key('action') \
            and self.macro.request.form['action'][0] == 'print'
        self.media = self.macro.request.form.get('media', [None])[0]
        self.querystr = self.print_mode and self.PROJECTION or ''


    def parse_args(self, args):
        """ parse the arguments passes
        """
        argstemp = args.split(',')
        for i in range(len(argstemp)):
            arg = argstemp[i].strip()
            self.args[i] = arg
            if '=' in arg:
                argname, argvalue = arg.split('=')
                self.args[argname.strip()] = argvalue.strip()

        self.get_maxdepth()
        self.get_fullname()
        self.get_navtable()
        self.get_ntype()
        self.get_showsys()
        if 'rootpage' in self.args:
            self.rootpage = self.args['rootpage']


    def get_maxdepth(self):
        """ get the depth
        """
        if not self.maxdepth is None:
            return self.maxdepth

        if 'maxdepth' in self.args:
            deptht = self.args['maxdepth']
        elif 1 in self.args:
            deptht = self.args[1]
        else:
            deptht = 0

        try:
            depth = int(deptht)
        except (IndexError, TypeError, ValueError, KeyError):
            depth = 0

        self.maxdepth = depth
        return self.maxdepth


    def get_ntype(self):
        """ get the navigation type
        """
        if self.ntype:
            return self.ntype

        if 'type' in self.args:
            ntype = self.args['type']
        elif 0 in self.args:
            ntype = self.args[0]
        else:
            ntype = 'children'

        self.ntype = ntype
        return self.ntype


    def get_fullname(self):
        """ get the fullname argument
        """
        if not self.fullname is None:
            return self.fullname

        self.fullname = False
        if 'fullname' in self.args:
            fulltemp = self.args['fullname']
            if fulltemp == '1' or fulltemp == 'True' or fulltemp == 'true' \
                or fulltemp == 'On' or fulltemp == 'on':
                self.fullname = True

        return self.fullname


    def get_showsys(self):
        """ get the fullname argument
        """
        if not self.showsys is None:
            return self.showsys

        self.showsys = False
        if 'showsys' in self.args:
            showsys = self.args['showsys']
            if showsys == '1' or showsys == 'True' or showsys == 'true' \
                or showsys == 'On' or showsys == 'on':
                self.showsys = True

        return self.showsys


    def get_navtable(self):
        """ get the navtable argument
        """
        if not self.navtable is None:
            return self.navtable

        self.navtable = True
        if 'navtable' in self.args:
            navtemp = self.args['navtable']
            if navtemp == '0' or navtemp == 'False' or navtemp == 'false'\
                or navtemp == 'Off' or navtemp == 'off':
                self.navtable = False

        return self.navtable


    def do_help(self):
        """ return the formatted help
        """
        macro = self.macro
        result = []
        result.append(macro.formatter.table(1))
        result.append(macro.formatter.table_row(1))
        result.append(macro.formatter.table_cell(1, {'colspan' : '2'}))
        result.append("""[[Navigation(args)]]: navigate slides or \
                            children and sibling pages""")
        result.append(macro.formatter.table_cell(0))
        result.append(macro.formatter.table_row(0))
        result.append(macro.formatter.table_row(1))
        result.append(macro.formatter.table_cell(1, {'colspan' : '2'}))
        result.append("""Examples: [[Navigation(roottree, maxdepth=3)]]\
                            [[Navigation(children, format=bullet, rootpage=HelpOnMacros)]]""")
        result.append(macro.formatter.table_cell(0))
        result.append(macro.formatter.table_row(0))
        result.append(macro.formatter.table_row(1))
        result.append(macro.formatter.table_cell(1))
        result.append('Arg Number and/or keyword')
        result.append(macro.formatter.table_cell(0))
        result.append(macro.formatter.table_cell(1))
        result.append('Argument Definition')
        result.append(macro.formatter.table_cell(0))
        result.append(macro.formatter.table_row(0))
        keys = self.keywordhelp.keys()
        keys.sort()
        for item in keys:
            result.append(macro.formatter.table_row(1))
            result.append(macro.formatter.table_cell(1))
            result.append(item)
            result.append(macro.formatter.table_cell(0))
            result.append(macro.formatter.table_cell(1))
            result.append(self.keywordhelp[item])
            result.append(macro.formatter.table_cell(0))
            result.append(macro.formatter.table_row(0))
        result.append(macro.formatter.table(0))
        return ''.join(result)


    def format(self, plist):
        """ dispatch to the correct formatting function
        """
        if 'format' in self.args:
            format = self.args['format']
        else:
            format = 'string'

        result2 = []

        if self.fullname:
            for item in plist:
                 result2.append((item[0], item[0]))
        else:
            result2 = plist

        fformat = getattr(self, 'format_' + format)
        return fformat(result2)


    def format_bullet(self, plist):
        """ format the result as bulleted list
        """
        plist.sort()
        # send list of template pages
        result = self.macro.formatter.bullet_list(1)
        for child, shortname in plist:
            result = result + \
                     self.macro.formatter.listitem(1) + \
                     Page(self.macro.request, child).link_to(
                                self.macro.request, text=shortname,
                                querystr=self.querystr) + \
                     self.macro.formatter.listitem(0)

        result = result + self.macro.formatter.bullet_list(0)
        return result


    def format_string(self, plist):
        """ format the result as a string
        """
        result = []

        for child, shortname in plist:
            result.append(Page(self.macro.request, child).link_to(
                                self.macro.request, text=shortname,
                                querystr=self.querystr))
            result.append(' &nbsp; ')
        return ''.join(result)


    def dispatch(self):
        """ Return None if in plain print mode (no navigational
            elements in printouts), else the proper HTML code.
        """
        if self.print_mode and self.media != 'projection':
            return None

        if self.ntype == 'help':
            return self.do_help()

        links = getattr(self, 'do_'+self.ntype, self.badscheme)(self.rootpage)

        if links and self.navtable:
            return '<table class="navigation"><tr><td>%s</td></tr></table>' % \
                                        links
        elif links:
            return links
        else:
            return None


    def badscheme(self, root=None):
        """ Bad scheme argument.
        """
        _ = self._
        scheme = self.args[0]
        return (self.macro.formatter.sysmsg(1) +
                self.macro.formatter.text(
            _("Unsupported navigation scheme '%(scheme)s'!") %
            {'scheme': scheme}) +
                self.macro.formatter.sysmsg(0))


    def do_children(self, root=None):
        """ Navigate to subpages from a parent page.
        """
        # delegate to siblings code, setting the parent explicitely
        return self.do_siblings(root or self.pagename)


    def do_siblings(self, root=None):
        """ Navigate from a subpage to its siblings.
        """
        _ = self._
        # get parent page name
        if self.rootpage and self.ntype == 'siblings':
            root = _getParent(self.rootpage)
        parent = root or _getParent(self.pagename)
        if not parent:
            return (self.macro.formatter.sysmsg(1) +
                    self.macro.formatter.text(_('No parent page found!'))+
                    self.macro.formatter.sysmsg(0))

        # iterate over children, adding links to all of them
        result = []
        children = _getPages(self.macro.request, '^%s/' % parent)
        for child in children:
            # display short page name, leaving out the parent path
            # (and make sure the name doesn't get wrapped)
            shortname = child[len(parent):]

            # possibly limit depth
            if self.maxdepth and shortname.count('/') > self.maxdepth:
                continue

            if not child == self.pagename:
                # link to sibling / child
                result.append((child, shortname))

        return self.format(result)


    def do_childtree(self, root=None):
        """ navigate to the subpages of the current page
        """
        return self.do_tree(root or self.pagename, currentdepth=0, parents={})


    def do_roottree(self, root=None):
        """ do a tree from the root
        """
        result = []

        if self.showsys:
            pages = _getPages(self.macro.request)
        else:
            def filter(name):
                return not wikiutil.isSystemPage(self.macro.request, name)
            pages = self.macro.request.rootpage.getPageList(filter=filter)

        if self.maxdepth > 0:
            self.maxdepth -= 1

        result.append('<ul>')
        for item in pages:
            if (not self.showsys and item == 'SystemPagesGroup') or '/' in item:
                continue
            result.append('<li>')
            result.append(Page(self.macro.request, item).link_to(
                                    self.macro.request, text=item,
                                    querystr=self.querystr))
            result.append('</li>')

            if self.maxdepth == 0:
                continue

            result.append(self.do_childtree(root=item))
        result.append('</ul>')

        return '\n'.join(result)


    def do_tree(self, root=None, currentdepth=0, parents={}):
        """ Navigate to subpages from a parent page.
        """
        _ = self._

        # get parent page name if no root was specified
        if root and self.ntype == 'tree' and currentdepth == 0:
            root = _getParent(root)
        parent = root or _getParent(self.pagename)
        if not parent:
            return (self.macro.formatter.sysmsg(1) +
                    self.macro.formatter.text(_('No parent page found!'))+
                    self.macro.formatter.sysmsg(0))
        else:
            parents[parent] = 1

        # limit depth if a depth was specified
        if self.maxdepth and currentdepth >= self.maxdepth:
            return ''

        # iterate over children, adding links to all of them
        result = []
        result.append('<ul>')
        children = _getPages(self.macro.request, '^%s/' % parent)
        for child in children:
            # display short page name, leaving out the parent path
            # (and make sure the name doesn't get wrapped)
            shortname = child[len(parent)+1:]
            if shortname.count('/') > 0:
                shortname = re.sub('/.*$', '', shortname)
                child = parent + '/' + shortname

            if parents.has_key(child):
                continue

            result.append('<li>')

            if child == self.pagename:
                # do not link to focus
                result.append(self.macro.formatter.text(shortname))
            else:
                # link to child
                if self.fullname:
                    shortname = child
                else:
                    shortname = child[len(parent)+1:]
                result.append(Page(self.macro.request, child).link_to(
                                    self.macro.request, text=shortname,
                                    querystr=self.querystr))

            result.append('</li>')
            result.append(self.do_tree(root=child,
                                        currentdepth=currentdepth+1,
                                        parents=parents))

        result.append('</ul>')
        return ''.join(result)


    def do_slideshow(self, focus=None):
        """ Slideshow master page links.

            If `focus` is set, it is the name of a slide page; these only
            get the mode toggle and edit links.
        """
        _ = self._
        curpage = focus or self.pagename
        result = []

        if self.print_mode:
            # projection mode
            label = _('Wiki')
            toggle = ''
            result.append(Page(self.macro.request, curpage).link_to(
                                        self.macro.request, text=_('Edit'),
                                        querystr='action=edit'))
            result.append(' &nbsp; ')
        else:
            # wiki mode
            label = _('Slideshow')
            toggle = self.PROJECTION

        # add mode toggle link
        result.append(Page(self.macro.request, curpage).link_to(
                                            self.macro.request, text=label,
                                            querystr=toggle))

        # leave out the following on slide pages
        if focus is None:
            children = _getPages(self.macro.request, '^%s/' % self.pagename)
            if children:
                # add link to first child if one exists
                result.append(' &nbsp; ')
                result.append(Page(self.macro.request, children[0]).link_to(
                                        self.macro.request, text=_('Start'),
                                        querystr=self.querystr))

        return ''.join(result)


    def do_slides(self, root=None):
        """ Navigate within a slide show.
        """
        _ = self._
        parent = root or _getParent(self.pagename)
        if not parent:
            return (self.macro.formatter.sysmsg(1) +
                    self.macro.formatter.text(_('No parent page found!')) +
                    self.macro.formatter.sysmsg(0))

        # prepare link generation
        result = []
        labels = ['^', '|<', '<<', '>>', '>|']
        filter_regex = '^%s/' % re.escape(parent)
        pos, size, links = _getLinks(self.macro.request, self.pagename,
                                        filter_regex)
        pos += 1
        links = zip(labels, (parent,) + links)

        # generate links to neighborhood
        for label, name in links:
            result.append(' ')
            if name:
                # active link
                result.append(Page(self.macro.request, name).link_to(
                                            self.macro.request, text=label,
                                            querystr=self.querystr))
            else:
                # ghosted link
                result.append(self.macro.formatter.text(label))
            result.append(' ')

            # position indicator in the middle
            if label == labels[2]:
                result.append(_('Slide %(pos)d of %(size)d') % {'pos': pos,
                                                            'size': size})

        return self.do_slideshow(focus=self.pagename) + ''.join(result)


def execute(macro, args):
    # get HTML code with the links
    navi = Navigation(macro, args or '').dispatch()

    if navi:
        return navi

    # navigation disabled in plain print mode
    return ''

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Moin-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/moin-user

Reply via email to