| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- <?php
- /* vim: set expandtab tabstop=4 shiftwidth=4: */
- // +----------------------------------------------------------------------+
- // | PHP version 4 |
- // +----------------------------------------------------------------------+
- // | Copyright (c) 1997-2003 The PHP Group |
- // +----------------------------------------------------------------------+
- // | This source file is subject to version 2.0 of the PHP license, |
- // | that is bundled with this package in the file LICENSE, and is |
- // | available through the world-wide-web at |
- // | http://www.php.net/license/2_02.txt. |
- // | If you did not receive a copy of the PHP license and are unable to |
- // | obtain it through the world-wide-web, please send a note to |
- // | license@php.net so we can mail you a copy immediately. |
- // +----------------------------------------------------------------------+
- // | Authors: Paul M. Jones <pmjones@ciaweb.net> |
- // +----------------------------------------------------------------------+
- //
- // $Id: toc.php,v 1.2 2004/01/31 17:09:46 pmjones Exp $
- /**
- *
- * This class implements a Text_Wiki_Rule to find all heading tokens and
- * build a table of contents. The %%TOC%% tag gets replaced with a list
- * of all the level-2 through level-6 headings.
- *
- * @author Paul M. Jones <pmjones@ciaweb.net>
- *
- * @package Text_Wiki
- *
- */
- class Text_Wiki_Rule_toc extends Text_Wiki_Rule {
-
-
- /**
- *
- * The regular expression used to parse the source text and find
- * matches conforming to this rule. Used by the parse() method.
- *
- * @access public
- *
- * @var string
- *
- * @see parse()
- *
- */
-
- var $regex = "/%%TOC%%/m";
-
-
- /**
- *
- * The collection of headings (text and levels).
- *
- * @access public
- *
- * @var array
- *
- * @see _getEntries()
- *
- */
-
- var $entry = array();
-
-
- /**
- *
- * Custom parsing (have to process heading entries first).
- *
- * @access public
- *
- * @see Text_Wiki::parse()
- *
- */
-
- function parse()
- {
- $this->_getEntries();
- parent::parse();
- }
-
-
- /**
- *
- * Generates a replacement for the matched text. Token options are:
- *
- * 'type' => ['list_start'|'list_end'|'item_end'|'item_end'|'target']
- *
- * 'level' => The heading level (1-6).
- *
- * 'count' => Which heading this is in the list.
- *
- * @access public
- *
- * @param array &$matches The array of matches from parse().
- *
- * @return string A token indicating the TOC collection point.
- *
- */
-
- function process(&$matches)
- {
- $output = $this->addToken(array('type' => 'list_start'));
-
- foreach ($this->entry as $key => $val) {
-
- $options = array(
- 'type' => 'item_start',
- 'count' => $val['count'],
- 'level' => $val['level']
- );
-
- $output .= $this->addToken($options);
-
- $output .= $val['text'];
-
- $output .= $this->addToken(array('type' => 'item_end'));
- }
-
- $output .= $this->addToken(array('type' => 'list_end'));
- return $output;
- }
-
-
- /**
- *
- * Finds all headings in the text and saves them in $this->entry.
- *
- * @access private
- *
- * @return void
- *
- */
-
- function _getEntries()
- {
- // the wiki delimiter
- $delim = $this->_wiki->delim;
-
- // list of all TOC entries (h2, h3, etc)
- $this->entry = array();
-
- // the new source text with TOC entry tokens
- $newsrc = '';
-
- // when passing through the parsed source text, keep track of when
- // we are in a delimited section
- $in_delim = false;
-
- // when in a delimited section, capture the token key number
- $key = '';
-
- // TOC entry count
- $count = 0;
-
- // pass through the parsed source text character by character
- $k = strlen($this->_wiki->_source);
- for ($i = 0; $i < $k; $i++) {
-
- // the current character
- $char = $this->_wiki->_source{$i};
-
- // are alredy in a delimited section?
- if ($in_delim) {
-
- // yes; are we ending the section?
- if ($char == $delim) {
-
- // yes, get the replacement text for the delimited
- // token number and unset the flag.
- $key = (int)$key;
- $rule = $this->_wiki->_tokens[$key][0];
- $opts = $this->_wiki->_tokens[$key][1];
- $in_delim = false;
-
- // is the key a start heading token
- // of level 2 or deeper?
- if ($rule == 'heading' &&
- $opts['type'] == 'start' &&
- $opts['level'] > 1) {
-
- // yes, add a TOC target link to the
- // tokens array...
- $token = $this->addToken(
- array(
- 'type' => 'target',
- 'count' => $count,
- 'level' => $opts['level']
- )
- );
-
- // ... and to the new source, before the
- // heading-start token.
- $newsrc .= $token . $delim . $key . $delim;
-
- // retain the toc item
- $this->entry[] = array (
- 'count' => $count,
- 'level' => $opts['level'],
- 'text' => $opts['text']
- );
-
- // increase the count for the next entry
- $count++;
-
- } else {
- // not a heading-start of 2 or deeper.
- // re-add the delimited token number
- // as it was in the original source.
- $newsrc .= $delim . $key . $delim;
- }
-
- } else {
-
- // no, add to the delimited token key number
- $key .= $char;
-
- }
-
- } else {
-
- // not currently in a delimited section.
- // are we starting into a delimited section?
- if ($char == $delim) {
- // yes, reset the previous key and
- // set the flag.
- $key = '';
- $in_delim = true;
- } else {
- // no, add to the output as-is
- $newsrc .= $char;
- }
- }
- }
-
- // replace with changed source text
- $this->_wiki->_source = $newsrc;
-
-
- /*
- // PRIOR VERSION
- // has problems mistaking marked-up numbers for delimited tokens
-
- // creates target tokens, retrieves heading level and text
- $this->entry = array();
- $count = 0;
-
- // loop through all tokens and get headings
- foreach ($this->_wiki->_tokens as $key => $val) {
-
- // only get heading starts of level 2 or deeper
- if ($val[0] == 'heading' &&
- $val[1]['type'] == 'start' &&
- $val[1]['level'] > 1) {
-
- // the level of this header
- $level = $val[1]['level'];
-
- // the text of this header
- $text = $val[1]['text'];
-
- // add a toc-target link to the tokens array
- $token = $this->addToken(
- array(
- 'type' => 'target',
- 'count' => $count,
- 'level' => $level
- )
- );
-
- // put the toc target token in front of the
- // heading-start token
- $start = $delim . $key . $delim;
- $this->_wiki->_source = str_replace($start, $token.$start,
- $this->_wiki->_source);
-
- // retain the toc item
- $this->entry[] = array (
- 'count' => $count,
- 'level' => $level,
- 'text' => $text
- );
-
- // increase the count for the next item
- $count++;
- }
- }
- */
- }
-
- /**
- *
- * Renders a token into text matching the requested format.
- *
- * @access public
- *
- * @param array $options The "options" portion of the token (second
- * element).
- *
- * @return string The text rendered from the token options.
- *
- */
-
- function renderXhtml($options)
- {
- // type, count, level
- extract($options);
-
- // the prefix used for anchor names
- $prefix = 'toc';
-
- if ($type == 'target') {
- // ... generate an anchor.
- return "<a name=\"$prefix$count\"></a>";
- }
-
- if ($type == 'list_start') {
- return "<p>\n";
- }
-
- if ($type == 'list_end') {
- return "</p>\n";
- }
-
- if ($type == 'item_start') {
-
- // build some indenting spaces for the text
- $indent = ($level - 2) * 4;
- $pad = str_pad('', $indent);
- $pad = str_replace(' ', ' ', $pad);
-
- // add an extra linebreak in front of heading-2
- // entries (makes for nice section separations)
- if ($level <= 2 && $count > 0) {
- $pad = "<br />\n$pad";
- }
-
- // create the entry line as a link to the toc anchor
- return "$pad<a href=\"#$prefix$count\">";
- }
-
- if ($type == 'item_end') {
- return "</a><br />\n";
- }
- }
- }
- ?>
|