1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24: 25: 26: 27: 28: 29: 30: 31:
32: class HtmlHelper extends AppHelper {
33: 34: 35:
36: 37: 38:
39: 40: 41: 42: 43:
44: var $tags = array(
45: 'meta' => '<meta%s/>',
46: 'metalink' => '<link href="%s"%s/>',
47: 'link' => '<a href="%s"%s>%s</a>',
48: 'mailto' => '<a href="mailto:%s" %s>%s</a>',
49: 'form' => '<form %s>',
50: 'formend' => '</form>',
51: 'input' => '<input name="%s" %s/>',
52: 'textarea' => '<textarea name="%s" %s>%s</textarea>',
53: 'hidden' => '<input type="hidden" name="%s" %s/>',
54: 'checkbox' => '<input type="checkbox" name="%s" %s/>',
55: 'checkboxmultiple' => '<input type="checkbox" name="%s[]"%s />',
56: 'radio' => '<input type="radio" name="%s" id="%s" %s />%s',
57: 'selectstart' => '<select name="%s"%s>',
58: 'selectmultiplestart' => '<select name="%s[]"%s>',
59: 'selectempty' => '<option value=""%s> </option>',
60: 'selectoption' => '<option value="%s"%s>%s</option>',
61: 'selectend' => '</select>',
62: 'optiongroup' => '<optgroup label="%s"%s>',
63: 'optiongroupend' => '</optgroup>',
64: 'checkboxmultiplestart' => '',
65: 'checkboxmultipleend' => '',
66: 'password' => '<input type="password" name="%s" %s/>',
67: 'file' => '<input type="file" name="%s" %s/>',
68: 'file_no_model' => '<input type="file" name="%s" %s/>',
69: 'submit' => '<input type="submit" %s/>',
70: 'submitimage' => '<input type="image" src="%s" %s/>',
71: 'button' => '<input type="%s" %s/>',
72: 'image' => '<img src="%s" %s/>',
73: 'tableheader' => '<th%s>%s</th>',
74: 'tableheaderrow' => '<tr%s>%s</tr>',
75: 'tablecell' => '<td%s>%s</td>',
76: 'tablerow' => '<tr%s>%s</tr>',
77: 'block' => '<div%s>%s</div>',
78: 'blockstart' => '<div%s>',
79: 'blockend' => '</div>',
80: 'tag' => '<%s%s>%s</%s>',
81: 'tagstart' => '<%s%s>',
82: 'tagend' => '</%s>',
83: 'para' => '<p%s>%s</p>',
84: 'parastart' => '<p%s>',
85: 'label' => '<label for="%s"%s>%s</label>',
86: 'fieldset' => '<fieldset%s>%s</fieldset>',
87: 'fieldsetstart' => '<fieldset><legend>%s</legend>',
88: 'fieldsetend' => '</fieldset>',
89: 'legend' => '<legend>%s</legend>',
90: 'css' => '<link rel="%s" type="text/css" href="%s" %s/>',
91: 'style' => '<style type="text/css"%s>%s</style>',
92: 'charset' => '<meta http-equiv="Content-Type" content="text/html; charset=%s" />',
93: 'ul' => '<ul%s>%s</ul>',
94: 'ol' => '<ol%s>%s</ol>',
95: 'li' => '<li%s>%s</li>',
96: 'error' => '<div%s>%s</div>'
97: );
98: 99: 100: 101: 102:
103: var $base = null;
104: 105: 106: 107: 108:
109: var $here = null;
110: 111: 112: 113: 114:
115: var $params = array();
116: 117: 118: 119: 120:
121: var $action = null;
122: 123: 124: 125: 126:
127: var $data = null;
128:
129: 130: 131:
132: 133: 134:
135: 136: 137: 138: 139: 140:
141: var $_crumbs = array();
142: 143: 144: 145: 146: 147:
148: var $__docTypes = array(
149: 'html4-strict' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
150: 'html4-trans' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
151: 'html4-frame' => '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
152: 'xhtml-strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
153: 'xhtml-trans' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
154: 'xhtml-frame' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
155: 'xhtml11' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
156: );
157: 158: 159: 160: 161: 162: 163:
164: function addCrumb($name, $link = null, $options = null) {
165: $this->_crumbs[] = array($name, $link, $options);
166: }
167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181:
182: function docType($type = 'xhtml-strict') {
183: if (isset($this->__docTypes[$type])) {
184: return $this->output($this->__docTypes[$type]);
185: }
186: return null;
187: }
188: 189: 190: 191: 192: 193: 194: 195: 196:
197: function meta($type, $url = null, $attributes = array(), $inline = true) {
198: if (!is_array($type)) {
199: $types = array(
200: 'rss' => array('type' => 'application/rss+xml', 'rel' => 'alternate', 'title' => $type, 'link' => $url),
201: 'atom' => array('type' => 'application/atom+xml', 'title' => $type, 'link' => $url),
202: 'icon' => array('type' => 'image/x-icon', 'rel' => 'icon', 'link' => $url),
203: 'keywords' => array('name' => 'keywords', 'content' => $url),
204: 'description' => array('name' => 'description', 'content' => $url),
205: );
206:
207: if ($type === 'icon' && $url === null) {
208: $types['icon']['link'] = $this->webroot('favicon.ico');
209: }
210:
211: if (isset($types[$type])) {
212: $type = $types[$type];
213: } elseif (!isset($attributes['type']) && $url !== null) {
214: if (is_array($url) && isset($url['ext'])) {
215: $type = $types[$url['ext']];
216: } else {
217: $type = $types['rss'];
218: }
219: } elseif (isset($attributes['type']) && isset($types[$attributes['type']])) {
220: $type = $types[$attributes['type']];
221: unset($attributes['type']);
222: } else {
223: $type = array();
224: }
225: } elseif ($url !== null) {
226: $inline = $url;
227: }
228: $attributes = array_merge($type, $attributes);
229: $out = null;
230:
231: if (isset($attributes['link'])) {
232: if (isset($attributes['rel']) && $attributes['rel'] === 'icon') {
233: $out = sprintf($this->tags['metalink'], $attributes['link'], $this->_parseAttributes($attributes, array('link'), ' ', ' '));
234: $attributes['rel'] = 'shortcut icon';
235: } else {
236: $attributes['link'] = $this->url($attributes['link'], true);
237: }
238: $out .= sprintf($this->tags['metalink'], $attributes['link'], $this->_parseAttributes($attributes, array('link'), ' ', ' '));
239: } else {
240: $out = sprintf($this->tags['meta'], $this->_parseAttributes($attributes, array('type'), ' ', ' '));
241: }
242:
243: if ($inline) {
244: return $this->output($out);
245: } else {
246: $view =& ClassRegistry::getObject('view');
247: $view->addScript($out);
248: }
249: }
250: 251: 252: 253: 254: 255:
256: function charset($charset = null) {
257: if (empty($charset)) {
258: $charset = strtolower(Configure::read('App.encoding'));
259: }
260: return $this->output(sprintf($this->tags['charset'], (!empty($charset) ? $charset : 'utf-8')));
261: }
262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277:
278: function link($title, $url = null, $htmlAttributes = array(), $confirmMessage = false, $escapeTitle = true) {
279: if ($url !== null) {
280: $url = $this->url($url);
281: } else {
282: $url = $this->url($title);
283: $title = $url;
284: $escapeTitle = false;
285: }
286:
287: if (isset($htmlAttributes['escape']) && $escapeTitle == true) {
288: $escapeTitle = $htmlAttributes['escape'];
289: }
290:
291: if ($escapeTitle === true) {
292: $title = h($title);
293: } elseif (is_string($escapeTitle)) {
294: $title = htmlentities($title, ENT_QUOTES, $escapeTitle);
295: }
296:
297: if (!empty($htmlAttributes['confirm'])) {
298: $confirmMessage = $htmlAttributes['confirm'];
299: unset($htmlAttributes['confirm']);
300: }
301: if ($confirmMessage) {
302: $confirmMessage = str_replace("'", "\'", $confirmMessage);
303: $confirmMessage = str_replace('"', '\"', $confirmMessage);
304: $htmlAttributes['onclick'] = "return confirm('{$confirmMessage}');";
305: } elseif (isset($htmlAttributes['default']) && $htmlAttributes['default'] == false) {
306: if (isset($htmlAttributes['onclick'])) {
307: $htmlAttributes['onclick'] .= ' event.returnValue = false; return false;';
308: } else {
309: $htmlAttributes['onclick'] = 'event.returnValue = false; return false;';
310: }
311: unset($htmlAttributes['default']);
312: }
313: return $this->output(sprintf($this->tags['link'], $url, $this->_parseAttributes($htmlAttributes), $title));
314: }
315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325:
326: function css($path, $rel = null, $htmlAttributes = array(), $inline = true) {
327: if (is_array($path)) {
328: $out = '';
329: foreach ($path as $i) {
330: $out .= "\n\t" . $this->css($i, $rel, $htmlAttributes, $inline);
331: }
332: if ($inline) {
333: return $out . "\n";
334: }
335: return;
336: }
337:
338: if (strpos($path, '://') !== false) {
339: $url = $path;
340: } else {
341: if ($path[0] !== '/') {
342: $path = CSS_URL . $path;
343: }
344:
345: if (strpos($path, '?') === false) {
346: if (!preg_match('/.*\.(css|php)$/i', $path)) {
347: $path .= '.css';
348: }
349: }
350: $timestampEnabled = (
351: (Configure::read('Asset.timestamp') === true && Configure::read() > 0) ||
352: Configure::read('Asset.timestamp') === 'force'
353: );
354:
355: $url = $this->webroot($path);
356: if (strpos($path, '?') === false && $timestampEnabled) {
357: $url .= '?' . @filemtime(WWW_ROOT . str_replace('/', DS, $path));
358: }
359: if (Configure::read('Asset.filter.css')) {
360: $pos = strpos($url, CSS_URL);
361: if ($pos !== false) {
362: $url = substr($url, 0, $pos) . 'ccss/' . substr($url, $pos + strlen(CSS_URL));
363: }
364: }
365: }
366:
367: if ($rel == 'import') {
368: $out = sprintf($this->tags['style'], $this->_parseAttributes($htmlAttributes, null, '', ' '), '@import url(' . $url . ');');
369: } else {
370: if ($rel == null) {
371: $rel = 'stylesheet';
372: }
373: $out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($htmlAttributes, null, '', ' '));
374: }
375: $out = $this->output($out);
376:
377: if ($inline) {
378: return $out;
379: } else {
380: $view =& ClassRegistry::getObject('view');
381: $view->addScript($out);
382: }
383: }
384: 385: 386: 387: 388: 389: 390:
391: function style($data, $inline = true) {
392: if (!is_array($data)) {
393: return $data;
394: }
395: $out = array();
396: foreach ($data as $key=> $value) {
397: $out[] = $key.':'.$value.';';
398: }
399: if ($inline) {
400: return implode(' ', $out);
401: }
402: return implode("\n", $out);
403: }
404: 405: 406: 407: 408: 409: 410:
411: function getCrumbs($separator = '»', $startText = false) {
412: if (!empty($this->_crumbs)) {
413: $out = array();
414: if ($startText) {
415: $out[] = $this->link($startText, '/');
416: }
417:
418: foreach ($this->_crumbs as $crumb) {
419: if (!empty($crumb[1])) {
420: $out[] = $this->link($crumb[0], $crumb[1], $crumb[2]);
421: } else {
422: $out[] = $crumb[0];
423: }
424: }
425: return $this->output(implode($separator, $out));
426: } else {
427: return null;
428: }
429: }
430: 431: 432: 433: 434: 435: 436:
437: function image($path, $options = array()) {
438: if (is_array($path)) {
439: $path = $this->url($path);
440: } elseif (strpos($path, '://') === false) {
441: if ($path[0] !== '/') {
442: $path = IMAGES_URL . $path;
443: }
444:
445: if ((Configure::read('Asset.timestamp') == true && Configure::read() > 0) || Configure::read('Asset.timestamp') === 'force') {
446: $path = $this->webroot($path) . '?' . @filemtime(WWW_ROOT . str_replace('/', DS, $path));
447: } else {
448: $path = $this->webroot($path);
449: }
450: }
451:
452: if (!isset($options['alt'])) {
453: $options['alt'] = '';
454: }
455:
456: $url = false;
457: if (!empty($options['url'])) {
458: $url = $options['url'];
459: unset($options['url']);
460: }
461:
462: $image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' '));
463:
464: if ($url) {
465: return $this->output(sprintf($this->tags['link'], $this->url($url), null, $image));
466: }
467:
468: return $this->output($image);
469: }
470: 471: 472: 473: 474: 475: 476: 477:
478: function tableHeaders($names, $trOptions = null, $thOptions = null) {
479: $out = array();
480: foreach ($names as $arg) {
481: $out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg);
482: }
483: $data = sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), implode(' ', $out));
484: return $this->output($data);
485: }
486: 487: 488: 489: 490: 491: 492: 493: 494: 495:
496: function tableCells($data, $oddTrOptions = null, $evenTrOptions = null, $useCount = false, $continueOddEven = true) {
497: if (empty($data[0]) || !is_array($data[0])) {
498: $data = array($data);
499: }
500:
501: if ($oddTrOptions === true) {
502: $useCount = true;
503: $oddTrOptions = null;
504: }
505:
506: if ($evenTrOptions === false) {
507: $continueOddEven = false;
508: $evenTrOptions = null;
509: }
510:
511: if ($continueOddEven) {
512: static $count = 0;
513: } else {
514: $count = 0;
515: }
516:
517: foreach ($data as $line) {
518: $count++;
519: $cellsOut = array();
520: $i = 0;
521: foreach ($line as $cell) {
522: $cellOptions = array();
523:
524: if (is_array($cell)) {
525: $cellOptions = $cell[1];
526: $cell = $cell[0];
527: } elseif ($useCount) {
528: $cellOptions['class'] = 'column-' . ++$i;
529: }
530: $cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell);
531: }
532: $options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions);
533: $out[] = sprintf($this->tags['tablerow'], $options, implode(' ', $cellsOut));
534: }
535: return $this->output(implode("\n", $out));
536: }
537: 538: 539: 540: 541: 542: 543: 544: 545: 546:
547: function tag($name, $text = null, $attributes = array(), $escape = false) {
548: if ($escape) {
549: $text = h($text);
550: }
551: if (!is_array($attributes)) {
552: $attributes = array('class' => $attributes);
553: }
554: if ($text === null) {
555: $tag = 'tagstart';
556: } else {
557: $tag = 'tag';
558: }
559: return $this->output(sprintf($this->tags[$tag], $name, $this->_parseAttributes($attributes, null, ' ', ''), $text, $name));
560: }
561: 562: 563: 564: 565: 566: 567: 568: 569: 570:
571: function div($class = null, $text = null, $attributes = array(), $escape = false) {
572: if ($class != null && !empty($class)) {
573: $attributes['class'] = $class;
574: }
575: return $this->tag('div', $text, $attributes, $escape);
576: }
577: 578: 579: 580: 581: 582: 583: 584: 585:
586: function para($class, $text, $attributes = array(), $escape = false) {
587: if ($escape) {
588: $text = h($text);
589: }
590: if ($class != null && !empty($class)) {
591: $attributes['class'] = $class;
592: }
593: if ($text === null) {
594: $tag = 'parastart';
595: } else {
596: $tag = 'para';
597: }
598: return $this->output(sprintf($this->tags[$tag], $this->_parseAttributes($attributes, null, ' ', ''), $text));
599: }
600: 601: 602: 603: 604: 605: 606: 607: 608: 609:
610: function nestedList($list, $attributes = array(), $itemAttributes = array(), $tag = 'ul') {
611: if (is_string($attributes)) {
612: $tag = $attributes;
613: $attributes = array();
614: }
615: $items = $this->__nestedListItem($list, $attributes, $itemAttributes, $tag);
616: return sprintf($this->tags[$tag], $this->_parseAttributes($attributes, null, ' ', ''), $items);
617: }
618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628:
629: function __nestedListItem($items, $attributes, $itemAttributes, $tag) {
630: $out = '';
631:
632: $index = 1;
633: foreach ($items as $key => $item) {
634: if (is_array($item)) {
635: $item = $key . $this->nestedList($item, $attributes, $itemAttributes, $tag);
636: }
637: if (isset($itemAttributes['even']) && $index % 2 == 0) {
638: $itemAttributes['class'] = $itemAttributes['even'];
639: } else if (isset($itemAttributes['odd']) && $index % 2 != 0) {
640: $itemAttributes['class'] = $itemAttributes['odd'];
641: }
642: $out .= sprintf($this->tags['li'], $this->_parseAttributes(array_diff_key($itemAttributes, array_flip(array('even', 'odd'))), null, ' ', ''), $item);
643: $index++;
644: }
645: return $out;
646: }
647: }
648: ?>