[svn-inject] Installing original source of quickappoint
[debian/quickappoint.git] / lib / html.php
1 <?php
2 // html related general functions
3
4 // html formating functions
5 // ========================
6
7 // This function creates a tag <$tag $paramkey="$paramvalue">$content</$tag>
8 // If is_null($content), a single tag will be createed (<$tag $paramkey="$paramvalue"/>).
9 // If a value or key of the $parameter hash is NULL, the key="value" entry will not appear.
10 // The content and the parameter are not encoded in any way.
11 function html_tag($tagname, $parameter, $content) {
12         $result = "<$tagname";
13         foreach($parameter as $key => $value) {
14                 if (!is_null($value) && !is_null($key))
15                 $result .= " $key=\"$value\"";
16         }
17         if (is_null($content)) return $result . '/>';
18         return $result . ">$content</$tagname>";
19 }
20
21
22 // Applies the function htmlentities on every value of an array.
23 function html_escape_array($array, $keystoo = FALSE) {
24         $newarray = array();
25         foreach($array as $key => $value) {
26                 if (is_string($value)) $value = htmlspecialchars($value);
27                 if ($keystoo && is_string($key)) $key = htmlspecialchars($key);
28                 $newarray[$key] = $value;
29         }
30         return $newarray;
31 }
32
33
34 // indents a text
35 function text_indent($text, $indentchar = "\t") {
36         if (strlen($text) == 0) return '';
37         $result = $indentchar . str_replace("\n", "\n$indentchar", $text);
38         if (substr($result, -2) == "\n$indentchar") $result = substr($result, 0, -strlen($indentchar));
39         return $result;
40 }
41
42
43 // Cuts a text to the specified max length and adds fill char. The cutting is done at word ends.
44 // If the text is shorter than maxlength, it returns text.
45 function text_cut($text, $maxlength, $fillchar = ' ...') {
46         if (strlen($text) <= $maxlength) return $text;
47         $text = wordwrap($text, $maxlength);
48         $lines = explode("\n", $text);
49         return $lines[0] . $fillchar;
50 }
51
52
53
54 // Shortcuts for creating simple things
55 // ====================================
56
57 // Shortcut for html_tag: You can use it in the following ways:
58 // html_element($tagname);
59 // html_element($tagname, $content [, $encode]);
60 // html_element($tagname, $parameter [, $encode]);
61 // html_element($tagname, $parameter, $content, [, $encode]);
62 // The optional argument $encode is FALSE by default.
63 // If $encode is TRUE, the $content _and_ the parameters _and_ the keys of the parameters are encoded.
64 function html_element($tagname) {
65         list($tagname, $parameter, $content) = html_element_decode(func_get_args());
66         return html_tag($tagname, $parameter, $content);
67 }
68
69
70 // same as html_element but it does not result in
71 // <tag>content</tag>
72 // but
73 // <tag>\n
74 // \t content\n
75 // </tag>
76 function html_ielement($tagname) {
77         list($tagname, $parameter, $content) = html_element_decode(func_get_args());
78         if (!is_null($content) && !$content == '') {
79                 $content = "\n" . text_indent($content);
80                 if (substr($content, -1) != "\n") $content .= "\n";
81         }
82         return html_tag($tagname, $parameter, $content);
83 }
84
85
86 // "internal" function to use at html_element and html_ielement
87 // Brings the arguments in the correct order and does the encoding
88 function html_element_decode($args) {
89         // Parameter
90         $tagname = $args[0];
91         $encode = FALSE;
92         $parameter = array();
93         $content = NULL;
94         for ($i=1; $i != count($args); ++$i) {
95                 $arg = $args[$i];
96                 if (is_bool($arg)) $encode = $arg;
97                 else if (is_array($arg)) $parameter = $arg;
98                 else if (is_string($arg)) $content = $arg;
99                 else die('unknown arguments in html_element');
100         }
101
102         // Encoding
103         if ($encode) {
104                 $parameter = html_escape_array($parameter, TRUE);
105                 if (!is_null($content)) $content = htmlspecialchars($content);
106         }
107
108         return array($tagname, $parameter, $content);
109 }
110
111
112
113 // Shortcuts for form fields
114 // =========================
115
116 // Helper function for the following form-field-generating functions
117 function html_input_basic($name, $value, $type, $additionalParameter = array()) {
118         $parameter = array('type' => $type, 'name' => $name, 'value' => $value);
119         $parameter = array_merge($parameter, $additionalParameter);
120         return html_element('input', $parameter, TRUE);
121 }
122
123
124 // Creates an hidden field
125 function html_input_hidden($name, $value) {
126         return html_input_basic($name, $value, 'hidden');
127 }
128
129
130 // Creates an input text field
131 function html_input_text($name, $value=NULL, $length=NULL, $size=NULL) {
132         return html_input_basic($name, $value, 'text', array('maxlength' => $length, 'size' => $size));
133 }
134
135
136 // Creates an input password field
137 function html_input_password($name, $value=NULL, $length=NULL, $size=NULL) {
138         return html_input_basic($name, $value, 'password', array('maxlength' => $length, 'size' => $size));
139 }
140
141
142 // Creates a submit field
143 function html_input_submit($name, $value) {
144         return html_input_basic($name, $value, 'submit');
145 }
146
147
148 // Creates a reset field
149 function html_input_reset($value) {
150         return html_input_basic(NULL, $value, 'reset');
151 }
152
153
154 // Creates a select box field
155 function html_input_select($name, $value=NULL, $hash, $encode=FALSE, $format=TRUE, $size=1) {
156         $options = '';
157         foreach($hash as $k => $v) {
158                 $parameter = array('value' => $k);
159                 if ($value == $k) $parameter['selected'] = 'selected';
160                 $options .= html_element('option', $parameter, $v, $encode) . "\n";
161         }
162         if ($format) $options = "\n" . text_indent($options);
163         if ($encode) $name = htmlspecialchars($name);
164         return html_element('select', array('name' => $name, 'size' => $size), $options);
165 }
166
167
168 // Creates a textarea field
169 function html_textarea($name, $value, $cols, $rows, $encode=FALSE) {
170         $parameter = array('name' => $name, 'cols' => $cols, 'rows' => $rows);
171         if (is_null($value)) $value = ''; 
172         return html_element('textarea', $parameter, $value, $encode);
173 }
174
175
176 // Creates a string for an img element. You can use the function as follows:
177 //   html_img($src) // alt=""
178 //   html_img($src, [$alt,] [$encode,] [$keyvaluearray])
179 //   html_img($src, [$alt,] [$keyvaluearray,] [$encode])
180 // keyvaluearray: supply additional attributes. default: array()
181 // encode: default: FALSE
182 // alt: default: ''
183 function html_img($src, $alt='') {
184         $encode = FALSE;
185         $attributes = array('src' => $src, 'alt' => $alt);
186         $args = func_get_args();
187         for($i = 2; $i != count($args); ++$i) {
188                 $arg = $args[$i];
189                 if (is_bool($arg)) $encode=$arg;
190                 if (is_array($arg)) $attributes=array_merge($attributes, $arg);
191         }
192         return html_element('img', $attributes, $encode);
193 }
194
195
196 // Same as above with additional title. If title is NULL, $title = $alt.
197 function html_img_title($src, $alt='', $title=NULL) {
198         $func_parameter = func_get_args();
199         if (is_null($title)) $title = $alt;
200         unset($func_parameter[2]);
201         $found = FALSE;
202         foreach($func_parameter as $k => $v) {
203                 if (is_array($v)) {
204                         $func_parameter[$k]['title'] = $title;
205                         $found = TRUE;
206                 }
207         }
208         if (!$found) $func_parameter[] = array('title' => $title);
209         return call_user_func_array('html_img', $func_parameter);
210 }
211
212
213
214 // DataInfo classes
215 // ================
216
217 // These classes are intended for use with EditForm.
218 // For all class fields, the value NULL means that a default value should be taken.
219
220 class DataInfo {
221         var $header;
222         var $name; // name for form.
223         var $default; // default value for insert
224
225         function DataInfo($name = NULL, $header = NULL, $default = NULL) {
226                 $this->name = $name;
227                 $this->header = $header;
228                 $this->default = $default;
229         }
230
231         // virtual...
232         // creates the head cell of the table
233         function createHtmlTableHeader() {
234                 if (!is_null($this->header))
235                         return html_element('span', array('class'=>'th'), $this->header, TRUE);
236         }
237
238         // virtual...
239         // creates the body cell of the table
240         function createHtmlTableBody($value) {
241                 return html_element('span', array('class'=>'td'), $this->createHtml($value));
242         }
243
244         // virtual...
245         // creates the body cell of an insert row of the table
246         function createHtmlTableInsertBody() {
247                 return html_element('span', array('class'=>'td'), $this->createInsertHtml());
248         }
249
250         // virtual...
251         function createHtml($value) {
252                 return '';
253         }
254
255         // virtual...
256         function createInsertHtml() {
257                 return $this->createHtml($this->default);
258         }
259 };
260
261
262 // This shows the text but is not "database sensitive"
263 class DiReadOnly extends DataInfo {
264         function DiReadOnly($header = NULL, $default = NULL) {
265                 $this->DataInfo(NULL, $header, $default);
266         }
267
268         function createHtml($value) {
269                 return htmlspecialchars($value);
270         }
271 };
272
273
274 class DiHidden extends DataInfo {
275         function DiHidden($name, $default = NULL) {
276                 $this->DataInfo($name, NULL, $default);
277         }
278
279         function createHtmlTableBody($value) {
280                 return $this->createHtml($value);
281         }
282
283         function createHtmlTableInsertBody() {
284                 return $this->createInsertHtml();
285         }
286
287         function createHtml($value) {
288                 return html_input_hidden($this->name, $value);
289         }
290
291         function createInsertHtml() {
292                 if (is_null($this->default)) return '';
293                 return $this->createHtml($this->default);
294         }
295 };
296
297 /*
298 class DiRawHtml extends DataInfo {
299         function createHtml($value) {
300                 return $value;
301         }
302 };
303 */
304
305
306 class DiTextEdit extends DataInfo {
307         var $length = NULL;
308         var $size = NULL;
309
310         function DiTextEdit($name, $header, $length = NULL, $size = NULL, $default = NULL) {
311                 $this->DataInfo($name, $header, $default);
312                 $this->length = $length;
313                 $this->size = $size;
314         }
315
316         function createHtml($value) {
317                 return html_input_text($this->name, $value, $this->length, $this->size);
318         }
319         
320         function createInsertHtml() {
321                 return $this->createHtml($this->default);
322         }       
323 };
324
325
326 class DiPasswordEdit extends DiTextEdit {
327         function createHtml($value) {
328                 return html_input_password($this->name, 'XXXXXX', $this->length, $this->size);
329         }
330         
331         function createInsertHtml() {
332                 return html_input_password($this->name, '', $this->length, $this->size);
333         }
334 };
335
336
337 // input: 1D array of arrays with 2 entries.
338 // the first will be used as key, the second as value.
339 // Useful to crate hash for DiSelect out of database query result.
340 function array_to_hash($array) {
341         $result = array();
342         foreach ($array as $row) {
343                 $result[$row[0]] = (string) $row[1];
344         }
345         return $result;
346 }
347
348
349 class DiSelect extends DataInfo {
350         var $hash;
351
352         function DiSelect($name, $heading, $hash) {
353                 $this->DataInfo($name, $heading);
354                 $this->hash = $hash;
355         }
356
357         function createHtml($value) {
358                 $hash = html_escape_array($this->hash, TRUE);
359                 return html_input_select($this->name, $value, $hash, TRUE);
360         }
361 };
362
363
364 class DiBoolEdit extends DataInfo {
365         function createHtml($value) {
366                 $hash = array('' => '---', 't' => _('Yes'), 'f' => _('No'));
367                 return html_input_select($this->name, $value, $hash);
368         }
369 };
370
371
372 class DiBoolReadOnly extends DataInfo {
373         function DiBoolReadOnly($header = NULL, $default = NULL) {
374                 $this->DataInfo(NULL, $header, $default);
375         }
376
377         function createHtml($value) {
378                 if ($value == 't') return htmlspecialchars(_('Yes'));
379                 if ($value == 'f') return htmlspecialchars(_('No'));
380                 return '';
381         }
382 };
383
384
385 // The data are not editable (but are shown) in normal rows.
386 // Therefore a lookup hash is used.
387 // In the "insert" row, a combobox is used.
388 class DiOnlyInputSelect extends DataInfo {
389         var $lookupHash; // hash for "normal" lines to lookup.
390         var $insertHash; // hash for comboBox for "insert" line.
391         
392         function DiOnlyInputSelect($name, $header, $default, $lookupHash, $insertHash) {
393                 $this->DataInfo($name, $header, $default);
394                 $this->lookupHash = $lookupHash;
395                 $this->insertHash = $insertHash;
396         }
397
398         function createHtml($value) {
399                 $hash = html_escape_array($this->lookupHash, TRUE);
400                 $hiddenField = html_input_hidden($this->name, $value);
401                 if (array_key_exists($value, $hash)) return $hiddenField . $hash[$value];
402                 return $hiddenField . '(' . htmlentities($value) . ')';
403         }
404
405         function createInsertHtml() {
406                 $hash = html_escape_array($this->insertHash, TRUE);
407                 return html_input_select($this->name, $this->default, $hash, TRUE);
408         }
409 };
410
411
412 class DiTextareaEdit extends DataInfo {
413         var $cols = NULL;
414         var $rows = NULL;
415
416         function DiTextareaEdit($name, $header, $cols = NULL, $rows = NULL) {
417                 $this->DataInfo($name, $header);
418                 $this->cols = $cols;
419                 $this->rows = $rows;
420         }
421
422         function createHtml($value) {
423                 return html_textarea($this->name, $value, $this->cols, $this->rows, TRUE);
424         }
425 };
426
427
428
429 // EditForm classes and functions
430 // ==============================
431
432 // creates an array of DataInfo classes suitable for the $dbresult.
433 // if fieldnamekeys === TRUE, the field names will be taken as keys,
434 //   else numbers will be taken.
435 // $header: the names of the header
436 // $size: the size of the field, if the type has a size.
437 // $length: the length of the field, if the type has a length. If NULL,
438 //   the $size will be taken.
439 // $header, $size, $length can each be:
440 // * assoziative array (hash): columnname => value
441 // * normal array: values "from left to right"
442 // * string functionname to apply to the default values i.e. ucwords.
443 // The value NULL means that this property is not taken,
444 // a value TRUE means that the default property is taken.
445 function html_defaultColumns(
446         $dbresult,
447         $fieldnamekeys = FALSE,
448         $header = NULL,
449         $size = NULL,
450         $length = NULL
451 ) {
452         for ($col = 0; $col != pg_num_fields($dbresult); ++$col) {
453                 // Name
454                 $cname = pg_field_name($dbresult, $col);
455
456                 // Type
457                 $ctype = pg_field_type($dbresult, $col);
458
459                 // Size
460                 $dsize = pg_field_size($dbresult, $col);
461                 $csize = FALSE;
462                 if (is_string($size)) $csize = $size($dsize);
463                 elseif (is_array($size) && array_key_exists($cname, $size)) $csize = $size[$cname];
464                 elseif (is_array($size) && array_key_exists($col, $size)) $csize = $size[$col];
465                 if ($csize === FALSE) $csize = $dsize;
466                 if ($csize == -1) $csize = NULL;
467
468                 // Length
469                 $clength = FALSE;
470                 if (is_string($length)) $clength = $length($csize);
471                 elseif (is_array($length) && array_key_exists($cname, $length)) $clength = $length[$cname];
472                 elseif (is_array($length) && array_key_exists($col, $length)) $clength = $length[$col];
473                 if ($clength === FALSE) $clength = $csize;
474
475                 // Header
476                 $cheader = FALSE;
477                 if (is_string($header)) $cheader = $header($cname);
478                 elseif (is_array($header) && array_key_exists($cname, $header)) $cheader = $header[$cname];
479                 elseif (is_array($header) && array_key_exists($col, $header)) $cheader = $header[$col];
480                 if ($cheader === FALSE) $cheader = $cname;
481
482                 // Create DataInfo class
483                 $di = NULL;
484                 if ($ctype == 'bool') $di = new DiBoolEdit($cname, $cheader);
485                 if (is_null($di)) $di = new DiTextEdit($cname, $cheader, $csize, $clength);
486                 if ($fieldnamekeys) $columns[$cname] = $di;
487                 else $columns[] = $di;
488         }
489         return $columns;
490 }
491
492
493 function html_createEditForm(
494         $action,
495         $nextpage, // data to fill in in the field :nextpage (needed by editdb.php)
496         $tablename,
497         $columns, // 1D Array of EfDataInfo classes
498         $data, // Array of rows, that are again arrays of columns
499         $insert=TRUE,
500         $update=TRUE,
501         $delete=TRUE
502 ) {
503         if (count($data) == 0 && !$insert) return;
504         $action = htmlspecialchars($action);
505
506         // fill in nextpage
507         $columns[] = new DiHidden(':nextpage', $nextpage);
508         foreach ($data as $rownum => $datarow) {
509                 $data[$rownum][] = $nextpage;
510         }
511         
512         // fill in tablename
513         $columns[] = new DiHidden(':tablename', $tablename);
514         foreach ($data as $rownum => $datarow) {
515                 $data[$rownum][] = $tablename;
516         }
517         
518         // head
519         $head = '';
520         foreach($columns as $column) {
521                 $h = $column->createHtmlTableHeader();
522                 if (strlen($h) > 0) $h .= "\n";
523                 $head .= $h;
524         }
525         $head .= html_element('span', array('class'=>'th'), '&nbsp;');
526         $result = html_ielement('div', array('class'=>'tr_head'), $head) . "\n";
527
528         // update
529         $rownr = 0;
530         foreach($data as $datarow) {
531                 $row = '';
532                 $columnnr = 0;
533                 foreach ($datarow as $field) {
534                         $column = $columns[$columnnr];                  
535                         $html = $column->createHtmlTableBody($field);
536                         if (strlen($html) > 0) $html .= "\n";
537                         $row .= $html;
538                         ++$columnnr;
539                 }
540                 $buttons = '';
541                 if ($update) $buttons .= html_input_submit(':operation_update', _('update'));
542                 if ($delete) $buttons .= html_input_submit(':operation_delete', _('delete'));
543                 $row .= html_element('span', array('class'=>'td'), $buttons);
544                 $class = ($rownr % 2 == 0) ? 'tr_even' : 'tr_odd';
545
546                 $result .= html_ielement('form', array('action' => $action, 'method' => 'post', 'class' => $class), $row) . "\n";
547                 ++$rownr;
548         }
549
550         // insert
551         if ($insert) {
552                 $row = '';
553                 foreach($columns as $column) {
554                         $html = $column->createHtmlTableInsertBody();
555                         if (strlen($html) > 0) $html .= "\n";
556                         $row .= $html;
557                 }
558                 $button = html_input_submit(':operation_insert', _('insert')) . "\n";
559                 $row .= html_element('span', array('class'=>'td'), $button);
560                 $result .= html_ielement('form', array('action' => $action, 'method' => 'post', 'class' => 'tr_insert'), $row);
561                 // $result .= html_ielement('div', array('class' => 'tr_insert'), $row);
562         }
563
564         return html_ielement('div', array('class'=>'table'), $result);
565 }
566
567
568 function html_createVEditForm(
569         $action,
570         $tablename,
571         $columns, // 1D Array of EfDataInfo classes
572         $data, // Array of rows, that are again arrays of columns
573         $insert=TRUE,
574         $update=TRUE,
575         $delete=TRUE
576 ) {
577         // fill in tablename
578         $columns[] = new DiHidden(':tablename', $tablename);
579         foreach ($data as $rownum => $datarow) {
580                 $data[$rownum][] = $tablename;
581         }
582
583         // Rows
584         $rows = '';
585         $rownr = 0;
586         foreach($data as $row) {
587                 $coltext = '';
588                 reset($columns);
589                 reset($row);
590                 while($column = current($columns)) {
591                         $head = $column->createHtmlTableHeader();
592                         $field = $column->createHtmlTableBody(current($row));
593                         $text = "$head\n$field";
594                         if (!is_null($column->header)) $text = html_ielement('tr', $text);
595                         $coltext .= "$text\n";
596                         next($columns);
597                         next($row);
598                 }
599                 $buttons = '';
600                 if ($update) $buttons .= html_input_submit(':operation_update', _('update'));
601                 if ($delete) $buttons .= html_input_submit(':operation_delete', _('delete'));
602                 $coltext .= '<tr><th>&nbsp;</th>' . html_element('td', $buttons) . "</tr>\n";
603                 $coltext = html_ielement('form', array('action' => $action, 'method' => 'post'), $coltext) . "\n";
604                 $class = ($rownr % 2 == 0) ? 'even' : 'odd';
605                 $coltext = html_ielement('table', array('class' => $class), $coltext) . "\n";
606                 $coltext = html_ielement('p', $coltext) . "\n";
607                 $rows .= $coltext;
608                 ++$rownr;
609         }
610
611         // Insert
612         if ($insert) {
613                 $coltext = '';
614                 reset($columns);
615                 while($column = current($columns)) {
616                         $head = $column->createHtmlTableHeader();
617                         $field = $column->createHtmlTableInsertBody();
618                         $text = "$head\n$field";
619                         if (!is_null($column->header)) $text = html_ielement('tr', $text);
620                         $coltext .= "$text\n";
621                         next($columns);
622                 }
623                 $button = html_input_submit(':operation_insert', _('insert'));
624                 $coltext .= '<tr><th>&nbsp;</th>' . html_element('td', $button) . "</tr>\n";
625                 $coltext = html_ielement('form', array('action' => $action, 'method' => 'post'), $coltext) . "\n";
626                 $coltext = html_ielement('table', array('class' => 'insert'), $coltext) . "\n";
627                 $coltext = html_ielement('p', $coltext) . "\n";
628                 $rows .= $coltext;
629         }
630
631         return $rows;
632 }
633
634
635 function html_createTable(
636         $head, // 1D Array of Head fields
637         $data // Array of rows, that are again arrays of columns
638 ) {
639         html_escape_array($head);
640         $thead = '<tr><th>' . implode('</th><th>', $head) . "</th></tr>\n";
641
642         $tbody = '';
643         $num = 0;
644         foreach($data as $row) {
645                 html_escape_array($row);
646                 $trow = '<td>' . implode('</td><td>', $row) . '</td>';
647                 $tbody .= html_element('tr', array('class' => ($num % 2 == 0 ? 'even' : 'odd')), $trow);
648                 ++$num;
649         }
650
651         return html_ielement('table', "$thead$tbody");
652 }
653
654 ?>