~tsep-dev/tsep/0.9-beta

« back to all changes in this revision

Viewing changes to branches/symfony/cake/libs/view/helpers/html.php

  • Committer: geoffreyfishing
  • Date: 2011-01-11 23:46:12 UTC
  • Revision ID: svn-v4:ae0de26e-ed09-4cbe-9a20-e40b4c60ac6c::125
Created a symfony branch for future migration to symfony

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Html Helper class file.
 
4
 *
 
5
 * Simplifies the construction of HTML elements.
 
6
 *
 
7
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 
8
 * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
 
9
 *
 
10
 * Licensed under The MIT License
 
11
 * Redistributions of files must retain the above copyright notice.
 
12
 *
 
13
 * @copyright     Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
 
14
 * @link          http://cakephp.org CakePHP(tm) Project
 
15
 * @package       cake
 
16
 * @subpackage    cake.cake.libs.view.helpers
 
17
 * @since         CakePHP(tm) v 0.9.1
 
18
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 
19
 */
 
20
/**
 
21
 * Html Helper class for easy use of HTML widgets.
 
22
 *
 
23
 * HtmlHelper encloses all methods needed while working with HTML pages.
 
24
 *
 
25
 * @package       cake
 
26
 * @subpackage    cake.cake.libs.view.helpers
 
27
 * @link http://book.cakephp.org/view/1434/HTML
 
28
 */
 
