You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

328 lines
11 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
function wikiplugin_mwtable_info()
{
return [
'name' => tra('MediaWiki Table'),
'documentation' => 'PluginMWTable',
'description' => tra('Display a table using MediaWiki syntax'),
'prefs' => [ 'wikiplugin_mwtable' ],
'body' => tra('URL'),
'validate' => 'all',
'iconname' => 'table',
'introduced' => 3,
'tags' => ['experimental'],
'params' => [
'fancy' => [
'safe' => true,
'required' => false,
'name' => tra('Fancy'),
'description' => tr('Set to true to apply additional formatting to the table (header style, odd/even
rows, etc.). Takes precedence over the %0wiki_classes%1 parameter.', '<code>', '</code>'),
'since' => '3.0',
'default' => 'false',
'filter' => 'word',
'options' => [
['text' => '', 'value' => ''],
['text' => tra('True'), 'value' => 'true'],
['text' => tra('False'), 'value' => 'false']
]
],
'wiki_classes' => [
'safe' => true,
'required' => false,
'name' => tra('Wiki Classes'),
'description' => tra('Determines whether wiki style classes will be used for the table and cells
(used by default)'),
'since' => '3.0',
'default' => 'true',
'filter' => 'word',
'options' => [
['text' => '', 'value' => ''],
['text' => tra('True'), 'value' => 'true'],
['text' => tra('False'), 'value' => 'false']
]
]
]
];
}
function wikiplugin_mwtable($data, $params)
{
global $tikilib;
// Parse the parameters
extract($params, EXTR_SKIP);
if (isset($fancy) and $fancy == "true") {
$fancy = true;
} else {
$fancy = false;
}
if (isset($wiki_classes) and $wiki_classes == "false") {
$wiki_classes = false;
} else {
$wiki_classes = true;
}
// set class constants
$default_class_table = "normal";
$default_class_heading = "";
$default_class_td_odd = "";
$default_class_td_odd = "";
if ($fancy) {
$default_class_table = "normal";
$default_class_heading = "heading";
$default_class_td_odd = "odd";
$default_class_td_even = "even";
} elseif ($wiki_classes) {
$default_class_table = "wikitable";
$default_class_td_odd = "wikicell";
$default_class_td_even = "wikicell";
}
// soe = start-of-element; eoe = end-of-element
// set the start position
$soe = 0;
// <table>: prefix = start-of-string, suffix = "\n"
$suffix = "\n";
$eoe = strpos($data, $suffix);
// we only have attributes
$element = substr($data, $soe, $eoe - strlen($suffix));
$attributes = _get_attributes($element);
_check_class_attribute($attributes, $default_class_table);
$wret .= _output_tag_with_attributes("table", $attributes, true);
// move soe - skip terminating suffix
$soe = $eoe + strlen($suffix);
// <table>: end (of start tag)
// <caption>: prefix = "|+", suffix = "\n"
$prefix = "|+";
$suffix = "\n";
if (substr($data, $soe, strlen($prefix)) == $prefix) {
$eoe = strpos($data, $suffix, $soe);
$element = substr($data, $soe + strlen($prefix), $eoe - $soe - strlen($prefix) - strlen($suffix));
if (strpos($element, "|")) {
// attributes present
list($attribs, $text) = explode("|", $element, 2);
$attributes = _get_attributes($attribs);
$wret .= _output_tag_with_attributes("caption", $attributes, true);
$wret .= trim($text);
} else {
$wret .= "<caption>" . trim($element);
}
$wret .= "</caption>\n";
// move soe - skip terminating suffix
$soe = $eoe + strlen($suffix);
}
// <caption>: end
// <col>: prefix = "?", suffix = "!" or "|-"
$prefix = "?";
$suffix = "!";
if (substr($data, $soe, strlen($prefix)) == $prefix) {
// the end of the column data is the start of the headings
// or the start of the rows
$pos_headings = strpos($data, "!", $soe);
$pos_rows = strpos($data, "|-", $soe);
if ($pos_headings) {
//assume if headings present they precede any row
$eoe = $pos_headings;
} else {
// assume element delimited by first row
$suffix = "|-";
$eoe = $pos_rows;
}
$element = substr($data, $soe + strlen($prefix), $eoe - $soe - strlen($prefix) - strlen($suffix));
// convert "??" to "\n?" to simplify splitting
$element = str_replace("??", "\n?", $element);
$columns = explode("?", $element);
foreach ($columns as $column) {
// we only have attributes
$attributes = _get_attributes($column);
$wret .= _output_tag_with_attributes("col", $attributes, true, true);
}
// move soe - keep terminating string
$soe = $eoe;
}
// <col>: end
// <th>: prefix = "!", suffix = "|-"
$prefix = "!";
$suffix = "|-";
if (substr($data, $soe, strlen($prefix)) == $prefix) {
// the end of the heading data is the start of the first row
$eoe = strpos($data, "|-", $soe);
$element = substr($data, $soe + strlen($prefix), $eoe - $soe - strlen($prefix) - strlen($suffix));
// convert "!!" to "\n!" to simplify splitting
$element = str_replace("!!", "\n!", $element);
$columns = explode("!", $element);
$wret .= "<tr>\n";
foreach ($columns as $column) {
// each column can have attributes and/or text
if (strpos($column, "|")) {
list($attribs, $text) = explode("|", $column, 2);
$attributes = _get_attributes($attribs);
_check_class_attribute($attributes, $default_class_headings);
$wret .= _output_tag_with_attributes("th", $attributes);
$wret .= trim($text);
} else {
// only one part so use as heading
$wret .= "<th>" . trim($column);
}
$wret .= "</th>\n";
}
$wret .= "</tr>\n";
// move soe - keep terminating "|-"
$soe = $eoe;
}
// <th>: end
// <tr>: prefix = "|-", suffix = "|-" or end-of-data
// skip over prefix for first row
$prefix = "|-";
$rows = explode($prefix, substr($data, $soe + strlen($prefix)));
$row_is_odd = true;
foreach ($rows as $row) {
// each row
if ($row_is_odd) {
$default_class_td = $default_class_td_odd;
} else {
$default_class_td = $default_class_td_even;
}
$row_is_odd = ! $row_is_odd;
// the end of row attributes is the end of the line/start of cell
$suffix = "\n|";
$eoe = strpos($row, $suffix);
$attribs = substr($row, 0, $eoe - strlen($suffix));
$attributes = _get_attributes($attribs);
$wret .= _output_tag_with_attributes("tr", $attributes, true);
// extract just the data for the cells - skip prefix of first cell
$soe = $eoe + strlen($suffix);
$row_cells = substr($row, $soe);
// the cells
$prefix = "\n|";
// convert "||" to "\n|" to simplify splitting
$row_cells = str_replace("||", $prefix, $row_cells);
// get cells - skip over prefix of first cell
$cells = explode($prefix, $row_cells);
foreach ($cells as $cell) {
if (strpos($cell, "|")) {
list($attribs, $text) = explode("|", $cell, 2);
$attributes = _get_attributes($attribs);
} else {
// only one part so use as text
$attributes = [];
$text = $cell;
}
_check_class_attribute($attributes, $default_class_td);
$wret .= _output_tag_with_attributes("td", $attributes);
$wret .= trim($text);
// end of cell
$wret .= "</td>\n";
}
// end the row
$wret .= "</tr>\n";
}
// End the table
$wret .= "</table>\n";
return $wret;
}
// We need a function to parse attributes as wiki syntax rules do
// funny things to the data.
// % needs to be enclosed in double-quotes to not be a dynamic variable
// double-quotes have become &quot; which is no good for an html attribute
//
// Return an associative array where value has had any delimiters removed.
function _get_attributes($string)
{
$attributes = [];
$cur_pos = 0;
while ($cur_pos < strlen($string)) {
// identify key
if (preg_match("/\s*(\w+)=/", $string, $matches, PREG_OFFSET_CAPTURE, $cur_pos)) {
$cur_pos += strlen($matches[0][0]); // skip whole pattern
$key = $matches[1][0]; // just store key
// identify value:
// use # as start/end character inclusion of / in value
if (preg_match("#([(&quot;)\"'\w:;%-/\.]+)(?=\s|\Z)#", $string, $matches, PREG_OFFSET_CAPTURE, $cur_pos)) {
$cur_pos += strlen($matches[0][0]); // skip whole pattern
$value = $matches[1][0]; // just store value
// remove delimiters (quote or double-quote if present)
$value = str_replace("'", "", $value);
$value = str_replace("&quot;", "", $value);
} else {
$value = substr($string, $cur_pos);
$cur_pos = strlen($string);
}
$attributes[$key] = $value;
} else {
$cur_pos = strlen($string);
}
}
return $attributes;
}
// If terminate_tag==False return in the form <tag attribute="value">
// If terminate_tag==True return in the form <tag attribute="value"/>
// The latter is only applicable to a few tags like <col>.
function _output_tag_with_attributes($tag, $attributes, $newline = false, $terminate_tag = false)
{
$output = "<" . $tag;
if (count($attributes)) {
foreach ($attributes as $key => $value) {
$output .= " " . $key . "=\"" . $value . "\"";
}
}
if ($terminate_tag) {
$output .= "/";
}
$output .= ">";
if ($newline) {
$output .= "\n";
}
return $output;
}
// Check the class element.
// if $add==True add default class to any existing class else replace
function _check_class_attribute(&$attributes, $default_class = "", $add = true)
{
// if no default class then nothing to do
if (strlen($default_class) == 0) {
return;
}
$class = $default_class;
if ($add and (array_key_exists("class", $attributes))) {
$class .= " " . $attributes["class"];
}
$attributes["class"] = $class;
}