1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703: 704: 705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829: 830: 831: 832: 833: 834: 835: 836:
<?php
require_once("AWLUtilities.php");
$BrowserCurrentRow = (object) array();
class BrowserColumn
{
var $Field;
var $Header;
var $Format;
var $Sql;
var $Align;
var $Class;
var $Type;
var $Translatable;
var $Hook;
var $current_row;
function BrowserColumn( $field, $header="", $align="", $format="", $sql="", $class="", $datatype="", $hook=null ) {
$this->Field = $field;
$this->Sql = $sql;
$this->Header = $header;
$this->Format = $format;
$this->Class = $class;
$this->Align = $align;
$this->Type = $datatype;
$this->Translatable = false;
$this->Hook = $hook;
}
function GetTarget() {
if ( $this->Sql == "" ) return $this->Field;
return "$this->Sql AS $this->Field";
}
function RenderHeader( $order_field, $order_direction, $browser_array_key=0, $forced_order=false ) {
global $c;
if ( $this->Align == "" ) $this->Align = "left";
$html = '<th class="'.$this->Align.'" '. ($this->Class == "" ? "" : "class=\"$this->Class\"") . '>';
$direction = 'A';
$image = "";
if ( !$forced_order && $order_field == $this->Field ) {
if ( strtoupper( substr( $order_direction, 0, 1) ) == 'A' ) {
$image = 'down';
$direction = 'D';
}
else {
$image = 'up';
}
$image = "<img class=\"order\" src=\"$c->images/$image.gif\" alt=\"$image\" />";
}
if ( !isset($browser_array_key) || $browser_array_key == '' ) $browser_array_key = 0;
if ( !$forced_order ) $html .= '<a href="'.replace_uri_params( $_SERVER['REQUEST_URI'], array( "o[$browser_array_key]" => $this->Field, "d[$browser_array_key]" => $direction ) ).'" class="order">';
$html .= ($this->Header == "" ? $this->Field : $this->Header);
if ( !$forced_order ) $html .= "$image</a>";
$html .= "</th>\n";
return $html;
}
function SetTranslatable() {
$this->Translatable = true;
}
function RenderValue( $value, $extraclass = "" ) {
global $session;
if ( $this->Type == 'date' || $this->Type == 'timestamp') {
$value = $session->FormattedDate( $value, $this->Type );
}
if ( $this->Hook && function_exists($this->Hook) ) {
dbg_error_log( "Browser", ":Browser: Hook for $this->Hook on column $this->Field");
$value = call_user_func( $this->Hook, $value, $this->Field, $this->current_row );
}
if ( $this->Translatable ) {
$value = translate($value);
}
$value = str_replace( "\n", "<br />", $value );
if ( substr(strtolower($this->Format),0,3) == "<td" ) {
$html = sprintf($this->Format,$value);
}
else {
$class = $this->Align . ($this->Class == "" ? "" : " $this->Class") . ($extraclass == "" ? "" : " $extraclass");
if ( $class != "" ) $class = ' class="'.$class.'"';
$html = sprintf('<td%s>',$class);
$html .= ($this->Format == "" ? $value : sprintf($this->Format,$value,$value));
$html .= "</td>\n";
}
return $html;
}
}
class Browser
{
var $Title;
var $SubTitle;
var $FieldNames;
var $Columns;
var $HiddenColumns;
var $Joins;
var $Where;
var $Distinct;
var $Union;
var $Order;
var $OrderField;
var $OrderDirection;
var $OrderBrowserKey;
var $ForcedOrder;
var $Grouping;
var $Limit;
var $Offset;
var $Query;
var $BeginRow;
var $CloseRow;
var $BeginRowArgs;
var $Totals;
var $TotalFuncs;
var $ExtraRows;
var $match_column;
var $match_value;
var $match_function;
var $DivOpen;
var $DivClose;
function Browser( $title = "" ) {
global $c;
$this->Title = $title;
$this->SubTitle = "";
$this->Distinct = "";
$this->Order = "";
$this->Limit = "";
$this->Offset = "";
$this->BeginRow = "<tr class=\"row%d\">\n";
$this->CloseRow = "</tr>\n";
$this->BeginRowArgs = array('#even');
$this->Totals = array();
$this->Columns = array();
$this->HiddenColumns = array();
$this->FieldNames = array();
$this->DivOpen = '<div id="browser">';
$this->DivClose = '</div>';
$this->ForcedOrder = false;
dbg_error_log( "Browser", ":Browser: New browser called $title");
}
function AddColumn( $field, $header="", $align="", $format="", $sql="", $class="", $datatype="", $hook=null ) {
$this->Columns[] = new BrowserColumn( $field, $header, $align, $format, $sql, $class, $datatype, $hook );
$this->FieldNames[$field] = count($this->Columns) - 1;
}
function AddHidden( $field, $sql="" ) {
$this->HiddenColumns[] = new BrowserColumn( $field, "", "", "", $sql );
$this->FieldNames[$field] = count($this->Columns) - 1;
}
function SetTitle( $new_title ) {
$this->Title = $new_title;
}
function Title( $new_title = null ) {
if ( isset($new_title) ) $this->Title = $new_title;
return $this->Title;
}
function SetTranslatable( $column_list ) {
$top = count($this->Columns);
for( $i=0; $i < $top; $i++ ) {
dbg_error_log( "Browser", "Comparing %s with column name list", $this->Columns[$i]->Field);
if ( in_array($this->Columns[$i]->Field,$column_list) ) $this->Columns[$i]->SetTranslatable();
}
$top = count($this->HiddenColumns);
for( $i=0; $i < $top; $i++ ) {
dbg_error_log( "Browser", "Comparing %s with column name list", $this->HiddenColumns[$i]->Field);
if ( in_array($this->HiddenColumns[$i]->Field,$column_list) ) $this->HiddenColumns[$i]->SetTranslatable();
}
}
function SetSubTitle( $sub_title ) {
$this->SubTitle = $sub_title;
}
function SetDiv( $open_div, $close_div ) {
$this->DivOpen = $open_div;
$this->DivClose = $close_div;
}
function SetJoins( $join_list ) {
$this->Joins = $join_list;
}
function SetUnion( $union_select ) {
$this->Union = $union_select;
}
function SetWhere( $where_clause ) {
$this->Where = $where_clause;
}
function SetDistinct( $distinct ) {
$this->Distinct = "DISTINCT ".$distinct;
}
function SetLimit( $limit_n ) {
$this->Limit = "LIMIT ".intval($limit_n);
}
function SetOffset( $offset_n ) {
$this->Offset = "OFFSET ".intval($offset_n);
}
function MoreWhere( $operator, $more_where ) {
if ( $this->Where == "" ) {
$this->Where = $more_where;
return;
}
$this->Where = "$this->Where $operator $more_where";
}
function AndWhere( $more_where ) {
$this->MoreWhere("AND",$more_where);
}
function OrWhere( $more_where ) {
$this->MoreWhere("OR",$more_where);
}
function AddGrouping( $field, $browser_array_key=0 ) {
if ( $this->Grouping == "" )
$this->Grouping = "GROUP BY ";
else
$this->Grouping .= ", ";
$this->Grouping .= clean_string($field);
}
function AddOrder( $field, $direction, $browser_array_key=0, $secondary=0 ) {
$field = check_by_regex($field,'/^[^\'"!\\\\()\[\]|*\/{}&%@~;:?<>]+$/');
if ( ! isset($this->FieldNames[$field]) ) return;
if ( !isset($this->Order) || $this->Order == "" )
$this->Order = "ORDER BY ";
else
$this->Order .= ", ";
if ( $secondary == 0 ) {
$this->OrderField = $field;
$this->OrderBrowserKey = $browser_array_key;
}
$this->Order .= $field;
if ( preg_match( '/^A/i', $direction) ) {
$this->Order .= " ASC";
if ( $secondary == 0)
$this->OrderDirection = 'A';
}
else {
$this->Order .= " DESC";
if ( $secondary == 0)
$this->OrderDirection = 'D';
}
}
function ForceOrder( $field, $direction ) {
$field = clean_string($field);
if ( ! isset($this->FieldNames[$field]) ) return;
if ( $this->Order == "" )
$this->Order = "ORDER BY ";
else
$this->Order .= ", ";
$this->Order .= $field;
if ( preg_match( '/^A/i', $direction) ) {
$this->Order .= " ASC";
}
else {
$this->Order .= " DESC";
}
$this->ForcedOrder = true;
}
function SetOrdering( $default_fld=null, $default_dir='A' , $browser_array_key=0 ) {
if ( isset( $_GET['o'][$browser_array_key] ) && isset($_GET['d'][$browser_array_key] ) ) {
$this->AddOrder( $_GET['o'][$browser_array_key], $_GET['d'][$browser_array_key], $browser_array_key );
}
else {
if ( ! isset($default_fld) ) $default_fld = $this->Columns[0];
$this->AddOrder( $default_fld, $default_dir, $browser_array_key );
}
}
function AddTotal( $column_name, $total_function = false ) {
$this->Totals[$column_name] = 0;
if ( $total_function != false ) {
$this->TotalFuncs[$column_name] = $total_function;
}
}
function GetTotal( $column_name ) {
return $this->Totals[$column_name];
}
function RowFormat( $beginrow, $closerow, $rowargs )
{
$argc = func_num_args();
$this->BeginRow = func_get_arg(0);
$this->CloseRow = func_get_arg(1);
$this->BeginRowArgs = array();
for( $i=2; $i < $argc; $i++ ) {
$this->BeginRowArgs[] = func_get_arg($i);
}
}
function DoQuery() {
$target_fields = "";
foreach( $this->Columns AS $k => $column ) {
if ( $target_fields != "" ) $target_fields .= ", ";
$target_fields .= $column->GetTarget();
}
if ( isset($this->HiddenColumns) ) {
foreach( $this->HiddenColumns AS $k => $column ) {
if ( $target_fields != "" ) $target_fields .= ", ";
$target_fields .= $column->GetTarget();
}
}
$where_clause = ((isset($this->Where) && $this->Where != "") ? "WHERE $this->Where" : "" );
$sql = sprintf( "SELECT %s %s FROM %s %s %s ", $this->Distinct, $target_fields,
$this->Joins, $where_clause, $this->Grouping );
if ( "$this->Union" != "" ) {
$sql .= "UNION $this->Union ";
}
$sql .= $this->Order . ' ' . $this->Limit . ' ' . $this->Offset;
$this->Query = new AwlQuery( $sql );
return $this->Query->Exec("Browse:$this->Title:DoQuery");
}
function AddRow( $column_values ) {
if ( !isset($this->ExtraRows) || typeof($this->ExtraRows) != 'array' ) $this->ExtraRows = array();
$this->ExtraRows[] = &$column_values;
}
function MatchedRow( $column, $value, $function ) {
$this->match_column = $column;
$this->match_value = $value;
$this->match_function = $function;
}
function ValueReplacement($matches)
{
$field_name = $matches[1];
if ( !isset($this->current_row->{$field_name}) && substr($field_name,0,4) == "URL:" ) {
$field_name = substr($field_name,4);
$replacement = urlencode($this->current_row->{$field_name});
}
else {
$replacement = (isset($this->current_row->{$field_name}) ? $this->current_row->{$field_name} : '');
}
dbg_error_log( "Browser", ":ValueReplacement: Replacing %s with %s", $field_name, $replacement);
return $replacement;
}
function Render( $title_tag = null, $subtitle_tag = null ) {
global $c, $BrowserCurrentRow;
if ( !isset($this->Query) ) $this->DoQuery();
dbg_error_log( "Browser", ":Render: browser $this->Title");
$html = $this->DivOpen;
if ( $this->Title != "" ) {
if ( !isset($title_tag) ) $title_tag = 'h1';
$html .= "<$title_tag>$this->Title</$title_tag>\n";
}
if ( $this->SubTitle != "" ) {
if ( !isset($subtitle_tag) ) $subtitle_tag = 'h2';
$html .= "<$subtitle_tag>$this->SubTitle</$subtitle_tag>\n";
}
$html .= "<table id=\"browse_table\">\n";
$html .= "<thead><tr class=\"header\">\n";
foreach( $this->Columns AS $k => $column ) {
$html .= $column->RenderHeader( $this->OrderField, $this->OrderDirection, $this->OrderBrowserKey, $this->ForcedOrder );
}
$html .= "</tr></thead>\n<tbody>";
$rowanswers = array();
while( $BrowserCurrentRow = $this->Query->Fetch() ) {
foreach( $this->BeginRowArgs AS $k => $fld ) {
if ( isset($BrowserCurrentRow->{$fld}) ) {
$rowanswers[$k] = $BrowserCurrentRow->{$fld};
}
else {
switch( $fld ) {
case '#even':
$rowanswers[$k] = ($this->Query->rownum() % 2);
break;
default:
$rowanswers[$k] = $fld;
}
}
}
$row_html = vsprintf( preg_replace("/#@even@#/", ($this->Query->rownum() % 2), $this->BeginRow), $rowanswers);
if ( isset($this->match_column) && isset($this->match_value) && $BrowserCurrentRow->{$this->match_column} == $this->match_value ) {
$row_html .= call_user_func( $this->match_function, $BrowserCurrentRow );
}
else {
foreach( $this->Columns AS $k => $column ) {
$row_html .= $column->RenderValue( (isset($BrowserCurrentRow->{$column->Field})?$BrowserCurrentRow->{$column->Field}:'') );
if ( isset($this->Totals[$column->Field]) ) {
if ( isset($this->TotalFuncs[$column->Field]) && function_exists($this->TotalFuncs[$column->Field]) ) {
$this->Totals[$column->Field] += $this->TotalFuncs[$column->Field]( $BrowserCurrentRow, $BrowserCurrentRow->{$column->Field} );
}
else {
$this->Totals[$column->Field] += doubleval( preg_replace( '/[^0-9.-]/', '', $BrowserCurrentRow->{$column->Field} ));
}
}
}
}
$row_html .= preg_replace("/#@even@#/", ($this->Query->rownum() % 2), $this->CloseRow);
$this->current_row = $BrowserCurrentRow;
$html .= preg_replace_callback("/##([^#]+)##/", array( &$this, "ValueReplacement"), $row_html );
}
if ( count($this->Totals) > 0 ) {
$BrowserCurrentRow = (object) "";
$row_html = "<tr class=\"totals\">\n";
foreach( $this->Columns AS $k => $column ) {
if ( isset($this->Totals[$column->Field]) ) {
$row_html .= $column->RenderValue( $this->Totals[$column->Field], "totals" );
}
else {
$row_html .= $column->RenderValue( "" );
}
}
$row_html .= "</tr>\n";
$this->current_row = $BrowserCurrentRow;
$html .= preg_replace_callback("/##([^#]+)##/", array( &$this, "ValueReplacement"), $row_html );
}
if ( count($this->ExtraRows) > 0 ) {
foreach( $this->ExtraRows AS $k => $v ) {
$BrowserCurrentRow = (object) $v;
foreach( $this->BeginRowArgs AS $k => $fld ) {
if ( isset( $BrowserCurrentRow->{$fld} ) ) {
$rowanswers[$k] = $BrowserCurrentRow->{$fld};
}
else {
switch( $fld ) {
case '#even':
$rowanswers[$k] = ($this->Query->rownum() % 2);
break;
default:
$rowanswers[$k] = $fld;
}
}
}
$row_html = vsprintf( preg_replace("/#@even@#/", ($this->Query->rownum() % 2), $this->BeginRow), $rowanswers);
if ( isset($this->match_column) && isset($this->match_value) && $BrowserCurrentRow->{$this->match_column} == $this->match_value ) {
$row_html .= call_user_func( $this->match_function, $BrowserCurrentRow );
}
else {
foreach( $this->Columns AS $k => $column ) {
$row_html .= $column->RenderValue( (isset($BrowserCurrentRow->{$column->Field}) ? $BrowserCurrentRow->{$column->Field} : '') );
}
}
$row_html .= preg_replace("/#@even@#/", ($this->Query->rownum() % 2), $this->CloseRow);
$this->current_row = $BrowserCurrentRow;
$html .= preg_replace_callback("/##([^#]+)##/", array( &$this, "ValueReplacement"), $row_html );
}
}
$html .= "</tbody>\n</table>\n";
$html .= $this->DivClose;
return $html;
}
}