includes/wikiengine/Parse/Mediawiki/Deflist.php
changeset 1027 98c052fc3337
parent 1026 f0431eb8161e
child 1028 dde4416dea00
equal deleted inserted replaced
1026:f0431eb8161e 1027:98c052fc3337
     1 <?php
       
     2 // vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4:
       
     3 /**
       
     4 * 
       
     5 * Mediawiki: Parse for definition lists.
       
     6 * 
       
     7 * @category Text
       
     8 * @package Text_Wiki
       
     9 * @author Justin Patrin <papercrane@reversefold.com>
       
    10 * @author Paul M. Jones <pmjones@php.net>
       
    11 * @author Moritz Venn <ritzmo@php.net>
       
    12 * @license LGPL
       
    13 * @version $Id: Deflist.php,v 1.1 2006/03/29 18:41:43 ritzmo Exp $
       
    14 * 
       
    15 */
       
    16 
       
    17 /**
       
    18 * 
       
    19 * Parses for definition lists.
       
    20 *
       
    21 * This class implements a Text_Wiki_Parse to find source text marked as a
       
    22 * definition list.
       
    23 * If a line starts with ';' or ':' it is considered a part of a definition
       
    24 * list. ';' indicates the term to be defined and ':' indicates its definition.
       
    25 * As in Mediawiki we also allow definition lists to only consist of one
       
    26 * item-type.
       
    27 *
       
    28 * @category Text
       
    29 * @package Text_Wiki
       
    30 * 
       
    31 * @author Justin Patrin <papercrane@reversefold.com>
       
    32 * @author Paul M. Jones <pmjones@php.net>
       
    33 * @author Moritz Venn <ritzmo@php.net>
       
    34 * 
       
    35 */
       
    36 
       
    37 class Text_Wiki_Parse_Deflist extends Text_Wiki_Parse {
       
    38     
       
    39     
       
    40     /**
       
    41     * 
       
    42     * The regular expression used to parse the source text and find
       
    43     * matches conforming to this rule.  Used by the parse() method.
       
    44     * 
       
    45     * @access public
       
    46     * 
       
    47     * @var string
       
    48     * 
       
    49     * @see parse()
       
    50     * 
       
    51     */
       
    52 
       
    53     var $regex = '/\n((?:\;|\:)+.*?\n(?!(?:\;|\:)+))/s';
       
    54  
       
    55    /**
       
    56     *
       
    57     * Generates a replacement for the matched text.  Token options are:
       
    58     *
       
    59     * 'type' =>
       
    60     *     'list_start'    : the start of a definition list
       
    61     *     'list_end'      : the end of a definition list
       
    62     *     'term_start'    : the start of a definition term
       
    63     *     'term_end'      : the end of a definition term
       
    64     *     'narr_start'    : the start of definition narrative
       
    65     *     'narr_end'      : the end of definition narrative
       
    66     *     'unknown'       : unknown type of definition portion
       
    67     *
       
    68     * 'level' => the indent level (0 for the first level, 1 for the
       
    69     * second, etc)
       
    70     *
       
    71     * 'count' => the list item number at this level. not needed for
       
    72     * xhtml, but very useful for PDF and RTF.
       
    73     *
       
    74     * @access public
       
    75     *
       
    76     * @param array &$matches The array of matches from parse().
       
    77     *
       
    78     * @return A series of text and delimited tokens marking the different
       
    79     * list text and list elements.
       
    80     *
       
    81     */ 
       
    82     function process(&$matches)
       
    83     {
       
    84         // the replacement text we will return
       
    85         $return = '';
       
    86         
       
    87         // the list of post-processing matches
       
    88         $list = array();
       
    89         
       
    90         // a stack of list-start and list-end types; we keep this
       
    91         // so that we know what kind of list we're working with
       
    92         // (bullet or number) and what indent level we're at.
       
    93         $stack = array();
       
    94         
       
    95         // the item count is the number of list items for any
       
    96         // given list-type on the stack
       
    97         $itemcount = array();
       
    98         
       
    99         // have we processed the very first list item?
       
   100         $pastFirst = false;
       
   101         
       
   102         // populate $list with this set of matches. $matches[1] is the
       
   103         // text matched as a list set by parse().
       
   104         preg_match_all(
       
   105             '/^((;|:)+)(.*?)$/ms',
       
   106             $matches[1],
       
   107             $list,
       
   108             PREG_SET_ORDER
       
   109         );
       
   110 
       
   111 	// loop through each list-item element.
       
   112         foreach ($list as $key => $val) {
       
   113             // $val[0] is the full matched list-item line
       
   114             // $val[1] is the type (* or #)
       
   115             // $val[2] is the level (number)
       
   116             // $val[3] is the list item text
       
   117             
       
   118             // how many levels are we indented? (1 means the "root"
       
   119             // list level, no indenting.)
       
   120             $level = strlen($val[1]);
       
   121             
       
   122             // get the list item type
       
   123             if ($val[2] == ';') {
       
   124                 $type = 'term';
       
   125             } elseif ($val[2] == ':') {
       
   126                 $type = 'narr';
       
   127             } else {
       
   128                 $type = 'unknown';
       
   129             }
       
   130             
       
   131             // get the text of the list item
       
   132             $text = $val[3];
       
   133 
       
   134             // add a level to the list?
       
   135             if ($level > count($stack)) {
       
   136 
       
   137                 // the current indent level is greater than the
       
   138                 // number of stack elements, so we must be starting
       
   139                 // a new list.  push the new list type onto the
       
   140                 // stack...
       
   141                 array_push($stack, $type);
       
   142 
       
   143 		// The new list has to be opened in an item (use current type)
       
   144 		if ($level > 1) {
       
   145 		$return .= $this->wiki->addToken(
       
   146 		    $this->rule,
       
   147 		    array(
       
   148 		        'type' => $type . '_start',
       
   149 		        'level' => $level - 1
       
   150                     )
       
   151                 );
       
   152 		}
       
   153 		// ...and add a list-start token to the return.
       
   154                 $return .= $this->wiki->addToken(
       
   155                     $this->rule, 
       
   156                     array(
       
   157                         'type' => 'list_start',
       
   158                         'level' => $level - 1
       
   159                     )
       
   160                 );
       
   161             }
       
   162 
       
   163 	    // remove a level from the list?
       
   164 	    while (count($stack) > $level) {
       
   165                 // so we don't keep counting the stack, we set up a temp
       
   166                 // var for the count.  -1 becuase we're going to pop the
       
   167                 // stack in the next command.  $tmp will then equal the
       
   168                 // current level of indent.
       
   169                 $tmp = count($stack) - 1;
       
   170                 
       
   171                 // as long as the stack count is greater than the
       
   172                 // current indent level, we need to end list types. 
       
   173                 // continue adding end-list tokens until the stack count
       
   174                 // and the indent level are the same.
       
   175                 $return .= $this->wiki->addToken(
       
   176                     $this->rule, 
       
   177                     array (
       
   178                         'type' => 'list_end',
       
   179                         'level' => $tmp
       
   180                     )
       
   181                 );
       
   182 
       
   183                 array_pop($stack);
       
   184 
       
   185 		// reset to the current (previous) list type so that
       
   186                 // the new list item matches the proper list type.
       
   187 		$type = $stack[$tmp - 1];
       
   188 
       
   189 		// Close the previously opened List item
       
   190 		$return .= $this->wiki->addToken(
       
   191                     $this->rule,
       
   192                     array (
       
   193                         'type' => $type . '_end',
       
   194                         'level' => $tmp
       
   195                     )
       
   196                 );
       
   197                 
       
   198                 // reset the item count for the popped indent level
       
   199                 unset($itemcount[$tmp + 1]);
       
   200             }
       
   201             
       
   202             // add to the item count for this list (taking into account
       
   203             // which level we are at).
       
   204             if (! isset($itemcount[$level])) {
       
   205                 // first count
       
   206                 $itemcount[$level] = 0;
       
   207             } else {
       
   208                 // increment count
       
   209                 $itemcount[$level]++;
       
   210             }
       
   211             
       
   212             // is this the very first item in the list?
       
   213             if (! $pastFirst) {
       
   214                 $first = true;
       
   215                 $pastFirst = true;
       
   216             } else {
       
   217                 $first = false;
       
   218             }
       
   219             
       
   220             // create a list-item starting token.
       
   221             $start = $this->wiki->addToken(
       
   222                 $this->rule, 
       
   223                 array(
       
   224                     'type' => $type . '_start',
       
   225                     'level' => $level,
       
   226                     'count' => $itemcount[$level],
       
   227                     'first' => $first
       
   228                 )
       
   229             );
       
   230             
       
   231             // create a list-item ending token.
       
   232             $end = $this->wiki->addToken(
       
   233                 $this->rule, 
       
   234                 array(
       
   235                     'type' => $type . '_end',
       
   236                     'level' => $level,
       
   237                     'count' => $itemcount[$level]
       
   238                 )
       
   239             );
       
   240             
       
   241             // add the starting token, list-item text, and ending token
       
   242             // to the return.
       
   243             $return .= $start . $text . $end;
       
   244         }
       
   245         
       
   246         // the last list-item may have been indented.  go through the
       
   247         // list-type stack and create end-list tokens until the stack
       
   248 	// is empty.
       
   249 	$level = count($stack);
       
   250 	while ($level > 0) {
       
   251 	    array_pop($stack);
       
   252             $return .= $this->wiki->addToken(
       
   253                 $this->rule, 
       
   254                 array (
       
   255                     'type' => 'list_end',
       
   256                     'level' => $level - 1
       
   257                 )
       
   258             );
       
   259 
       
   260             // if we are higher than level 1 we need to close fake items
       
   261             if ($level > 1) {
       
   262 		$return .= $this->wiki->addToken(
       
   263                 $this->rule,
       
   264                 array (
       
   265                     'type' => $stack[$level - 2] . '_end',
       
   266                     'level' => $level - 2
       
   267                 )
       
   268                 );
       
   269 	    }
       
   270 	    $level = count($stack);
       
   271 	}
       
   272         
       
   273         // we're done!  send back the replacement text.
       
   274         return "\n" . $return . "\n\n";
       
   275     }
       
   276 }
       
   277 ?>