Dir Plugin

dir plugin by Jacobus Geluk
Show content of current namespace, including sub namespaces and/or parent/sibling namespaces, in a table or list.

Last updated on 2008-06-28. Provides Syntax.
Compatible with DokuWiki 2006-11-06.

Requires pagelist.
Similar to dirlisting.

Tagged with namespaces, pages.

The following security issue was reported for this plugin:

XSS vulnerability allows arbitrary JavaScript insertion. Author informed on 2009-06-16.

It is not recommended to use this plugin until this issue was fixed. Plugin authors should read the plugin security guidelines.

Description

The Dir plugin searches a specified directory / namespace and lists the found pages in a tabular form, like the pagelist plugin. The main difference with the pagelist plugin is that the pages to be listed do not have to be specified manually. It resembles the “archive>” tag in the blog plugin, but has some different options.

The produced table of pages can be sorted. Pages with certain tags can be selected or skipped (this only works if the tag plugin is installed).

If the discussion plugin is installed, the number of comments of a page can be shown in a column. If the tags plugin is installed, the tags of a page can be shown in a column.

The dir plugin has rudimentary support for the DokuTeXit plugin in the sense that it generates LaTeX output for that plugin.

Syntax Plugin

~~DIR[[:<namespace>][?<flags>]]~~
<namespace> Can be a list, separated with semicolons, of:
. The current namespace
.. The parent namespace
subnamespace The name of a sub namespace. Same as .:subnamespace
..:sibling The name of a sibling namespace
:: The root namespace
<flags> Can be any of the following, in any order:
cols A semicolon separated list of column names, see “Supported Column Names” below.
hdrs A semicolon separated list of column header names.
skip A semicolon separated list of namespaces or page names that should be skipped.
Namespaces must end with a colon.
tag A semicolon separated list of tags that each page should have.
Pages that do not have all these tags are skipped.
A tag with a ! put in front of it means that a page with such a tag is skipped.
sort A semicolon separated list of column names to be sorted, see “Supported Column Names” below.
Append -ascending (default) or -descending to each column name to get the desired effect. -a and -d work too.
widedesc Shows the description of each page in an additional full width row.
noheader Do not show a header.
table Use the table style (styling of the pagelist plugin is used)
list Use the list style (styling of the pagelist plugin is used)
nodefaulttitle When this flag (or ndt) is present, the titles shown in the page column will not be the default titles but the page name itself.
If you have one or more namespaces and some flags, do not forget to put the question mark between them!
Supported
Column Names
DescriptionSortable
page Link to the page
desc Description of the page (See also “widedesc”)
description ,,
user Full user names of the contributors
userid User id's of the contributors
date See mdate
mdate Modification date
cdate Creation date
comments Number of comments in the discussion section
tags The tags of the page

Examples

If you put in a line like this, you will simply get a listing of all pages in the current namespace and below:

~~DIR~~

You can also add some columns, by starting with a question mark, the specification of the namespace is skipped. The current namespace will be used:

~~DIR?cols=page;user~~

You can add your own column headers:

~~DIR?cols=page;user;comments&hdrs=Whatever;User;# Comments~~

To display a wide description of the page, below each page row, you can use the &widedesc option:

~~DIR?cols=page;user;comments&hdrs=Whatever;User;# Comments&widedesc~~

To skip a sub namespace named archive:

~~DIR?skip=archive~~

To select only pages that have the tag “important”:

~~DIR?tag=important~~

To skip pages that have the tag “concept”: (This currently only works when you also show the “tags” column, as in ~~DIR?cols=page;tags&tag=!concept~~) – jg

~~DIR?tag=!concept~~

To select pages that have the tag book and the tag ebook and not the tag fiction:

~~DIR?tag=book;ebook;!fiction~~

To sort the pages by userid with a descending creation date:

~~DIR?cols=page;user&sort=userid;cdate-d~~

To show the pages in a sub namespace called “x”:

~~DIR:.:x:~~

To show the pages in a sibling namespace:

~~DIR:..:y:~~

To show the pages in a sibling namespace with two columns, page title and user id:

~~DIR:..:y:?cols=page;user&hdrs=Page Title;User ID~~

Installation

