source: github/program/include/html.php @ 54d830f

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since 54d830f was 54d830f, checked in by thomascube <thomas@…>, 5 years ago

Fix html quoting in textareas

  • Property mode set to 100644
File size: 17.2 KB
Line 
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 */
28class html
29{
30    protected $tagname;
31    protected $attrib = array();
32    protected $allowed;
33    protected $content;
34
35    protected 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 */
247class 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 */
296class 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
307class 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 */
355class 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'] = ($value && (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 */
385class 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'] = ($value && (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 */
415class html_textarea extends html
416{
417    protected $tagname = 'textarea';
418    protected $allowed_attrib = array('name','rows','cols','wrap');
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 */
470class 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' => ((!empty($option['value']) && 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 */
528class 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?>
Note: See TracBrowser for help on using the repository browser.