29
class HtmlHelper extends AppHelper {
 
30
/**
 
31
 * html tags used by this helper.
 
32
 *
 
33
 * @var array
 
34
 * @access public
 
35
 */
 
36
        var $tags = array(
 
37
                'meta' => '<meta%s/>',
 
38
                'metalink' => '<link href="%s"%s/>',
 
39
                'link' => '<a href="%s"%s>%s</a>',
 
40
                'mailto' => '<a href="mailto:%s" %s>%s</a>',
 
41
                'form' => '<form %s>',
 
42
                'formend' => '</form>',
 
43
                'input' => '<input name="%s" %s/>',
 
44
                'textarea' => '<textarea name="%s" %s>%s</textarea>',
 
45
                'hidden' => '<input type="hidden" name="%s" %s/>',
 
46
                'checkbox' => '<input type="checkbox" name="%s" %s/>',
 
47
                'checkboxmultiple' => '<input type="checkbox" name="%s[]"%s />',
 
48
                'radio' => '<input type="radio" name="%s" id="%s" %s />%s',
 
49
                'selectstart' => '<select name="%s"%s>',
 
50
                'selectmultiplestart' => '<select name="%s[]"%s>',
 
51
                'selectempty' => '<option value=""%s>&nbsp;</option>',
 
52
                'selectoption' => '<option value="%s"%s>%s</option>',
 
53
                'selectend' => '</select>',
 
54
                'optiongroup' => '<optgroup label="%s"%s>',
 
55
                'optiongroupend' => '</optgroup>',
 
56
                'checkboxmultiplestart' => '',
 
57
                'checkboxmultipleend' => '',
 
58
                'password' => '<input type="password" name="%s" %s/>',
 
59
                'file' => '<input type="file" name="%s" %s/>',
 
60
                'file_no_model' => '<input type="file" name="%s" %s/>',
 
61
                'submit' => '<input %s/>',
 
62
                'submitimage' => '<input type="image" src="%s" %s/>',
 
63
                'button' => '<button type="%s"%s>%s</button>',
 
64
                'image' => '<img src="%s" %s/>',
 
65
                'tableheader' => '<th%s>%s</th>',
 
66
                'tableheaderrow' => '<tr%s>%s</tr>',
 
67
                'tablecell' => '<td%s>%s</td>',
 
68
                'tablerow' => '<tr%s>%s</tr>',
 
69
                'block' => '<div%s>%s</div>',
 
70
                'blockstart' => '<div%s>',
 
71
                'blockend' => '</div>',
 
72
                'tag' => '<%s%s>%s</%s>',
 
73
                'tagstart' => '<%s%s>',
 
74
                'tagend' => '</%s>',
 
75
                'para' => '<p%s>%s</p>',
 
76
                'parastart' => '<p%s>',
 
77
                'label' => '<label for="%s"%s>%s</label>',
 
78
                'fieldset' => '<fieldset%s>%s</fieldset>',
 
79
                'fieldsetstart' => '<fieldset><legend>%s</legend>',
 
80
                'fieldsetend' => '</fieldset>',
 
81
                'legend' => '<legend>%s</legend>',
 
82
                'css' => '<link rel="%s" type="text/css" href="%s" %s/>',
 
83
                'style' => '<style type="text/css"%s>%s</style>',
 
84
                'charset' => '<meta http-equiv="Content-Type" content="text/html; charset=%s" />',
 
85
                'ul' => '<ul%s>%s</ul>',
 
86
                'ol' => '<ol%s>%s</ol>',
 
87
                'li' => '<li%s>%s</li>',
 
88
                'error' => '<div%s>%s</div>',
 
89
                'javascriptblock' => '<script type="text/javascript"%s>%s</script>',
 
90
                'javascriptstart' => '<script type="text/javascript">',
 
91
                'javascriptlink' => '<script type="text/javascript" src="%s"%s></script>',
 
92
                'javascriptend' => '</script>'
 
93
        );
 
94
 
 
95
/**
 
96
 * Breadcrumbs.
 
97
 *
 
98
 * @var array
 
99
 * @access protected
 
100
 */
 
101
        var $_crumbs = array();
 
102
 
 
103
/**
 
104
 * Names of script files that have been included once
 
105
 *
 
106
 * @var array
 
107
 * @access private
 
108
 */
 
109
        var $__includedScripts = array();
 
110
/**
 
111
 * Options for the currently opened script block buffer if any.
 
112
 *
 
113
 * @var array
 
114
 * @access protected
 
115
 */
 
116
        var $_scriptBlockOptions = array();
 
117
/**
 
118
 * Document type definitions
 
119
 *
 
120
 * @var array
 
121
 * @access private
 
122
 */
 
123
        var $__docTypes = array(
 
124
                'html4-strict'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
 
125
                'html4-trans'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
 
126
                'html4-frame'  => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
 
127
                'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
 
128
                'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
 
129
                'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
 
130
                'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
 
131
        );
 
132
 
 
133
/**
 
134
 * Adds a link to the breadcrumbs array.
 
135
 *
 
136
 * @param string $name Text for link
 
137
 * @param string $link URL for link (if empty it won't be a link)
 
138
 * @param mixed $options Link attributes e.g. array('id'=>'selected')
 
139
 * @return void
 
140
 * @see HtmlHelper::link() for details on $options that can be used.
 
141
 * @access public
 
142
 */
 
143
        function addCrumb($name, $link = null, $options = null) {
 
144
                $this->_crumbs[] = array($name, $link, $options);
 
145
        }
 
146
 
 
147
/**
 
148
 * Returns a doctype string.
 
149
 *
 
150
 * Possible doctypes:
 
151
 *
 
152
 *  - html4-strict:  HTML4 Strict.
 
153
 *  - html4-trans:  HTML4 Transitional.
 
154
 *  - html4-frame:  HTML4 Frameset.
 
155
 *  - xhtml-strict: XHTML1 Strict.
 
156
 *  - xhtml-trans: XHTML1 Transitional.
 
157
 *  - xhtml-frame: XHTML1 Frameset.
 
158
 *  - xhtml11: XHTML1.1.
 
159
 *
 
160
 * @param string $type Doctype to use.
 
161
 * @return string Doctype string
 
162
 * @access public
 
163
 * @link http://book.cakephp.org/view/1439/docType
 
164
 */
 
165
        function docType($type = 'xhtml-strict') {
 
166
                if (isset($this->__docTypes[$type])) {
 
167
                        return $this->__docTypes[$type];
 
168
                }
 
169
                return null;
 
170
        }
 
171
 
 
172
/**
 
173
 * Creates a link to an external resource and handles basic meta tags
 
174
 *
 
175
 * ### Options
 
176
 *
 
177
 * - `inline` Whether or not the link element should be output inline, or in scripts_for_layout.
 
178
 *
 
179
 * @param string $type The title of the external resource
 
180
 * @param mixed $url The address of the external resource or string for content attribute
 
181
 * @param array $options Other attributes for the generated tag. If the type attribute is html,
 
182
 *    rss, atom, or icon, the mime-type is returned.
 
183
 * @return string A completed `<link />` element.
 
184
 * @access public
 
185
 * @link http://book.cakephp.org/view/1438/meta
 
186
 */
 
187
        function meta($type, $url = null, $options = array()) {
 
188
                $inline = isset($options['inline']) ? $options['inline'] : true;
 
189
                unset($options['inline']);
 
190
 
 
191
                if (!is_array($type)) {
 
192
                        $types = array(
 
193
                                'rss'   => array('type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $url),
 
194
                                'atom'  => array('type' => 'application/atom+xml', 'title' => $type, 'link' => $url),
 
195
                                'icon'  => array('type' => 'image/x-icon', 'rel' => 'icon', 'link' => $url),
 
196
                                'keywords' => array('name' => 'keywords', 'content' => $url),
 
197
                                'description' => array('name' => 'description', 'content' => $url),
 
198
                        );
 
199
 
 
200
                        if ($type === 'icon' && $url === null) {
 
201
                                $types['icon']['link'] = $this->webroot('favicon.ico');
 
202
                        }
 
203
 
 
204
                        if (isset($types[$type])) {
 
205
                                $type = $types[$type];
 
206
                        } elseif (!isset($options['type']) && $url !== null) {
 
207
                                if (is_array($url) && isset($url['ext'])) {
 
208
                                        $type = $types[$url['ext']];
 
209
                                } else {
 
210
                                        $type = $types['rss'];
 
211
                                }
 
212
                        } elseif (isset($options['type']) && isset($types[$options['type']])) {
 
213
                                $type = $types[$options['type']];
 
214
                                unset($options['type']);
 
215
                        } else {
 
216
                                $type = array();
 
217
                        }
 
218
                } elseif ($url !== null) {
 
219
                        $inline = $url;
 
220
                }
 
221
                $options = array_merge($type, $options);
 
222
                $out = null;
 
223
 
 
224
                if (isset($options['link'])) {
 
225
                        if (isset($options['rel']) && $options['rel'] === 'icon') {
 
226
                                $out = sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' '));
 
227
                                $options['rel'] = 'shortcut icon';
 
228
                        } else {
 
229
                                $options['link'] = $this->url($options['link'], true);
 
230
                        }
 
231
                        $out .= sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' '));
 