Download the plugin-dir.tgz file in the lib/plugins directory and unzip it, it will put a file called syntax.php in the lib/plugins/dir directory. This plugin requires the pagelist plugin and will use the plugins discussion and tags if they are installed.

You can also use the plugin manager to download and install the plugin, use this URL:
http://www.skateboardmaniaks.nl/_media/plugin/plugin-dir.tgz

Discussion

I'm having a problem with the DIR plugin not inserting a </table> tag at the end of the table. On some pages it works and on others it doesn't. This is the syntax that generates the bad HTML: ~~DIR?table&cols=page;tags;mdate&sort=page~~ It's kind of annoying because with the ending table tag, all of the page contents after the directory listing is swallowed in the last cell of the table. I have temp fix: inserting <html></table></html> immediately after the above DIR text. — clint, 18.10.2008

Thanks for the work, the plugin works basically fine. Only the dates are always set at '01.01.1970' (following my date format string 'd.m.Y'). Any hints? — breg, 31.10.2007 17:28

The dates are taken from each page with the p_get_metadata function, which is a function of the DokuWiki itself. So the dir plugin does not produce these dates itself. — jg

Nice work, but what's the syntax for listing a subcategory?
For example what should I write to list all the subpages of A:B:* ?
~~DIR:A:B~~

That would have to be: — jg

~~DIR:.:A:B~~
I'm trying to use this plugin with version 2007-06-26b.
When I simply insert ~~DIR~~ it properly lists pages on my test install; however, when I try to use a more advanced function (such as ~~DIR:cols=page;user;mdate~~) it tells me “There are no documents to show.” Is there some kind of compatibility issue with 2007-06-26b?

Not that I know of. In the 2008-02-25 version of the plugin I changed the syntax a little bit, the namespace specification should start with a colon and the specification of any flags should start with a question mark. So, your statement should like like this: — jg

~~DIR?cols=page;user;mdate~~
Hello, i install, and work fine.. but, i need the names of pages without underline; example, pagetitle is hello_world,
but i want show “Hello world”. its possible?
Thanks for the plugin! I am trying to get pages sorted by title (first header, not file name) but I don't see a way to do that. Am I missing it? sort=page gives me filename order. Here is how I invoke it:
~~DIR?sort=page-a&hdrs=additional topics~~
Hi, the download archive seems to be broken (8b).
Hi
1: Shouldn't the start-pages be listed in the same level as all other pages in the namespace? In the current implementation, the start-page of a subnamespace is on the same level as all pages of the current namespace, whats kinda confusing.
2: Could the namespace-names be shown in the tree-view or as a column? I find it confusing to have a tree full of starts, if I have many start-pages.
3: I think there is an issue about security and ACL. Pages not accessible for the current user should not be listed (especially the description can contain confidential information).
4: Whats the syntax to get a list of all pages (=root namespace) independent of current namespace? Solved, its DIR::
5: where does desc come from? Seems to me it's the unformatted content of the page? Shouldn't it be the given revision description?
6: user and userid have valid content only if the specific page had been edited at least once (not only created)
Thanks for considering
Benny Wegner 2008/07/14 01:23
The archive file seems as corrupted, can you update the download link or upload the file again?
5:
change function _tableCellContent in syntax.php to see the page title in description
modify the line 964:$this→_put ($this→_getMeta ($page, “description”, “abstract”)) ;
to: $this→_put ($this→_getMeta ($page, “title”)) ;
Ralph Hahn 2009/01/01 09:33
Hi,
Just been trying out this plugin and noticed a bug/issue. When I filter by using the tag flag it only filters correctly if I actually have tags as a displayed column. If I don't have a tags column it ignores what tags I've asked it to filter on.
So this works: -
~~DIR:.:mynamespace:?cols=page;tags&hdrs=Service&tag=Service&table~~

> And this doesn't work: -

~~DIR:.:mynamespace:?cols=page&hdrs=Service&tag=Service&table~~

> — Anthony Yates 2009/01/13 17:36

I've now managed to fix this by changing some code in the plug-in. I found that it was only loading the tag plugin if you showed the column, it was not loading it if you just had the flag set. If you open syntax.php in the dir plugin folder and look for the function “function _initOpts”, should be on line 353. This is where it detects the flag switches. Change the code for the tag switch, starts on line 369, from this: -
case "tag":
        $val = split (';', trim ($val, ';')) ;
        break ;
