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

Documentation generated on Mon, 11 Mar 2019 13:56:53 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.