232
                } else {
 
233
                        $out = sprintf($this->tags['meta'], $this->_parseAttributes($options, array('type'), ' ', ' '));
 
234
                }
 
235
 
 
236
                if ($inline) {
 
237
                        return $out;
 
238
                } else {
 
239
                        $view =& ClassRegistry::getObject('view');
 
240
                        $view->addScript($out);
 
241
                }
 
242
        }
 
243
 
 
244
/**
 
245
 * Returns a charset META-tag.
 
246
 *
 
247
 * @param string $charset The character set to be used in the meta tag. If empty,
 
248
 *  The App.encoding value will be used. Example: "utf-8".
 
249
 * @return string A meta tag containing the specified character set.
 
250
 * @access public
 
251
 * @link http://book.cakephp.org/view/1436/charset
 
252
 */
 
253
        function charset($charset = null) {
 
254
                if (empty($charset)) {
 
255
                        $charset = strtolower(Configure::read('App.encoding'));
 
256
                }
 
257
                return sprintf($this->tags['charset'], (!empty($charset) ? $charset : 'utf-8'));
 
258
        }
 
259
 
 
260
/**
 
261
 * Creates an HTML link.
 
262
 *
 
263
 * If $url starts with "http://" this is treated as an external link. Else,
 
264
 * it is treated as a path to controller/action and parsed with the
 
265
 * HtmlHelper::url() method.
 
266
 *
 
267
 * If the $url is empty, $title is used instead.
 
268
 *
 
269
 * ### Options
 
270
 *
 
271
 * - `escape` Set to false to disable escaping of title and attributes.
 
272
 *
 
273
 * @param string $title The content to be wrapped by <a> tags.
 
274
 * @param mixed $url Cake-relative URL or array of URL parameters, or external URL (starts with http://)
 
275
 * @param array $options Array of HTML attributes.
 
276
 * @param string $confirmMessage JavaScript confirmation message.
 
277
 * @return string An `<a />` element.
 
278
 * @access public
 
279
 * @link http://book.cakephp.org/view/1442/link
 
280
 */
 