To this: -
case "tag":
        $val = split (';', trim ($val, ';')) ;
        $this->_loadPlugin ("tag") ;
        break ;
This should then fix it. Not sure if this is the correct way, but it worked for me.
Anthony Yates 2009/02/02 16:27
Hi, I need multi column view & namespace only view
Hi, I just can't get tags to work… It lists all the pages and completely ignores the tag parameter (~~DIR?tag=2009~~ lists all pages, not only those with 2009 tag)… any suggestions? I have installed the tag plugin after dir plugin, but tag plugin itself is working fine…
I had the same problem see above. I've now managed to fix it.

Greetings. I have discovered the following bug… FIXME If a page is created with no edits yet, the user and userid columns do not return the creator (which it should since there is not a contributor array). The fix is shown in the following plugins/dir/syntax.php code snippet (needs to be added to the userid case as well)…

    case "user":
      $users = $this->_getMeta ($page, "contributor") ;
      if (is_array ($users)) {
        $index = 0 ;
        foreach ($users as $userid => $user) {
          if ($user && $user <> '') {
            if ($index++ > 0) {
              $this->_putNewLine () ;
            }
            $this->_put ($user) ;
          }
        }
      }
  else {$this->_put ($users) ;} //<===the missing statement!
      break ;

(I forgot to say thanks for a great plugin! –Scott Sampson)


After moving my Dokuwiki to another server, I had to remove it, because of fatal errors.
Bernd M. Radowicz 2009/03/08 13:25

Alternate Version

I have taken the liberty to extend the functionality of this plugin a little bit to make it more useful when used in a sidebar.

More specifically, I have:

  • Added two new flags: collapse and ego
  • Namespaces that are not accessible for the current user's ACL are removed from the listing.

Since the changes are fairly limited, I didn't want to make it into a separate plugin. I hope the author likes the extensions and integrates them in his original source.

Background

I am using DokuWiki with a sidebar template (the Better Navigation Template). Until now, I created sidebars for each namespace that would show me the pages in that namespace, together with links to higher level namespaces and their siblings. This gives the effect that all namespaces but one are collapsed. Clicking on another namespace would “expand” that namespace and “collapse” the one you are leaving. Maintaining this manually was tedious. So I started looking for automated alternatives. The DIR plugin came closest to my goal: it automatically generates a list of all pages in a namespace. Its limitation for me is that it really shows all pages and namespaces. In a large wiki, that would mean a very big table of contents in the sidebar. Or I would have to start again with creating separate sidebars for separate namespaces, thus kind of defeating my original goal.

So I have implemented an additional flag called “collapse”. When this flag is set, the generated list will only show pages in the current namespace, together with sibling namespaces on all the higher level namespaces.

With this additional flag, I can create only one top-level sidebar and my whole wiki has got the perfect navigation !

The second flag -ego- was added because the philosophy of the Better Navigation Template is that the navigation should indicate in a simple way where in the wiki the user is currently browsing. For this the Better Navigation Template sets the name of the current page in the sidebar in bold. However, the default dir plugin removes the current page from the dir listing, which is contrary to the navigation idea. The ego flag remedies this: when the ego flag is set, the current page will also be listed in the dir listing. As such the Better Navigation Template can highlight it.

Q Why not use the DokuWiki index as sidebar ? This is what the Better Navigation template uses by default. This does show a collapsible and expandable list of all pages in the wiki, but it has some disadvantages for me:

  • It doesn't keep track of where you are in the wiki. It will always show the same index, which you can navigate through. So it may show too much or too little information depending on where you are or where you want to go. I prefer to see the context of my current page (meaning more detail in the navigation close to the current page, and less detail further away in the navigation).
  • It shows namespace names as tree structure items. But namespaces don't have titles. Especially with the philosophy of the Better Navigation template, it makes sense that the navigation uses titles as these have more meaning to the readers than simply the page names. In contrast, the DIR plugin uses the index pages of namespaces (start by default) as tree structure items. Each start page can have a title, which makes for potentially better navigation.

Usage

