00001 <?php
00013 class tpTable extends Plugin
00014 {
00015 var $guid = 0;
00016
00020 function tpTable() {
00021 $this->Plugin();
00022 $this->depend('html','form');
00023 }
00024
00036 function build_table($params)
00037 {
00038 $attribs = $this->_getparam($params, 'attribs', array());
00039 $tbl_id = isset($attribs['id']) ? $attribs['id'] : 'table'.++$this->guid;
00040
00041
00042 $out = '<table id="'.$tbl_id.'" cellspacing="0" class="';
00043 if(isset($params['class'])) {
00044 $out .= $params['class'].' ';
00045 }
00046 $out .= 'table-highlight"';
00047 foreach($attribs as $k=>$v) {
00048 $out .= " $k=\"$v\"";
00049 }
00050 $out .= ">\n";
00051
00052
00053 if(isset($params['headers']) && is_array($params['headers'])) {
00054 $out .= "<tr>\n";
00055 foreach($params['headers'] as $label) {
00056 $out .= "<th>$label</th>\n";
00057 }
00058 $out .= "</tr>\n";
00059 }
00060
00061
00062 $rowct = 0;
00063 foreach($params['rows'] as $row) {
00064 $out .= '<tr';
00065 if(++$rowct % 2 == 1) {
00066 $out .= ' class="altrow"';
00067 }
00068
00069 $out .= '>'."\n";
00070 foreach($row as $data) {
00071 $out .= "<td>$data</td>\n";
00072 }
00073 $out .= "</tr>\n";
00074 }
00075
00076 $js = "$('table.table-highlight tr').click(function(){ $(this).parent().parent().find('tr').removeClass('selected');$(this).addClass('selected'); });";
00077 $js .= "$('table.table-highlight tr').mouseover(function(){ $(this).addClass('highlight'); });";
00078 $js .= "$('table.table-highlight tr').mouseout(function(){ $(this).removeClass('highlight'); });";
00079 $this->depends->html->js_run('tpTable:highlight', $js);
00080
00081 $out .= "</table>\n";
00082 return $out;
00083 }
00084
00122 function build_grid($params)
00123 {
00124 $guid = 'grid' . ++$this->guid;
00125 $class = $this->_getparam($params, 'class', 'grid');
00126 $options = $this->_getparam($params, 'options', array());
00127 $data_id = $this->_getparam($params, 'data_id', 'id');
00128 $grid_url = $this->_getparam($params, 'url', url(CURRENT_URL));
00129 $pp_opts = $this->_getparam($params, 'perpage_opts', array(50,200,500,1000));
00130
00131 if(!isset($params['noresults_txt'])) $params['noresults_txt'] = __('No Matches');
00132
00133
00134 $this->depends->html->js_load('jq_tooltip', 'jq/jquery.tooltip');
00135 $this->depends->html->js_run('jq_tooltip', '$(\'td.options img\').Tooltip({showURL:false,extraClass:\'action\'});');
00136 $this->depends->html->css_load('tooltip', 'tooltip');
00137
00138
00139 $this->depends->html->css_load('grid');
00140 $this->depends->html->js_load('grid');
00141
00142
00143 if($this->_opt_isset($options, 'ajax')) {
00144 $this->depends->html->js_load('ajax');
00145 $this->depends->html->js_run('grid', '$(\'.ajax_action\').click(grid_dispatch);');
00146 }
00147
00148 $cb_vars = array();
00149 if(isset($params['cb_vars'])) {
00150 foreach($params['cb_vars'] as $k=>$v) {
00151
00152 $cb_vars[$k] =& $params['cb_vars']["$k"];
00153 }
00154 }
00155
00156 $totals = array();
00157 if(isset($params['totals'])) {
00158 foreach($params['totals'] as $k=>$v) {
00159 $totals[$k] = 0;
00160 }
00161 }
00162
00163
00164 $out = '';
00165
00166
00167
00168 $p = $params;
00169 unset($p['data']);
00170 $out .= '<script type="text/javascript">';
00171 $out .= 'if(typeof window.grid == "undefined") window.grid = {};';
00172
00173 $out .= "window.grid.{$guid} = '".str_replace("'", "\\'", serialize($p))."';";
00174 $out .= "</script>\n";
00175
00176
00177 $out .= '<table id="'.$guid.'" cellspacing="0"';
00178 if($class) {
00179 $out .= ' class="'.$class.'"';
00180 }
00181 $out .= ">\n";
00182
00183
00184 if(!$this->_opt_isset($options, 'noheaders')) {
00185 $out .= "<tr class=\"label\">\n";
00186 $i = 0;
00187 foreach($params['columns'] as $name=>$column) {
00188 $style = array();
00189 $class = array();
00190 $out .= '<th';
00191 if(++$i == count($params['columns'])) $style[] = 'border-right:none';
00192 if(!preg_match('|^_OPTIONS_|', $name)) {
00193 if($_GET['s_f'] == $name) {
00194 $class[] = 'hover';
00195 } else {
00196 $out .= ' onMouseOver="$(this).addClass(\'hover\')"';
00197 $out .= ' onMouseOut="$(this).removeClass(\'hover\')"';
00198 }
00199 if(!$this->_opt_isset($options, 'nosorting') && !$column['nosort']) {
00200 $out .= ' onClick="return grid_sort(this);"';
00201 }
00202 if(preg_match('|^_MULTI_|', $name)) $style[] = 'text-align:center';
00203 }
00204 $out .= ' class="'.implode(' ',$class).'"';
00205 $out .= ' style="'.implode(';',$style).'">';
00206 if(preg_match('|^_OPTIONS_|', $name)) {
00207 if($name == '_OPTIONS_' && !$this->_opt_isset($options, 'nofilters') && !$this->_opt_isset($options, 'nofilterbutton')) {
00208
00209 $out .= $this->depends->html->link(__('Filter Help'), url('/static/filters.en.html'), false, true, array('class'=>'help'), true);
00210 } else {
00211 $out .= mb_substr($name, 9);
00212 }
00213 } else {
00214 if(preg_match('|^_MULTI_|',$name)) {
00215 $label = mb_substr($name, 7);
00216 $name = '_m_'.strtolower($label);
00217 } else {
00218 $label = $column['label'] ? $column['label'] : ' ';
00219 }
00220 if(!$this->_opt_isset($options, 'nosorting') && !$column['nosort']) {
00221
00222 $GET = $_GET;
00223 $qs = array();
00224 $sortdir = ($GET['s_f'] == $name && $GET['s_d'] == 'asc') ? 'desc' : 'asc';
00225 $GET['s_f'] = $name;
00226 $GET['s_d'] = $sortdir;
00227 foreach($GET as $k=>$v) $qs[] = "$k=$v";
00228 $qs = implode('&', $qs);
00229 if($_GET['s_f'] == $name) {
00230 $arrowimg = $_GET['s_d'] == 'desc' ? 'arrow_black_down.gif' : 'arrow_black_up.gif';
00231 $out .= ' '.$this->depends->html->image('icons/'.$arrowimg, array('style'=>'float:right'));
00232 }
00233 $label = '<a href="'.$grid_url.'?'.$qs.'">'.$label.'</a>';
00234 }
00235 $out .= $label;
00236 }
00237 $out .= "</th>\n";
00238 }
00239 $out .= "</tr>\n";
00240 }
00241
00242
00243 if(!$this->_opt_isset($options, 'nofilters')) {
00244
00245 $out .= '<form method="get" action="'.$grid_url.'">';
00246
00247 foreach($_GET as $k=>$v) {
00248
00249 if($k == 'p_p' || $k == 'p_pp') continue;
00250 $out .= $this->depends->form->hidden($k, $v, array('id'=>"{$guid}_1_$k"));
00251 }
00252 $out .= "<tr class=\"filter\">\n";
00253 $i = 0;
00254 foreach($params['columns'] as $name=>$column) {
00255 $style = array();
00256 $class = array();
00257 $out .= '<th';
00258 if(++$i == count($params['columns'])) $style[] = 'border-right:none';
00259 if($_GET['s_f'] == $name) $class[] = 'hover';
00260 if(preg_match('|^_MULTI_|', $name)) $style[] = 'text-align:center';
00261 $out .= ' class="'.implode(' ',$class).'"';
00262 $out .= ' style="'.implode(';',$style).'">';
00263 if(preg_match('|^_OPTIONS_|', $name)) {
00264 if($name == '_OPTIONS_' && !$this->_opt_isset($options, 'nofilters') && !$this->_opt_isset($options, 'nofilterbutton')) {
00265 $out .= $this->depends->form->submit('filter_submit',__('Filter'),array('style'=>'width:auto'))."</th>\n";
00266 } else {
00267 $out .= ' ';
00268 }
00269 continue;
00270 }
00271 if(preg_match('|^_MULTI_|', $name)) {
00272 $mname = strtolower(mb_substr($name, 7));
00273 if($mname) $mname .= '_';
00274 $out .= $this->depends->form->checkbox("_{$mname}all",'all','',false,array('style'=>'width:auto;border:none','onClick'=>"var c=this.checked; $('#$guid input[@type=checkbox][@name^={$mname}ids]').attr('checked',c?'checked':'')"))."</th>\n";
00275 continue;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284 if($column['type'] == 'none') {
00285 $elem = '';
00286 } else {
00287 $t = mb_substr($column['type'], 0, 1);
00288 if($t == '') $t = 't';
00289 $expr = isset($column['expr']) ? 'f_'.$t.'_'.$column['expr'] : 'f_'.$t.'_'.$name;
00290 $opts = array(''=>'');
00291 if(is_array($column['options'])) foreach($column['options'] as $k=>$v) $opts[$k] = $v;
00292 if(is_array($column['options_nokeys'])) foreach($column['options_nokeys'] as $v) $opts[$v] = $v;
00293 $attribs = isset($column['attribs']) ? $column['attribs'] : array();
00294 switch($column['type']) {
00295 case 'select': $elem = $this->depends->form->select($expr, $_GET[$expr], $opts, '', false, $attribs); break;
00296 case 'date': $elem = $this->depends->form->date($expr, $_GET[$expr], '%Y-%m-%d', $attribs); break;
00297 case 'text':
00298 default: $elem = $this->depends->form->text($expr, $_GET[$expr], isset($column['flength']) ? $column['flength'] : 10, 255, $attribs);
00299 }
00300 }
00301 $out .= "$elem</th>\n";
00302 }
00303 $out .= "</tr>\n";
00304 $out .= '</form>';
00305 }
00306
00307 $cb_vars = array();
00308 if(isset($params['cb_vars'])) {
00309 foreach($params['cb_vars'] as $k=>$v) {
00310
00311 $cb_vars[$k] =& $params['cb_vars']["$k"];
00312 }
00313 }
00314
00315 $totals = array();
00316 if(isset($params['totals'])) {
00317 foreach($params['totals'] as $k=>$v) {
00318 $totals[$k] = 0;
00319 }
00320 }
00321
00322
00323 $rowct = 0;
00324 if(!count($params['data'])) {
00325 $out .= "<tr>\n";
00326 $out .= "<td colspan=\"100%\"><p>{$params['noresults_txt']}</p></td>\n";
00327 $out .= "</tr>\n";
00328 }
00329
00330
00331 $multi_form = false;
00332 foreach($params['columns'] as $name=>$column) {
00333 if(preg_match('|^_MULTI_|', $name)) $multi_form = true;
00334 }
00335 if($multi_form) {
00336 $out .= '<form name="multi" id="multi" method="get" action="'.$grid_url.'">';
00337 }
00338
00339 foreach($params['data'] as $row) {
00340 $tr_dom_id = 'tr'.$this->guid++;
00341 $out .= '<tr id="'.$tr_dom_id.'"';
00342 $class = array();
00343 if(++$rowct % 2 != 1) $class[] = 'altrow';
00344 if(isset($params['rowclassfn'])) {
00345 $class[] = $params['rowclassfn']($row);
00346 }
00347 $out .= ' class="'.implode(' ',$class).'"';
00348
00349 if($params['rowclick']) {
00350 $subs = array();
00351 preg_match_all('|<([A-z0-9\._-]+)>|U', $params['rowclick'], $subs);
00352 $out .= ' onClick="location.href=\''.$params['rowclick'].'\'.replace(\'_ID_\',\''.$this->_getrowdata($row, $data_id).'\')';
00353 if(is_array($subs[1])) foreach($subs[1] as $s) {
00354 $out .= ".replace('<$s>','".$this->_getrowdata($row, $s)."')";
00355 }
00356 $out .= '"';
00357 }
00358 $out .= '>';
00359
00360 // fancy highlight/hover stuff
00361 $js = "$('#{$guid} tr').click(function(){ $('#{$guid} tr').removeClass('selected');$(this).addClass('selected'); });";
00362 $js .= "$('#{$guid} tr').mouseover(function(){ $(this).addClass('highlight'); });";
00363 $js .= "$('#{$guid} tr').mouseout(function(){ $(this).removeClass('highlight'); });";
00364 $this->depends->html->js_run("tpTable:$guid:highlight", $js);
00365
00366 foreach($params['columns'] as $name=>$column) {
00367 $out .= '<td';
00368 if(isset($column['align'])) {
00369 $out .= ' align="'.$column['align'].'"';
00370 }
00371 if(preg_match('|^_OPTIONS_|', $name)) {
00372 $out .= ' class="options">';
00373 foreach($column as $opt) {
00374 if(function_exists($opt)) {
00375 $out .= $opt($cb_vars, $row);
00376 } else {
00377 // perform substitutions in URL
00378 $lnk = str_replace('_ID_', $this->_getrowdata($row, $data_id), $opt).' ';
00379
00380 $subs = array();
00381 preg_match_all('|<([A-z0-9\._-]+)>|U', $lnk, $subs);
00382 if(is_array($subs[1])) foreach($subs[1] as $s) {
00383 $lnk = str_replace("<$s>", $this->_getrowdata($row, $s), $lnk);
00384 }
00385 $out .= $lnk;
00386 }
00387 }
00388 } else if(preg_match('|^_MULTI_|', $name)) {
00389 $mname = strtolower(mb_substr($name, 7));
00390 if($mname) $mname .= '_';
00391 $out .= ' class="multi">';
00392 $out .= '<input type="checkbox" style="border:none" name="'.$mname.'ids[]" value="'.$this->_getrowdata($row, $data_id).'"';
00393 if($this->_getrowdata($row, "_m_$mname")) $out .= ' checked="checked"';
00394 $out .= '></td>'."\n";
00395 } else {
00396 $out .= '>';
00397 $data = $this->_getrowdata($row, $name);
00398 if(isset($totals[$name])) {
00399 $totals[$name] += $data;
00400 }
00401 /*
00402 * Mangle row data if necessary
00403 */
00404 if(isset($column['display_map'][$data])) {
00405 $data = $column['display_map'][$data];
00406 } else if(isset($column['cb_fn']) || isset($column['display_func'])) {
00407 // 'cb_fn' is the old one, left for compatibility
00408 $f = isset($column['display_func']) ? $column['display_func'] : $column['cb_fn'];
00409 if(!function_exists($f)) {
00410 // it's not a function, so create one
00411 // $g is an array of all global callback vars as defined in cb_vars
00412 // $d is the full data array for this row
00413 $f = create_function('$g,$d', $f);
00414 }
00415 $data = $f($cb_vars, $row);
00416 } else if(isset($column['format'])) {
00417 $data = sprintf($column['format'], $data);
00418 } else if(isset($column['date_format'])) {
00419 if($data == '0000-00-00') {
00420 $data = __('Never');
00421 } else {
00422 $data = date($column['date_format'], strtotime($data));
00423 }
00424 }
00425 $out .= $data;
00426 }
00427 $out .= "</td>\n";
00428 }
00429 $out .= "</tr>\n";
00430 // this <tr> is used by grids that load subcontent via AJAX
00431 $out .= '<tr id="'.$tr_dom_id.'_form" class="ajaxcontent"';
00432 $out .= "><td id=\"{$tr_dom_id}_form_td\" style=\"display:none;padding-left:13px\" colspan=\"100%\"></td></tr>\n";
00433 }
00434
00435
00436 if(!$this->_opt_isset($options, 'nototals') && count($totals)) {
00437 $out .= "<tr class=\"totals\">\n";
00438 $i = 0;
00439 foreach($params['columns'] as $name=>$column) {
00440 $out .= '<td';
00441 if(isset($column['align'])) {
00442 $out .= ' align="'.$column['align'].'"';
00443 }
00444 $out .= '>';
00445 if($i == 0 && !isset($totals[$name])) {
00446 $out .= '<strong>'.__('Totals').':</strong>';
00447 }
00448 if(isset($totals[$name])) {
00449 if(isset($params['totals'][$name]['format'])) {
00450 $totals[$name] = sprintf($params['totals'][$name]['format'], $totals[$name]);
00451 }
00452 $out .= '<strong>'.$totals[$name].'</strong>';
00453 }
00454 $out .= "</td>\n";
00455 $i++;
00456 }
00457 $out .= "</tr>\n";
00458 }
00459
00460
00461 if(!empty($params['data'])) {
00462 $has_multi = false;
00463 foreach($params['columns'] as $name=>$column) {
00464 if(preg_match('|^_MULTI_|', $name)) $has_multi = true;
00465 }
00466 if($has_multi) {
00467 $out .= '<tr class="multi">'."\n";
00468 foreach($params['columns'] as $name=>$column) {
00469 $out .= '<td>';
00470 if(preg_match('|^_MULTI_|', $name)) {
00471 foreach($column as $action) $out .= $action."<br/>";
00472 }
00473 $out .= '</td>';
00474 }
00475 $out .= "</tr>\n";
00476 }
00477 }
00478 if($multi_form) {
00479
00480 $out .= '</form>';
00481 }
00482
00483
00484 $numpages = 0;
00485 if(isset($params['rows'])) {
00486 $numpages = (int)($params['rows'] / $params['perpage']);
00487 if($params['rows'] % $params['perpage']) $numpages++;
00488 }
00489 if(!$this->_opt_isset($options, 'nopagination') && $numpages > 1) {
00490 $cp = $params['curpage'];
00491 $pp = $params['perpage'];
00492 $out .= "<tr class=\"pagination\">\n";
00493 $out .= '<form name="changepp" method="get" action="'.$grid_url.'">';
00494
00495 foreach($_GET as $k=>$v) {
00496 if($k != 'p_p' && $k != 'p_pp') {
00497 $out .= $this->depends->form->hidden($k, $v, array('id'=>"{$guid}_2_$k"));
00498 }
00499 }
00500 $out .= '<td colspan="100%">';
00501 $out .= '<div style="float:right">';
00502 $page = $this->_pagelink($cp, $cp, $pp, $grid_url);
00503
00504 if($cp > 1) {
00505 $page = $this->_pagelink($cp-1, $cp, $pp, $grid_url).$page;
00506 $left = $cp - 2;
00507 if($left > 0) {
00508 if($left > 2) $page = '... '.$page;
00509 if($left > 1) $page = $this->_pagelink(2, $cp, $pp, $grid_url).$page;
00510 $page = $this->_pagelink(1, $cp, $pp, $grid_url).$page;
00511 }
00512 }
00513
00514 if($cp < $numpages) {
00515 $page = $page.$this->_pagelink($cp+1, $cp, $pp, $grid_url);
00516 $left = $numpages - $cp - 1;
00517 if($left > 0) {
00518 if($left > 2) $page = $page.'... ';
00519 if($left > 1) $page = $page.$this->_pagelink($numpages-1, $cp, $pp, $grid_url);
00520 $page = $page.$this->_pagelink($numpages, $cp, $pp, $grid_url);
00521 }
00522 }
00523 $out .= rtrim($page);
00524 $out .= '</div>';
00525 $out .= __('Showing').' ';
00526 if(!isset($pp_opts[$pp])) {
00527 $pp_opts[] = $pp;
00528 sort($pp_opts);
00529 }
00530 $out .= $this->depends->form->select('p_pp', $pp, array_hash($pp_opts), '', false, array('onChange'=>'document.changepp.submit();'));
00531 $out .= " ".__('per page').' ('.__('total records').": {$params['rows']})\n";
00532
00533 $out .= "</td>\n";
00534 $out .= "</form>\n";
00535 $out .= "</tr>\n";
00536 }
00537
00538 $out .= "</table>\n";
00539 return $out;
00540 }
00541
00542 function _getrowdata($row, $idx)
00543 {
00544 if(is_array($idx)) {
00545 if(count($idx) == 1) {
00546 return $row[$idx[0]];
00547 }
00548 $singleidx = array_shift($idx);
00549 return $this->_getrowdata($row[$singleidx], $idx);
00550 }
00551 return $row[$idx];
00552 }
00553
00554 function _pagelink($pagenum, $curpage, $perpage, $url)
00555 {
00556 if($pagenum == $curpage) {
00557 $out = "<span>$pagenum</span> ";
00558 } else {
00559
00560 $_GET['p_p'] = $pagenum;
00561 $_GET['p_pp'] = $perpage;
00562 $qs = array();
00563 foreach($_GET as $k=>$v) {
00564 $qs[] = "$k=$v";
00565 }
00566 $qs = implode('&', $qs);
00567 $out = '<a href="'.$url.'?'.$qs.'">'.$pagenum.'</a> ';
00568 }
00569 return $out;
00570 }
00571
00572
00573
00574
00575 function _opt_isset($options, $optname)
00576 {
00577 foreach($options as $k=>$v) {
00578 if($k === $optname) return $v;
00579 if($v === $optname) return true;
00580 }
00581 return false;
00582 }
00583
00584
00585
00586
00587
00588 function _getparam(&$params, $name, $default)
00589 {
00590 if(!isset($params[$name])) $params[$name] = $default;
00591 return $params[$name];
00592 }
00593
00594 }
00595
00596 ?>