====== Lists Syntax PlugIn ======
---- plugin ----
description: (X)HTML style un/ordered lists.
author : Matthias Watermann
email : support@mwat.de
type : syntax
lastupdate : 2008-03-28
compatible : 2005-07-13+
depends :
conflicts :
similar : mllist, yalist
tags : list
----
While DokuWiki's current implementation of [[http://www.w3.org/TR/html401/struct/lists.html#h-10.2|un/ordered lists]] satisfies the need for basic list markup, it does //not// allow for embedding several block elements((such as paragraphs, tables or other (nested) lists etc.)) in a list item.
Depending on the structure of a certain document this may be just enough.
Sometimes, however, there is actually a need for nesting other block elements in a list item.
And that's where this [[#Plugin Source|plugin]] enters the game:
It provides the ability to wrap other block elements((inline markup, of course, is possible as usual)) in a list item.
:!: **Note**: This [[#Plugin Source|plugin]] functionally **replaces** (and enhances) DokuWiki's builtin handling of un/ordered lists.
Both list markup styles // must not // be mixed in a document((otherwise unexpected results will occur which are likely to render the page's markup invalid)).
If you won't ever need un/ordered lists with nested block elements // do not install // this plugin.
===== Usage =====
The markup implemented by this [[#plugin_source|plugin]] is very similar to
DokuWiki's builtin syntax: first unordered list item second unordered list item third unordered list item first ordered list item second ordered list item third ordered list item first one-liner item first paragraph of second item. Second paragraph of second item. Third paragraph of second item. A two-liner item one item two item three item four item one item two no.1 of item two no.2 of item two first of item two's no.2 second of item two's no.2 item one item two no.1 of item two no.2 of item two first of ? second of ? item one item two no.1 of item two no.2 of item two first of ? second of ?
* Usage:
* The returned array holds the following fields:
*
* This method is important for correct XHTML nesting. It returns
* one of the following values:
*
* The $aState parameter gives the type of pattern
* which triggered the call to this method:
*
* The method checks for the given $aFormat and returns
* FALSE when a format isn't supported. $aRenderer
* contains a reference to the renderer object which is currently
* handling the rendering. The contents of $aData is the
* return value of the handle() method.
* \s*$|i', $aRenderer->doc, $hits)) {
$hits = -strlen($hits[0]);
$aRenderer->doc = substr($aRenderer->doc, 0, $hits)
. '<' . $LISTS[$aData[1]] . '>';
} else {
$aRenderer->doc .= ' \s*$|',
$aRenderer->doc, $hits)) {
// replace rudimentary LI
$hits = -strlen($hits[0]);
$aRenderer->doc = substr($aRenderer->doc, 0, $hits)
. '
* first unordered list item <
* second unordered list item <
* third unordered list item <
- first ordered list item <
- second ordered list item <
- third ordered list item <
Note the ''%%<%%''((''less_than'', ASCII char #60)) character marking the end of each list item((This additional ''less_than'' character makes the difference compared to DokuWiki's builtin syntax where the very first ''linefeed'' character marks the end of the list item.));
optional ''whitespace''((''Whitespace'': any of the ''space'' (ASCII #32), ''formfeed'' (ASCII #12), ''newline'' (ASCII #10), ''carriage return'' (ASCII #13), ''horizontal tab'' (ASCII #9) characters)) before the ''less_than'' character is silently ignored.
The //end of a list// is marked up by an additional newline;
in other words: The very last item of a list (i.e. its terminating ''less_than'' character) is followed by //two// consecutive ''linefeeds''((''linefeed'' (''newline''), ASCII char #10)).
Each list item's //first// line((In contrast to DokuWiki's builtin list markup this [[#plugin_source|plugin]] //does// allow a list item to span several lines in a wiki document.)) must be indented by at least two spaces((''space'', ASCII char #32; not to be confused with ''blanks'', ASCII char #255)) or a TAB((''tabulator'', ASCII char #9)) (one ''TAB'' is worth two ''spaces'' et vice versa) followed by either a ''%%*%%'' (''asterisk''((''asterisk'', ASCII char #42))) for items of an //unordered// list or a ''%%-%%'' (''hyphen''((''hyphen'' (minus sign), ASCII char #45))) for items of an //ordered// list.
The text between the list type indicator (''asterisk'' or ''hyphen'') and the ''less_than'' character is used as the list item's //contents//.
The contents of a list item can contain anything including other lists (of the same or a different kind), several paragraphs, tables, code blocks etc. (see the examples [[#Examples|below]]).
When using ''linefeeds'' in list items the second and all following lines must not be indented because that would cause DokuWiki's builtin //preformatted/code// parser/renderer to markup those lines as ''preformatted code'' blocks --- but, of course, that can be exactly the intention of the indentation...
==== Examples ====
The simplest form of un/ordered list's markup is already shown [[#Usage|above]].
The resulting HTML would look like this:
=== Item with several paragraphs ===
Supposing we need more than just one (possibly huge) paragraph in an item's contents the wiki markup could look like this:
* first one-liner item <
* first paragraph of second item.
Second paragraph
of second item.
Third paragraph
of second item. <
* A two-liner\\ list item <
As usual an empty line marks the start of a new paragraph.
The resulting HTML would be as follows:
The empty lines in the HTML output are //not// caused by this [[#plugin_source|plugin]] but by DokuWiki's builtin paragraph handling.
=== Mixing list types ===
The [[#plugin_source|plugin]] allows for easily changing the list type (un/ordered) within a list. Consider the following example:
list item
* item one <
- item two <
* item three <
- item four <
Can you imagine the resulting HTML code? Well, here it comes:
Surprised? --- No? --- OK. ---
While this example doesn't really make sense, it at least demonstrates the ease of list handling provided by this [[#Plugin Source|plugin]].
The automatic list type handling actually comes in handy with the next example.
=== Nesting lists ===
What about a list of lists?
That's easily marked up by indenting the nested list items by two more spaces((or one TABulator character)).
Here, for instance, we'll get a three levels deep list:
* item one <
* item two
- no.1 of item two<
- no.2 of item two
* first of item two's no.2<
* second of item two's no.2<
<
<
Note the two ''less_than'' characters at the end:
the first one terminates the ''//no.2 of item two//'' (which contains a nested unordered list) and the second closes the ''//item two//'' (containing an ordered list with an embedded unordered list). ---
There can be, of course, additional text before those lonely ''less_than'' characters (which would end up as trailing paragraphs).
Please //note//, however, that such text //must not// start with markup((e.g. **strong**, //emphasized// or __underlined__ or block elements like e.g. tables));
in case you need markup here, just place a ''space''((and, as with elements which need to begin on a newline (like tables) an additional ''linefeed'' character)) at the line's start to make it work correctly((This is because without lookahead for the following markup to come (which is not possible with DokuWiki's current parser) there's no way to automatically figure out what such a text is supposed to "mean", formally speaking, and unexpected/unintended paragraphs will be inserted, or inline markup ends up without a context.)).
The resulting HTML markup:
Now consider the //almost// identical markup:
* item one <
* item two
- no.1 of item two<
- no.2 of item two<
* first of ?<
* second of ?<
<
Here ''//no.2 of item two//'' is closed before the ''//first of ?//'' item is added.
In consequence the following unordered list cannot be a "child" of the latter but gets embedded in a new (automatically created) list item which contains nothing else apart from the "child list".
It results in this HTML code:
A third (slightly different) variant would be this:
* item one <
* item two <
- no.1 of item two<
- no.2 of item two<
* first of ?<
* second of ?<
Here each list item is closed before another one is opened.
This means that both nested lists are embedded in, say, "anonymous" list items.
The HTML code here:
===== Installation =====
It's quite easy to integrate this plugin with your DokuWiki:
- Download the [[http://dev.mwat.de/dw/syntax_plugin_lists.zip|source archive]] (~5KB) and unpack it in your DokuWiki plugin directory ''{dokuwiki}/lib/plugins'' (make sure, included subdirectories are unpacked correctly); this will create the directory ''{dokuwiki}/lib/plugins/lists''.
- Make sure both the new directory and the files therein are readable by the web-server e.g.
chown apache:apache dokuwiki/lib/plugins/* -Rc
You might as well use the [[http://www.dokuwiki.org/plugin:plugin_manager|plugin manager]] for installing or updating this plugin.
===== Plugin Source =====
Here comes the [[http://www.gnu.org/licenses/gpl.html|GPLed]] PHP source((The comments within the [[#Plugin Source|source]] file are suitable for the OSS [[http://www.stack.nl/~dimitri/doxygen/index.html|doxygen]] tool, a documentation system for C++, C, Java, Objective-C, Python, IDL and to some extent PHP, C#, and D. ---
Since I'm working with different programming languages it's a great ease to have one tool that handles the docs for all of them.)) for those who'd like to scan it before actually installing it:
syntax_plugin_lists.php - A PHP4 class that implements
* a DokuWiki plugin for un/ordered lists block
* elements.
*
*
* * unordered item <
* - ordered item <
*
* Copyright (C) 2005, 2007 DFG/M.Watermann, D-10247 Berlin, FRG
* All rights reserved
* EMail : <support@mwat.de>
*
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*
* @return Array Information about this plugin class.
* @public
* @static
*/
function getInfo() {
return array(
'author' => 'Matthias Watermann',
'email' => 'support@mwat.de',
'date' => '2007-08-15',
'name' => 'List Syntax Plugin',
'desc' => 'Add HTML Style Un/Ordered Lists',
'url' => 'http://www.dokuwiki.org/plugin:lists');
} // getInfo()
/**
* Define how this plugin is handled regarding paragraphs.
*
*
*
* @return String 'normal' .
* @public
* @static
*/
function getPType() {
return 'normal';
} // getPType()
/**
* Where to sort in?
*
* @return Integer 8, an arbitrary value smaller
* Doku_Parser_Mode_listblock (10).
* @public
* @static
*/
function getSort() {
// class 'Doku_Parser_Mode_preformated' returns 20
// class 'Doku_Parser_Mode_listblock' returns 10
return 8;
} // getSort()
/**
* Get the type of syntax this plugin defines.
*
* @return String 'container'.
* @public
* @static
*/
function getType() {
return 'container';
} // getType()
/**
* Handler to prepare matched data for the rendering process.
*
*
*
* @param $aMatch String The text matched by the patterns.
* @param $aState Integer The lexer state for the match.
* @param $aPos Integer The character position of the matched text.
* @param $aHandler Object Reference to the Doku_Handler object.
* @return Array Index [0] holds the current
* $aState, index [1] the match prepared for
* the render() method.
* @public
* @see render()
* @static
*/
function handle($aMatch, $aState, $aPos, &$aHandler) {
static $CHARS; static $ENTS;
if (! is_array($CHARS)) {
$CHARS = array('&','<', '>');
} // if
if (! is_array($ENTS)) {
$ENTS = array('&', '<', '>');
} // if
switch ($aState) {
case DOKU_LEXER_ENTER:
// fall through
case DOKU_LEXER_MATCHED:
$hits = array();
if (preg_match('|\n*((\s*)(.))|', $aMatch, $hits)) {
return array($aState, $hits[3],
strlen(str_replace(' ', "\t", $hits[2])));
} // if
return array($aState, $aMatch);
case DOKU_LEXER_UNMATCHED:
$hits = array();
if (preg_match('|^\s*\x3C$|', $aMatch, $hits)) {
return array(DOKU_LEXER_UNMATCHED, '', +1);
} // if
if (preg_match('|(.*?)\s+\x3C$|s', $aMatch, $hits)) {
return array(DOKU_LEXER_UNMATCHED,
str_replace($CHARS, $ENTS,
str_replace('\<', '<', $hits[1])), +1);
} // if
if (preg_match('|(.*[^\x5C])\x3C$|s', $aMatch, $hits)) {
return array(DOKU_LEXER_UNMATCHED,
str_replace($CHARS, $ENTS,
str_replace('\<', '<', $hits[1])), +1);
} // if
return array(DOKU_LEXER_UNMATCHED,
str_replace($CHARS, $ENTS,
str_replace('\<', '<', $aMatch)), -1);
case DOKU_LEXER_EXIT:
// end of list
default:
return array($aState);
} // switch
} // handle()
/**
* Add exit pattern to lexer.
*
* @public
*/
function postConnect() {
// make sure the RegEx 'eats' only _one_ LF:
$this->Lexer->addExitPattern('(?<=\x3C)\n(?=\n)', PLUGIN_LISTS);
} // postConnect()
/**
* Handle the actual output creation.
*
*
'; $INLI[$LEVEL] = 1; // closing P needed return TRUE; case DOKU_LEXER_UNMATCHED: // $aData[0] :: match state // $aData[1] :: text // $aData[2] :: +1(EoT), -1(start/inbetween) if (0 < $aData[2]) { // last part of item's text if (strlen($aData[1])) { if (isset($INLI[$LEVEL])) { $aRenderer->doc .= (0 < $INLI[$LEVEL]) // LI P ? $aData[1] . '
' . $aData[1] . '
'; } else { // no LI if (1 < $LEVEL) { // assume a trailing LI text --$LEVEL; $aRenderer->doc .= '' . $LISTS[$CURRENT[$LEVEL + 1]] . '>' . $aData[1] . '
'; } else { //XXX: There must be no data w/o context; the markup is broken. Whatever we // could do it would be WRONG (and break XHMTL validity); hence comment: $aRenderer->doc .= ''; } // if } // if } else { // empty data $hits = array(); if (preg_match('|\s*\s*$|', $aRenderer->doc, $hits)) { $hits = -strlen($hits[0]); // remove empty list item $aRenderer->doc = substr($aRenderer->doc, 0, $hits); } else if (preg_match('|\s*
\s*$|', $aRenderer->doc, $hits)) { $hits = -strlen($hits[0]); $aRenderer->doc = substr($aRenderer->doc, 0, $hits) . '
' . $aData[1]; } // if } else { // data w/o context if (1 < $LEVEL) { // assume a trailing LI text --$LEVEL; $aRenderer->doc .= '' . $LISTS[$CURRENT[$LEVEL + 1]] . '>
' . $aData[1]; $INLI[$LEVEL] = 1; } else { $aRenderer->doc .= $aData[1]; } // if } // if } // if return TRUE; case DOKU_LEXER_EXIT: while (1 < $LEVEL) { --$LEVEL; $aRenderer->doc .= ''. $LISTS[$CURRENT[$LEVEL + 1]] .'>'; if (isset($INLI[$LEVEL])) { $aRenderer->doc .= (0 < $INLI[$LEVEL]) ? '
' : ''; } // if } // while // Since we have to use PType 'normal' we must open // a new paragraph for the following text $aRenderer->doc = preg_replace('|\s*\s*
\s*|', '', $aRenderer->doc) . ''. $LISTS[$CURRENT[$LEVEL]] .'>';
$CURRENT = $INLI = array();
$LEVEL = 1;
default:
return TRUE;
} // switch
} // render()
//@}
} // class syntax_plugin_lists
} // if
//Setup VIM: ex: et ts=2 enc=utf-8 :
?>
==== Presentation ====
The accompanying CSS presentation rules:
ol,ul,div.dokuwiki ol,div.dokuwiki ul{list-style-position:outside;list-style-image:none;margin:0 0 0.6ex 0;padding:0 0 0 1ex;background:#fff;color:#000;text-align:left;line-height:1.4;}
ol li,ul li{padding:0;}
ol li{margin:0 0 0 3.5ex;}
ul li{margin:0 0 0 2ex;}
ol li div,ul li div,ol li p,ul li p{margin:0;padding:0;font-weight:normal;}
ul{list-style-type:disc;}
ul ul{list-style-type:square;}
ol{list-style-type:decimal;}
ol ol{list-style-type:upper-roman;}
ol ol ol{list-style-type:lower-alpha;}
ol ol ol ol{list-style-type:lower-greek;}
ol li div.li,ul li div.li{display:inline;}
Of course, you're free to modify this styles((The [[http://dev.mwat.de/dw/syntax_plugin_lists.zip|source archive]] contains a commented and indented stylesheet for your information.)) to suit your personal needs or aesthetics((Just be careful when modifying a CSS file: both the order and the selector groupings are important for CSS to work as intended/expected.)).
==== Changes ====
__2008-03-28__:\\
* minor CSS changes;
__2007-08-15__:\\
* added GPL link and fixed some doc problems;
__2007-01-05__:\\
* moved entity replacements from 'render()' to 'handle()';\\
* modified 'render()' to avoid useless whitespace;
__2005-09-03__:\\
+ first public release
//[[support@mwat.de|Matthias Watermann]] 2008-03-28//
===== See also =====
==== Plugins by the same author ====
* [[bomfix|BOMfix Plugin]] -- ignore Byte-Order-Mark characters in your pages
* [[code2|Code Syntax Plugin]] -- use syntax highlighting of code fragments in your pages
* [[deflist|Definition List Syntax Plugin]] -- use the only complete definition lists in your pages
* [[diff|Diff Syntax Plugin]] -- use highlighting of diff files (aka "patches") in your pages((obsoleted by incorporating its ability into the [[code2|Code]] plugin))
* [[hr|HR Syntax Plugin]] -- use horizontal rules in nested block elements of your pages
* [[lang|LANGuage Syntax Plugin]] -- markup different languages in your pages
* [[lists|Lists Syntax Plugin]] -- use the only complete un-/ordered lists in your pages
* [[nbsp|NBSP Syntax Plugin]] -- use Non-Breakable-Spaces in your pages
* [[nstoc|NsToC Syntax Plugin]] -- use automatically generated namespace indices
* [[shy|Shy Syntax Plugin]] -- use soft hyphens in your pages
* [[tip|Tip Syntax Plugin]] -- add hint areas to your pages
===== Discussion =====
Hints, comments, suggestions ...
To be compatible with default css style, a
blahblahblah
> Thanks for your note, but I consider that additional ''DIV'' pointless (and a waste of memory and bandwidth btw). It's not needed at all for CSS as one can always use ''li'', ''ol li'' or ''ol li.level1'' to select the item wanted. So I intentionally left that superflous markup away.\\ //--- [[support@mwat.de|Matthias Watermann]] 2005-09-13//
>> Just a note. The div is there with an intention. This is the only way to style the number of a list item different than the item itself. The li gets a blue colour and for the div it is set back to black again. --- //[[andi@splitbrain.org|Andreas Gohr]] 2005-09-13 19:22//
>>> While that looks like an interesting effect I don't think that it's worth the ''DIV'' since it blows up the document's structure w/o any real benefit. A CSS compliant way for colouring your list numbers would be something like this:\\ '' %% ol li.level1 { color: #009; }%%''\\ '' %% ol li.level2 { color: #090; }%%''\\ '' %% ol li.level3 { color: #900; }%%''\\ '' %% ol li > * { color: #000; }%%''\\ You could even ommit the child-selector ''%%>%%'' to support outdated browsers not supporting CSS2 (like M$IE) and still get the //visual// effect you want w/o any additional HTML markup.\\ //--- [[support@mwat.de|Matthias Watermann]] 2005-09-14 07:40//
>>>> Ok, as I use my own template, a CSS modification seems better than an additional HTML markup. Thanks. --- //[[samuel.degrande@lifl.fr|Samuel Degrande]] 2005-09-14 11:26//
>>>>> I'm using IE6 and you definitely need the extra div tag in my version. I have hacked it to work but I thought I would raise the point - very useful plugin by the way. Dav Bacci 26th Jan 2006
It would be nice if the plugin provided a way to specify the starting point of ordered lists (e.g. start a list with 3.). I realize that the start attribute is deprecated, but I believe there is a way to do this in CSS. \\ --- //[[joe+dokuwiki@nahmias.net|Joe Nahmias]] 2006-07-18 11:40//
The lists plugin is definitely useful, especially when working with multi-paragraph list items or those with a mixture of text and graphics. I'd like to second the request to fix the div tag - without it unordered list text displays as regular blue and ordered list text displays as bold blue.
\\ --- //[[esisler@westminster.lib.co.us|Eric Sisler]] 2006-11-17 18:41//
> Colouring is a matter of CSS, //not// (X)HTML (see the discussion/example above). -- Besides, are you sure that using different colours for the list item marker and its content does enhance your readers understanding? Personally I'd consider such fancy games just distractive -- but, of course, it's a matter of habit.\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-01-18 13:05//
Neat idea for a plugin, but I don't like it since it breaks existing wiki syntax. Have you thought about just having a special tag for list items which need to contain other items?
* List item 1
* List item 2
*> list item 3 with nesting
Nested paragraph.
>
* List item 4
>I'm not sure what you mean with "breaks existing wiki syntax".\\ (1.) As noted above the whole point of this plugin was to provide a wiki markup that resembles the whole power of (X)HTML lists. Compared with DokuWiki's basic list markup of course such an approach must use a markup that differs from the builtin one.\\ (2.) Even after installing this plugin you can still use the "old" markup style because the plugin's RegEx won't match that builtin list markup.\\ (3.) Although strongly deprecated((after all, one should stick to one style of markup unless you like to bewilder your users)) under some conditions it's even possible to use both markup styles in a single page((if the "extended" list is placed before the "basic" one)).\\ --- //[[support@mwat.de|Matthias Watermann]] 2007-07-16 12:35//
Thank you for a nice plugin. I have a question and a remark:
* Is there a way to reduce spacing between items to the same as in the basic lists? I changed "line-height:1.4" in plugin's style.css to "line-height:1.5em" (as in dokuwiki's default.css), but it didn't help -- items are still too widely spaced.
* I no expert at all in CSS or the blocks use bold text now (inherit from item number, I guess)
> Try installing the [[code2|Code Syntax Plugin]]: It comes with its own CSS file which you could modify in case the colouring doesn't match your taste.\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/03/28 12:49//
To get these things back I (again not an expert in CSS) had to modify style.css (add color:__text__;) as well as dokuwiki's default.css (add font-weight: normal; line-height: 1.2; to div.dokuwiki pre). Modifying default.css just to get back the default behavior does not seem right, and I am not sure I took care of all possible cases (i.e. may be other elements are affected as well?). Is there another way?
> The ''line-height'' setting of DokuWiki's default CSS is just wrong (i.e. too small): It doesn't take into account that (a) there are characters with ascenders/descenders and (b) the footnote links are placed above the standard character's topline. That results in a broken layout((the visual effect of which is increased if your browser has to make the font-size bigger to make the pages legible since DokuWiki's default setting is far too small for modern high-resolution displays)). So instead of trying to reproduce the errors of DokuWiki's default CSS with all plugins one should correct or replace the default CSS. If you care for your readers you should never use a ''line-height'' setting smaller ''1.3'' (but possibly greater) and [[http://meyerweb.com/eric/thoughts/2006/02/08/unitless-line-heights/|never use a unit]] qualifier (such as ''em'', ''ex'' etc.).\\ --- //[[support@mwat.de|Matthias Watermann]] 2008/03/28 12:33//
\\