281
        function link($title, $url = null, $options = array(), $confirmMessage = false) {
 
282
                $escapeTitle = true;
 
283
                if ($url !== null) {
 
284
                        $url = $this->url($url);
 
285
                } else {
 
286
                        $url = $this->url($title);
 
287
                        $title = $url;
 
288
                        $escapeTitle = false;
 
289
                }
 
290
 
 
291
                if (isset($options['escape'])) {
 
292
                        $escapeTitle = $options['escape'];
 
293
                }
 
294
 
 
295
                if ($escapeTitle === true) {
 
296
                        $title = h($title);
 
297
                } elseif (is_string($escapeTitle)) {
 
298
                        $title = htmlentities($title, ENT_QUOTES, $escapeTitle);
 
299
                }
 
300
 
 
301
                if (!empty($options['confirm'])) {
 
302
                        $confirmMessage = $options['confirm'];
 
303
                        unset($options['confirm']);
 
304
                }
 
305
                if ($confirmMessage) {
 
306
                        $confirmMessage = str_replace("'", "\'", $confirmMessage);
 
307
                        $confirmMessage = str_replace('"', '\"', $confirmMessage);
 
308
                        $options['onclick'] = "return confirm('{$confirmMessage}');";
 
309
                } elseif (isset($options['default']) && $options['default'] == false) {
 
310
                        if (isset($options['onclick'])) {
 
311
                                $options['onclick'] .= ' event.returnValue = false; return false;';
 
312
                        } else {
 
313
                                $options['onclick'] = 'event.returnValue = false; return false;';
 
314
                        }
 
315
                        unset($options['default']);
 
316
                }
 
317
                return sprintf($this->tags['link'], $url, $this->_parseAttributes($options), $title);
 
318
        }
 
319
 
 
320
/**
 
321
 * Creates a link element for CSS stylesheets.
 
322
 *
 
323
 * ### Options
 
324
 *
 
325
 * - `inline` If set to false, the generated tag appears in the head tag of the layout. Defaults to true
 
326
 *
 
327
 * @param mixed $path The name of a CSS style sheet or an array containing names of
 
328
 *   CSS stylesheets. If `$path` is prefixed with '/', the path will be relative to the webroot
 
329
 *   of your application. Otherwise, the path will be relative to your CSS path, usually webroot/css.
 
330
 * @param string $rel Rel attribute. Defaults to "stylesheet". If equal to 'import' the stylesheet will be imported.
 
331
 * @param array $options Array of HTML attributes.
 
332
 * @return string CSS <link /> or <style /> tag, depending on the type of link.
 
333
 * @access public
 
334
 * @link http://book.cakephp.org/view/1437/css
 
335
 */
 
336
        function css($path, $rel = null, $options = array()) {
 
337
                $options += array('inline' => true);
 
338
                if (is_array($path)) {
 
339
                        $out = '';
 
340
                        foreach ($path as $i) {
 
341
                                $out .= "\n\t" . $this->css($i, $rel, $options);
 
342
                        }
 
343
                        if ($options['inline'])  {
 
344
                                return $out . "\n";
 
345
                        }
 
346
                        return;
 
347
                }
 
348
 
 
349
                if (strpos($path, '://') !== false) {
 
350
                        $url = $path;
 
351
                } else {
 
352
                        if ($path[0] !== '/') {
 
353
                                $path = CSS_URL . $path;
 
354
                        }
 
355
 
 
356
                        if (strpos($path, '?') === false) {
 
357
                                if (substr($path, -4) !== '.css') {
 
358
                                        $path .= '.css';
 
359
                                }
 
360
                        }
 
361
                        $url = $this->assetTimestamp($this->webroot($path));
 
362
 
 
363
                        if (Configure::read('Asset.filter.css')) {
 
364
                                $pos = strpos($url, CSS_URL);
 
365
                                if ($pos !== false) {
 
366
                                        $url = substr($url, 0, $pos) . 'ccss/' . substr($url, $pos + strlen(CSS_URL));
 
367
                                }
 
368
                        }
 
369
                }
 
370
 
 
371
                if ($rel == 'import') {
 
372
                        $out = sprintf($this->tags['style'], $this->_parseAttributes($options, array('inline'), '', ' '), '@import url(' . $url . ');');
 
373
                } else {
 
374
                        if ($rel == null) {
 
375
                                $rel = 'stylesheet';
 
376
                        }
 
377
                        $out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($options, array('inline'), '', ' '));
 
378
                }
 
379
 
 
380
                if ($options['inline']) {
 
381
                        return $out;
 
382
                } else {
 
383
                        $view =& ClassRegistry::getObject('view');
 
384
                        $view->addScript($out);
 
385
                }
 
386
        }
 
387
 
 
388
/**
 
389
 * Returns one or many `<script>` tags depending on the number of scripts given.
 
390
 *
 
391
 * If the filename is prefixed with "/", the path will be relative to the base path of your
 
392
 * application.  Otherwise, the path will be relative to your JavaScript path, usually webroot/js.
 
393
 *
 
394
 * Can include one or many Javascript files.
 
395
 *
 
396
 * ### Options
 
397
 *
 
398
 * - `inline` - Whether script should be output inline or into scripts_for_layout.
 
399
 * - `once` - Whether or not the script should be checked for uniqueness. If true scripts will only be
 
400
 *   included once, use false to allow the same script to be included more than once per request.
 
401
 *
 
402
 * @param mixed $url String or array of javascript files to include
 
403
 * @param mixed $options Array of options, and html attributes see above. If boolean sets $options['inline'] = value
 
404
 * @return mixed String of `<script />` tags or null if $inline is false or if $once is true and the file has been
 
405
 *   included before.
 
406
 * @access public
 
407
 * @link http://book.cakephp.org/view/1589/script
 
408
 */
 
