function wikiplugin_fancytable($data, $params)
{
    global $prefs;
    $tagremove = array();
    $pluginremove = array();
    static $iFancytable = 0;
    ++$iFancytable;
    extract($params, EXTR_SKIP);
    if (empty($sortable)) {
        $sortable = 'n';
    }
    $msg = '';
    if (isset($sortable) && $sortable != 'n') {
        $ts = new Table_Plugin();
        if ($ts->perms !== false) {
            $ts->setSettings('fancytable_' . $iFancytable, 'n', $sortable, isset($sortList) ? $sortList : null, isset($tsortcolumns) ? $tsortcolumns : null, isset($tsfilters) ? $tsfilters : null, isset($tsfilteroptions) ? $tsfilteroptions : null, isset($tspaginate) ? $tspaginate : null);
        } else {
            $sort = false;
        }
        if (is_array($ts->settings)) {
            Table_Factory::build('plugin', $ts->settings);
            $sort = true;
        } else {
            $sort = false;
        }
        if ($sort === false) {
            if ($prefs['feature_jquery_tablesorter'] === 'n') {
                $msg = '<em>' . tra('The jQuery Sortable Tables feature must be activated for the sort feature to work.') . '</em>';
            } elseif ($prefs['disableJavascript'] === 'y') {
                $msg = '<em>' . tra('Javascript must be enabled for the sort feature to work.') . '</em>';
            } else {
                $msg = '<em>' . tra('Unable to load the jQuery Sortable Tables feature.') . '</em>';
            }
        }
    } else {
        $sort = false;
    }
    //Start the table
    $style = $sort === true ? ' style="visibility:hidden"' : '';
    $wret = '<div id="fancytable_' . $iFancytable . '"' . $style . '>' . "\r\t";
    $wret .= '<table class="normal" id="fancytable_' . $iFancytable . '_table">' . "\r\t";
    //Header
    if (isset($head)) {
        //set header class
        if (!empty($headclass)) {
            $tdhdr = "\r\t\t\t" . '<th class="' . $headclass . '"';
        } else {
            $tdhdr = "\r\t\t\t<th";
        }
        //replace tiki tags, plugins and other enclosing characters with hash strings before creating table so that any
        //pipes (| or ~|~) inside aren't mistaken for cell dividers
        preprocess_section($head, $tagremove, $pluginremove);
        if ($sort) {
            $type = 'hs';
        } else {
            $type = 'h';
        }
        //now create header table rows
        $headrows = process_section($head, $type, '>>', $tdhdr, '</th>', isset($colwidths) ? $colwidths : '', isset($headaligns) ? $headaligns : '', isset($headvaligns) ? $headvaligns : '');
        //restore original tags and plugin syntax
        postprocess_section($headrows, $tagremove, $pluginremove);
        $wret .= '<thead>' . $headrows . "\r\t" . '</thead>' . "\r\t" . '<tbody>';
    }
    //Body
    //replace tiki tags, plugins and other enclosing characters with hash strings before creating table so that any
    //pipes (| or ~|~) inside aren't mistaken for cell dividers
    preprocess_section($data, $tagremove, $pluginremove);
    if ($sort) {
        $type = 'bs';
        //sortable body rows - do not assign odd/even class to these since jquery will do it
    } else {
        $type = 'b';
        //plain body rows
    }
    //now create table body rows
    $bodyrows = process_section($data, $type, "\n", "\r\t\t\t" . '<td', '</td>', isset($colwidths) ? $colwidths : '', isset($colaligns) ? $colaligns : '', isset($colvaligns) ? $colvaligns : '');
    //restore original tags and plugin syntax
    postprocess_section($bodyrows, $tagremove, $pluginremove);
    $wret .= $bodyrows;
    //end the table
    if (isset($head)) {
        $wret .= "\r\t" . '</tbody>';
    }
    $wret .= "\r" . '</table></div>' . "\r" . $msg;
    return $wret;
}
function wikiplugin_fancytable($data, $params)
{
    global $prefs;
    $tagremove = array();
    $pluginremove = array();
    static $iFancytable = 0;
    ++$iFancytable;
    extract($params, EXTR_SKIP);
    if (empty($sortable)) {
        $sortable = 'n';
    }
    $msg = '';
    if (isset($sortable) && $sortable != 'n') {
        include_once 'lib/jquery_tiki/tablesorter/tablesorter-helper.php';
        $tshelper = new tablesorterHelper();
        $tshelper->createCode('fancytable_' . $iFancytable, $sortable, isset($sortList) ? $sortList : null, isset($tsfilters) ? $tsfilters : null, isset($tsfilteroptions) ? $tsfilteroptions : null, isset($tspaginate) ? $tspaginate : null);
        $sort = $tshelper->code !== false ? true : false;
        $tshelper->loadJq();
        if ($sort === false) {
            $msg = tra('The JQuery Sortable Tables feature must be activated for the sort feature to work.');
        }
    } else {
        $sort = false;
    }
    //Start the table
    $wret = '<table class="normal" id="fancytable_' . $iFancytable . '">' . "\r\t";
    //Header
    if (isset($head)) {
        //set header class
        if (!empty($headclass)) {
            $tdhdr = "\r\t\t\t" . '<th class="' . $headclass;
            if (!$sort) {
                $tdhdr .= '"';
            }
        } else {
            $tdhdr = "\r\t\t\t<th";
        }
        //replace tiki tags, plugins and other enclosing characters with hash strings before creating table so that any
        //pipes (| or ~|~) inside aren't mistaken for cell dividers
        preprocess_section($head, $tagremove, $pluginremove);
        if ($sort) {
            $type = 'hs';
        } else {
            $type = 'h';
        }
        //now create header table rows
        $headrows = process_section($head, $type, '>>', $tdhdr, '</th>', isset($colwidths) ? $colwidths : '', isset($headaligns) ? $headaligns : '', isset($headvaligns) ? $headvaligns : '', isset($tshelper) ? $tshelper : null);
        //restore original tags and plugin syntax
        postprocess_section($headrows, $tagremove, $pluginremove);
        $buttons = isset($tshelper) ? $tshelper->createThead() : '';
        $wret .= '<thead>' . $buttons . $headrows . "\r\t" . '</thead>' . "\r\t" . '<tbody>';
    }
    //Body
    //replace tiki tags, plugins and other enclosing characters with hash strings before creating table so that any
    //pipes (| or ~|~) inside aren't mistaken for cell dividers
    preprocess_section($data, $tagremove, $pluginremove);
    if ($sort) {
        $type = 'bs';
        //sortable body rows - do not assign odd/even class to these since jquery will do it
    } else {
        $type = 'b';
        //plain body rows
    }
    //now create table body rows
    $bodyrows = process_section($data, $type, "\n", "\r\t\t\t" . '<td', '</td>', isset($colwidths) ? $colwidths : '', isset($colaligns) ? $colaligns : '', isset($colvaligns) ? $colvaligns : '');
    //restore original tags and plugin syntax
    postprocess_section($bodyrows, $tagremove, $pluginremove);
    $wret .= $bodyrows;
    //end the table
    if (isset($head)) {
        $wret .= "\r\t" . '</tbody>';
    }
    $wret .= "\r" . '</table>' . "\r" . $msg;
    return $wret;
}
function wikiplugin_fancytable($data, $params)
{
	global $tikilib, $prefs;
	static $iFancytable = 0;
	++$iFancytable;
	extract($params, EXTR_SKIP);
	if (empty($sortable)) $sortable = 'n';

	// Start the table
	$wret = '<table class="normal'.($sortable=='y'? ' fancysort':'').'" id="fancytable_'.$iFancytable.'">' . "\r\t";
	
	//mask tiki tag content during processing and bring back at the end so that any pipes (| or ~|~) 
	//inside of tags aren't mistaken for cell dividers
	//pattern covers (( )), [ ], ~np~ ~/np~, ~tc~ ~/tc~, ~hc~ ~/hc~, { }
	$pattern = '/(\(\([^\)\)]+\)\)|\[[^\]]+\]|~np~(?:(?!~\/np~).)*~\/np~|~tc~(?:(?!~\/tc~).)*~\/tc~'
				. '|~hc~(?:(?!~\/hc~).)*~\/hc~|\{(?:(?!\}).)*\})/';
	//process header
	if (isset($head)) {
		if (!empty($headclass)) {
			$tdhdr = "\r\t\t\t<th class=\"$headclass\"";
		} else {
			$tdhdr = "\r\t\t\t<th";
		}
		preg_match_all($pattern, $head, $head_matches);
		//replace all tiki tags in the header with numbered strings while being processed
		$head = preg_replace_callback($pattern, 'replace_head', $head);
		//process header rows
		$headrows = process_section($head, 'h', '>>', $tdhdr, '</th>', isset($colwidths) ? $colwidths : '', isset($headaligns) ? $headaligns : '', isset($headvaligns) ? $headvaligns : '');
		//bring the tiki tags back into the header. static veriable needed in case of multiple tables
		static $hh = 0;
		foreach ($head_matches[0] as $head_match) {
			$headrows = str_replace('~~~head' . $hh . '~~~', $head_match, $headrows);
			$hh++;
		}
		$wret .= '<thead>' . $headrows . "\r\t" . '</thead>' . "\r\t" . '<tbody>';
	}
	//process body
	preg_match_all($pattern, $data, $body_matches);
	//replace all tiki tags in the body with numbered strings while being processed
	$data = preg_replace_callback($pattern, 'replace_body', $data);
	if ($sortable == 'y' && $prefs['disableJavascript'] == 'n' && $prefs['feature_jquery_tablesorter'] == 'y') {
		$type = 's';	//sortable rows - do not assign odd/even class to these since jquery will do it
	} else {
		$type = 'r';	//plain rows
	}
	//process table body rows
	$bodyrows = process_section($data, $type, "\n", '', '</td>', isset($colwidths) ? $colwidths : '', isset($colaligns) ? $colaligns : '', isset($colvaligns) ? $colvaligns : '');
	//bring the tiki tags back into the body. static veriable needed in case of multiple tables
	static $bb = 0;
	foreach ($body_matches[0] as $body_match) {
		$bodyrows = str_replace('~~~body' . $bb . '~~~', $body_match, $bodyrows);
		$bb++;
	}
	$wret .= $bodyrows;

	//end the table
	if (isset($head)) {
		$wret .= "\r\t" . '</tbody>';
	}
	$wret .= "\r" . '</table>' . "\r";
	if ($sortable == 'y' && $prefs['disableJavascript'] == 'n') {
		if ($prefs['feature_jquery_tablesorter'] != 'y') {
			$wret .= tra('The feature must be activated:').' feature_jquery_tablesorter';
		}
		if (empty($sortList)) {
			$js = '$("#fancytable_'.$iFancytable.'").tablesorter({widgets: ["zebra"]});';
		} else {
			$js = '$("#fancytable_'.$iFancytable.'").tablesorter({sortList:['.$sortList.'], widgets: ["zebra"]});';
		}
		global $headerlib;
		$headerlib->add_jq_onready($js);
	}
	return $wret;
}