svncommit
2008-09-18 cc0d55cbcbc3cfef82ce86b8cb5df5936be97c65
commit | author | age
47124c 1 <?php
T 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();
e3e597 32     protected $allowed = array();
47124c 33     protected $content;
T 34
8fa58e 35     public static $common_attrib = array('id','class','style','title','align');
36c236 36     public static $containers = array('div','span','p','h1','h2','h3','form','textarea','table','tr','th','td','style');
47124c 37     public static $lc_tags = true;
T 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     {
e3e597 58         return self::tag($this->tagname, $this->attrib, $this->content, array_merge(self::$common_attrib, $this->allowed));
47124c 59     }
T 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         }
f5aa16 101         return self::tag('div', $attr, $cont, array_merge(self::$common_attrib, array('onclick')));
47124c 102     }
T 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         }
6d6e06 148         return self::tag('a', $attr, $cont, array_merge(self::$common_attrib, array('href','target','name','onclick','onmouseover','onmouseout','onmousedown','onmouseup')));
47124c 149     }
T 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';
491a6e 251     protected $allowed = array('type','name','value','size','tabindex','autocomplete','checked','onchange','onclick','disabled','readonly','spellcheck');
47124c 252
T 253     public function __construct($attrib = array())
254     {
255         if (is_array($attrib)) {
256             $this->attrib = $attrib;
257         }
258
259         if ($attrib['type']) {
260             $this->type = $attrib['type'];
261         }
262
263         if ($attrib['newline']) {
264             $this->newline = true;
265         }
266     }
267
268     /**
269      * Compose input tag
270      *
271      * @param string Field value
272      * @param array Additional attributes to override
273      * @return string HTML output
274      */
275     public function show($value = null, $attrib = null)
276     {
277         // overwrite object attributes
278         if (is_array($attrib)) {
279             $this->attrib = array_merge($this->attrib, $attrib);
280         }
281
282         // set value attribute
283         if ($value !== null) {
284             $this->attrib['value'] = $value;
285         }
286         // set type
287         $this->attrib['type'] = $this->type;
288         return parent::show();
289     }
290 }
291
292 /**
293  * Class to create an HTML password field
294  *
295  * @package HTML
296  */
297 class html_passwordfield extends html_inputfield
298 {
299     protected $type = 'password';
300 }
301
302 /**
303  * Class to create an hidden HTML input field
304  *
305  * @package HTML
306  */
307
308 class html_hiddenfield extends html_inputfield
309 {
310     protected $type = 'hidden';
311     protected $fields_arr = array();
312     protected $newline = true;
313
314     /**
315      * Constructor
316      *
317      * @param array Named tag attributes
318      */
319     public function __construct($attrib = null)
320     {
321         if (is_array($attrib)) {
322             $this->add($attrib);
323         }
324     }
325
326     /**
327      * Add a hidden field to this instance
328      *
329      * @param array Named tag attributes
330      */
331     public function add($attrib)
332     {
333         $this->fields_arr[] = $attrib;
334     }
335
336     /**
337      * Create HTML code for the hidden fields
338      *
339      * @return string Final HTML code
340      */
341     public function show()
342     {
343         $out = '';
344         foreach ($this->fields_arr as $attrib) {
345             $out .= self::tag($this->tagname, array('type' => $this->type) + $attrib);
346         }
347         return $out;
348     }
349 }
350
351 /**
352  * Class to create HTML radio buttons
353  *
354  * @package HTML
355  */
356 class html_radiobutton extends html_inputfield
357 {
358     protected $type = 'radio';
359
360     /**
361      * Get HTML code for this object
362      *
363      * @param string Value of the checked field
364      * @param array Additional attributes to override
365      * @return string HTML output
366      */
367     public function show($value = '', $attrib = null)
368     {
369         // overwrite object attributes
370         if (is_array($attrib)) {
371             $this->attrib = array_merge($this->attrib, $attrib);
372         }
373
374         // set value attribute
ff6def 375         $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']);
47124c 376
T 377         return parent::show();
378     }
379 }
380
381 /**
382  * Class to create HTML checkboxes
383  *
384  * @package HTML
385  */
386 class html_checkbox extends html_inputfield
387 {
388     protected $type = 'checkbox';
389
390     /**
391      * Get HTML code for this object
392      *
393      * @param string Value of the checked field
394      * @param array Additional attributes to override
395      * @return string HTML output
396      */
397     public function show($value = '', $attrib = null)
398     {
399         // overwrite object attributes
400         if (is_array($attrib)) {
401             $this->attrib = array_merge($this->attrib, $attrib);
402         }
403
404         // set value attribute
ff6def 405         $this->attrib['checked'] = ((string)$value == (string)$this->attrib['value']);
47124c 406
T 407         return parent::show();
408     }
409 }
410
411 /**
412  * Class to create an HTML textarea
413  *
414  * @package HTML
415  */
416 class html_textarea extends html
417 {
418     protected $tagname = 'textarea';
491a6e 419     protected $allowed = array('name','rows','cols','wrap','tabindex','onchange','disabled','readonly','spellcheck');
47124c 420
T 421     /**
422      * Get HTML code for this object
423      *
424      * @param string Textbox value
425      * @param array Additional attributes to override
426      * @return string HTML output
427      */
428     public function show($value = '', $attrib = null)
429     {
430         // overwrite object attributes
431         if (is_array($attrib)) {
432             $this->attrib = array_merge($this->attrib, $attrib);
433         }
434
435         // take value attribute as content
54d830 436         if (empty($value) && !empty($this->attrib['value'])) {
47124c 437             $value = $this->attrib['value'];
T 438         }
439
440         // make shure we don't print the value attribute
441         if (isset($this->attrib['value'])) {
442             unset($this->attrib['value']);
443         }
444
6025c8 445         if (!empty($value) && !ereg('mce_editor', $this->attrib['class'])) {
54d830 446             $value = Q($value, 'strict', false);
47124c 447         }
6025c8 448
e3e597 449         return self::tag($this->tagname, $this->attrib, $value, array_merge(self::$common_attrib, $this->allowed));
47124c 450     }
T 451 }
452
453 /**
454  * Builder for HTML drop-down menus
455  * Syntax:<pre>
456  * // create instance. arguments are used to set attributes of select-tag
457  * $select = new html_select(array('name' => 'fieldname'));
458  *
459  * // add one option
460  * $select->add('Switzerland', 'CH');
461  *
462  * // add multiple options
463  * $select->add(array('Switzerland','Germany'), array('CH','DE'));
464  *
465  * // generate pulldown with selection 'Switzerland'  and return html-code
466  * // as second argument the same attributes available to instanciate can be used
467  * print $select->show('CH');
468  * </pre>
469  *
470  * @package HTML
471  */
472 class html_select extends html
473 {
474     protected $tagname = 'select';
475     protected $options = array();
cb3538 476     protected $allowed = array('name','size','tabindex','autocomplete','multiple','onchange','disabled');
47124c 477     
T 478     /**
479      * Add a new option to this drop-down
480      *
481      * @param mixed Option name or array with option names
482      * @param mixed Option value or array with option values
483      */
484     public function add($names, $values = null)
485     {
486         if (is_array($names)) {
487             foreach ($names as $i => $text) {
488                 $this->options[] = array('text' => $text, 'value' => $values[$i]);
489             }
490         }
491         else {
492             $this->options[] = array('text' => $names, 'value' => $values);
493         }
494     }
495
496
497     /**
498      * Get HTML code for this object
499      *
500      * @param string Value of the selection option
501      * @param array Additional attributes to override
502      * @return string HTML output
503      */
504     public function show($select = array(), $attrib = null)
505     {
506         // overwrite object attributes
507         if (is_array($attrib)) {
508             $this->attrib = array_merge($this->attrib, $attrib);
509         }
510
511         $this->content = "\n";
512         $select = (array)$select;
513         foreach ($this->options as $option) {
514             $attr = array(
515                 'value' => $option['value'],
ff6def 516                 'selected' => (in_array($option['value'], $select, true) ||
5b3dd4 517                   in_array($option['text'], $select, true)) ? 1 : null);
47124c 518
T 519             $this->content .= self::tag('option', $attr, Q($option['text']));
520         }
521         return parent::show();
522     }
523 }
524
525
526 /**
527  * Class to build an HTML table
528  *
529  * @package HTML
530  */
531 class html_table extends html
532 {
533     protected $tagname = 'table';
534     protected $allowed = array('id','class','style','width','summary','cellpadding','cellspacing','border');
535     private $header = array();
536     private $rows = array();
537     private $rowindex = 0;
538     private $colindex = 0;
539
540
541     public function __construct($attrib = array())
542     {
543         $this->attrib = array_merge($attrib, array('summary' => '', 'border' => 0));
544     }
545
546     /**
547      * Add a table cell
548      *
549      * @param array Cell attributes
550      * @param string Cell content
551      */
552     public function add($attr, $cont)
553     {
554         if (is_string($attr)) {
555             $attr = array('class' => $attr);
556         }
557
558         $cell = new stdClass;
559         $cell->attrib = $attr;
560         $cell->content = $cont;
561
562         $this->rows[$this->rowindex]->cells[$this->colindex] = $cell;
563         $this->colindex++;
564
565         if ($this->attrib['cols'] && $this->colindex == $this->attrib['cols']) {
566             $this->add_row();
567         }
568     }
569
570     /**
571      * Add a table header cell
572      *
573      * @param array Cell attributes
574      * @param string Cell content
575      */
83a763 576     public function add_header($attr, $cont)
47124c 577     {
T 578         if (is_string($attr))
579         $attr = array('class' => $attr);
580
581         $cell = new stdClass;
582         $cell->attrib = $attr;
583         $cell->content = $cont;
584         $this->header[] = $cell;
585     }
586
587     /**
588      * Jump to next row
589      *
590      * @param array Row attributes
591      */
83a763 592     public function add_row($attr = array())
47124c 593     {
T 594         $this->rowindex++;
595         $this->colindex = 0;
596         $this->rows[$this->rowindex] = new stdClass;
597         $this->rows[$this->rowindex]->attrib = $attr;
598         $this->rows[$this->rowindex]->cells = array();
599     }
600
601
602     /**
603      * Build HTML output of the table data
604      *
605      * @param array Table attributes
606      * @return string The final table HTML code
607      */
46290a 608     public function show($attrib = null)
47124c 609     {
f92aba 610         if (is_array($attrib))
T 611             $this->attrib = array_merge($this->attrib, $attrib);
46290a 612         
f92aba 613         $thead = $tbody = "";
47124c 614
T 615         // include <thead>
616         if (!empty($this->header)) {
617             $rowcontent = '';
618             foreach ($this->header as $c => $col) {
83a763 619                 $rowcontent .= self::tag('td', $col->attrib, $col->content);
47124c 620             }
T 621             $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent));
622         }
623
624         foreach ($this->rows as $r => $row) {
625             $rowcontent = '';
626             foreach ($row->cells as $c => $col) {
627                 $rowcontent .= self::tag('td', $col->attrib, $col->content);
628             }
629
630             if ($r < $this->rowindex || count($row->cells)) {
83a763 631                 $tbody .= self::tag('tr', $row->attrib, $rowcontent);
47124c 632             }
T 633         }
634
635         if ($this->attrib['rowsonly']) {
636             return $tbody;
637         }
638
639         // add <tbody>
640         $this->content = $thead . self::tag('tbody', null, $tbody);
641
642         unset($this->attrib['cols'], $this->attrib['rowsonly']);
643         return parent::show();
644     }
645 }
646
f5aa16 647 ?>