409
        function script($url, $options = array()) {
 
410
                if (is_bool($options)) {
 
411
                        list($inline, $options) = array($options, array());
 
412
                        $options['inline'] = $inline;
 
413
                }
 
414
                $options = array_merge(array('inline' => true, 'once' => true), $options);
 
415
                if (is_array($url)) {
 
416
                        $out = '';
 
417
                        foreach ($url as $i) {
 
418
                                $out .= "\n\t" . $this->script($i, $options);
 
419
                        }
 
420
                        if ($options['inline'])  {
 
421
                                return $out . "\n";
 
422
                        }
 
423
                        return null;
 
424
                }
 
425
                if ($options['once'] && isset($this->__includedScripts[$url])) {
 
426
                        return null;
 
427
                }
 
428
                $this->__includedScripts[$url] = true;
 
429
 
 
430
                if (strpos($url, '://') === false) {
 
431
                        if ($url[0] !== '/') {
 
432
                                $url = JS_URL . $url;
 
433
                        }
 
434
                        if (strpos($url, '?') === false && substr($url, -3) !== '.js') {
 
435
                                $url .= '.js';
 
436
                        }
 
437
                        $url = $this->assetTimestamp($this->webroot($url));
 
438
 
 
439
                        if (Configure::read('Asset.filter.js')) {
 
440
                                $url = str_replace(JS_URL, 'cjs/', $url);
 
441
                        }
 
442
                }
 
443
                $attributes = $this->_parseAttributes($options, array('inline', 'once'), ' ');
 
444
                $out = sprintf($this->tags['javascriptlink'], $url, $attributes);
 
445
 
 
446
                if ($options['inline']) {
 
447
                        return $out;
 
448
                } else {
 
449
                        $view =& ClassRegistry::getObject('view');
 
450
                        $view->addScript($out);
 
451
                }
 
452
        }
 
453
 
 
454
/**
 
455
 * Wrap $script in a script tag.
 
456
 *
 
457
 * ### Options
 
458
 *
 
459
 * - `safe` (boolean) Whether or not the $script should be wrapped in <![CDATA[ ]]>
 
460
 * - `inline` (boolean) Whether or not the $script should be added to $scripts_for_layout or output inline
 
461
 *
 
462
 * @param string $script The script to wrap
 
463
 * @param array $options The options to use.
 
464
 * @return mixed string or null depending on the value of `$options['inline']`
 
465
 * @access public
 
466
 * @link http://book.cakephp.org/view/1604/scriptBlock
 
467
 */
 
468
        function scriptBlock($script, $options = array()) {
 
469
                $options += array('safe' => true, 'inline' => true);
 
470
                if ($options['safe']) {
 
471
                        $script  = "\n" . '//<![CDATA[' . "\n" . $script . "\n" . '//]]>' . "\n";
 
472
                }
 
473
                $inline = $options['inline'];
 
474
                unset($options['inline'], $options['safe']);
 
475
                $attributes = $this->_parseAttributes($options, ' ', ' ');
 
476
                if ($inline) {
 
477
                        return sprintf($this->tags['javascriptblock'], $attributes, $script);
 
478
                } else {
 
479
                        $view =& ClassRegistry::getObject('view');
 
480
                        $view->addScript(sprintf($this->tags['javascriptblock'], $attributes, $script));
 
481
                        return null;
 
482
                }
 
483
        }
 
484
 
 
485
/**
 
486
 * Begin a script block that captures output until HtmlHelper::scriptEnd()
 
487
 * is called. This capturing block will capture all output between the methods
 
488
 * and create a scriptBlock from it.
 
489
 *
 
490
 * ### Options
 
491
 *
 
492
 * - `safe` Whether the code block should contain a CDATA
 
493
 * - `inline` Should the generated script tag be output inline or in `$scripts_for_layout`
 
494
 *
 
495
 * @param array $options Options for the code block.
 
496
 * @return void
 
497
 * @access public
 
498
 * @link http://book.cakephp.org/view/1605/scriptStart
 
499
 */
 
500
        function scriptStart($options = array()) {
 
501
                $options += array('safe' => true, 'inline' => true);
 
502
                $this->_scriptBlockOptions = $options;
 
503
                ob_start();
 
504
                return null;
 
505
        }
 
506
 
 
507
/**
 
508
 * End a Buffered section of Javascript capturing.
 
509
 * Generates a script tag inline or in `$scripts_for_layout` depending on the settings
 
510
 * used when the scriptBlock was started
 
511
 *
 
512
 * @return mixed depending on the settings of scriptStart() either a script tag or null
 
513
 * @access public
 
514
 * @link http://book.cakephp.org/view/1606/scriptEnd
 
515
 */
 
516
        function scriptEnd() {
 
517
                $buffer = ob_get_clean();
 
518
                $options = $this->_scriptBlockOptions;
 
519
                $this->_scriptBlockOptions = array();
 
520
                return $this->scriptBlock($buffer, $options);
 
521
        }
 
522
 
 
523
/**
 
524
 * Builds CSS style data from an array of CSS properties
 
525
 *
 
526
 * ### Usage:
 
527
 *
 
528
 * {{{
 
529
 * echo $html->style(array('margin' => '10px', 'padding' => '10px'), true);
 
530
 *
 
531
 * // creates
 
532
 * 'margin:10px;padding:10px;'
 
533
 * }}}
 
534
 *
 
535
 * @param array $data Style data array, keys will be used as property names, values as property values.
 
536
 * @param boolean $oneline Whether or not the style block should be displayed on one line.
 
537
 * @return string CSS styling data
 
538
 * @access public
 
539
 * @link http://book.cakephp.org/view/1440/style
 
540
 */
 
541
        function style($data, $oneline = true) {
 
542
                if (!is_array($data)) {
 
543
                        return $data;
 
544
                }
 
545
                $out = array();
 
546
                foreach ($data as $key=> $value) {
 
547
                        $out[] = $key.':'.$value.';';
 
548
                }
 
549
                if ($oneline) {
 
550
                        return join(' ', $out);
 
551
                }
 
552
                return implode("\n", $out);
 
553
        }
 
554
 
 
555
/**
 
556
 * Returns the breadcrumb trail as a sequence of &raquo;-separated links.
 
557
 *
 
558
 * @param string $separator Text to separate crumbs.
 
559
 * @param string $startText This will be the first crumb, if false it defaults to first crumb in array
 
560
 * @return string Composed bread crumbs
 
561
 * @access public
 
562
 */
 
563
        function getCrumbs($separator = '&raquo;', $startText = false) {
 
564
                if (!empty($this->_crumbs)) {
 
565
                        $out = array();
 
566
                        if ($startText) {
 
567
                                $out[] = $this->link($startText, '/');
 
568
                        }
 
569
 
 
570
                        foreach ($this->_crumbs as $crumb) {
 
571
                                if (!empty($crumb[1])) {
 
572
                                        $out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
 
573
                                } else {
 
574
                                        $out[] = $crumb[0];
 
575
                                }
 
576
                        }
 
577
                        return join($separator, $out);
 
578
                } else {
 
579
                        return null;
 
580
                }
 
581
        }
 
582
 
 
583
/**
 
584
 * Creates a formatted IMG element. If `$options['url']` is provided, an image link will be
 
585
 * generated with the link pointed at `$options['url']`.  This method will set an empty
 
586
 * alt attribute if one is not supplied.
 
587
 *
 
588
 * ### Usage
 
589
 *
 
590
 * Create a regular image:
 
591
 *
 
592
 * `echo $html->image('cake_icon.png', array('alt' => 'CakePHP'));`
 
593
 *
 
594
 * Create an image link:
 
595
 *
 
596
 * `echo $html->image('cake_icon.png', array('alt' => 'CakePHP', 'url' => 'http://cakephp.org'));`
 
597
 *
 
598
 * @param string $path Path to the image file, relative to the app/webroot/img/ directory.
 
599
 * @param array $options Array of HTML attributes.
 
600
 * @return string completed img tag
 
601
 * @access public
 
602
 * @link http://book.cakephp.org/view/1441/image
 
603
 */
 
