alecpl
2012-01-06 e86a21bd83a0ae6cadfe9c919582951f306d3b64
commit | author | age
47124c 1 <?php
4c6b66 2
47124c 3 /*
T 4  +-----------------------------------------------------------------------+
5  | program/include/rcube_html_page.php                                   |
6  |                                                                       |
e019f2 7  | This file is part of the Roundcube PHP suite                          |
044d66 8  | Copyright (C) 2005-2011 The Roundcube Dev Team                       |
47124c 9  | Licensed under the GNU GPL                                            |
T 10  |                                                                       |
11  | CONTENTS:                                                             |
12  |   Class to build XHTML page output                                    |
13  |                                                                       |
14  +-----------------------------------------------------------------------+
15  | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16  +-----------------------------------------------------------------------+
17
1d786c 18  $Id$
47124c 19
T 20 */
21
22 /**
23  * Class for HTML page creation
24  *
25  * @package HTML
26  */
27 class rcube_html_page
28 {
4c6b66 29     protected $scripts_path = '';
T 30     protected $script_files = array();
ba3377 31     protected $css_files = array();
4c6b66 32     protected $scripts = array();
ecb9fb 33     protected $charset = RCMAIL_CHARSET;
4c6b66 34     protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
T 35
36     protected $title = '';
37     protected $header = '';
38     protected $footer = '';
39     protected $body = '';
74be73 40     protected $base_path = '';
4c6b66 41
T 42
43     /** Constructor */
44     public function __construct() {}
47124c 45
T 46     /**
47      * Link an external script file
48      *
49      * @param string File URL
50      * @param string Target position [head|foot]
51      */
52     public function include_script($file, $position='head')
53     {
54         static $sa_files = array();
a267c6 55
A 56         if (!preg_match('|^https?://|i', $file) && $file[0] != '/') {
57             $file = $this->scripts_path . $file;
58             if ($fs = @filemtime($file)) {
59                 $file .= '?s=' . $fs;
60             }
61         }
47124c 62
T 63         if (in_array($file, $sa_files)) {
64             return;
65         }
ba3377 66
A 67         $sa_files[] = $file;
68
47124c 69         if (!is_array($this->script_files[$position])) {
T 70             $this->script_files[$position] = array();
71         }
a267c6 72
47124c 73         $this->script_files[$position][] = $file;
T 74     }
75
76     /**
77      * Add inline javascript code
78      *
79      * @param string JS code snippet
80      * @param string Target position [head|head_top|foot]
81      */
82     public function add_script($script, $position='head')
83     {
84         if (!isset($this->scripts[$position])) {
a267c6 85             $this->scripts[$position] = "\n" . rtrim($script);
A 86         }
87         else {
88             $this->scripts[$position] .= "\n" . rtrim($script);
47124c 89         }
ba3377 90     }
A 91
92     /**
93      * Link an external css file
94      *
95      * @param string File URL
96      */
97     public function include_css($file)
98     {
99         $this->css_files[] = $file;
47124c 100     }
T 101
102     /**
103      * Add HTML code to the page header
5c461b 104      *
A 105      * @param string $str HTML code
47124c 106      */
T 107     public function add_header($str)
108     {
a267c6 109         $this->header .= "\n" . $str;
47124c 110     }
T 111
112     /**
113      * Add HTML code to the page footer
114      * To be added right befor </body>
5c461b 115      *
A 116      * @param string $str HTML code
47124c 117      */
T 118     public function add_footer($str)
119     {
a267c6 120         $this->footer .= "\n" . $str;
47124c 121     }
T 122
123     /**
124      * Setter for page title
5c461b 125      *
A 126      * @param string $t Page title
47124c 127      */
T 128     public function set_title($t)
129     {
130         $this->title = $t;
131     }
132
133     /**
134      * Setter for output charset.
135      * To be specified in a meta tag and sent as http-header
5c461b 136      *
A 137      * @param string $charset Charset
47124c 138      */
T 139     public function set_charset($charset)
140     {
141         $this->charset = $charset;
142     }
143
144     /**
145      * Getter for output charset
5c461b 146      *
A 147      * @return string Output charset
47124c 148      */
T 149     public function get_charset()
150     {
151         return $this->charset;
152     }
153
154     /**
155      * Reset all saved properties
156      */
157     public function reset()
158     {
159         $this->script_files = array();
2eb794 160         $this->scripts      = array();
A 161         $this->title        = '';
162         $this->header       = '';
163         $this->footer       = '';
164         $this->body         = '';
47124c 165     }
T 166
167     /**
168      * Process template and write to stdOut
169      *
170      * @param string HTML template
171      * @param string Base for absolute paths
172      */
173     public function write($templ='', $base_path='')
174     {
175         $output = empty($templ) ? $this->default_template : trim($templ);
176
177         // set default page title
178         if (empty($this->title)) {
e019f2 179             $this->title = 'Roundcube Mail';
47124c 180         }
T 181
182         // replace specialchars in content
ba3377 183         $page_title  = Q($this->title, 'show', FALSE);
A 184         $page_header = '';
185         $page_footer = '';
47124c 186
T 187         // include meta tag with charset
188         if (!empty($this->charset)) {
189             if (!headers_sent()) {
190                 header('Content-Type: text/html; charset=' . $this->charset);
191             }
ba3377 192             $page_header = '<meta http-equiv="content-type"';
A 193             $page_header.= ' content="text/html; charset=';
194             $page_header.= $this->charset . '" />'."\n";
47124c 195         }
T 196
197         // definition of the code to be placed in the document header and footer
198         if (is_array($this->script_files['head'])) {
199             foreach ($this->script_files['head'] as $file) {
011e80 200                 $page_header .= html::script($file);
47124c 201             }
T 202         }
203
204         $head_script = $this->scripts['head_top'] . $this->scripts['head'];
205         if (!empty($head_script)) {
011e80 206             $page_header .= html::script(array(), $head_script);
47124c 207         }
T 208
209         if (!empty($this->header)) {
ba3377 210             $page_header .= $this->header;
47124c 211         }
T 212
044d66 213         // put docready commands into page footer
T 214         if (!empty($this->scripts['docready'])) {
215             $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
216         }
a98ee3 217
47124c 218         if (is_array($this->script_files['foot'])) {
T 219             foreach ($this->script_files['foot'] as $file) {
011e80 220                 $page_footer .= html::script($file);
47124c 221             }
T 222         }
223
909a3a 224         if (!empty($this->footer)) {
A 225             $page_footer .= $this->footer . "\n";
47124c 226         }
T 227
909a3a 228         if (!empty($this->scripts['foot'])) {
011e80 229             $page_footer .= html::script(array(), $this->scripts['foot']);
47124c 230         }
T 231
232         // find page header
74be73 233         if ($hpos = stripos($output, '</head>')) {
ba3377 234             $page_header .= "\n";
47124c 235         }
T 236         else {
237             if (!is_numeric($hpos)) {
74be73 238                 $hpos = stripos($output, '<body');
47124c 239             }
74be73 240             if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
47124c 241                 while ($output[$hpos] != '>') {
T 242                     $hpos++;
243                 }
244                 $hpos++;
245             }
ba3377 246             $page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
47124c 247         }
T 248
249         // add page hader
250         if ($hpos) {
a98ee3 251             $output = substr_replace($output, $page_header, $hpos, 0);
47124c 252         }
T 253         else {
ba3377 254             $output = $page_header . $output;
47124c 255         }
T 256
ba3377 257         // add page footer
74be73 258         if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
a98ee3 259             $output = substr_replace($output, $page_footer."\n", $fpos, 0);
47124c 260         }
T 261         else {
ba3377 262             $output .= "\n".$page_footer;
47124c 263         }
T 264
ba3377 265         // add css files in head, before scripts, for speed up with parallel downloads
A 266         if (!empty($this->css_files) && 
267             (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
268         ) {
269             $css = '';
270             foreach ($this->css_files as $file) {
a267c6 271                 $css .= html::tag('link', array('rel' => 'stylesheet',
A 272                     'type' => 'text/css', 'href' => $file, 'nl' => true));
ba3377 273             }
a98ee3 274             $output = substr_replace($output, $css, $pos, 0);
ba3377 275         }
47124c 276
798764 277         $this->base_path = $base_path;
ba3377 278
47124c 279         // correct absolute paths in images and other tags
798764 280         // add timestamp to .js and .css filename
ba3377 281         $output = preg_replace_callback(
A 282             '!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
798764 283             array($this, 'file_callback'), $output);
47124c 284         $output = str_replace('$__skin_path', $base_path, $output);
T 285
798764 286         // trigger hook with final HTML content to be sent
T 287         $hook = rcmail::get_instance()->plugins->exec_hook("send_page", array('content' => $output));
288         if (!$hook['abort']) {
a267c6 289             if ($this->charset != RCMAIL_CHARSET) {
798764 290                 echo rcube_charset_convert($hook['content'], RCMAIL_CHARSET, $this->charset);
a267c6 291             }
A 292             else {
798764 293                 echo $hook['content'];
a267c6 294             }
798764 295         }
3510d7 296     }
a98ee3 297
533e86 298     /**
T 299      * Callback function for preg_replace_callback in write()
5c461b 300      *
A 301      * @return string Parsed string
533e86 302      */
74be73 303     private function file_callback($matches)
533e86 304     {
2eb794 305         $file = $matches[3];
74be73 306
A 307         // correct absolute paths
a267c6 308         if ($file[0] == '/') {
2eb794 309             $file = $this->base_path . $file;
a267c6 310         }
74be73 311
A 312         // add file modification timestamp
a267c6 313         if (preg_match('/\.(js|css)$/', $file)) {
A 314             if ($fs = @filemtime($file)) {
315                 $file .= '?s=' . $fs;
316             }
317         }
74be73 318
a267c6 319         return $matches[1] . '=' . $matches[2] . $file . $matches[4];
533e86 320     }
47124c 321 }