Although it works on all kinds of pages, the collapse flag is really designed to be used on a sidebar.

  • Install a sidebar template (like Better Navigation Template))
  • Download and install my modified dir plugin: http://www.kobaltwit.be/plugin_dir_GeertJanssens.tgz. Alternatively, you could use the plugin manager to install this plugin. Simply use:
    http://www.kobaltwit.be/plugin_dir_GeertJanssens.tgz
  • Create a sidebar page in the root namespace
  • Enter this content:
    ====== Navigation ======
    
    [[:start]]
    
    ~~DIR::?noheader&skip=:playground:;:wiki:&list&collapse&ego~~
    
    [[mailto:some@email.addr]]

And there you go !

Comments

  • In addition to the collapse and ego flags, I have also added some code to hide namespaces that are not readable by the current user's ACL. In a setup where certain subnamespaces are readable for an unreadable namespace, these subnamespaces will be hidden from the navigation. It works quite well with the collapse flag, but I haven't tested this yet without this flag. It may cause unexpected behaviour.
  • Some things to note about my proposed sidebar content:
    • I set a title in the sidebar: this ensures that the link generated by the DIR syntax to the sidebar itself also has a nice title (Navigation), instead of having the pagename (sidebar) shown.
    • With the collapse flag, this link to the sidebar is only visible on pages in the root namespace.
    • Under the DIR entry in the sidebar, I have added another link (a mailto link in this case). I have done so because it seems there is a rendering bug in the DIR plugin when used with the “Better Navigation” template. If DIR is the last thing to render, the whole contents of the page ends up in the sidebar. Adding something else to render (a link, an numbered list item, a copyright statement, …) this bug doesn't seem to pop up.

Diff file

These are the changes I made (compared to version 0.5 from 2008-06-26):

--- dir-org/syntax.php  2008-06-28 20:04:55.000000000 +0200
+++ dir/syntax.php      2008-11-04 10:34:38.000000000 +0100
@@ -289,16 +289,20 @@
    * Get the namespace of the parent directory
    * (always prefixed and postfixed with a colon, root is ':')
    */
