New table class that makes it easy to use goodies like paging etc.
[moodle.git] / lib / tablelib.php
CommitLineData
7270d81f 1<?php // $Id$
2
3class flexible_table {
4
5 var $uniqueid = NULL;
6 var $attributes = array();
7 var $headers = array();
8 var $columns = array();
9 var $column_style = array();
10 var $column_suppress = array();
11 var $setup = false;
12 var $sess = NULL;
13 var $baseurl = NULL;
14
15 var $is_collapsible = false;
16 var $is_sortable = false;
17 var $use_pages = false;
18 var $use_initials = false;
19
20 var $pagesize = 30;
21 var $currpage = 0;
22 var $totalrows = 0;
23
24 function flexible_table($uniqueid) {
25 $this->uniqueid = $uniqueid;
26 }
27
28 function sortable($bool) {
29 $this->is_sortable = $bool;
30 }
31
32 function collapsible($bool) {
33 $this->is_collapsible = $bool;
34 }
35
36 function pageable($bool) {
37 $this->use_pages = $bool;
38 }
39
40 function initialbars($bool) {
41 $this->use_initials = $bool;
42 }
43
44 function pagesize($perpage, $total) {
45 $this->pagesize = $perpage;
46 $this->totalrows = $total;
47 $this->use_pages = true;
48 }
49
50 function set_attribute($attribute, $value) {
51 $this->attributes[$attribute] = $value;
52 }
53
54 function column_suppress($column) {
55 if(isset($this->column_suppress[$column])) {
56 $this->column_suppress[$column] = true;
57 }
58 }
59
60 function column_style($column, $property, $value) {
61 if(isset($this->column_style[$column])) {
62 $this->column_style[$column][$property] = $value;
63 }
64 }
65
66 function column_style_all($property, $value) {
67 foreach(array_keys($this->columns) as $column) {
68 $this->column_style[$column][$property] = $value;
69 }
70 }
71
72 function define_baseurl($url) {
73 $this->reseturl = $url;
74 if(!strpos($url, '?')) {
75 $this->baseurl = $url.'?';
76 }
77 else {
78 $this->baseurl = $url.'&amp;';
79 }
80 }
81
82 function define_columns($columns) {
83 $this->columns = array();
84 $this->column_style = array();
85 $colnum = 0;
86
87 foreach($columns as $column) {
88 $this->columns[$column] = $colnum++;
89 $this->column_style[$column] = array();
90 $this->column_suppress[$column] = false;
91 }
92 }
93
94 function define_headers($headers) {
95 $this->headers = $headers;
96 }
97
98 function make_styles_string(&$styles) {
99 if(empty($styles)) {
100 return '';
101 }
102
103 $string = ' style="';
104 foreach($styles as $property => $value) {
105 $string .= $property.':'.$value.';';
106 }
107 $string .= '"';
108 return $string;
109 }
110
111 function make_attributes_string(&$attributes) {
112 if(empty($attributes)) {
113 return '';
114 }
115
116 $string = ' ';
117 foreach($attributes as $attr => $value) {
118 $string .= ($attr.'="'.$value.'" ');
119 }
120
121 return $string;
122 }
123
124 function setup() {
125 global $SESSION, $CFG;
126
127 if(empty($this->columns) || empty($this->uniqueid)) {
128 return false;
129 }
130
131 if(!isset($SESSION->flextable) || isset($SESSION->flextable) && $SESSION->flextable->uniqueid != $this->uniqueid) {
132 $SESSION->flextable = new stdClass;
133 $SESSION->flextable->uniqueid = $this->uniqueid;
134 $SESSION->flextable->collapse = array();
135 $SESSION->flextable->sortby = '';
136 $SESSION->flextable->sortdir = '';
137 $SESSION->flextable->i_first = '';
138 $SESSION->flextable->i_last = '';
139 }
140
141 $this->sess = &$SESSION->flextable;
142
143 if(!empty($_GET['tshow']) && isset($this->columns[$_GET['tshow']])) {
144 // Show this column
145 $this->sess->collapse[$_GET['tshow']] = false;
146 }
147 else if(!empty($_GET['thide']) && isset($this->columns[$_GET['thide']])) {
148 // Hide this column
149 $this->sess->collapse[$_GET['thide']] = true;
150 if($this->sess->sortby == $_GET['thide']) {
151 $this->sess->sortby = '';
152 $this->sess->sortdir = '';
153 }
154 }
155
156 // Now, update the column attributes for collapsed columns
157 foreach(array_keys($this->columns) as $column) {
158 if(!empty($this->sess->collapse[$column])) {
159 $this->column_style[$column]['width'] = '10px';
160 }
161 }
162
163 if(
164 !empty($_GET['tsort']) &&
165 (isset($this->columns[$_GET['tsort']]) ||
166 (($_GET['tsort'] == 'firstname' || $_GET['tsort'] == 'lastname') && isset($this->columns['fullname']))
167 ))
168 {
169 if(empty($this->sess->collapse[$_GET['tsort']])) {
170 if($this->sess->sortby == $_GET['tsort']) {
171 $this->sess->sortdir = $this->sess->sortdir == SORT_ASC ? SORT_DESC : SORT_ASC;
172 }
173 else {
174 $this->sess->sortby = $_GET['tsort'];
175 $this->sess->sortdir = SORT_ASC;
176 }
177 }
178 }
179
180 if(isset($_GET['tilast'])) {
181 if(empty($_GET['tilast']) || is_numeric(strpos(get_string('alphabet'), $_GET['tilast']))) {
182 $this->sess->i_last = $_GET['tilast'];
183 }
184 }
185
186 if(isset($_GET['tifirst'])) {
187 if(empty($_GET['tifirst']) || is_numeric(strpos(get_string('alphabet'), $_GET['tifirst']))) {
188 $this->sess->i_first = $_GET['tifirst'];
189 }
190 }
191
192 if(empty($this->baseurl)) {
193 $getcopy = $_GET;
194 unset($getcopy['tshow']);
195 unset($getcopy['thide']);
196 unset($getcopy['tsort']);
197 unset($getcopy['tifirst']);
198 unset($getcopy['tilast']);
199 unset($getcopy['page']);
200
201 $strippedurl = strip_querystring(qualified_me());
202
203 if(!empty($getcopy)) {
204 $first = false;
205 $querystring = '';
206 foreach($getcopy as $var => $val) {
207 if(!$first) {
208 $first = true;
209 $querystring .= '?'.$var.'='.$val;
210 }
211 else {
212 $querystring .= '&amp;'.$var.'='.$val;
213 }
214 }
215 $this->reseturl = $strippedurl.$querystring;
216 $querystring .= '&amp;';
217 }
218 else {
219 $this->reseturl = $strippedurl.$querystring;
220 $querystring = '?';
221 }
222
223 $this->baseurl = strip_querystring(qualified_me()) . $querystring;
224 }
225
226 // If it's "the first time" we 've been here, forget the previous initials filters
227 if(qualified_me() == $this->reseturl) {
228 $this->sess->i_first = '';
229 $this->sess->i_last = '';
230 }
231
232 $this->currpage = optional_param('page', 0);
233 $this->setup = true;
234 }
235
236 function get_sql_sort() {
237 if(!$this->setup) {
238 return false;
239 }
240 if(!empty($this->sess->sortby)) {
241 return $this->sess->sortby.($this->sess->sortdir == SORT_ASC ? ' ASC' : ' DESC');
242 }
243 }
244
245 function get_page_start() {
246 if(!$this->use_pages) {
247 return '';
248 }
249 return $this->currpage * $this->pagesize;
250 }
251
252 function get_page_size() {
253 if(!$this->use_pages) {
254 return '';
255 }
256 return $this->pagesize;
257 }
258
259 function get_sql_where() {
260 if(!isset($this->columns['fullname'])) {
261 return '';
262 }
263
264 $LIKE = sql_ilike();
265 if(!empty($this->sess->i_first) && !empty($this->sess->i_last)) {
266 return 'firstname '.$LIKE.' \''.$this->sess->i_first.'%\' AND lastname '.$LIKE.' \''.$this->sess->i_last.'%\'';
267 }
268 else if(!empty($this->sess->i_first)) {
269 return 'firstname '.$LIKE.' \''.$this->sess->i_first.'%\'';
270 }
271 else if(!empty($this->sess->i_last)) {
272 return 'lastname '.$LIKE.' \''.$this->sess->i_last.'%\'';
273 }
274
275 return '';
276 }
277
278 function print_html() {
279 global $CFG;
280
281 if(!$this->setup) {
282 return false;
283 }
284
285 $colcount = count($this->columns);
286
287 // Do we need to print initial bars?
288
289 if($this->use_initials && isset($this->columns['fullname'])) {
290
291 $strall = get_string('all');
292 $alpha = explode(',', get_string('alphabet'));
293
294 // Bar of first initials
295
296 echo '<div class="initialbar">'.get_string('firstname').' : ';
297 if(!empty($this->sess->i_first)) {
298 echo '<a href="'.$this->baseurl.'tifirst=">'.$strall.'</a>';
299 } else {
300 echo '<strong>'.$strall.'</strong>';
301 }
302 foreach ($alpha as $letter) {
303 if ($letter == $this->sess->i_first) {
304 echo ' <strong>'.$letter.'</strong>';
305 } else {
306 echo ' <a href="'.$this->baseurl.'tifirst='.$letter.'">'.$letter.'</a>';
307 }
308 }
309 echo '</div>';
310
311 // Bar of last initials
312
313 echo '<div class="initialbar">'.get_string('lastname').' : ';
314 if(!empty($this->sess->i_last)) {
315 echo '<a href="'.$this->baseurl.'tilast=">'.$strall.'</a>';
316 } else {
317 echo '<strong>'.$strall.'</strong>';
318 }
319 foreach ($alpha as $letter) {
320 if ($letter == $this->sess->i_last) {
321 echo ' <strong>'.$letter.'</strong>';
322 } else {
323 echo ' <a href="'.$this->baseurl.'tilast='.$letter.'">'.$letter.'</a>';
324 }
325 }
326 echo '</div>';
327
328 }
329
330 // End of initial bars code
331
332 // Paging bar
333 if($this->use_pages) {
334 print_paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl);
335 }
336
337 if(empty($this->data)) {
338 return;
339 }
340
341
342 $suppress_enabled = array_sum($this->column_suppress);
343 $suppress_lastrow = NULL;
344 // Start of main data table
345
346 echo '<table'.$this->make_attributes_string($this->attributes).'>';
347
348 echo '<tr>';
349 foreach($this->columns as $column => $index) {
350 $icon_hide = '';
351 $icon_sort = '';
352
353 if($this->is_collapsible) {
354 if(!empty($this->sess->collapse[$column])) {
355 $icon_hide = ' <a href="'.$this->baseurl.'tshow='.$column.'"><img src="'.$CFG->pixpath.'/t/switch_plus.gif" title="'.get_string('show').' '.$this->headers[$index].'" /></a>';
356 }
357 else if($this->headers[$index] !== NULL) {
358 $icon_hide = ' <a href="'.$this->baseurl.'thide='.$column.'"><img src="'.$CFG->pixpath.'/t/switch_minus.gif" title="'.get_string('hide').' '.$this->headers[$index].'" /></a>';
359 }
360 }
361
362 switch($column) {
363
364 case 'fullname':
365 if($this->is_sortable) {
366 $icon_sort_first = $icon_sort_last = '';
367 if($this->sess->sortby == 'firstname') {
368 if($this->sess->sortdir == SORT_ASC) {
369 $icon_sort_first = ' <img src="'.$CFG->pixpath.'/t/down.gif" />';
370 }
371 else {
372 $icon_sort_first = ' <img src="'.$CFG->pixpath.'/t/up.gif" />';
373 }
374 }
375 else if($this->sess->sortby == 'lastname') {
376 if($this->sess->sortdir == SORT_ASC) {
377 $icon_sort_last = ' <img src="'.$CFG->pixpath.'/t/down.gif" />';
378 }
379 else {
380 $icon_sort_last = ' <img src="'.$CFG->pixpath.'/t/up.gif" />';
381 }
382 }
383 $this->headers[$index] = '<a href="'.$this->baseurl.'tsort=firstname">'.get_string('firstname').'</a> '.$icon_sort_first.' / '.
384 '<a href="'.$this->baseurl.'tsort=lastname">'.get_string('lastname').'</a> '.$icon_sort_last;
385 }
386 break;
387
388 default:
389 if($this->is_sortable) {
390 if($this->sess->sortby == $column) {
391 if($this->sess->sortdir == SORT_ASC) {
392 $icon_sort = ' <img src="'.$CFG->pixpath.'/t/down.gif" />';
393 }
394 else {
395 $icon_sort = ' <img src="'.$CFG->pixpath.'/t/up.gif" />';
396 }
397 }
398 $this->headers[$index] = '<a href="'.$this->baseurl.'tsort='.$column.'">'.$this->headers[$index].'</a>';
399 }
400 }
401
402 if($this->headers[$index] === NULL) {
403 echo '<th class="header c'.$index.'">&nbsp;</th>';
404 }
405 else if(!empty($this->sess->collapse[$column])) {
406 echo '<th class="header c'.$index.'">'.$icon_hide.'</th>';
407 }
408 else {
409 echo '<th class="header c'.$index.'" nowrap="nowrap"'.$this->make_styles_string($this->column_style[$column]).'>'.$this->headers[$index].$icon_sort.'<div class="commands">'.$icon_hide.'</div></th>';
410 }
411
412 }
413 echo '</tr>';
414
415 if(!empty($this->data)) {
416 $oddeven = 1;
417 $colbyindex = array_flip($this->columns);
418 foreach($this->data as $row) {
419 $oddeven = $oddeven ? 0 : 1;
420 echo '<tr class="r'.$oddeven.'">';
421
422 // If we have a separator, print it
423 if($row === NULL && $colcount) {
424 echo '<td colspan="'.$colcount.'"><div class="tabledivider"></div></td>';
425 }
426 else {
427 foreach($row as $index => $data) {
428 if($index >= $colcount) {
429 break;
430 }
431 $column = $colbyindex[$index];
432 echo '<td class="cell c'.$index.'"'.$this->make_styles_string($this->column_style[$column]).'>';
433 if(empty($this->sess->collapse[$column])) {
434 if($this->column_suppress[$column] && $suppress_lastrow !== NULL && $suppress_lastrow[$index] === $data) {
435 echo '&nbsp;';
436 }
437 else {
438 echo $data;
439 }
440 }
441 else {
442 echo '&nbsp;';
443 }
444 echo '</td>';
445 }
446 }
447 echo '</tr>';
448 if($suppress_enabled) {
449 $suppress_lastrow = $row;
450 }
451 }
452 }
453
454 echo '</table>';
455
456 }
457
458 function add_data($row) {
459 if(!$this->setup) {
460 return false;
461 }
462 $this->data[] = $row;
463 }
464
465 function add_separator() {
466 if(!$this->setup) {
467 return false;
468 }
469 $this->data[] = NULL;
470 }
471
472}
473
474?>