604
        function image($path, $options = array()) {
 
605
                if (is_array($path)) {
 
606
                        $path = $this->url($path);
 
607
                } elseif (strpos($path, '://') === false) {
 
608
                        if ($path[0] !== '/') {
 
609
                                $path = IMAGES_URL . $path;
 
610
                        }
 
611
                        $path = $this->assetTimestamp($this->webroot($path));
 
612
                }
 
613
 
 
614
                if (!isset($options['alt'])) {
 
615
                        $options['alt'] = '';
 
616
                }
 
617
 
 
618
                $url = false;
 
619
                if (!empty($options['url'])) {
 
620
                        $url = $options['url'];
 
621
                        unset($options['url']);
 
622
                }
 
623
 
 
624
                $image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' '));
 
625
 
 
626
                if ($url) {
 
627
                        return sprintf($this->tags['link'], $this->url($url), null, $image);
 
628
                }
 
629
                return $image;
 
630
        }
 
631
 
 
632
/**
 
633
 * Returns a row of formatted and named TABLE headers.
 
634
 *
 
635
 * @param array $names Array of tablenames.
 
636
 * @param array $trOptions HTML options for TR elements.
 
637
 * @param array $thOptions HTML options for TH elements.
 
638
 * @return string Completed table headers
 
639
 * @access public
 
640
 * @link http://book.cakephp.org/view/1446/tableHeaders
 
641
 */
 
642
        function tableHeaders($names, $trOptions = null, $thOptions = null) {
 
643
                $out = array();
 
644
                foreach ($names as $arg) {
 
645
                        $out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg);
 
646
                }
 
647
                return sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), join(' ', $out));
 
648
        }
 
649
 
 
650
/**
 
651
 * Returns a formatted string of table rows (TR's with TD's in them).
 
652
 *
 
653
 * @param array $data Array of table data
 
654
 * @param array $oddTrOptions HTML options for odd TR elements if true useCount is used
 
655
 * @param array $evenTrOptions HTML options for even TR elements
 
656
 * @param bool $useCount adds class "column-$i"
 
657
 * @param bool $continueOddEven If false, will use a non-static $count variable,
 
658
 *    so that the odd/even count is reset to zero just for that call.
 
659
 * @return string Formatted HTML
 
660
 * @access public
 
661
 * @link http://book.cakephp.org/view/1447/tableCells
 
662
 */
 
663
        function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true) {
 
664
                if (empty($data[0]) || !is_array($data[0])) {
 
665
                        $data = array($data);
 
666
                }
 
667
 
 
668
                if ($oddTrOptions === true) {
 
669
                        $useCount = true;
 
670
                        $oddTrOptions = null;
 
671
                }
 
672
 
 
673
                if ($evenTrOptions === false) {
 
674
                        $continueOddEven = false;
 
675
                        $evenTrOptions = null;
 
676
                }
 
677
 
 
678
                if ($continueOddEven) {
 
679
                        static $count = 0;
 
680
                } else {
 
681
                        $count = 0;
 
682
                }
 
683
 
 
684
                foreach ($data as $line) {
 
685
                        $count++;
 
686
                        $cellsOut = array();
 
687
                        $i = 0;
 
688
                        foreach ($line as $cell) {
 
689
                                $cellOptions = array();
 
690
 
 
691
                                if (is_array($cell)) {
 
692
                                        $cellOptions = $cell[1];
 
693
                                        $cell = $cell[0];
 
694
                                } elseif ($useCount) {
 
695
                                        $cellOptions['class'] = 'column-' . ++$i;
 
696
                                }
 
697
                                $cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell);
 
698
                        }
 
699
                        $options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions);
 
700
                        $out[] = sprintf($this->tags['tablerow'], $options, implode(' ', $cellsOut));
 
701
                }
 
702
                return implode("\n", $out);
 
703
        }
 
704
 
 
705
/**
 
706
 * Returns a formatted block tag, i.e DIV, SPAN, P.
 
707
 *
 
708
 * ### Options
 
709
 *
 
710
 * - `escape` Whether or not the contents should be html_entity escaped.
 
711
 *
 
712
 * @param string $name Tag name.
 
713
 * @param string $text String content that will appear inside the div element.
 
714
 *   If null, only a start tag will be printed
 
715
 * @param array $options Additional HTML attributes of the DIV tag, see above.
 
716
 * @return string The formatted tag element
 
717
 * @access public
 
718
 * @link http://book.cakephp.org/view/1443/tag
 
719
 */
 
720
        function tag($name, $text = null, $options = array()) {
 
721
                if (is_array($options) && isset($options['escape']) && $options['escape']) {
 
722
                        $text = h($text);
 
723
                        unset($options['escape']);
 
724
                }
 
725
                if (!is_array($options)) {
 
726
                        $options = array('class' => $options);
 
727
                }
 
728
                if ($text === null) {
 
729
                        $tag = 'tagstart';
 
730
                } else {
 
731
                        $tag = 'tag';
 
732
                }
 
733
                return sprintf($this->tags[$tag], $name, $this->_parseAttributes($options, null, ' ', ''), $text, $name);
 
734
        }
 