-  function _getParentNS () {
+  function _getParentNS ($id) {

-    global $ID ;
+    // global $ID ;

-    $curNS = getNS ($ID) ;
+    $curNS = getNS ($id) ;

     if ($curNS == '')
       return ':' ;

-    return ':' . $curNS . ':' ;
+    if (substr ($curNS, 0, 1) != ':') {
+      $curNS = ':' . $curNS;
+    }
+
+    return $curNS . ':' ;
   }

   /**
@@ -314,9 +318,9 @@
     if (substr ($ns, 0, 2) == '.:') {
       $ns = ':' . getNS ($ID) . substr ($ns, 1) ;
     } elseif (substr ($ns, 0, 3) == '..:') {
-      $ns = $this->_getParentNS () . substr ($ns, 3) ;
+      $ns = $this->_getParentNS ($ID) . substr ($ns, 3) ;
     } elseif ($ns == '..') {
-      $ns = $this->_getParentNS () ;
+      $ns = $this->_getParentNS ($ID) ;
     } elseif (substr ($ns, 0, 1) == ':') {
     } elseif ($ns == '.' || $ns == '*') {
       $ns = ':' . getNS ($ID) ;
@@ -354,6 +358,8 @@

     $this->opts = array () ;
     $this->opts ["noheader"] = false ;
+    $this->opts ["collapse"] = false ;
+    $this->opts ["ego"] = false ;

     $flags = split ('\&', $flags) ;

@@ -361,12 +367,14 @@
       $tmp = split ("=", $par) ;
       $key = $tmp [0] ;
       $val = $tmp [1] ;
      case "skip":y) {
+      switch ($key) {
+      case "skip":
       case "cols":
       case "hdrs":
       case "sort":
       case "tag":
        break ; split (';', trim ($val, ';')) ;
+        $val = split (';', trim ($val, ';')) ;
+        break ;
       case "noheader":
       case "nohead":
       case "nohdr":
@@ -378,6 +386,14 @@
         $key = "noheader" ;
         $val = false ;
         break ;
+      case "collapse":
+        $key = "collapse" ;
+        $val = true ;
+        break ;
+      case "ego":
+        $key = "ego" ;
+        $val = true ;
+        break ;
       case "nodefaulttitle":
       case "ndt":
         $key = "nodefaulttitle" ;
@@ -394,7 +410,8 @@
         $this->style = "list" ;
         break ;
       case "debug":
      }  $this->debug = true ;
+        $this->debug = true ;
+      }
       $this->opts [$key] = $val;
     }
   }
@@ -579,7 +596,7 @@
     //
     switch ($type) {
     case "f":
-      if ($fqid == ':' . $ID) // If we found ourself, skip it
+      if (($fqid == ':' . $ID) && ! $this->opts ["ego"]) // If we found ourself, skip it
         return false ;
       $pageName = noNS ($id) ;
       if ($pageName == $this->start)
@@ -596,6 +613,13 @@
           }
         }
       }
+      if ( $this->opts ["collapse"] ) {
+        // With collapse, only show:
+        // - pages within the same namespace as the current page
+        if ( $this->_getParentNS($fqid) != $this->_getParentNS($ID) ) {
+          return false ;
+        }
+      }
       $linkid = $fqid ;
       break ;
     case "d":
@@ -606,7 +630,37 @@
           return false ;
         }
       }
+      if ( $this->opts ["collapse"] ) {
+        // With collapse, only show:
+        // - sibling namespaces of the current namespace and it's ancestors
+        $curPathSplit = split (":", trim (getNS($ID), ":")) ;
+        $fqidPathSplit = split (":", trim (getNS($fqid), ":")) ;
+
+        // Find the last parent namespace that matches
+        // If there is only one more child namespace in the namespace under evaluation,
+        // Then this is a sibling of one of the parent namespaces of the current page.
+        // Siblings are ok, grandchild namespaces and below should be skipped (for collapse).
+        $clevel = 0 ;
+        if (count ($curPathSplit) > 0) {
+          while (($clevel < count($fqidPathSplit) - 1) && ($clevel < count($curPathSplit))) {
+            if ($curPathSplit[$clevel] == $fqidPathSplit[$clevel]) {
+              $clevel++ ;
+            } else {
+              break ;
+            }
+          }
+        }
+        if (count($fqidPathSplit) > $clevel + 1) {
+          return false;
+        }
+      }
+
       $linkid = $fqid . $this->start ;
+
+      // Don't add startpages the user isn't authorized to read
+      if (auth_quickaclcheck (substr($linkid,1)) < AUTH_READ)
+        return false ;
+
       break ;
     }

Any suggestions, comments, questions: — Geert Janssens 2008/11/04 10:44

Bug

There is an ACL bug with this plugin. When you call Dir plugin with relative path, the page, should be able to be seen, is hidden. It comes from auth_quickaclcheck function with relative path. That function checks the path as absolute path.

I make a patch for that, but it's dirty fixing. Please anyone fix it properly.

Daichi Kitagawa 2008/11/17 2:33

Situation with the bug

For example, the pages are:

  • namespaceA
    • pageA
    • namespaceB
      • pageB

the acls are:

  • * @ALL none
  • namespaceA:* @ALL Read

and you write this in pageA

~~DIR~~

Although all user has permission to read pageB, ACL check function compares the acls with string 'namespaceB:pageB', and it returns 'none'. So Dir plugin doesn't list pageB.

In this situation, the plugin have to call the function with 'namespaceA:namespaceB:pageB'. In addition, the string ':namespaceA:namespaceB:pageB' is not collect too.

Diff

--- syntax.php.org      2008-06-29 03:04:55.000000000 +0900
+++ syntax.php          2008-11-17 01:20:22.000000000 +0900
@@ -640,7 +640,7 @@
         return false ;
       //check ACL
       $id = pathID ($file) ;
-      if (auth_quickaclcheck ($id) < AUTH_READ)
+      if (auth_quickaclcheck (substr($ns.$id,1,-1)) < AUTH_READ)
         return false ;
       $this->_addFoundPage ($data, $ns, $id, $type, $level) ;
     }
 
plugin/dir.txt · Last modified: 2009/06/16 13:59 by 193.9.13.142
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Imprint Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki
WikiForumIRCBugsDarcsXRefTranslate