summaryrefslogtreecommitdiff
path: root/inc/parser
diff options
context:
space:
mode:
Diffstat (limited to 'inc/parser')
-rw-r--r--inc/parser/handler.php130
-rw-r--r--inc/parser/lexer.php2
-rw-r--r--inc/parser/metadata.php5
-rw-r--r--inc/parser/parser.php6
-rw-r--r--inc/parser/renderer.php29
-rw-r--r--inc/parser/xhtml.php109
6 files changed, 171 insertions, 110 deletions
diff --git a/inc/parser/handler.php b/inc/parser/handler.php
index 9fe5866ad..0b8b79254 100644
--- a/inc/parser/handler.php
+++ b/inc/parser/handler.php
@@ -12,15 +12,12 @@ class Doku_Handler {
var $status = array(
'section' => false,
- 'section_edit_start' => -1,
- 'section_edit_level' => 1,
- 'section_edit_title' => ''
);
var $rewriteBlocks = true;
function Doku_Handler() {
- $this->CallWriter = & new Doku_Handler_CallWriter($this);
+ $this->CallWriter = new Doku_Handler_CallWriter($this);
}
function _addCall($handler, $args, $pos) {
@@ -40,14 +37,10 @@ class Doku_Handler {
if ( $this->status['section'] ) {
$last_call = end($this->calls);
array_push($this->calls,array('section_close',array(), $last_call[2]));
- if ($this->status['section_edit_start']>1) {
- // ignore last edit section if there is only one header
- array_push($this->calls,array('section_edit',array($this->status['section_edit_start'], 0, $this->status['section_edit_level'], $this->status['section_edit_title']), $last_call[2]));
- }
}
if ( $this->rewriteBlocks ) {
- $B = & new Doku_Handler_Block();
+ $B = new Doku_Handler_Block();
$this->calls = $B->process($this->calls);
}
@@ -97,8 +90,6 @@ class Doku_Handler {
}
function header($match, $state, $pos) {
- global $conf;
-
// get level and title
$title = trim($match);
$level = 7 - strspn($title,'=');
@@ -108,13 +99,6 @@ class Doku_Handler {
if ($this->status['section']) $this->_addCall('section_close',array(),$pos);
- if ($level<=$conf['maxseclevel']) {
- $this->_addCall('section_edit',array($this->status['section_edit_start'], $pos-1, $this->status['section_edit_level'], $this->status['section_edit_title']), $pos);
- $this->status['section_edit_start'] = $pos;
- $this->status['section_edit_level'] = $level;
- $this->status['section_edit_title'] = $title;
- }
-
$this->_addCall('header',array($title,$level,$pos), $pos);
$this->_addCall('section_open',array($level),$pos);
@@ -212,7 +196,7 @@ class Doku_Handler {
$this->_footnote = true;
- $ReWriter = & new Doku_Handler_Nest($this->CallWriter,'footnote_close');
+ $ReWriter = new Doku_Handler_Nest($this->CallWriter,'footnote_close');
$this->CallWriter = & $ReWriter;
$this->_addCall('footnote_open', array(), $pos);
break;
@@ -240,7 +224,7 @@ class Doku_Handler {
function listblock($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = & new Doku_Handler_List($this->CallWriter);
+ $ReWriter = new Doku_Handler_List($this->CallWriter);
$this->CallWriter = & $ReWriter;
$this->_addCall('list_open', array($match), $pos);
break;
@@ -302,7 +286,7 @@ class Doku_Handler {
function preformatted($match, $state, $pos) {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = & new Doku_Handler_Preformatted($this->CallWriter);
+ $ReWriter = new Doku_Handler_Preformatted($this->CallWriter);
$this->CallWriter = & $ReWriter;
$this->_addCall('preformatted_start',array(), $pos);
break;
@@ -328,7 +312,7 @@ class Doku_Handler {
switch ( $state ) {
case DOKU_LEXER_ENTER:
- $ReWriter = & new Doku_Handler_Quote($this->CallWriter);
+ $ReWriter = new Doku_Handler_Quote($this->CallWriter);
$this->CallWriter = & $ReWriter;
$this->_addCall('quote_start',array($match), $pos);
break;
@@ -360,21 +344,16 @@ class Doku_Handler {
function code($match, $state, $pos, $type='code') {
if ( $state == DOKU_LEXER_UNMATCHED ) {
$matches = explode('>',$match,2);
- $matches[0] = trim($matches[0]);
-
- list($language,$filename) = explode(' ',$matches[0],2);
- $language = trim($language);
- $filename = trim($filename);
- if ( $language == '' ) $language = null;
- if ( $language == '-' ) $language = null;
- if ( $filename == '' ) $filename = null;
- # We shortcut html here.
- if($language == 'html') $language = 'html4strict';
- $this->_addCall(
- $type,
- array($matches[1],$language,$filename),
- $pos
- );
+
+ $param = preg_split('/\s+/', $matches[0], 2, PREG_SPLIT_NO_EMPTY);
+ while(count($param) < 2) array_push($param, null);
+
+ // We shortcut html here.
+ if ($param[0] == 'html') $param[0] = 'html4strict';
+ if ($param[0] == '-') $param[0] = null;
+ array_unshift($param, $matches[1]);
+
+ $this->_addCall($type, $param, $pos);
}
return true;
}
@@ -580,10 +559,10 @@ class Doku_Handler {
case DOKU_LEXER_ENTER:
- $ReWriter = & new Doku_Handler_Table($this->CallWriter);
+ $ReWriter = new Doku_Handler_Table($this->CallWriter);
$this->CallWriter = & $ReWriter;
- $this->_addCall('table_start', array(), $pos);
+ $this->_addCall('table_start', array($pos + 1), $pos);
if ( trim($match) == '^' ) {
$this->_addCall('tableheader', array(), $pos);
} else {
@@ -592,7 +571,7 @@ class Doku_Handler {
break;
case DOKU_LEXER_EXIT:
- $this->_addCall('table_end', array(), $pos);
+ $this->_addCall('table_end', array($pos), $pos);
$this->CallWriter->process();
$ReWriter = & $this->CallWriter;
$this->CallWriter = & $ReWriter->CallWriter;
@@ -1196,7 +1175,7 @@ class Doku_Handler_Table {
$this->tableStart($call);
break;
case 'table_row':
- $this->tableRowClose(array('tablerow_close',$call[1],$call[2]));
+ $this->tableRowClose($call);
$this->tableRowOpen(array('tablerow_open',$call[1],$call[2]));
break;
case 'tableheader':
@@ -1204,7 +1183,7 @@ class Doku_Handler_Table {
$this->tableCell($call);
break;
case 'table_end':
- $this->tableRowClose(array('tablerow_close',$call[1],$call[2]));
+ $this->tableRowClose($call);
$this->tableEnd($call);
break;
default:
@@ -1216,13 +1195,13 @@ class Doku_Handler_Table {
}
function tableStart($call) {
- $this->tableCalls[] = array('table_open',array(),$call[2]);
+ $this->tableCalls[] = array('table_open',$call[1],$call[2]);
$this->tableCalls[] = array('tablerow_open',array(),$call[2]);
$this->firstCell = true;
}
function tableEnd($call) {
- $this->tableCalls[] = array('table_close',array(),$call[2]);
+ $this->tableCalls[] = array('table_close',$call[1],$call[2]);
$this->finalizeTable();
}
@@ -1242,7 +1221,7 @@ class Doku_Handler_Table {
break;
}
}
- $this->tableCalls[] = $call;
+ $this->tableCalls[] = array('tablerow_close', array(), $call[2]);
if ( $this->currentCols > $this->maxCols ) {
$this->maxCols = $this->currentCols;
@@ -1287,6 +1266,7 @@ class Doku_Handler_Table {
// Adjust to num cols not num col delimeters
$this->tableCalls[0][1][] = $this->maxCols - 1;
$this->tableCalls[0][1][] = $this->maxRows;
+ $this->tableCalls[0][1][] = array_shift($this->tableCalls[0][1]);
} else {
trigger_error('First element in table call list is not table_open');
}
@@ -1299,19 +1279,24 @@ class Doku_Handler_Table {
// Look for the colspan elements and increment the colspan on the
// previous non-empty opening cell. Once done, delete all the cells
// that contain colspans
- foreach ( $this->tableCalls as $key => $call ) {
+ for ($key = 0 ; $key < count($this->tableCalls) ; ++$key) {
+ $call = $this->tableCalls[$key];
- if ( $call[0] == 'tablerow_open' ) {
+ switch ($call[0]) {
+ case 'tablerow_open':
$lastRow++;
$lastCell = 0;
+ break;
- } else if ( $call[0] == 'tablecell_open' || $call[0] == 'tableheader_open' ) {
+ case 'tablecell_open':
+ case 'tableheader_open':
$lastCell++;
$cellKey[$lastRow][$lastCell] = $key;
+ break;
- } else if ( $call[0] == 'table_align' ) {
+ case 'table_align':
$prev = in_array($this->tableCalls[$key-1][0], array('tablecell_open', 'tableheader_open'));
$next = in_array($this->tableCalls[$key+1][0], array('tablecell_close', 'tableheader_close'));
@@ -1335,8 +1320,9 @@ class Doku_Handler_Table {
// Now convert the whitespace back to cdata
$this->tableCalls[$key][0] = 'cdata';
+ break;
- } else if ( $call[0] == 'colspan' ) {
+ case 'colspan':
$this->tableCalls[$key-1][1][0] = false;
@@ -1356,8 +1342,9 @@ class Doku_Handler_Table {
$toDelete[] = $key-1;
$toDelete[] = $key;
$toDelete[] = $key+1;
+ break;
- } else if ( $call[0] == 'rowspan' ) {
+ case 'rowspan':
if ( $this->tableCalls[$key-1][0] == 'cdata' ) {
// ignore rowspan if previous call was cdata (text mixed with :::) we don't have to check next call as that wont match regex
@@ -1365,25 +1352,48 @@ class Doku_Handler_Table {
} else {
- $this->tableCalls[$key-1][1][2] = false;
-
+ $spanning_cell = null;
for($i = $lastRow-1; $i > 0; $i--) {
if ( $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tablecell_open' || $this->tableCalls[$cellKey[$i][$lastCell]][0] == 'tableheader_open' ) {
- if ( false !== $this->tableCalls[$cellKey[$i][$lastCell]][1][2] ) {
- $this->tableCalls[$cellKey[$i][$lastCell]][1][2]++;
+ if ($this->tableCalls[$cellKey[$i][$lastCell]][1][2] >= $lastRow - $i) {
+ $spanning_cell = $i;
break;
}
}
}
+ if (is_null($spanning_cell)) {
+ // No spanning cell found, so convert this cell to
+ // an empty one to avoid broken tables
+ $this->tableCells[$key][1][1] = '';
+ continue;
+ }
+ $this->tableCalls[$cellKey[$spanning_cell][$lastCell]][1][2]++;
+
+ $this->tableCalls[$key-1][1][2] = false;
$toDelete[] = $key-1;
$toDelete[] = $key;
- $toDelete[] = $key+1;
+ $toDelete[] = $key+1;
}
+ break;
+
+ case 'tablerow_close':
+
+ // Fix broken tables by adding missing cells
+ while (++$lastCell < $this->maxCols) {
+ array_splice($this->tableCalls, $key, 0, array(
+ array('tablecell_open', array(1, null, 1), $call[2]),
+ array('cdata', array(''), $call[2]),
+ array('tablecell_close', array(), $call[2])));
+ $key += 3;
+ }
+
+ break;
+
}
}
@@ -1504,13 +1514,7 @@ class Doku_Handler_Block {
//remove the whole paragraph
array_splice($this->calls,$i);
}else{
- if ($this->calls[count($this->calls)-1][0] == 'section_edit') {
- $tmp = array_pop($this->calls);
- $this->calls[] = array('p_close',array(), $pos);
- $this->calls[] = $tmp;
- } else {
- $this->calls[] = array('p_close',array(), $pos);
- }
+ $this->calls[] = array('p_close',array(), $pos);
}
$this->inParagraph = false;
diff --git a/inc/parser/lexer.php b/inc/parser/lexer.php
index afd260a05..211945d8f 100644
--- a/inc/parser/lexer.php
+++ b/inc/parser/lexer.php
@@ -295,7 +295,7 @@ class Doku_Lexer {
$this->_case = $case;
$this->_regexes = array();
$this->_parser = &$parser;
- $this->_mode = &new Doku_LexerStateStack($start);
+ $this->_mode = new Doku_LexerStateStack($start);
$this->_mode_handlers = array();
}
diff --git a/inc/parser/metadata.php b/inc/parser/metadata.php
index fc60e5774..f635ea1d5 100644
--- a/inc/parser/metadata.php
+++ b/inc/parser/metadata.php
@@ -334,8 +334,7 @@ class Doku_Renderer_metadata extends Doku_Renderer {
$this->_firstimage($name['src']);
if ($this->capture){
- if ($name) $this->doc .= $name;
- else $this->doc .= '<'.$url.'>';
+ $this->doc .= $this->_getLinkTitle($name, '<' . $url . '>');
}
}
@@ -345,7 +344,7 @@ class Doku_Renderer_metadata extends Doku_Renderer {
if ($this->capture){
list($wikiUri, $hash) = explode('#', $wikiUri, 2);
- $name = $this->_getLinkTitle($name, $wikiName.'>'.$wikiUri);
+ $name = $this->_getLinkTitle($name, $wikiUri);
$this->doc .= $name;
}
}
diff --git a/inc/parser/parser.php b/inc/parser/parser.php
index a78b08a29..435b8aa46 100644
--- a/inc/parser/parser.php
+++ b/inc/parser/parser.php
@@ -61,7 +61,7 @@ class Doku_Parser {
function addBaseMode(& $BaseMode) {
$this->modes['base'] = & $BaseMode;
if ( !$this->Lexer ) {
- $this->Lexer = & new Doku_Lexer($this->Handler,'base', true);
+ $this->Lexer = new Doku_Lexer($this->Handler,'base', true);
}
$this->modes['base']->Lexer = & $this->Lexer;
}
@@ -413,8 +413,8 @@ class Doku_Parser_Mode_listblock extends Doku_Parser_Mode {
}
function connectTo($mode) {
- $this->Lexer->addEntryPattern('\n {2,}[\-\*]',$mode,'listblock');
- $this->Lexer->addEntryPattern('\n\t{1,}[\-\*]',$mode,'listblock');
+ $this->Lexer->addEntryPattern('[ \t]*\n {2,}[\-\*]',$mode,'listblock');
+ $this->Lexer->addEntryPattern('[ \t]*\n\t{1,}[\-\*]',$mode,'listblock');
$this->Lexer->addPattern('\n {2,}[\-\*]','listblock');
$this->Lexer->addPattern('\n\t{1,}[\-\*]','listblock');
diff --git a/inc/parser/renderer.php b/inc/parser/renderer.php
index 6082e935d..7e52cfce2 100644
--- a/inc/parser/renderer.php
+++ b/inc/parser/renderer.php
@@ -49,6 +49,15 @@ class Doku_Renderer extends DokuWiki_Plugin {
trigger_error('getFormat() not implemented in '.get_class($this), E_USER_WARNING);
}
+ /**
+ * Allow the plugin to prevent DokuWiki from reusing an instance
+ *
+ * @return bool false if the plugin has to be instantiated
+ */
+ function isSingleton() {
+ return false;
+ }
+
//handle plugin rendering
function plugin($name,$data){
@@ -85,8 +94,6 @@ class Doku_Renderer extends DokuWiki_Plugin {
function header($text, $level, $pos) {}
- function section_edit($start, $end, $level, $name) {}
-
function section_open($level) {}
function section_close() {}
@@ -231,9 +238,9 @@ class Doku_Renderer extends DokuWiki_Plugin {
$src,$title=NULL,$align=NULL,$width=NULL,$height=NULL,$cache=NULL
) {}
- function table_open($maxcols = NULL, $numrows = NULL){}
+ function table_open($maxcols = NULL, $numrows = NULL, $pos){}
- function table_close(){}
+ function table_close($pos){}
function tablerow_open(){}
@@ -264,20 +271,12 @@ class Doku_Renderer extends DokuWiki_Plugin {
list($name,$hash) = explode('#',$name,2);
if($hash) return $hash;
- //trim colons or slash of a namespace link
- $name = rtrim($name,':');
- if($conf['useslash'])
- $name = rtrim($name,'/');
-
+ $name = strtr($name,';',':');
if($conf['useslash']){
- $nssep = '[:;/]';
- }else{
- $nssep = '[:;]';
+ $name = strtr($name,'/',':');
}
- $name = preg_replace('!.*'.$nssep.'!','',$name);
- if(!$name) return $this->_simpleTitle($conf['start']);
- return $name;
+ return noNSorNS($name);
}
/**
diff --git a/inc/parser/xhtml.php b/inc/parser/xhtml.php
index 4d5333f7a..5a3d945d1 100644
--- a/inc/parser/xhtml.php
+++ b/inc/parser/xhtml.php
@@ -29,6 +29,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
var $doc = ''; // will contain the whole document
var $toc = array(); // will contain the Table of Contents
+ private $sectionedits = array(); // A stack of section edit data
var $headers = array();
var $footnotes = array();
@@ -39,6 +40,40 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
var $_counter = array(); // used as global counter, introduced for table classes
var $_codeblock = 0; // counts the code and file blocks, used to provide download links
+ /**
+ * Register a new edit section range
+ *
+ * @param $type string The section type identifier
+ * @param $title string The section title
+ * @param $start int The byte position for the edit start
+ * @return string A marker class for the starting HTML element
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ public function startSectionEdit($start, $type, $title = null) {
+ static $lastsecid = 0;
+ $this->sectionedits[] = array(++$lastsecid, $start, $type, $title);
+ return 'sectionedit' . $lastsecid;
+ }
+
+ /**
+ * Finish an edit section range
+ *
+ * @param $end int The byte position for the edit end; null for the rest of
+ the page
+ * @author Adrian Lang <lang@cosmocode.de>
+ */
+ public function finishSectionEdit($end = null) {
+ list($id, $start, $type, $title) = array_pop($this->sectionedits);
+ if (!is_null($end) && $end <= $start) {
+ return;
+ }
+ $this->doc .= "<!-- EDIT$id " . strtoupper($type) . ' ';
+ if (!is_null($title)) {
+ $this->doc .= '"' . str_replace('"', '', $title) . '" ';
+ }
+ $this->doc .= "[$start-" . (is_null($end) ? '' : $end) . '] -->';
+ }
+
function getFormat(){
return 'xhtml';
}
@@ -51,6 +86,17 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
}
function document_end() {
+ // Finish open section edits.
+ while (count($this->sectionedits) > 0) {
+ if ($this->sectionedits[count($this->sectionedits) - 1][1] <= 1) {
+ // If there is only one section, do not write a section edit
+ // marker.
+ array_pop($this->sectionedits);
+ } else {
+ $this->finishSectionEdit();
+ }
+ }
+
if ( count ($this->footnotes) > 0 ) {
$this->doc .= '<div class="footnotes">'.DOKU_LF;
@@ -106,6 +152,8 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
}
function header($text, $level, $pos) {
+ global $conf;
+
if(!$text) return; //skip empty headlines
$hid = $this->_headerToLink($text,true);
@@ -122,30 +170,24 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
}
$this->lastlevel = $level;
+ if ($level <= $conf['maxseclevel'] &&
+ count($this->sectionedits) > 0 &&
+ $this->sectionedits[count($this->sectionedits) - 1][2] === 'section') {
+ $this->finishSectionEdit($pos - 1);
+ }
+
// write the header
- $this->doc .= DOKU_LF.'<h'.$level.'><a name="'.$hid.'" id="'.$hid.'">';
+ $this->doc .= DOKU_LF.'<h'.$level;
+ if ($level <= $conf['maxseclevel']) {
+ $this->doc .= ' class="' . $this->startSectionEdit($pos, 'section', $text) . '"';
+ }
+ $this->doc .= '><a name="'.$hid.'" id="'.$hid.'">';
$this->doc .= $this->_xmlEntities($text);
$this->doc .= "</a></h$level>".DOKU_LF;
}
- /**
- * Section edit marker is replaced by an edit button when
- * the page is editable. Replacement done in 'inc/html.php#html_secedit'
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @author Ben Coburn <btcoburn@silicodon.net>
- */
- function section_edit($start, $end, $level, $name) {
- global $conf;
-
- if ($start!=-1 && $level<=$conf['maxseclevel']) {
- $name = str_replace('"', '', $name);
- $this->doc .= '<!-- SECTION "'.$name.'" ['.$start.'-'.(($end===0)?'':$end).'] -->';
- }
- }
-
function section_open($level) {
- $this->doc .= "<div class=\"level$level\">".DOKU_LF;
+ $this->doc .= '<div class="level' . $level . '">' . DOKU_LF;
}
function section_close() {
@@ -400,6 +442,13 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$this->doc .= '</a></dt>'.DOKU_LF.'<dd>';
}
+ if ($text{0} == "\n") {
+ $text = substr($text, 1);
+ }
+ if (substr($text, -1) == "\n") {
+ $text = substr($text, 0, -1);
+ }
+
if ( is_null($language) ) {
$this->doc .= '<pre class="'.$type.'">'.$this->_xmlEntities($text).'</pre>'.DOKU_LF;
} else {
@@ -517,6 +566,14 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
function internallink($id, $name = NULL, $search=NULL,$returnonly=false,$linktype='content') {
global $conf;
global $ID;
+
+ $params = '';
+ $parts = explode('?', $id, 2);
+ if (count($parts) === 2) {
+ $id = $parts[0];
+ $params = $parts[1];
+ }
+
// default name is based on $id as given
$default = $this->_simpleTitle($id);
@@ -550,7 +607,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
}
$link['more'] = '';
$link['class'] = $class;
- $link['url'] = wl($id);
+ $link['url'] = wl($id, $params);
$link['name'] = $name;
$link['title'] = $id;
//add search string
@@ -845,14 +902,16 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
}
// $numrows not yet implemented
- function table_open($maxcols = NULL, $numrows = NULL){
+ function table_open($maxcols = NULL, $numrows = NULL, $pos){
+ global $lang;
// initialize the row counter used for classes
$this->_counter['row_counter'] = 0;
- $this->doc .= '<table class="inline">'.DOKU_LF;
+ $this->doc .= '<div class="table ' . $this->startSectionEdit($pos, 'table') . '"><table class="inline">'.DOKU_LF;
}
- function table_close(){
- $this->doc .= '</table>'.DOKU_LF;
+ function table_close($pos){
+ $this->doc .= '</table></div>'.DOKU_LF;
+ $this->finishSectionEdit($pos);
}
function tablerow_open(){
@@ -966,7 +1025,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
}elseif($ext == 'jpg' || $ext == 'jpeg'){
//try to use the caption from IPTC/EXIF
require_once(DOKU_INC.'inc/JpegMeta.php');
- $jpeg =& new JpegMeta(mediaFN($src));
+ $jpeg =new JpegMeta(mediaFN($src));
if($jpeg !== false) $cap = $jpeg->getTitle();
if($cap){
$title = $this->_xmlEntities($cap);
@@ -1019,7 +1078,7 @@ class Doku_Renderer_xhtml extends Doku_Renderer {
$att['class'] = "media$align";
if($align == 'right') $att['align'] = 'right';
if($align == 'left') $att['align'] = 'left';
- $ret .= html_flashobject(ml($src,array('cache'=>$cache)),$width,$height,
+ $ret .= html_flashobject(ml($src,array('cache'=>$cache),true,'&'),$width,$height,
array('quality' => 'high'),
null,
$att,