735
 
 
736
/**
 
737
 * Returns a formatted DIV tag for HTML FORMs.
 
738
 *
 
739
 * ### Options
 
740
 *
 
741
 * - `escape` Whether or not the contents should be html_entity escaped.
 
742
 *
 
743
 * @param string $class CSS class name of the div element.
 
744
 * @param string $text String content that will appear inside the div element.
 
745
 *   If null, only a start tag will be printed
 
746
 * @param array $options Additional HTML attributes of the DIV tag
 
747
 * @return string The formatted DIV element
 
748
 * @access public
 
749
 * @link http://book.cakephp.org/view/1444/div
 
750
 */
 
751
        function div($class = null, $text = null, $options = array()) {
 
752
                if (!empty($class)) {
 
753
                        $options['class'] = $class;
 
754
                }
 
755
                return $this->tag('div', $text, $options);
 
756
        }
 
757
 
 
758
/**
 
759
 * Returns a formatted P tag.
 
760
 *
 
761
 * ### Options
 
762
 *
 
763
 * - `escape` Whether or not the contents should be html_entity escaped.
 
764
 *
 
765
 * @param string $class CSS class name of the p element.
 
766
 * @param string $text String content that will appear inside the p element.
 
767
 * @param array $options Additional HTML attributes of the P tag
 
768
 * @return string The formatted P element
 
769
 * @access public
 
770
 * @link http://book.cakephp.org/view/1445/para
 
771
 */
 
772
        function para($class, $text, $options = array()) {
 
773
                if (isset($options['escape'])) {
 
774
                        $text = h($text);
 
775
                }
 
776
                if ($class != null && !empty($class)) {
 
777
                        $options['class'] = $class;
 
778
                }
 
779
                if ($text === null) {
 
780
                        $tag = 'parastart';
 
781
                } else {
 
782
                        $tag = 'para';
 
783
                }
 
784
                return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $text);
 
785
        }
 
786
 
 
787
/**
 
788
 * Build a nested list (UL/OL) out of an associative array.
 
789
 *
 
790
 * @param array $list Set of elements to list
 
791
 * @param array $options Additional HTML attributes of the list (ol/ul) tag or if ul/ol use that as tag
 
792
 * @param array $itemOptions Additional HTML attributes of the list item (LI) tag
 
793
 * @param string $tag Type of list tag to use (ol/ul)
 
794
 * @return string The nested list
 
795
 * @access public
 
796
 */
 
797
        function nestedList($list, $options = array(), $itemOptions = array(), $tag = 'ul') {
 
798
                if (is_string($options)) {
 
799
                        $tag = $options;
 
800
                        $options = array();
 
801
                }
 
802
                $items = $this->__nestedListItem($list, $options, $itemOptions, $tag);
 
803
                return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $items);
 
804
        }
 
805
 
 
806
/**
 
807
 * Internal function to build a nested list (UL/OL) out of an associative array.
 
808
 *
 
809
 * @param array $list Set of elements to list
 
810
 * @param array $options Additional HTML attributes of the list (ol/ul) tag
 
811
 * @param array $itemOptions Additional HTML attributes of the list item (LI) tag
 
812
 * @param string $tag Type of list tag to use (ol/ul)
 
813
 * @return string The nested list element
 
814
 * @access private
 
815
 * @see HtmlHelper::nestedList()
 
816
 */
 
817
        function __nestedListItem($items, $options, $itemOptions, $tag) {
 
818
                $out = '';
 
819
 
 
820
                $index = 1;
 
821
                foreach ($items as $key => $item) {
 
822
                        if (is_array($item)) {
 
823
                                $item = $key . $this->nestedList($item, $options, $itemOptions, $tag);
 
824
                        }
 
825
                        if (isset($itemOptions['even']) && $index % 2 == 0) {
 
826
                                $itemOptions['class'] = $itemOptions['even'];
 
827
                        } else if (isset($itemOptions['odd']) && $index % 2 != 0) {
 
828
                                $itemOptions['class'] = $itemOptions['odd'];
 
829
                        }
 
830
                        $out .= sprintf($this->tags['li'], $this->_parseAttributes($itemOptions, array('even', 'odd'), ' ', ''), $item);
 
831
                        $index++;
 
832
                }
 
833
                return $out;
 
834
        }
 
835
}