Better Navigation Template Details

Credit

The foundation of my Better Navigation template work has been borrowed from the work done by Chris. More info can be found here. In particular, I reused the following:

  • the idea to define the sidebar content in a specific wiki page
  • the idea to have a sidebar page per namespace and look up the most appropriate one
  • the way to use the stylesheet to position the sidebar
  • the php and css code, as a starting point

I extended and adapted the implementation to achieve my goals.

Goals

I had a number of design goals with my Better Navigation template:

  • Make sure all Navigation Issues are addressed
  • No changes to the core DokuWiki code
  • Minimal changes to the default stylesheet, same philosophy and no tricks

Code implementation details

Introduction

The Better Navigation template uses some supporting php code. This has been placed in sidebar.php file in the sidebar directory. This file is automatically included in the main.php file in the same directory. The following sections describe the details for the php function.

Finding the master sidebar file

// recursive function to establish best sidebar file to be used
function getSidebarFN($ns, $file) {
 
  // check for wiki page = $ns:$file (or $file where no namespace)
  $nsFile = ($ns) ? "$ns:$file" : $file;
  if (file_exists(wikiFN($nsFile))) return wikiFN($nsFile);
 
  // remove deepest namespace level and call function recursively
 
  // no namespace left, exit with no file found	
  if (!$ns) return '';
 
  $i = strrpos($ns, ":");
  $ns = ($i) ? substr($ns, 0, $i) : false;	
  return getSidebarFN($ns, $file);
}

The getSidebarFN function is used to lookup the wiki page that contains the sidebar content. It is the page called sidebar in the current namespace, or in the namespace “closest” to the current one.

Generating the sidebar xhtml

/**
 * Returns xhtml for a virtual local sidebar file
 * based on instructions from a master file
 *
 * Uses and creates a cachefile
 *
 * @author Jan Decaluwe <jan@jandecaluwe.com>
 * by adapting the p_cached_xhtml function in dokuwiki
 *
 */
function p_sidebar_cached_xhtml($localFile, $masterFile){
  global $conf;
  $cache  = getCacheName($localFile.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.xhtml');
  $purge  = $conf['cachedir'].'/purgefile';
  // check if cache can be used
  $cachetime = @filemtime($cache); // 0 if not exists
 
  if( @file_exists($masterFile)                                       // does the source exist
      && $cachetime > @filemtime($masterFile)                         // cache is fresh
      && ((time() - $cachetime) < $conf['cachetime'])                 // and is cachefile young enough
      && !isset($_REQUEST['purge'])                                   // no purge param was set
      && ($cachetime > @filemtime($purge))                            // and newer than the purgefile
      && ($cachetime > @filemtime(DOKU_INC.'conf/dokuwiki.php'))      // newer than the config file
      && ($cachetime > @filemtime(DOKU_INC.'conf/local.php'))         // newer than the local config file
      && ($cachetime > @filemtime(DOKU_INC.'inc/parser/xhtml.php'))   // newer than the renderer
      && ($cachetime > @filemtime(DOKU_INC.'inc/parser/parser.php'))  // newer than the parser
      && ($cachetime > @filemtime(DOKU_INC.'inc/parser/handler.php')))// newer than the handler
  {
    //well then use the cache
    $parsed = io_readfile($cache);
    $parsed .= "\n<!-- cachefile $cache used -->\n";
  }else{
    $parsed = p_render('xhtml', p_cached_instructions($masterFile),$info); //try to use cached instructions
 
    if($info['cache']){
      io_saveFile($cache,$parsed); //save cachefile
      $parsed .= "\n<!-- no cachefile used, but created -->\n";
    }else{
      @unlink($cache); //try to delete cachefile
      $parsed .= "\n<!-- no cachefile used, caching forbidden -->\n";
    }
  }
 
  return $parsed;
}

The p_sidebar_cached_xhtml_sidebar function returns the xhtml for the sidebar. This function has a degree of sophistication that warrants further explanation. As can be seen, the xhtml is cached based on a “local” filename, but the instructions come from a “master” file. In this way, the same instructions from a master sidebar file can generate different xhtml versions for the local sidebars. As the xhtml generation is influenced by the current page $ID, this mechanism is used to accomplish one of my goals (see Navigation Issues), namely that a navigation link to the current page should be highlighted.

Note that the plain text version of the local sidebar file doesn't actually have to exist - it can be a virtual file with a well-chosen file name.

The top-level function

function html_sidebar() {
  global $ID;
  global $ACT;
 
  if ($ACT != 'show') return '';
 
  // determine master sidebar file
  $masterFile = getSidebarFN(getNS($ID), 'sidebar');
 
  // open sidebar <div>
  echo("<div id='sidebar'>");
 
  // determine what to display
  if ($masterFile) {
    // virtual hidden local sidebar filename
    $fn = wikiFN($ID.'_sidebar');
    $localFile = dirname($fn).'/_'.basename($fn);
    print p_sidebar_cached_xhtml($localFile, $masterFile);
  }
  else {
    html_index('.');
  }
 
  // close sidebar <div>
  echo("</div>");
}

The html_sidebar function is the top-level function that returns the xhtml for the sidebar. It is included at the right place in the main template file.

Note that the local sidebar file has a “hidden” name, which means that it cannot be accessed as a regular wiki page. Note also that the sidebar is only shown (and possibly created) when a page is viewed; not during edit, diff, search, etc. This is logical and prevents unnecessary local sidebar page creation, e.g. as the result of a search for an unknown page.

Style sheet details

The sidebar related styles are mostly put in a separate stylesheet called sidebar.css. The style sheet design.css from the default template is used unchanged. The layout.css style sheet has some minimal changes related to the tagline and the location of the logo and the page name.

In the sidebar.css stylesheet, the div for the page class is modified as follows:

/* the document */
div.dokuwiki div.page_with_sidebar {
  margin-top: 4px;
  margin-left:  0em;
  margin-right: 0em;
  padding-left: 1em;
  text-align: justify;
  width: 75%;
  float: left;
  border-left: 1px solid __border__;
}

Note that the layout is defined by floating. I would have preferred to indicate the left border of the page indirectly, by the background of the sidebar spanning the whole page length. However, this seems difficult to achieve with div based layout (as opposed to table-based layout). Therefore, I gave the page itself a left border line.

Secondly, the div for the sidebar id is added:

/* ---- Sidebar ---- */
div.dokuwiki div#sidebar {
  margin-top: 1em;
  margin-left:  0em;
  margin-right: -1px;
  border-right: 1px solid __border__;
  padding-top: 0.5em;
  padding-bottom: 0.7em;
  padding-left: 0em;
  float: left;
  background-color: __background_neu__;
  width: 20%;
  font-size: 80%;
}
 
 
div.dokuwiki div#sidebar ul {
  list-style-type: none;
  list-style-image: none;
  line-height: 1.2em;
  margin: 0;
  padding-top: 0.2em;
  padding-left: 1em;
  padding-bottom: 0.3em;
  /* padding: 0.2em 0 0.3em 1em; */ 
}
 
div.dokuwiki div#sidebar ul ul {
  padding-top: 0;
  padding-bottom: 0;
}
 
 
div.dokuwiki div#sidebar ul li {
  background: transparent url(images/tocdot2.gif) 0 0.6em no-repeat;
  padding-left:0.4em;
}
 
div.dokuwiki div#sidebar ul li.clear {
  background-image: none;
  padding-left:0.4em;
}
 
div.dokuwiki div#sidebar a {
  color: __extern__;
  text-decoration:none;
}
 
div.dokuwiki div#sidebar a:hover {
  color: __text__;
  text-decoration:underline; 
}
 
div.dokuwiki div#sidebar a.urlextern {
  background: transparent;
  padding: 0;  
  color: __extern__;
  text-decoration:none;
}
 
/* special headlines */
div.dokuwiki div#sidebar h1 {font-size: 100%; margin-left: 4px; margin-bottom: 0.5em; border-bottom: none;}

The sidebar uses the same background and font size as the breadcrumbs. This should help to indicate that it is part of the site navigation.

I see the content of the sidebar as a Table of Contents for the site. Therefore, the list items definitions are copied from those of the generated in-page Table of Contents.

Issues

  • As said before, I prefer a hierarchical Table of Contents-like list in the sidebar. On the other hand, you may want to use section headings. However, the current stylesheet doesn't contain any special code to style these appropriately.

Talk

Not sure where best to put comments as there is no forum so I'm putting them here. I agree with the better navigation goals. I've tried out the template. It seems to be missing the admin setup though. Where are the sidebar-left / sidebar-right and inside / outside options. A general comment on the DokuWiki style is that everything is pushed hard against the screen edges. Has anyone any good CSS fixes? Transistor 2007.05.06.

Please use the dokuwiki mailing list / newsgroup for discussions instead of this page, you'll get better help from much more people and template writers over there. As for your questions: The admin setup has nothing to do with a template but with access control. Also, there are more powerful sidebar templates than mine which may have the options you search for. — Jan Decaluwe 2007/05/06 18:26
navigation/sidebar_details.txt · Last modified: 2011/09/12 13:12 by jandecaluwe
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki