Text_Wiki
[ class tree: Text_Wiki ] [ index: Text_Wiki ] [ all elements ]

Source for file List.php

Documentation is available at List.php

  1. <?php
  2.  
  3. /**
  4.  *
  5.  * Parses for bulleted and numbered lists.
  6.  *
  7.  * This class implements a Text_Wiki_Parse to find source text marked as
  8.  * a bulleted or numbered list.  In short, if a line starts with '*' then
  9.  * it is a bullet list item; if a line starts with '#' then it is a
  10.  * number list item.  Multiple * or # indicate an indented sub-list.
  11.  * The list items must be on sequential lines, and are ended by blank lines.
  12.  * Using a non-* non-# character at the beginning of a line ends the list.
  13.  * Note that single newline characters may be eaten beforehand by other rules.
  14.  *
  15.  * @category Text
  16.  *
  17.  * @package Text_Wiki
  18.  *
  19.  * @author Justin Patrin <papercrane@reversefold.com>
  20.  * @author Paul M. Jones <pmjones@php.net>
  21.  * @author Michele Tomaiuolo <tomamic@yahoo.it>
  22.  *
  23.  * @license LGPL
  24.  *
  25.  * @version $Id: List.php 240550 2007-08-01 07:57:34Z mic $
  26.  *
  27.  */
  28.  
  29. class Text_Wiki_Parse_List extends Text_Wiki_Parse {
  30.  
  31.  
  32.     /**
  33.      *
  34.      * The regular expression used to parse the source text and find
  35.      * matches conforming to this rule.  Used by the parse() method.
  36.      *
  37.      * @access public
  38.      *
  39.      * @var string 
  40.      *
  41.      * @see parse()
  42.      *
  43.      */
  44.  
  45.     var $regex = '/\n((\*[^\#\-\*]|\-[^\-\d\*\#]|\#[^\#\-\*]).*?)\n(?![\*\-#])/s';
  46.  
  47.     /**
  48.      *
  49.      * Generates a replacement for the matched text.  Token options are:
  50.      *
  51.      * 'type' =>
  52.      *     'bullet_start' : the start of a bullet list
  53.      *     'bullet_end'   : the end of a bullet list
  54.      *     'number_start' : the start of a number list
  55.      *     'number_end'   : the end of a number list
  56.      *     'item_start'   : the start of item text (bullet or number)
  57.      *     'item_end'     : the end of item text (bullet or number)
  58.      *     'unknown'      : unknown type of list or item
  59.      *
  60.      * 'level' => the indent level (0 for the first level, 1 for the
  61.      * second, etc)
  62.      *
  63.      * 'count' => the list item number at this level. not needed for
  64.      * xhtml, but very useful for PDF and RTF.
  65.      *
  66.      * @access public
  67.      *
  68.      * @param array &$matches The array of matches from parse().
  69.      *
  70.      * @return series of text and delimited tokens marking the different
  71.      *  list text and list elements.
  72.      *
  73.      */
  74.  
  75.     function process(&$matches)
  76.     {
  77.         // the replacement text we will return
  78.         $return '';
  79.  
  80.         // the list of post-processing matches
  81.         $list = array();
  82.  
  83.         // a stack of list-start and list-end types; we keep this
  84.         // so that we know what kind of list we're working with
  85.         // (bullet or number) and what indent level we're at.
  86.         $stack = array();
  87.  
  88.         // the item count is the number of list items for any
  89.         // given list-type on the stack
  90.         $itemcount = array();
  91.  
  92.         // have we processed the very first list item?
  93.         $pastFirst = false;
  94.  
  95.         // populate $list with this set of matches. $matches[1] is the
  96.         // text matched as a list set by parse().
  97.         preg_match_all(
  98.             '/^((\*|\-|#)+) *(.*?)$/ms',
  99.             $matches[1],
  100.             $list,
  101.             PREG_SET_ORDER
  102.         );
  103.         
  104.         if (count($list=== 1 && $matches[0][0=== '*' && $matches[0][1!== ' ' && strpos($matches[0]'*'1)) {
  105.             return $matches[0];
  106.         }
  107.  
  108.         // loop through each list-item element.
  109.         foreach ($list as $key => $val{
  110.             // $val[0] is the full matched list-item line
  111.             // $val[1] is the level (number)
  112.             // $val[2] is the type (* or #)
  113.             // $val[3] is the list item text
  114.  
  115.             // how many levels are we indented? (1 means the "root"
  116.             // list level, no indenting.)
  117.             $stars $val[1];
  118.             $level strlen($stars);
  119.             $last $stars[strlen($stars- 1];
  120.  
  121.             // get the list item type
  122.             if ($last == '*' || $last == '-'{
  123.                 $type 'bullet';
  124.             elseif ($last == '#'{
  125.                 $type 'number';
  126.             else {
  127.                 $type 'unknown';
  128.             }
  129.  
  130.             // get the text of the list item
  131.             $text $val[3];
  132.  
  133.             // remove a level from the list?
  134.             while (count($stack$level || (count($stack== $level && $type != $stack[$level - 1])) {
  135.  
  136.                 // so we don't keep counting the stack, we set up a temp
  137.                 // var for the count.  -1 becuase we're going to pop the
  138.                 // stack in the next command.  $tmp will then equal the
  139.                 // current level of indent.
  140.                 $tmp count($stack- 1;
  141.  
  142.                 // as long as the stack count is greater than the
  143.                 // current indent level, we need to end list types.
  144.                 // continue adding end-list tokens until the stack count
  145.                 // and the indent level are the same.
  146.                 $return .= $this->wiki->addToken(
  147.                     $this->rule,
  148.                     array (
  149.                         'type' => array_pop($stack'_list_end',
  150.                         'level' => $tmp
  151.                     )
  152.                 );
  153.  
  154.                 // reset to the current (previous) list type so that
  155.                 // the new list item matches the proper list type.
  156.                 if ($tmp{
  157.                     $oldtype $stack[$tmp - 1];
  158.                 }
  159.  
  160.                 // reset the item count for the popped indent level
  161.                 unset($itemcount[$tmp + 1]);
  162.             }
  163.  
  164.             // add a level to the list?
  165.             if ($level count($stack)) {
  166.  
  167.                 // the current indent level is greater than the
  168.                 // number of stack elements, so we must be starting
  169.                 // a new list.  push the new list type onto the
  170.                 // stack...
  171.                 array_push($stack$type);
  172.  
  173.                 // ...and add a list-start token to the return.
  174.                 $return .= $this->wiki->addToken(
  175.                     $this->rule,
  176.                     array(
  177.                         'type' => $type '_list_start',
  178.                         'level' => $level - 1
  179.                     )
  180.                 );
  181.             }
  182.  
  183.             // add to the item count for this list (taking into account
  184.             // which level we are at).
  185.             if (isset($itemcount[$level])) {
  186.                 // first count
  187.                 $itemcount[$level= 0;
  188.             else {
  189.                 // increment count
  190.                 $itemcount[$level]++;
  191.             }
  192.  
  193.             // is this the very first item in the list?
  194.             if ($pastFirst{
  195.                 $first = true;
  196.                 $pastFirst = true;
  197.             else {
  198.                 $first = false;
  199.             }
  200.  
  201.             // create a list-item starting token.
  202.             $start $this->wiki->addToken(
  203.                 $this->rule,
  204.                 array(
  205.                     'type' => $type '_item_start',
  206.                     'level' => $level,
  207.                     'count' => $itemcount[$level],
  208.                     'first' => $first
  209.                 )
  210.             );
  211.  
  212.             // create a list-item ending token.
  213.             $end $this->wiki->addToken(
  214.                 $this->rule,
  215.                 array(
  216.                     'type' => $type '_item_end',
  217.                     'level' => $level,
  218.                     'count' => $itemcount[$level]
  219.                 )
  220.             );
  221.  
  222.             // add the starting token, list-item text, and ending token
  223.             // to the return.
  224.             $return .= "\n" $start $text $end;
  225.         }
  226.  
  227.         // the last list-item may have been indented.  go through the
  228.         // list-type stack and create end-list tokens until the stack
  229.         // is empty.
  230.         while (count($stack> 0{
  231.             $return .= $this->wiki->addToken(
  232.                 $this->rule,
  233.                 array (
  234.                     'type' => array_pop($stack'_list_end',
  235.                     'level' => count($stack)
  236.                 )
  237.             );
  238.         }
  239.  
  240.         // we're done!  send back the replacement text.
  241.         return "\n\n" $return "\n\n";
  242.     }
  243. }
  244. ?>

Documentation generated on Mon, 11 Mar 2019 15:40:30 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.