diff --git a/_test/helper.test.php b/_test/helper.test.php index c85c59e..9be35c3 100644 --- a/_test/helper.test.php +++ b/_test/helper.test.php @@ -133,6 +133,18 @@ function testFormatData() { $helper = new helper_plugin_data(); $renderer = new data_dummy_renderer(); + $dwVersion = getVersionData(); + + $matchString = 'http://www.dokuwiki.org'; + if(isset($dwVersion['date'])) + { + preg_match('/(\d+)-(\d+)-(\d+)/',$dwVersion['date'],$dwDate); + if(mktime(0, 0, 0, $dwDate[2], $dwDate[3], $dwDate[1]) > mktime(0, 0, 0, 7, 30, 2015)) + { + $matchString = 'http://www.dokuwiki.org'; + } + } + $this->assertEquals('value1, value2, val', $helper->_formatData(array('type' => ''), "value1\n value2\n val", $renderer)); @@ -156,16 +168,20 @@ function testFormatData() { $helper->_formatData(array('type' => 'mail'), "pa:ge some user", $renderer)); $conf['mailguard'] = 'visible'; - $this->assertEquals('pa:ge', + $this->assertEquals('pa:ge', $helper->_formatData(array('type' => 'mail'), "pa:ge", $renderer)); - $this->assertEquals('some user', + $this->assertEquals('some user', $helper->_formatData(array('type' => 'mail'), "pa:ge some user", $renderer)); - $this->assertEquals('url', + $this->assertEquals('url', $helper->_formatData(array('type' => 'url'), "url", $renderer)); - $this->assertEquals('value', + // This test's output is different across dokuwiki versions (order of arguments) + $this->assertEquals($matchString, + $helper->_formatData(array('type' => 'url'), "http://www.dokuwiki.org", $renderer)); + + $this->assertEquals('link: ?dataflt%5B0%5D=_%3Dvalue value', $helper->_formatData(array('type' => 'tag'), "value", $renderer)); $this->assertEquals(strftime('%Y/%m/%d %H:%M', 1234567), diff --git a/helper.php b/helper.php index 51752b8..b7bbec4 100644 --- a/helper.php +++ b/helper.php @@ -212,15 +212,37 @@ public function ensureAbsoluteId($id) { return $id; } + /** + * Return formated data, depending on column type and DokuWiki version + * + * @param array $column + * @param string $value + * @param Doku_Renderer $R + * @return string + */ + function _formatData($column, $value, Doku_Renderer $R) + { + $dwVersion = getVersionData(); + if(isset($dwVersion['date'])) + { + preg_match('/(\d+)-(\d+)-(\d+)/',$dwVersion['date'],$dwDate); + if(mktime(0, 0, 0, $dwDate[2], $dwDate[3], $dwDate[1]) > mktime(0, 0, 0, 7, 30, 2015)) + { + return $this->_formatDataNew($column, $value, $R); + } + } + return $this->_formatDataOld($column, $value, $R); + } + /** * Return XHTML formated data, depending on column type * - * @param array $column - * @param string $value - * @param Doku_Renderer_xhtml $R + * @param array $column + * @param string $value + * @param Doku_Renderer $R * @return string */ - function _formatData($column, $value, Doku_Renderer_xhtml $R) { + function _formatDataOld($column, $value, Doku_Renderer $R) { global $conf; $vals = explode("\n", $value); $outs = array(); @@ -275,6 +297,7 @@ function _formatData($column, $value, Doku_Renderer_xhtml $R) { list($id, $title) = explode(' ', $val, 2); $id = $this->_addPrePostFixes($column['type'], $id); $id = obfuscate(hsc($id)); + $titleId = $id; if(!$title) { $title = $id; } else { @@ -283,11 +306,21 @@ function _formatData($column, $value, Doku_Renderer_xhtml $R) { if($conf['mailguard'] == 'visible') { $id = rawurlencode($id); } - $outs[] = '' . $title . ''; + $outs[] = '' . $title . ''; break; case 'url': $val = $this->_addPrePostFixes($column['type'], $val); - $outs[] = $this->external_link($val, false, 'urlextern'); + $url = $val; + $schemes = getSchemes(); + list($scheme) = explode('://', $url); + if(!in_array($scheme, $schemes)) $url = ''; + + // is there still an URL? + if(!$url) { + $outs[] = $val; + } else { + $outs[] = $this->external_link($val, false, 'urlextern'); + } break; case 'tag': // per default use keyname as target page, but prefix on aliases @@ -296,10 +329,9 @@ function _formatData($column, $value, Doku_Renderer_xhtml $R) { } else { $target = $this->_addPrePostFixes($column['type'], ''); } - - $outs[] = '' . hsc($val) . ''; + $params = buildURLparams($this->_getTagUrlparam($column, $val)); + $url = str_replace('/', ':', cleanID($target)) . '?' . $params; + $outs[] = $R->internallink($url, hsc($val), true); break; case 'timestamp': $outs[] = dformat($val); @@ -363,6 +395,156 @@ function _formatData($column, $value, Doku_Renderer_xhtml $R) { return join(', ', $outs); } + /** + * Return formated data, depending on column type + * + * @param array $column + * @param string $value + * @param Doku_Renderer $R + * @return string + */ + function _formatDataNew($column, $value, Doku_Renderer $R) { + global $conf; + $vals = explode("\n", $value); + $outs = array(); + + //multivalued line from db result for pageid and wiki has only in first value the ID + $storedID = ''; + + foreach($vals as $val) { + $val = trim($val); + if($val == '') continue; + + $type = $column['type']; + if(is_array($type)) { + $type = $type['type']; + } + switch($type) { + case 'page': + $val = $this->_addPrePostFixes($column['type'], $val); + $val = $this->ensureAbsoluteId($val); + $outs[] = $R->internallink($val, null, null, true); + break; + case 'title': + list($id, $title) = explode('|', $val, 2); + $id = $this->_addPrePostFixes($column['type'], $id); + $id = $this->ensureAbsoluteId($id); + $outs[] = $R->internallink($id, $title, null, true); + break; + case 'pageid': + list($id, $title) = explode('|', $val, 2); + + //use ID from first value of the multivalued line + if($title == null) { + $title = $id; + if(!empty($storedID)) { + $id = $storedID; + } + } else { + $storedID = $id; + } + + $id = $this->_addPrePostFixes($column['type'], $id); + + $outs[] = $R->internallink($id, $title, null, true); + break; + case 'nspage': + // no prefix/postfix here + $val = ':' . $column['key'] . ":$val"; + + $outs[] = $R->internallink($val, null, null, true); + break; + case 'mail': + list($id, $title) = explode(' ', $val, 2); + $id = $this->_addPrePostFixes($column['type'], $id); + if(!$title) { + $title = $id; + } else { + $title = hsc($title); + } + $outs[] = $R->emaillink($id, $title, true); + break; + case 'url': + $val = $this->_addPrePostFixes($column['type'], $val); + $outs[] = $R->externallink($val, null, true); + break; + case 'tag': + // per default use keyname as target page, but prefix on aliases + if(!is_array($column['type'])) { + $target = $column['key'] . ':'; + } else { + $target = $this->_addPrePostFixes($column['type'], ''); + } + + $params = buildURLparams($this->_getTagUrlparam($column, $val)); + $url = str_replace('/', ':', cleanID($target)) . '?' . $params; + // FIXME: The title is lost when moving to $R->internallink, + // but this syntax is required to support different renderers. + // $title = sprintf($this->getLang('tagfilter'), hsc($val)); + $outs[] = $R->internallink($url, hsc($val), true); + break; + case 'timestamp': + $outs[] = dformat($val); + break; + case 'wiki': + global $ID; + $oldid = $ID; + list($ID, $data) = explode('|', $val, 2); + + //use ID from first value of the multivalued line + if($data == null) { + $data = $ID; + $ID = $storedID; + } else { + $storedID = $ID; + } + $data = $this->_addPrePostFixes($column['type'], $data); + + // Trim document_{start,end}, p_{open,close} from instructions + $allinstructions = p_get_instructions($data); + $wraps = 1; + if(isset($allinstructions[1]) && $allinstructions[1][0] == 'p_open') { + $wraps ++; + } + $instructions = array_slice($allinstructions, $wraps, -$wraps); + + $outs[] = p_render($R->getFormat(), $instructions, $byref_ignore); + $ID = $oldid; + break; + default: + $val = $this->_addPrePostFixes($column['type'], $val); + //type '_img' or '_img' + if(substr($type, 0, 3) == 'img') { + $width = (int) substr($type, 3); + if(!$width) { + $width = $this->getConf('image_width'); + } + + list($mediaid, $title) = explode('|', $val, 2); + if($title === null) { + $title = $column['key'] . ': ' . basename(str_replace(':', '/', $mediaid)); + } else { + $title = trim($title); + } + + if(media_isexternal($val)) { + $html = $R->externalmedia($mediaid, $title, $align = null, $width, $height = null, $cache = null, $linking = 'direct', true); + } else { + $html = $R->internalmedia($mediaid, $title, $align = null, $width, $height = null, $cache = null, $linking = 'direct', true); + } + if(strpos($html, 'mediafile') === false) { + $html = str_replace('href', 'rel="lightbox" href', $html); + } + + $outs[] = $html; + } else { + $outs[] = hsc($val); + } + } + } + return join(', ', $outs); + } + /** * Split a column name into its parts * diff --git a/syntax/list.php b/syntax/list.php index c13d0b3..37fc6c3 100644 --- a/syntax/list.php +++ b/syntax/list.php @@ -20,50 +20,121 @@ function connectTo($mode) { $this->Lexer->addSpecialPattern('----+ *datalist(?: [ a-zA-Z0-9_]*)?-+\n.*?\n----+', $mode, 'plugin_data_list'); } - protected $before_item = '
  • '; - protected $after_item = '
  • '; - protected $before_val = ''; - protected $after_val = ' '; + /** + * Before item in list + * + * @param Doku_Renderer $R + */ + protected function before_item(Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= '
  • '; + break; + case 'odt': + $R->listitem_open(); + $R->listcontent_open(); + break; + } + } + + /** + * After item in list + * + * @param Doku_Renderer $R + */ + protected function after_item(Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= '
  • '; + break; + case 'odt': + $R->listcontent_close(); + $R->listitem_close(); + break; + } + } /** * Before value in listitem * - * @param array $data instructions by handler - * @param int $colno column number - * @return string + * @param string $class The CSS class + * @param Doku_Renderer $R */ - protected function beforeVal(&$data, $colno) { + protected function before_val($class, Doku_Renderer $R) + { + return; + } + + /** + * After value in listitem + * + * @param Doku_Renderer $R + */ + protected function after_val(Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= ' '; + break; + case 'odt': + $R->doc .= ' '; + break; + } + } + + /** + * Before value in listitem + * + * @param array $data instructions by handler + * @param int $colno column number + * @param string $class the xhtml class + * @param Doku_Renderer $R the current DokuWiki renderer + */ + protected function beforeVal(&$data, $colno, $class, Doku_Renderer $R) { if($data['sepbyheaders'] AND $colno === 0) { - return $data['headers'][$colno]; + $R->doc .= $data['headers'][$colno]; } else { - return $this->before_val; + $this->before_val($class, $R); } } /** * After value in listitem * - * @param array $data - * @param int $colno - * @return string + * @param array $data + * @param int $colno + * @param Doku_Renderer $R */ - protected function afterVal(&$data, $colno) { + protected function afterVal(&$data, $colno, Doku_Renderer $R) { if($data['sepbyheaders']) { - return $data['headers'][$colno + 1]; + $R->doc .= $data['headers'][$colno + 1]; } else { - return $this->after_val; + $this->after_val($R); } } /** * Create list header * - * @param array $clist keys of the columns - * @param array $data instruction by handler - * @return string html of table header + * @param array $clist keys of the columns + * @param array $data instruction by handler + * @param Doku_Renderer $R the current DokuWiki renderer */ - function preList($clist, $data) { - return '
    '; + break; + case 'odt': + $R->listu_close(); + break; + } } } diff --git a/syntax/table.php b/syntax/table.php index ef98106..9c79779 100644 --- a/syntax/table.php +++ b/syntax/table.php @@ -223,10 +223,80 @@ function handle($match, $state, $pos, Doku_Handler $handler) { return $data; } - protected $before_item = ''; - protected $after_item = ''; - protected $before_val = ''; - protected $after_val = ''; + /** + * Before item in list + * + * @param Doku_Renderer $R + */ + protected function before_item(Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= ''; + break; + case 'odt': + $R->tablerow_open(); + break; + } + } + + /** + * After item in list + * + * @param Doku_Renderer $R + */ + protected function after_item(Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= ''; + break; + case 'odt': + $R->tablerow_close(); + break; + } + } + + /** + * Before value in listitem + * + * @param string $class The CSS class + * @param Doku_Renderer $R + */ + protected function before_val($class, Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= sprintf("", $class); + break; + case 'odt': + $R->tablecell_open(); + $R->p_open(); + break; + } + } + + /** + * After value in listitem + * + * @param Doku_Renderer $R + */ + protected function after_val(Doku_Renderer $R) + { + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= ''; + break; + case 'odt': + $R->p_close(); + $R->tablecell_close(); + break; + } + } /** * Handles the actual output creation. @@ -237,7 +307,7 @@ function handle($match, $state, $pos, Doku_Handler $handler) { * @return boolean rendered correctly? (however, returned value is not used at the moment) */ function render($format, Doku_Renderer $R, $data) { - if($format != 'xhtml') return false; + if(($format != 'xhtml') && ($format != 'odt')) return false; /** @var Doku_Renderer_xhtml $R */ if(is_null($data)) return false; @@ -286,28 +356,27 @@ function render($format, Doku_Renderer $R, $data) { } //start table/list - $R->doc .= $this->preList($clist, $data); + $this->preList($clist, $data, $R); foreach($rows as $rownum => $row) { // build data rows - $R->doc .= $this->before_item; + $this->before_item($R); if($data['rownumbers']) { - $R->doc .= sprintf($this->before_val, 'class="' . $classes[0] . '"'); + $this->before_val('class="' . $classes[0] . '"', $R); $R->doc .= $rownum + 1; - $R->doc .= $this->after_val; + $this->after_val($R); } foreach(array_values($row) as $num => $cval) { $num_rn = $num + $offset; - $R->doc .= sprintf($this->beforeVal($data, $num_rn), 'class="' . $classes[$num_rn] . '"'); + $this->beforeVal($data, $num_rn, 'class="' . $classes[$num_rn] . '"', $R); $R->doc .= $this->dthlp->_formatData( $data['cols'][$clist[$num]], $cval, $R ); - $R->doc .= $this->afterVal($data, $num_rn); - + $this->afterVal($data, $num_rn, $R); // clean currency symbols $nval = str_replace('$€₤', '', $cval); $nval = str_replace('/ [A-Z]{0,3}$/', '', $nval); @@ -323,9 +392,9 @@ function render($format, Doku_Renderer $R, $data) { } } - $R->doc .= $this->after_item; + $this->after_item($R); } - $R->doc .= $this->postList($data, $cnt); + $this->postList($data, $cnt, $R); return true; } @@ -333,33 +402,34 @@ function render($format, Doku_Renderer $R, $data) { /** * Before value in table cell * - * @param array $data instructions by handler - * @param int $colno column number - * @return string + * @param array $data instructions by handler + * @param int $colno column number + * @param string $class the xhtml class + * @param Doku_Renderer $R the current DokuWiki renderer */ - protected function beforeVal(&$data, $colno) { - return $this->before_val; + protected function beforeVal(&$data, $colno, $class, Doku_Renderer $R) { + $this->before_val($class, $R); } /** * After value in table cell * - * @param array $data - * @param int $colno - * @return string + * @param array $data + * @param int $colno + * @param Doku_Renderer $R */ - protected function afterVal(&$data, $colno) { - return $this->after_val; + protected function afterVal(&$data, $colno, Doku_Renderer $R) { + $this->after_val($R); } /** * Create table header * - * @param array $clist keys of the columns - * @param array $data instruction by handler - * @return string html of table header + * @param array $clist keys of the columns + * @param array $data instruction by handler + * @param Doku_Renderer $R the current DokuWiki renderer */ - function preList($clist, $data) { + function preList($clist, $data, Doku_Renderer $R) { global $ID; global $conf; @@ -459,7 +529,32 @@ function preList($clist, $data) { $text .= ''; } - return $text; + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= $text; + break; + case 'odt': + $R->p_close(); + $ncols = count($data['headers']); + if($data['rownumbers']) + $ncols += 1; + $R->table_open($ncols); + $R->tablerow_open(); + if($data['rownumbers']) + { + $R->tableheader_open(); + $R->tableheader_close(); + } + foreach($data['headers'] as $num => $head) + { + $R->tableheader_open(); + $R->doc .= $head; + $R->tableheader_close(); + } + $R->tablerow_close(); + break; + } } /** @@ -469,24 +564,24 @@ function preList($clist, $data) { * @param array $clist keys of the columns * @param Doku_Renderer $R */ - function nullList($data, $clist, $R) { - $R->doc .= $this->preList($clist, $data); + function nullList($data, $clist, Doku_Renderer $R) { + $this->preList($clist, $data, $R); $R->tablerow_open(); $R->tablecell_open(count($clist), 'center'); $R->cdata($this->getLang('none')); $R->tablecell_close(); $R->tablerow_close(); - $R->doc .= ''; + $this->postList($data, 0, $R); } /** * Create table footer * - * @param array $data instruction by handler() - * @param int $rowcnt number of rows - * @return string html of table footer + * @param array $data instruction by handler() + * @param int $rowcnt number of rows + * @param Doku_Renderer $R the current DokuWiki renderer */ - function postList($data, $rowcnt) { + function postList($data, $rowcnt, Doku_Renderer $R) { global $ID; $text = ''; // if summarize was set, add sums @@ -550,7 +645,16 @@ function postList($data, $rowcnt) { } $text .= ''; - return $text; + + switch($R->getFormat()) + { + case 'xhtml': + $R->doc .= $text; + break; + case 'odt': + $R->table_close(); + break; + } } /**