]> git.donarmstrong.com Git - roundcube.git/blob - program/include/html.php
Imported Upstream version 0.2~alpha
[roundcube.git] / program / include / html.php
1 <?php
2
3 /*
4  +-----------------------------------------------------------------------+
5  | program/include/html.php                                              |
6  |                                                                       |
7  | This file is part of the RoundCube Webmail client                     |
8  | Copyright (C) 2005-2008, RoundCube Dev, - Switzerland                 |
9  | Licensed under the GNU GPL                                            |
10  |                                                                       |
11  | PURPOSE:                                                              |
12  |   Helper class to create valid XHTML code                             |
13  |                                                                       |
14  +-----------------------------------------------------------------------+
15  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16  +-----------------------------------------------------------------------+
17
18  $Id: $
19
20  */
21
22
23 /**
24  * Class for HTML code creation
25  *
26  * @package HTML
27  */
28 class html
29 {
30     protected $tagname;
31     protected $attrib = array();
32     protected $allowed;
33     protected $content;
34
35     public static $common_attrib = array('id','class','style','title','align');
36     public static $containers = array('div','span','p','h1','h2','h3','form','textarea');
37     public static $lc_tags = true;
38
39     /**
40      * Constructor
41      *
42      * @param array Hash array with tag attributes
43      */
44     public function __construct($attrib = array())
45     {
46         if (is_array($attrib)) {
47             $this->attrib = $attrib;
48         }
49     }
50
51     /**
52      * Return the tag code
53      *
54      * @return string The finally composed HTML tag
55      */
56     public function show()
57     {
58         return self::tag($this->tagname, $this->attrib, $this->content, $this->allowed);
59     }
60
61     /****** STATIC METHODS *******/
62
63     /**
64      * Generic method to create a HTML tag
65      *
66      * @param string Tag name
67      * @param array  Tag attributes as key/value pairs
68      * @param string Optinal Tag content (creates a container tag)
69      * @param array  List with allowed attributes, omit to allow all
70      * @return string The XHTML tag
71      */
72     public static function tag($tagname, $attrib = array(), $content = null, $allowed_attrib = null)
73     {
74         $inline_tags = array('a','span','img');
75         $suffix = $attrib['nl'] || ($content && $attrib['nl'] !== false && !in_array($tagname, $inline_tags)) ? "\n" : '';
76
77         $tagname = self::$lc_tags ? strtolower($tagname) : $tagname;
78         if ($content || in_array($tagname, self::$containers)) {
79             $templ = $attrib['noclose'] ? "<%s%s>%s" : "<%s%s>%s</%s>%s";
80             unset($attrib['noclose']);
81             return sprintf($templ, $tagname, self::attrib_string($attrib, $allowed_attrib), $content, $tagname, $suffix);
82         }
83         else {
84             return sprintf("<%s%s />%s", $tagname, self::attrib_string($attrib, $allowed_attrib), $suffix);
85         }
86     }
87
88     /**
89      * Derrived method for <div> containers
90      *
91      * @param mixed  Hash array with tag attributes or string with class name
92      * @param string Div content
93      * @return string HTML code
94      * @see html::tag()
95      */
96     public static function div($attr = null, $cont = null)
97     {
98         if (is_string($attr)) {
99             $attr = array('class' => $attr);
100         }
101         return self::tag('div', $attr, $cont, self::$common_attrib);
102     }
103
104     /**
105      * Derrived method for <p> blocks
106      *
107      * @param mixed  Hash array with tag attributes or string with class name
108      * @param string Paragraph content
109      * @return string HTML code
110      * @see html::tag()
111      */
112     public static function p($attr = null, $cont = null)
113     {
114         if (is_string($attr)) {
115             $attr = array('class' => $attr);
116         }
117         return self::tag('p', $attr, $cont, self::$common_attrib);
118     }
119
120     /**
121      * Derrived method to create <img />
122      *
123      * @param mixed Hash array with tag attributes or string with image source (src)
124      * @return string HTML code
125      * @see html::tag()
126      */
127     public static function img($attr = null)
128     {
129         if (is_string($attr)) {
130             $attr = array('src' => $attr);
131         }
132         return self::tag('img', $attr + array('alt' => ''), null, array_merge(self::$common_attrib, array('src','alt','width','height','border','usemap')));
133     }
134
135     /**
136      * Derrived method for link tags
137      *
138      * @param mixed  Hash array with tag attributes or string with link location (href)
139      * @param string Link content
140      * @return string HTML code
141      * @see html::tag()
142      */
143     public static function a($attr, $cont)
144     {
145         if (is_string($attr)) {
146             $attr = array('href' => $attr);
147         }
148         return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, array('href','target','name','onclick','onmouseover','onmouseout')));
149     }
150
151     /**
152      * Derrived method for inline span tags
153      *
154      * @param mixed  Hash array with tag attributes or string with class name
155      * @param string Tag content
156      * @return string HTML code
157      * @see html::tag()
158      */
159     public static function span($attr, $cont)
160     {
161         if (is_string($attr)) {
162             $attr = array('class' => $attr);
163         }
164         return self::tag('span', $attr, $cont, self::$common_attrib);
165     }
166
167     /**
168      * Derrived method for form element labels
169      *
170      * @param mixed  Hash array with tag attributes or string with 'for' attrib
171      * @param string Tag content
172      * @return string HTML code
173      * @see html::tag()
174      */
175     public static function label($attr, $cont)
176     {
177         if (is_string($attr)) {
178             $attr = array('for' => $attr);
179         }
180         return self::tag('label', $attr, $cont, array_merge(self::$common_attrib, array('for')));
181     }
182
183     /**
184      * Derrived method for line breaks
185      *
186      * @return string HTML code
187      * @see html::tag()
188      */
189     public static function br()
190     {
191         return self::tag('br');
192     }
193
194     /**
195      * Create string with attributes
196      *
197      * @param array Associative arry with tag attributes
198      * @param array List of allowed attributes
199      * @return string Valid attribute string
200      */
201     public static function attrib_string($attrib = array(), $allowed = null)
202     {
203         if (empty($attrib)) {
204             return '';
205         }
206
207         $allowed_f = array_flip((array)$allowed);
208         $attrib_arr = array();
209         foreach ($attrib as $key => $value) {
210             // skip size if not numeric
211             if (($key=='size' && !is_numeric($value))) {
212                 continue;
213             }
214
215             // ignore "internal" or not allowed attributes
216             if ($key == 'nl' || ($allowed && !isset($allowed_f[$key])) || $value === null) {
217                 continue;
218             }
219
220             // skip empty eventhandlers
221             if (preg_match('/^on[a-z]+/', $key) && !$value) {
222                 continue;
223             }
224
225             // attributes with no value
226             if (in_array($key, array('checked', 'multiple', 'disabled', 'selected'))) {
227                 if ($value) {
228                     $attrib_arr[] = sprintf('%s="%s"', $key, $key);
229                 }
230             }
231             else if ($key=='value') {
232                 $attrib_arr[] = sprintf('%s="%s"', $key, Q($value, 'strict', false));
233             }
234             else {
235                 $attrib_arr[] = sprintf('%s="%s"', $key, Q($value));
236             }
237         }
238         return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
239     }
240 }
241
242 /**
243  * Class to create an HTML input field
244  *
245  * @package HTML
246  */
247 class html_inputfield extends html
248 {
249     protected $tagname = 'input';
250     protected $type = 'text';
251
252     public function __construct($attrib = array())
253     {
254         if (is_array($attrib)) {
255             $this->attrib = $attrib;
256         }
257
258         if ($attrib['type']) {
259             $this->type = $attrib['type'];
260         }
261
262         if ($attrib['newline']) {
263             $this->newline = true;
264         }
265     }
266
267     /**
268      * Compose input tag
269      *
270      * @param string Field value
271      * @param array Additional attributes to override
272      * @return string HTML output
273      */
274     public function show($value = null, $attrib = null)
275     {
276         // overwrite object attributes
277         if (is_array($attrib)) {
278             $this->attrib = array_merge($this->attrib, $attrib);
279         }
280
281         // set value attribute
282         if ($value !== null) {
283             $this->attrib['value'] = $value;
284         }
285         // set type
286         $this->attrib['type'] = $this->type;
287         return parent::show();
288     }
289 }
290
291 /**
292  * Class to create an HTML password field
293  *
294  * @package HTML
295  */
296 class html_passwordfield extends html_inputfield
297 {
298     protected $type = 'password';
299 }
300
301 /**
302  * Class to create an hidden HTML input field
303  *
304  * @package HTML
305  */
306
307 class html_hiddenfield extends html_inputfield
308 {
309     protected $type = 'hidden';
310     protected $fields_arr = array();
311     protected $newline = true;
312
313     /**
314      * Constructor
315      *
316      * @param array Named tag attributes
317      */
318     public function __construct($attrib = null)
319     {
320         if (is_array($attrib)) {
321             $this->add($attrib);
322         }
323     }
324
325     /**
326      * Add a hidden field to this instance
327      *
328      * @param array Named tag attributes
329      */
330     public function add($attrib)
331     {
332         $this->fields_arr[] = $attrib;
333     }
334
335     /**
336      * Create HTML code for the hidden fields
337      *
338      * @return string Final HTML code
339      */
340     public function show()
341     {
342         $out = '';
343         foreach ($this->fields_arr as $attrib) {
344             $out .= self::tag($this->tagname, array('type' => $this->type) + $attrib);
345         }
346         return $out;
347     }
348 }
349
350 /**
351  * Class to create HTML radio buttons
352  *
353  * @package HTML
354  */
355 class html_radiobutton extends html_inputfield
356 {
357     protected $type = 'radio';
358
359     /**
360      * Get HTML code for this object
361      *
362      * @param string Value of the checked field
363      * @param array Additional attributes to override
364      * @return string HTML output
365      */
366     public function show($value = '', $attrib = null)
367     {
368         // overwrite object attributes
369         if (is_array($attrib)) {
370             $this->attrib = array_merge($this->attrib, $attrib);
371         }
372
373         // set value attribute
374         $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']);
375
376         return parent::show();
377     }
378 }
379
380 /**
381  * Class to create HTML checkboxes
382  *
383  * @package HTML
384  */
385 class html_checkbox extends html_inputfield
386 {
387     protected $type = 'checkbox';
388
389     /**
390      * Get HTML code for this object
391      *
392      * @param string Value of the checked field
393      * @param array Additional attributes to override
394      * @return string HTML output
395      */
396     public function show($value = '', $attrib = null)
397     {
398         // overwrite object attributes
399         if (is_array($attrib)) {
400             $this->attrib = array_merge($this->attrib, $attrib);
401         }
402
403         // set value attribute
404         $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']);
405
406         return parent::show();
407     }
408 }
409
410 /**
411  * Class to create an HTML textarea
412  *
413  * @package HTML
414  */
415 class html_textarea extends html
416 {
417     protected $tagname = 'textarea';
418     protected $allowed_attrib = array('name','rows','cols','wrap','tabindex');
419
420     /**
421      * Get HTML code for this object
422      *
423      * @param string Textbox value
424      * @param array Additional attributes to override
425      * @return string HTML output
426      */
427     public function show($value = '', $attrib = null)
428     {
429         // overwrite object attributes
430         if (is_array($attrib)) {
431             $this->attrib = array_merge($this->attrib, $attrib);
432         }
433
434         // take value attribute as content
435         if (empty($value) && !empty($this->attrib['value'])) {
436             $value = $this->attrib['value'];
437         }
438
439         // make shure we don't print the value attribute
440         if (isset($this->attrib['value'])) {
441             unset($this->attrib['value']);
442         }
443
444         if (!empty($value) && !isset($this->attrib['mce_editable'])) {
445             $value = Q($value, 'strict', false);
446         }
447         return self::tag($this->tagname, $this->attrib, $value, array_merge(self::$common_attrib, $this->allowed_attrib));
448     }
449 }
450
451 /**
452  * Builder for HTML drop-down menus
453  * Syntax:<pre>
454  * // create instance. arguments are used to set attributes of select-tag
455  * $select = new html_select(array('name' => 'fieldname'));
456  *
457  * // add one option
458  * $select->add('Switzerland', 'CH');
459  *
460  * // add multiple options
461  * $select->add(array('Switzerland','Germany'), array('CH','DE'));
462  *
463  * // generate pulldown with selection 'Switzerland'  and return html-code
464  * // as second argument the same attributes available to instanciate can be used
465  * print $select->show('CH');
466  * </pre>
467  *
468  * @package HTML
469  */
470 class html_select extends html
471 {
472     protected $tagname = 'select';
473     protected $options = array();
474     
475     /**
476      * Add a new option to this drop-down
477      *
478      * @param mixed Option name or array with option names
479      * @param mixed Option value or array with option values
480      */
481     public function add($names, $values = null)
482     {
483         if (is_array($names)) {
484             foreach ($names as $i => $text) {
485                 $this->options[] = array('text' => $text, 'value' => $values[$i]);
486             }
487         }
488         else {
489             $this->options[] = array('text' => $names, 'value' => $values);
490         }
491     }
492
493
494     /**
495      * Get HTML code for this object
496      *
497      * @param string Value of the selection option
498      * @param array Additional attributes to override
499      * @return string HTML output
500      */
501     public function show($select = array(), $attrib = null)
502     {
503         // overwrite object attributes
504         if (is_array($attrib)) {
505             $this->attrib = array_merge($this->attrib, $attrib);
506         }
507
508         $this->content = "\n";
509         $select = (array)$select;
510         foreach ($this->options as $option) {
511             $attr = array(
512                 'value' => $option['value'],
513                 'selected' => (in_array($option['value'], $select, true) ||
514             in_array($option['text'], $select, true)) ? 1 : null);
515
516             $this->content .= self::tag('option', $attr, Q($option['text']));
517         }
518         return parent::show();
519     }
520 }
521
522
523 /**
524  * Class to build an HTML table
525  *
526  * @package HTML
527  */
528 class html_table extends html
529 {
530     protected $tagname = 'table';
531     protected $allowed = array('id','class','style','width','summary','cellpadding','cellspacing','border');
532     private $header = array();
533     private $rows = array();
534     private $rowindex = 0;
535     private $colindex = 0;
536
537
538     public function __construct($attrib = array())
539     {
540         $this->attrib = array_merge($attrib, array('summary' => '', 'border' => 0));
541     }
542
543     /**
544      * Add a table cell
545      *
546      * @param array Cell attributes
547      * @param string Cell content
548      */
549     public function add($attr, $cont)
550     {
551         if (is_string($attr)) {
552             $attr = array('class' => $attr);
553         }
554
555         $cell = new stdClass;
556         $cell->attrib = $attr;
557         $cell->content = $cont;
558
559         $this->rows[$this->rowindex]->cells[$this->colindex] = $cell;
560         $this->colindex++;
561
562         if ($this->attrib['cols'] && $this->colindex == $this->attrib['cols']) {
563             $this->add_row();
564         }
565     }
566
567     /**
568      * Add a table header cell
569      *
570      * @param array Cell attributes
571      * @param string Cell content
572      */
573     private function add_header($attr, $cont)
574     {
575         if (is_string($attr))
576         $attr = array('class' => $attr);
577
578         $cell = new stdClass;
579         $cell->attrib = $attr;
580         $cell->content = $cont;
581         $this->header[] = $cell;
582     }
583
584     /**
585      * Jump to next row
586      *
587      * @param array Row attributes
588      */
589     private function add_row($attr = array())
590     {
591         $this->rowindex++;
592         $this->colindex = 0;
593         $this->rows[$this->rowindex] = new stdClass;
594         $this->rows[$this->rowindex]->attrib = $attr;
595         $this->rows[$this->rowindex]->cells = array();
596     }
597
598
599     /**
600      * Build HTML output of the table data
601      *
602      * @param array Table attributes
603      * @return string The final table HTML code
604      */
605     public function show($attr = array())
606     {
607         $this->attrib = array_merge($this->attrib, $attr);
608         $thead = $tbody = "";
609
610         // include <thead>
611         if (!empty($this->header)) {
612             $rowcontent = '';
613             foreach ($this->header as $c => $col) {
614                 $rowcontent .= self::tag('th', $col->attrib, $col->content);
615             }
616             $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent));
617         }
618
619         foreach ($this->rows as $r => $row) {
620             $rowcontent = '';
621             foreach ($row->cells as $c => $col) {
622                 $rowcontent .= self::tag('td', $col->attrib, $col->content);
623             }
624
625             if ($r < $this->rowindex || count($row->cells)) {
626                 $tbody .= self::tag('tr', $rows->attrib, $rowcontent);
627             }
628         }
629
630         if ($this->attrib['rowsonly']) {
631             return $tbody;
632         }
633
634         // add <tbody>
635         $this->content = $thead . self::tag('tbody', null, $tbody);
636
637         unset($this->attrib['cols'], $this->attrib['rowsonly']);
638         return parent::show();
639     }
640 }
641
642 ?>