Commit eab107a5 authored by jepso's avatar jepso

added Pdf output capability to manual

parent fd86c7a4
<?php
error_reporting(E_ALL);
$includePath = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'vendor'
. PATH_SEPARATOR . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'lib';
$includePath = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'lib' . PATH_SEPARATOR
. dirname(__FILE__) . DIRECTORY_SEPARATOR . 'lib' . PATH_SEPARATOR
. dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'vendor';
set_include_path($includePath);
set_include_path($includePath);
require_once('Doctrine.php');
require_once('Sensei/Sensei.php');
require_once('DocTool.php');
require_once('Cache.php');
spl_autoload_register(array('Doctrine', 'autoload'));
spl_autoload_register(array('Sensei', 'autoload'));
spl_autoload_register('autoload');
// Executes the 'svn info' command for the current directory and parses the last
// changed revision.
$revision = 0;
exec('svn info .', $output);
foreach ($output as $line) {
if (preg_match('/^Last Changed Rev: ([0-9]+)$/', $line, $matches)) {
$revision = $matches[1];
break;
/**
* A generic autoload function
*
* Filename is generated from class name by replacing underscores with
* directory separators and by adding a '.php' extension.
*
* Then the filename is searched from include paths, and if found it is
* included with require_once().
*
* @param $class string class name to be loaded
* @return bool true if a class was loaded, false otherwise
*/
function autoload($class)
{
if (class_exists($class, false)) {
return false;
}
$paths = explode(PATH_SEPARATOR, get_include_path());
$filename = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
foreach($paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $filename)) {
require_once($filename);
return true;
}
}
return false;
}
/**
* Returns the revision of a SVN controlled file.
*
* The revision is acquired by executing the 'svn info' command for the file and
* parsing the last changed revision from the output.
*
* @param $file string filename
* @return int|false revision of the file, or false on failure
*/
function getSvnRevision($file)
{
exec('svn info ' . $file, $output);
foreach ($output as $line) {
if (preg_match('/^Last Changed Rev: ([0-9]+)$/', $line, $matches)) {
return $matches[1];
}
}
return false;
}
$cacheDir = './cache/';
$cacheRevFile = $cacheDir . 'revision.txt';
$cacheRev = 0;
/**
* Wraps a Doctrine_Cache_Db and suppresses all exceptions thrown by caching
* operations. Uses Sqlite as database backend.
*/
class Cache
{
protected $_cache = null;
/**
* Constructs a cache object.
*
* If cache table does not exist, creates one.
*
* @param $cacheFile string filename of the sqlite database
*/
public function __construct($cacheFile)
{
try {
$dsn = 'sqlite:' . $cacheFile;
$dbh = new PDO($dsn);
$conn = Doctrine_Manager::connection($dbh);
$options = array(
'connection' => $conn,
'tableName' => 'cache'
);
$cache = new Cache($cacheDir, 'cache');
$this->_cache = new Doctrine_Cache_Db($options);
try {
$this->_cache->createTable();
} catch (Doctrine_Connection_Exception $e) {
if ($e->getPortableCode() !== Doctrine::ERR_ALREADY_EXISTS) {
$this->_cache = null;
}
}
// Checks the revision cache files were created from
if (file_exists($cacheRevFile)) {
$cacheRev = (int) file_get_contents($cacheRevFile);
} catch (Exception $e) {
$this->_cache = null;
}
}
/**
* Fetches a cache record from cache.
*
* @param $id string the id of the cache record
* @return string fetched cache record, or false on failure
*/
public function fetch($id)
{
if ($this->_cache !== null) {
try {
return $this->_cache->fetch($id);
} catch (Exception $e) {
return false;
}
}
return false;
}
/**
* Saves a cache record to cache.
*
* @param $data mixed the data to be saved to cache
* @param $id string the id of the cache record
* @return bool True on success, false on failure
*/
public function save($data, $id)
{
if ($this->_cache !== null) {
try {
return $this->_cache->save($data, $id);
} catch (Exception $e) {
return false;
}
}
return false;
}
/**
* Deletes all cached records from cache.
*
* @return True on success, false on failure
*/
public function deleteAll()
{
if ($this->_cache !== null) {
try {
return $this->_cache->deleteAll();
} catch (Exception $e) {
return false;
}
}
return false;
}
}
// Empties the cache directory and saves the current revision to a file, if SVN
// revision is greater than cache revision
// Temporary directory used by cache and LaTeX to Pdf conversion
$tempDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'tmp';
// The file where cached data is saved
$cacheFile = $tempDir . DIRECTORY_SEPARATOR . 'cache.sq3';
$cache = new Cache($cacheFile);
// Fetch the revision of cached data
$cacheRev = $cache->fetch('revision');
// Check the revision of documentation files
$revision = getSvnRevision('.');
// Is current SVN revision greater than the revision of cached data?
if ($revision > $cacheRev) {
$cache->clear();
@file_put_contents($cacheRevFile, $revision);
$cache->deleteAll(); // cached data is not valid anymore
$cache->save($revision, 'revision');
}
// Load table of contents from cache
$toc = $cache->fetch('toc');
if ($cache->begin()) {
$tool = new DocTool('docs/en.txt');
// $tool->setOption('clean-url', true);
// If table of contents was not cached, parse it from documentation files
if ( ! $toc instanceof Sensei_Doc_Toc) {
$toc = new Sensei_Doc_Toc('docs/en.txt');
$cache->save($toc, 'toc');
}
$baseUrl = '';
$title = 'Doctrine Manual';
$section = null;
// Which format to output docs
if (isset($_GET['format'])) {
$format = ucfirst(strtolower($_GET['format']));
if (isset($_GET['chapter'])) {
$section = $tool->findByPath($_GET['chapter']);
if ($tool->getOption('clean-url')) {
$baseUrl = '../';
}
switch ($format) {
case 'Xhtml':
case 'Latex':
case 'Pdf':
break;
default:
$format = 'Xhtml'; // default if invalid format is specified
break;
}
if (isset($_GET['one-page'])) {
$tool->setOption('one-page', true);
$tool->setOption('max-level', 0);
$section = null;
$baseUrl = '';
}
} else {
$format = 'Xhtml'; // default if no format is specified
}
$rendererClass = 'Sensei_Doc_Renderer_' . $format;
$renderer = new $rendererClass($toc);
$renderer->setOptions(array(
'title' => 'Doctrine Manual',
'author' => 'Konsta Vesterinen',
'version' => 'Rev. ' . $revision,
'subject' => 'Object relational mapping',
'keywords' => 'PHP, ORM, object relational mapping, Doctrine, database'
));
$cacheId = $format;
switch ($format) {
case 'Latex':
$renderer->setOption('template', file_get_contents('templates/latex.tpl.php'));
$headers = array(
'Content-Type: application/latex',
'Content-Disposition: attachment; filename=doctrine-manual.tex'
);
break;
if ($section) {
while ($section->getLevel() > 1) {
$section = $section->getParent();
case 'Pdf':
$renderer->setOption('template', file_get_contents('templates/latex.tpl.php'));
$renderer->setOptions(array(
'temp_dir' => $tempDir,
'pdflatex_path' => '/usr/bin/pdflatex',
'lock' => true
));
$headers = array(
'Content-Type: application/pdf',
'Content-Disposition: attachment; filename=doctrine-manual.pdf'
);
break;
case 'Xhtml':
default:
$renderer->setOption('template', file_get_contents('templates/xhtml.tpl.php'));
$viewIndex = true;
if (isset($_GET['one-page'])) {
$viewIndex = false;
}
if (isset($_GET['chapter'])) {
$section = $toc->findByPath($_GET['chapter']);
$tool->setOption('section', $section);
$title .= ' - Chapter ' . $section->getIndex() . ' ' . $section->getName();
}
if ($section && $section->getLevel() === 1) {
$title = $renderer->getOption('title') . ' - Chapter '
. $section->getIndex() . ' ' . $section->getName();
$renderer->setOptions(array(
'section' => $section,
'url_prefix' => '?chapter=',
'title' => $title
));
$cacheId .= '-' . $section->getPath();
$viewIndex = false;
}
}
break;
if ($tool->getOption('clean-url')) {
$tool->setOption('base-url', $baseUrl);
}
if (isset($viewIndex) && $viewIndex) {
$title = $renderer->getOption('title');
include 'templates/index.tpl.php';
} else {
$output = $cache->fetch($cacheId);
if ($output === false) {
try {
$output = $renderer->render();
} catch (Exception $e) {
die($e->getMessage());
}
$cache->save($output, $cacheId);
}
include 'template.php';
if (isset($headers)) {
foreach ($headers as $header) {
header($header);
}
}
// buffer output
ob_start();
echo $output;
ob_end_flush();
$cache->end();
}
......@@ -29,6 +29,7 @@ class Text_Wiki_Doc extends Text_Wiki {
'Delimiter',
'Code',
'Raw',
'Heading',
'Horiz',
'Break',
'Blockquote',
......
<?php
/**
* Parses for links to other documentation sections.
*
* @category Text
* @package Text_Wiki
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @license LGPL
* @version $Id$
*
*/
class Text_Wiki_Parse_Doclink extends Text_Wiki_Parse {
var $conf = array(
......
......@@ -61,11 +61,15 @@ class Text_Wiki_Parse_Prefilter extends Text_Wiki_Parse {
// convert tabs to four-spaces
$this->wiki->source = str_replace("\t", " ",
$this->wiki->source);
// add extra newline before code tags to prevent xhtml validation errors
// remove trailing spaces
$this->wiki->source = preg_replace('/ +\n/', "\n", $this->wiki->source);
// add extra newlines before and after code tags to prevent xhtml
// validation errors
$this->wiki->source = preg_replace(
';^(<code(?:\s[^>]*)?>(?:.*?)</code>(?:\s|$));msi',
"\n\\1", $this->wiki->source);
"\n$1\n\n", $this->wiki->source);
// add extra newlines at the top and end; this
// seems to help many rules.
......
<?php
/**
*
* Parses for table markup.
*
* @category Text
*
* @package Text_Wiki
*
* @author Paul M. Jones <pmjones@php.net>
*
* @license LGPL
*
* @version $Id: Table.php,v 1.3 2005/02/23 17:38:29 pmjones Exp $
*
*/
/**
*
* Parses for table markup.
*
* This class implements a Text_Wiki_Parse to find source text marked as a
* set of table rows, where a line start and ends with double-pipes (||)
* and uses double-pipes to separate table cells. The rows must be on
* sequential lines (no blank lines between them) -- a blank line
* indicates the beginning of a new table.
*
* @category Text
*
* @package Text_Wiki
*
* @author Paul M. Jones <pmjones@php.net>
*
*/
class Text_Wiki_Parse_Table extends Text_Wiki_Parse {
/**
*
* 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 = '/\n((\|\|).*)(\n)(?!(\|\|))/Us';
/**
*
* Generates a replacement for the matched text.
*
* Token options are:
*
* 'type' =>
* 'table_start' : the start of a bullet list
* 'table_end' : the end of a bullet list
* 'row_start' : the start of a number list
* 'row_end' : the end of a number list
* 'cell_start' : the start of item text (bullet or number)
* 'cell_end' : the end of item text (bullet or number)
*
* 'cols' => the number of columns in the table (for 'table_start')
*
* 'rows' => the number of rows in the table (for 'table_start')
*
* 'span' => column span (for 'cell_start')
*
* 'attr' => column attribute flag (for 'cell_start')
*
* @access public
*
* @param array &$matches The array of matches from parse().
*
* @return A series of text and delimited tokens marking the different
* table elements and cell text.
*
*/
function process(&$matches)
{
// our eventual return value
$return = '';
// the number of columns in the table
$num_cols = 0;
// the number of rows in the table
$num_rows = 0;
// the maximum content lengths in the column cells
$col_widths = array();
// the maximum row length of the table
$table_width = 0;
// rows are separated by newlines in the matched text
$rows = explode("\n", $matches[1]);
// loop through each row
foreach ($rows as $row) {
// increase the row count
$num_rows ++;
$row_length = 0;
// start a new row
$return .= $this->wiki->addToken(
$this->rule,
array('type' => 'row_start')
);
// cells are separated by double-pipes
$cell = explode("||", $row);
// get the number of cells (columns) in this row
$last = count($cell) - 1;
// is this more than the current column count?
// (we decrease by 1 because we never use cell zero)
if ($last - 1 > $num_cols) {
// increase the column count
$num_cols = $last - 1;
}
// by default, cells span only one column (their own)
$span = 1;
// ignore cell zero, and ignore the "last" cell; cell zero
// is before the first double-pipe, and the "last" cell is
// after the last double-pipe. both are always empty.
for ($i = 1; $i < $last; $i ++) {
// if there is no content at all, then it's an instance
// of two sets of || next to each other, indicating a
// span.
if ($cell[$i] == '') {
// add to the span and loop to the next cell
$span += 1;
continue;
} else {
// this cell has content.
// find any special "attr"ibute cell markers
if (substr($cell[$i], 0, 2) == '> ') {
// right-align
$attr = 'right';
$cell[$i] = substr($cell[$i], 2);
} elseif (substr($cell[$i], 0, 2) == '= ') {
// center-align
$attr = 'center';
$cell[$i] = substr($cell[$i], 2);
} elseif (substr($cell[$i], 0, 2) == '< ') {
// left-align
$attr = 'left';
$cell[$i] = substr($cell[$i], 2);
} elseif (substr($cell[$i], 0, 2) == '~ ') {
$attr = 'header';
$cell[$i] = substr($cell[$i], 2);
} else {
$attr = null;
}
$content = trim($cell[$i]);
// content length of this cell
$cell_length = strlen($content);
// add content length to row length
$row_length += $cell_length;
// update column width if this cell's length is greater than
// old column width
if ( ! isset($col_widths[$i]) || $cell_length > $col_widths[$i]) {
$col_widths[$i] = $cell_length;
}
// start a new cell...
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => 'cell_start',
'attr' => $attr,
'span' => $span
)
);
// ...add the content...
$return .= $content;
// ...and end the cell.
$return .= $this->wiki->addToken(
$this->rule,
array (
'type' => 'cell_end',
'attr' => $attr,
'span' => $span
)
);
// reset the span.
$span = 1;
}
}
// update table width if the row was wider than previous rows
if ($row_length > $table_width) {
$table_width = $row_length;
}
// end the row
$return .= $this->wiki->addToken(
$this->rule,
array('type' => 'row_end')
);
}
// wrap the return value in start and end tokens
$return =
$this->wiki->addToken(
$this->rule,
array(
'type' => 'table_start',
'rows' => $num_rows,
'cols' => $num_cols,
'table_width' => $table_width,
'col_widths' => $col_widths
)
)
. $return .
$this->wiki->addToken(
$this->rule,
array(
'type' => 'table_end'
)
);
// we're done!
return "\n$return\n\n";
}
}
?>
\ No newline at end of file
<?php
/**
*
* Formats parsed Text_Wiki for LaTeX rendering.
*
* $Id: Latex.php,v 1.2 2004/09/25 19:05:13 pmjones Exp $
*
* @author Jeremy Cowgar <jeremy@cowgar.com>
*
* @package Text_Wiki
*
* @todo [http://google.com] becomes 1 with a LaTeX footnote in subscript.
* This should be a normal LaTeX footnote associated with the
* previous word?
*
* @todo parse "..." to be ``...''
*
* @todo parse '...' to be `...'
*
* @todo move escape_latex to a static function, move escaping to the
* individual .php files they are associated with
*
* @todo allow the user to add conf items to do things like
* + A custom document header
* + Custom page headings
* + Include packages
* + Set Title, Author, Date
* + Include a title page
* + Not output Document Head/Foot (maybe combinding many pages?)
*
*/
class Text_Wiki_Render_Latex extends Text_Wiki_Render {
function escape_latex ($txt) {
$txt = str_replace("\\", "\\\\", $txt);
$txt = str_replace('#', '\#', $txt);
$txt = str_replace('$', '\$', $txt);
$txt = str_replace('%', '\%', $txt);
$txt = str_replace('^', '\^', $txt);
$txt = str_replace('&', '\&', $txt);
$txt = str_replace('_', '\_', $txt);
$txt = str_replace('{', '\{', $txt);
$txt = str_replace('}', '\}', $txt);
$txt = str_replace('<', '\textless{}', $txt);
$txt = str_replace('>', '\textgreater{}', $txt);
// Typeset things a bit prettier than normas
$txt = str_replace('~', '$\sim$', $txt);
$txt = str_replace('...', '\ldots', $txt);
return $txt;
}
function escape($tok, $ele) {
if (isset($tok[$ele])) {
$tok[$ele] = $this->escape_latex($tok[$ele]);
}
return $tok;
}
function pre()
{
foreach ($this->wiki->tokens as $k => $tok) {
if ($tok[0] == 'Code' || $tok[0] == 'Phplookup') {
continue;
}
$tok[1] = $this->escape($tok[1], 'text');
$tok[1] = $this->escape($tok[1], 'page');
$tok[1] = $this->escape($tok[1], 'href');
$this->wiki->tokens[$k] = $tok;
}
$this->wiki->source = $this->escape_latex($this->wiki->source);
return '';
}
function post()
{
return '';
}
}
<?php
class Text_Wiki_Render_Latex_Code extends Text_Wiki_Render {
/**
*
* 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 token($options)
{
$text = $options['text'];
$attr = $options['attr'];
$type = strtolower($attr['type']);
if ($type == 'php') {
if (substr($options['text'], 0, 5) != '<?php') {
// PHP code example:
// add the PHP tags
$text = "<?php\n\n" . $options['text'] . "\n\n?>"; // <?php
}
}
$text = "\\begin{lstlisting}\n$text\n\\end{lstlisting}\n\n";
if ($type != '') {
$text = "\\lstset{language=$type}\n" . $text;
} else {
$text = "\\lstset{language={}}\n" . $text;
}
return $text;
}
}
?>
<?php
class Text_Wiki_Render_Latex_Heading extends Text_Wiki_Render {
function token($options)
{
// get nice variable names (type, level)
extract($options);
if ($type == 'start') {
switch ($level)
{
case '1':
return '\chapter{';
case '2':
return '\section{';
case '3':
return '\subsection{';
case '4':
return '\subsubsection{';
case '5':
return '\paragraph{';
case '6':
return '\subparagraph{';
}
}
if ($type == 'end') {
return "}\n";
}
}
}
?>
\ No newline at end of file
<?php
class Text_Wiki_Render_Latex_List extends Text_Wiki_Render {
/**
*
* Renders a token into text matching the requested format.
*
* This rendering method is syntactically and semantically compliant
* with XHTML 1.1 in that sub-lists are part of the previous list item.
*
* @access public
*
* @param array $options The "options" portion of the token (second
* element).
*
* @return string The text rendered from the token options.
*
*/
function token($options)
{
// make nice variables (type, level, count)
extract($options);
switch ($type)
{
case 'bullet_list_start':
return "\\begin{itemize}\n";
case 'bullet_list_end':
return "\\end{itemize}\n";
case 'number_list_start':
return "\\begin{enumerate}\n";
/*$depth = 'enumi' . str_pad('', $level, 'i');
$enum = '\arabic';
if (isset($format)) {
switch ($format) {
case 'a':
$enum = '\alph';
break;
case 'A':
$enum = '\Alph';
break;
case 'i':
$enum = '\roman';
break;
case 'I':
$enum = '\Roman';
break;
}
}
return '\renewcommand{\labelenumi}{' . $enum . '{' . $depth .
"}}\n\\begin{enumerate}\n";*/
case 'number_list_end':
return "\\end{enumerate}\n";
case 'bullet_item_start':
case 'number_item_start':
return '\item{';
case 'bullet_item_end':
case 'number_item_end':
return "}\n";
default:
// ignore item endings and all other types.
// item endings are taken care of by the other types
// depending on their place in the list.
return '';
break;
}
}
}
?>
<?php
class Text_Wiki_Render_Latex_Phplookup extends Text_Wiki_Render {
/**
*
* 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 token($options)
{
$text = trim($options['text']);
// take off the final parens for functions
if (substr($text, -2) == '()') {
$q = substr($text, 0, -2);
} else {
$q = $text;
}
$formatObj = $this->wiki->formatObj[$this->format];
// toggg 2006/02/05 page name must be url encoded (e.g. may contain spaces)
$q = $formatObj->escape_latex($this->urlEncode($q));
$text = $formatObj->escape_latex($text);
return '\texttt{' . $text . '}\footnote{\url{http://php.net/' . $q . '}}';
}
}
?>
<?php
class Text_Wiki_Render_Latex_Table extends Text_Wiki_Render {
var $cell_id = 0;
var $cell_count = 0;
var $is_spanning = false;
var $conf = array(
'css_table' => null,
'css_tr' => null,
'css_th' => null,
'css_td' => null
);
/**
*
* 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 token($options)
{
// make nice variable names (type, attr, span)
extract($options);
switch ($type)
{
case 'table_start':
$this->cell_count = $cols;
$max_width = 60;
$available_width = $max_width;
$avg_width = $available_width / (float) count($col_widths);
$calc_col_widths = array();
while (count($col_widths) > 0) {
$found_thinner = false;
foreach ($col_widths as $k => $col_width) {
if ($col_width <= $avg_width) {
$found_thinner = true;
$available_width -= $col_width;
$calc_col_widths[$k] = $col_width / (float) $max_width;
unset($col_widths[$k]);
}
}
if (count($col_widths) > 0) {
$avg_width = $available_width / (float) count($col_widths);
}
if ( ! $found_thinner) {
foreach ($col_widths as $k => $col_width) {
$calc_col_widths[$k] = $avg_width / (float) $max_width;
unset($col_widths[$k]);
}
}
}
$tbl_start = '{\centering \begingroup' . "\n"
. '\setlength{\newtblsparewidth}{\linewidth-' . 2 * ($cols + 1) . '\tabcolsep}' . "\n"
. '\begin{longtable}{|';
for ($a=0; $a < $this->cell_count; $a++) {
$tbl_start .= 'p{' . round($calc_col_widths[$a + 1], 4) . '\newtblsparewidth}|';
}
$tbl_start .= "}\n";
return $tbl_start;
case 'table_end':
return "\\hline\n\\end{longtable}\n\\endgroup}\n\n";
case 'caption_start':
return "\\caption{";
case 'caption_end':
return "}\n";
case 'row_start':
$this->is_spanning = false;
$this->cell_id = 0;
return "\\hline\n";
case 'row_end':
return "\\\\\n";
case 'cell_start':
if ($span > 1) {
$col_spec = '';
if ($this->cell_id == 0) {
$col_spec = '|';
}
$col_spec .= 'l|';
$this->cell_id += $span;
$this->is_spanning = true;
return '\multicolumn{' . $span . '}{' . $col_spec . '}{';
}
$this->cell_id += 1;
if ($attr === 'header') {
return '\bfseries ';
} else {
return '';
}
case 'cell_end':
$out = '';
if ($this->is_spanning) {
$this->is_spanning = false;
$out = '}';
}
if ($this->cell_id != $this->cell_count) {
$out .= ' & ';
}
return $out;
default:
return '';
}
}
}
?>
<?php
class Text_Wiki_Render_Latex_Url extends Text_Wiki_Render {
var $conf = array(
'target' => false,
'images' => true,
'img_ext' => array('jpg', 'jpeg', 'gif', 'png')
);
/**
*
* 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 token($options)
{
// create local variables from the options array (text,
// href, type)
extract($options);
if ($options['type'] == 'start') {
return '';
} else if ($options['type'] == 'end') {
return '\url{' . $href . '}';
} else {
if ($text === $href) {
return '\url{' . $href . '}';
}
return $text . '\footnote{\url{' . $href . '}}';
}
}
}
?>
......@@ -12,7 +12,7 @@
* @version CVS: $Id: Code.php,v 1.13 2006/02/10 23:07:03 toggg Exp $
* @link http://pear.php.net/package/Text_Wiki
*/
require_once('highlight.php');
/**
* This class renders code blocks in XHTML.
*
......@@ -47,7 +47,7 @@ class Text_Wiki_Render_Xhtml_Code extends Text_Wiki_Render {
*/
function token($options)
{
{
$text = $options['text'];
$attr = $options['attr'];
$type = strtolower($attr['type']);
......@@ -72,7 +72,7 @@ class Text_Wiki_Render_Xhtml_Code extends Text_Wiki_Render {
// <pre>...</pre> tags)
$h = new PHP_Highlight(true);
$h->loadString($text);
$text = $h->toHtml(true);
$text = @$h->toHtml(true);
$text = str_replace('&nbsp;', ' ', $text);
......
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><?php echo $title; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="styles/basic.css" media="screen"/>
<link rel="stylesheet" type="text/css" href="styles/print.css" media="print"/>
</head>
<body>
<div id="wrap">
<div id="content">
<h1><?php echo $title; ?></h1>
<p>There are several different versions of this manual available online:
<ul>
<li>View as <a href="?one-page">all chapters in one page</a>.</li>
<li>View as <a href="?chapter=<?php echo $toc->findByIndex('1.')->getPath(); ?>">one chapter per page</a>.</li>
<li>Download the <a href="?format=pdf">PDF version</a>.</li>
</ul>
</p>
</div>
</div>
</body>
</html>
\documentclass[11pt,a4paper]{book}
\usepackage{ifpdf}
\ifpdf
\usepackage{thumbpdf}
\pdfcompresslevel=9
\fi
\usepackage[latin1]{inputenc}
\usepackage[margin=2cm, twoside, bindingoffset=1cm]{geometry}
\usepackage{fancyhdr}
\usepackage{url}
\usepackage{calc}
\usepackage{longtable}
\usepackage{listings}
\usepackage{color}
\usepackage[
pdftex,
colorlinks,
bookmarks,
pdftitle={%TITLE%},
pdfauthor={%AUTHOR%},
pdfsubject={%SUBJECT%},
pdfkeywords={%KEYWORDS%}]{hyperref}
\pdfadjustspacing=1
\newdimen\newtblsparewidth
\pagestyle{fancy}
\renewcommand{\chaptermark}[1]{\markboth{\chaptername\ \thechapter.\ #1}{}}
\renewcommand{\sectionmark}[1]{\markright{\thesection.\ #1}}
\fancyhf{}
\fancyhead[LE]{\nouppercase{\bfseries\leftmark}}
\fancyhead[RO]{\nouppercase{\bfseries\rightmark}}
\fancyhead[RE, LO]{\bfseries{%TITLE%}}
\fancyfoot[RO, LE]{\bfseries\thepage}
\renewcommand{\headrulewidth}{0.5pt}
\renewcommand{\footrulewidth}{0.5pt}
\addtolength{\headheight}{2.5pt}
\fancypagestyle{plain}{
\fancyhead{}
\fancyfoot{}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0pt}
}
\definecolor{light-gray}{gray}{0.97}
\definecolor{keyword}{rgb}{0.47, 0.53, 0.6}
\definecolor{string}{rgb}{0.73, 0.53, 0.27}
\definecolor{comment}{rgb}{0.6, 0.6, 0.53}
\lstset{
columns=fixed,
basicstyle=\footnotesize\ttfamily,
identifierstyle=\color{black},
keywordstyle=\color{keyword},
stringstyle=\color{string},
commentstyle=\color{comment}\itshape,
backgroundcolor=\color{light-gray},
frame=single,
framerule=0pt,
breaklines,
showstringspaces=false
}
\lstdefinelanguage{PHP}
{morekeywords={
% Case-sensitive keywords:
abstract,and,as,break,case,catch,class,const,continue,default,die,do,echo,
else,elseif,endfor,endforeach,endswitch,endwhile,extends,for,global,final,
foreach,function,if,implements,import,include,include_once,instanceof,
interface,list,namespace,new,or,print,private,protected,public,require,
require_once,return,static,switch,throw,try,var,while,xor,
% Case-insensitive keywords:
true,True,TRUE,false,False,FALSE,null,Null,NULL},
morekeywords=[2]{
array,bool,boolean,double,float,int,integer,object,real,string,unset},
otherkeywords={-,.,~,^,@,;,:,\%,|,=,+,!,?,&,<,>},
sensitive=true,
morecomment=[l]{//}, % C++ line comment
morecomment=[l]{\#}, % Bash line comment
morecomment=[s]{/*}{*/}, % C block comment
morestring=[b]{'}, % single-quoted string
morestring=[b]{"} % double-quoted string
}
\setcounter{tocdepth}{5}
\setcounter{secnumdepth}{5}
\title{%TITLE%}
\author{%AUTHOR%}
\date{%VERSION%\\ \today}
\begin{document}
\maketitle
\tableofcontents
\setlength{\parindent}{0pt}
\setlength{\parskip}{1.5ex plus 0.7ex minus 0.6ex}
%CONTENT%
\end{document}
......@@ -4,15 +4,17 @@
<head>
<title><?php echo $title; ?></title>
<title>%TITLE%</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="%SUBJECT%" />
<meta name="keywords" content="%KEYWORDS" />
<link rel="stylesheet" type="text/css" href="<?php echo $baseUrl; ?>styles/basic.css" media="screen"/>
<link rel="stylesheet" type="text/css" href="<?php echo $baseUrl; ?>styles/print.css" media="print"/>
<link rel="stylesheet" type="text/css" href="styles/basic.css" media="screen"/>
<link rel="stylesheet" type="text/css" href="styles/print.css" media="print"/>
<!--[if gte IE 5.5]>
<![if lt IE 7]>
<link rel="stylesheet" type="text/css" href="<?php echo $baseUrl; ?>styles/iefix.css"/>
<link rel="stylesheet" type="text/css" href="styles/iefix.css"/>
<![endif]>
<![endif]-->
......@@ -23,9 +25,9 @@ var tocStickyText = "sticky"; var tocUnstickyText = 'unstick';
//]]>
</script>
<script type="text/javascript" src="<?php echo $baseUrl; ?>scripts/mootools.v1.11.js"></script>
<script type="text/javascript" src="<?php echo $baseUrl; ?>scripts/tree.js"></script>
<script type="text/javascript" src="<?php echo $baseUrl; ?>scripts/toc.js"></script>
<script type="text/javascript" src="scripts/mootools.v1.11.js"></script>
<script type="text/javascript" src="scripts/tree.js"></script>
<script type="text/javascript" src="scripts/toc.js"></script>
</head>
......@@ -33,46 +35,23 @@ var tocStickyText = "sticky"; var tocUnstickyText = 'unstick';
<div id="wrap">
<?php if($tool->getOption('section') || $tool->getOption('one-page')): ?>
<div id="sidebar">
<div id="table-of-contents">
<h1>Table of Contents</h1>
<?php $tool->renderToc(); ?>
%TOC%
<p>
<?php if($tool->getOption('one-page')): ?>
<a href="<?php echo ($tool->getOption('clean-url') ? "${baseUrl}chapter/" : '?chapter=') . $tool->findByIndex('1.')->getPath(); ?>">View one chapter per page</a>
<?php else: ?>
<a href="<?php echo ($tool->getOption('clean-url') ? "${baseUrl}one-page" : '?one-page=1') . '#' . $tool->getOption('section')->getPath(); ?>">View all in one page</a>
<?php endif; ?>
</p>
<p><a href=".">Index</a></p>
</div>
</div>
<?php endif; ?>
<div id="content">
<?php if($tool->getOption('section') || $tool->getOption('one-page')): ?>
<?php $tool->render(); ?>
<?php else: ?>
<h1>Doctrine Manual</h1>
<p>You can view this manual online as
<ul>
<li><a href="<?php echo $tool->getOption('clean-url') ? "${baseUrl}one-page" : '?one-page=1'; ?>">everything on a single page</a>, or</li>
<li><a href="<?php echo $tool->makeUrl($tool->findByIndex('1.')->getPath()); ?>">one chapter per page</a>.</li>
</ul>
</p>
<?php endif; ?>
%CONTENT%
</div>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://sourceforge.net/projects/sensei>.
*/
/**
* Sensei_Doc_Renderer
*
* @package Sensei_Doc
* @category Documentation
* @license http://www.gnu.org/licenses/lgpl.txt LGPL
* @link http://sourceforge.net/projects/sensei
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @version $Revision$
* @since 1.0
*/
abstract class Sensei_Doc_Renderer
{
protected $_wiki;
protected $_toc;
protected $_options = array();
public function __construct(Sensei_Doc_Toc $toc, array $options = array())
{
$defaultOptions = array(
'title' => 'Title',
'author' => 'Author',
'version' => '',
'subject' => 'Subject',
'keywords' => 'key, word',
'template' => ''
);
$this->_options = array_merge($defaultOptions, $this->_options);
$this->setOptions($options);
$this->_toc = $toc;
$this->_wiki = Text_Wiki::singleton('Doc');
$this->_wiki->setParseConf('Doclink', 'toc', $this->_toc);
}
abstract public function render();
public function setOptions(array $options)
{
foreach ($options as $option => $value) {
$this->setOption($option, $value);
}
}
public function setOption($option, $value)
{
if (is_string($option)) {
if (array_key_exists($option, $this->_options)) {
$this->_options[$option] = $value;
} else {
throw new Exception('Unknown option ' . $option . '.');
}
} else {
throw new Exception('Option must be a string.');
}
}
public function getOption($option)
{
return $this->_options[$option];
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://sourceforge.net/projects/sensei>.
*/
/**
* Sensei_Doc_Renderer_Exception
*
* @package Sensei
* @category Sensei Core
* @license http://www.gnu.org/licenses/lgpl.txt LGPL
* @link http://sourceforge.net/projects/sensei
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @version $Revision$
* @since 1.0
*/
class Sensei_Doc_Renderer_Exception extends Exception
{ }
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://sourceforge.net/projects/sensei>.
*/
/**
* Sensei_Doc_Renderer_Latex
*
* @package Sensei_Doc
* @category Documentation
* @license http://www.gnu.org/licenses/lgpl.txt LGPL
* @link http://sourceforge.net/projects/sensei
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @version $Revision$
* @since 1.0
*/
class Sensei_Doc_Renderer_Latex extends Sensei_Doc_Renderer
{
public function __construct(Sensei_Doc_Toc $toc, array $options = array())
{
parent::__construct($toc, $options);
}
protected function _mergeSections($section = null)
{
if ($section === null) {
$section = $this->_toc;
}
$text = '';
for ($i = 0; $i < count($section); $i++) {
$child = $section->getChild($i);
$text .= str_repeat('+', $child->getLevel()) . $child->getName() . "\n";
$text .= $child->getText() . "\n";
$text .= $this->_mergeSections($child);
}
return $text;
}
public function render()
{
$content = $this->_wiki->transform($this->_mergeSections(), 'Latex');
$output = $this->_options['template'];
$output = str_replace('%TITLE%', $this->_options['title'], $output);
$output = str_replace('%AUTHOR%', $this->_options['author'], $output);
$output = str_replace('%VERSION%', $this->_options['version'], $output);
$output = str_replace('%SUBJECT%', $this->_options['subject'], $output);
$output = str_replace('%KEYWORDS%', $this->_options['keywords'], $output);
$output = str_replace('%CONTENT%', $content, $output);
return $output;
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://sourceforge.net/projects/sensei>.
*/
/**
* Sensei_Doc_Renderer_Pdf
*
* @package Sensei_Doc
* @category Documentation
* @license http://www.gnu.org/licenses/lgpl.txt LGPL
* @link http://sourceforge.net/projects/sensei
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @version $Revision$
* @since 1.0
*/
class Sensei_Doc_Renderer_Pdf extends Sensei_Doc_Renderer
{
protected $_options = array(
'temp_dir' => '/tmp',
'pdflatex_path' => '/usr/bin/pdflatex',
'lock' => false
);
protected static $_tmpFileExtensions = array('tex', 'aux', 'out', 'log', 'toc', 'pdf');
protected $_tmpFilename;
public function __construct(Sensei_Doc_Toc $toc, array $options = array())
{
parent::__construct($toc, $options);
}
public function testRequirements()
{
exec($this->_options['pdflatex_path'] . ' --version', $output);
if ( ! isset($output[0]) || substr($output[0], 0, 6) !== 'pdfTeX') {
$message = 'pdfLaTeX does not seem to be installed, or pdflatex_path'
. ' option does not point to pdfLaTeX executable.';
throw new Sensei_Doc_Renderer_Exception($message);
}
}
/**
* Deletes temporary files generated during LaTeX to PDF conversion.
*/
protected function _cleanUp()
{
foreach (self::$_tmpFileExtensions as $extension) {
$filename = $this->_options['temp_dir'] . DIRECTORY_SEPARATOR
. $this->tmpFilename . '.' . $extension;
@unlink($filename);
}
}
public function render()
{
$this->testRequirements();
// Filename to be used by temporary files
$this->tmpFilename = md5($this->_options['title']);
// Change working directory to the temporary directory
$currentDir = getcwd();
if ( ! @chdir($this->_options['temp_dir'])) {
throw new Sensei_Doc_Renderer_Exception('Could not change to temporary directory.');
}
if ($this->_options['lock']) {
$lockFile = $this->tmpFilename . '.lock';
// Check if lock exists
if (file_exists($lockFile)) {
throw new Sensei_Doc_Renderer_Exception('Pdf is being generated at the moment.');
}
// Create a lock (just an empty file)
if (($fp = @fopen($lockFile, 'w')) === false) {
throw new Sensei_Doc_Renderer_Exception('Could not create a lock file.');
}
fclose($fp);
}
$latexRenderer = new Sensei_Doc_Renderer_Latex($this->_toc);
// Set the options of the Latex renderer to be the same as this instance
// of PDF renderer.
foreach ($this->_options as $option => $value) {
try {
$latexRenderer->setOption($option, $value);
} catch (Exception $e){
// Do nothing. Latex renderer does not have all options of PDF
// renderer.
}
}
// Render the wiki source to latex
$latex = $latexRenderer->render();
// Open a temporary file for writing the latex source to
if ( ! @file_put_contents($this->tmpFilename . '.tex', $latex, LOCK_EX)) {
$this->_cleanUp(); // delete temporary files
throw new Sensei_Doc_Renderer_Exception('Could not write latex source to a temporary file.');
}
// Run pdfLaTeX to create the PDF file.
$command = $this->_options['pdflatex_path'] . ' -interaction=nonstopmode '
. $this->tmpFilename . '.tex';
exec($command);
// Second run generates table of contents
exec($command);
// Since table of contents is multiple pages long, we need a third run
// in order to fix incorrect page numbers in table of contents
exec($command);
// Read the generated PDF file
$pdf = @file_get_contents($this->tmpFilename . '.pdf');
if ($pdf === false) {
$this->_cleanUp(); // delete temporary files
throw new Sensei_Doc_Renderer_Exception('An error occured during the Latex to PDF conversion.');
}
// Delete temporary files
$this->_cleanUp();
// Remove lock file
if ($this->_options['lock']) {
@unlink($lockFile);
}
// Switch back to the previous working directory
chdir($currentDir);
return $pdf;
}
}
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://sourceforge.net/projects/sensei>.
*/
/**
* Sensei_Doc_Renderer_Xhtml
*
* @package Sensei_Doc
* @category Documentation
* @license http://www.gnu.org/licenses/lgpl.txt LGPL
* @link http://sourceforge.net/projects/sensei
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @version $Revision$
* @since 1.0
*/
class Sensei_Doc_Renderer_Xhtml extends Sensei_Doc_Renderer
{
/**
* Available options
*
* (Sensei_Doc_Section|null) section :
* Section to be rendered. If null all sections will be rendered.
*
* (string) url_prefix :
* All URLs pointing to sections will be prefixed with this.
*/
protected $_options = array(
'section' => null,
'url_prefix' => ''
);
public function __construct(Sensei_Doc_Toc $toc, array $options = array())
{
parent::__construct($toc, $options);
$this->_wiki->setRenderConf('xhtml', 'Doclink', 'url_callback', array(&$this, 'makeUrl'));
}
/**
* Renders table of contents as nested unordered lists.
*
* @return string rendered table of contents
*/
public function renderToc()
{
return $this->_renderToc($this->_toc);
}
/**
* Renders table of contents recursively as nested unordered lists.
*
* @param $section Sensei_Doc_Toc|Sensei_Doc_Section
* @return string rendered table of contents
*/
protected function _renderToc($section)
{
$output = '';
if ($section instanceof Sensei_Doc_Toc) {
$class = ' class="tree"';
} elseif ($section !== $this->_options['section']) {
$class = ' class="closed"';
} else {
$class = '';
}
$output .= '<ul' . $class . '>' . "\n";
for ($i = 0; $i < $section->count(); $i++) {
$child = $section->getChild($i);
$text = $child->getIndex() . ' ' . $child->getName();
$href = $this->makeUrl($child);
$output .= '<li><a href="' . $href . '">' . $text . '</a>';
if ($child->count() > 0) {
$output .= "\n";
$output .= $this->_renderToc($child);
}
$output .= '</li>' . "\n";
}
$output .= '</ul>' . "\n";
return $output;
}
/**
* Renders section defined by 'section' option. If 'section' option is not
* set, renders all sections.
*
* @return string rendered sections
*/
public function render()
{
$section = $this->_options['section'];
if ($section instanceof Sensei_Doc_Section) {
$content = $this->_renderSection($section);
} else {
// No section was set, so let's render all sections
$content = '';
for ($i = 0; $i < count($this->_toc); $i++) {
$content .= $this->_renderSection($this->_toc->getChild($i));
}
}
$output = $this->_options['template'];
$output = str_replace('%TITLE%', $this->_options['title'], $output);
$output = str_replace('%AUTHOR%', $this->_options['author'], $output);
$output = str_replace('%SUBJECT%', $this->_options['subject'], $output);
$output = str_replace('%KEYWORDS%', $this->_options['keywords'], $output);
$output = str_replace('%TOC%', $this->renderToc(), $output);
$output = str_replace('%CONTENT%', $content, $output);
return $output;
}
/**
* Renders a sections and its children
*
* @param $section Sensei_Doc_Section section to be rendered
* @return string rendered sections
*/
protected function _renderSection(Sensei_Doc_Section $section)
{
$output = '';
$title = $section->getIndex() . ' ' . $section->getName();
$level = $section->getLevel();
if ($level === 1) {
$class = ' class="chapter"';
$title = 'Chapter ' . $title;
} else {
$class = ' class="section"';
}
$output .= '<div' . $class .'>' . "\n";
$output .= "<h$level>";
if ( ! ($this->_options['section'] instanceof Sensei_Doc_Section)
|| ($level > $this->_options['section']->getLevel())) {
$anchor = $this->makeAnchor($section);
$output .= '<a href="#' . $anchor . '" id="' . $anchor . '">';
$output .= $title . '</a>';
} else {
$output .= $title;
}
$output .= "</h$level>";
// Transform section contents from wiki syntax to XHTML
$output .= $this->_wiki->transform($section->getText());
// Render children of this section recursively
for ($i = 0; $i < count($section); $i++) {
$output .= $this->_renderSection($section->getChild($i));
}
$output .= '</div>' . "\n";
return $output;
}
public function makeUrl(Sensei_Doc_Section $section)
{
$url = $this->_options['url_prefix'];
if ($this->_options['section'] instanceof Sensei_Doc_Section) {
$path = $section->getPath();
$level = $this->_options['section']->getLevel();
$url .= implode(':', array_slice(explode(':', $path), 0, $level));
}
$anchor = $this->makeAnchor($section);
if ($anchor !== '') {
$url .= '#' . $anchor;
}
return $url;
}
public function makeAnchor(Sensei_Doc_Section $section)
{
$path = $section->getPath();
if ($this->_options['section'] instanceof Sensei_Doc_Section) {
$level = $this->_options['section']->getLevel();
return implode(':', array_slice(explode(':', $path), $level));
} else {
return $path;
}
}
}
......@@ -1007,9 +1007,10 @@ class Text_Wiki {
}
if ($this->renderingType == 'preg') {
$this->output = preg_replace_callback('/'.$this->delim.'(\d+)'.$this->delim.'/',
$this->output .= preg_replace_callback('/'.$this->delim.'(\d+)'.$this->delim.'/',
array(&$this, '_renderToken'),
$this->source);
/*
//Damn strtok()! Why does it "skip" empty parts of the string. It's useless now!
} elseif ($this->renderingType == 'strtok') {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment