1: <?php namespace Laravel;
2:
3: class HTML {
4:
5: /**
6: * The registered custom macros.
7: *
8: * @var array
9: */
10: public static $macros = array();
11:
12: /**
13: * Cache application encoding locally to save expensive calls to config::get().
14: *
15: * @var string
16: */
17: public static $encoding = null;
18:
19: /**
20: * Registers a custom macro.
21: *
22: * @param string $name
23: * @param Closure $macro
24: * @return void
25: */
26: public static function macro($name, $macro)
27: {
28: static::$macros[$name] = $macro;
29: }
30:
31: /**
32: * Convert HTML characters to entities.
33: *
34: * The encoding specified in the application configuration file will be used.
35: *
36: * @param string $value
37: * @return string
38: */
39: public static function entities($value)
40: {
41: return htmlentities($value, ENT_QUOTES, static::encoding(), false);
42: }
43:
44: /**
45: * Convert entities to HTML characters.
46: *
47: * @param string $value
48: * @return string
49: */
50: public static function decode($value)
51: {
52: return html_entity_decode($value, ENT_QUOTES, static::encoding());
53: }
54:
55: /**
56: * Convert HTML special characters.
57: *
58: * The encoding specified in the application configuration file will be used.
59: *
60: * @param string $value
61: * @return string
62: */
63: public static function specialchars($value)
64: {
65: return htmlspecialchars($value, ENT_QUOTES, static::encoding(), false);
66: }
67:
68: /**
69: * Generate a link to a JavaScript file.
70: *
71: * <code>
72: * // Generate a link to a JavaScript file
73: * echo HTML::script('js/jquery.js');
74: *
75: * // Generate a link to a JavaScript file and add some attributes
76: * echo HTML::script('js/jquery.js', array('defer'));
77: * </code>
78: *
79: * @param string $url
80: * @param array $attributes
81: * @return string
82: */
83: public static function script($url, $attributes = array())
84: {
85: $url = URL::to_asset($url);
86:
87: return '<script src="'.$url.'"'.static::attributes($attributes).'></script>'.PHP_EOL;
88: }
89:
90: /**
91: * Generate a link to a CSS file.
92: *
93: * If no media type is selected, "all" will be used.
94: *
95: * <code>
96: * // Generate a link to a CSS file
97: * echo HTML::style('css/common.css');
98: *
99: * // Generate a link to a CSS file and add some attributes
100: * echo HTML::style('css/common.css', array('media' => 'print'));
101: * </code>
102: *
103: * @param string $url
104: * @param array $attributes
105: * @return string
106: */
107: public static function style($url, $attributes = array())
108: {
109: $defaults = array('media' => 'all', 'type' => 'text/css', 'rel' => 'stylesheet');
110:
111: $attributes = $attributes + $defaults;
112:
113: $url = URL::to_asset($url);
114:
115: return '<link href="'.$url.'"'.static::attributes($attributes).'>'.PHP_EOL;
116: }
117:
118: /**
119: * Generate a HTML span.
120: *
121: * @param string $value
122: * @param array $attributes
123: * @return string
124: */
125: public static function span($value, $attributes = array())
126: {
127: return '<span'.static::attributes($attributes).'>'.static::entities($value).'</span>';
128: }
129:
130: /**
131: * Generate a HTML link.
132: *
133: * <code>
134: * // Generate a link to a location within the application
135: * echo HTML::link('user/profile', 'User Profile');
136: *
137: * // Generate a link to a location outside of the application
138: * echo HTML::link('http://google.com', 'Google');
139: * </code>
140: *
141: * @param string $url
142: * @param string $title
143: * @param array $attributes
144: * @param bool $https
145: * @return string
146: */
147: public static function link($url, $title = null, $attributes = array(), $https = null)
148: {
149: $url = URL::to($url, $https);
150:
151: if (is_null($title)) $title = $url;
152:
153: return '<a href="'.$url.'"'.static::attributes($attributes).'>'.static::entities($title).'</a>';
154: }
155:
156: /**
157: * Generate a HTTPS HTML link.
158: *
159: * @param string $url
160: * @param string $title
161: * @param array $attributes
162: * @return string
163: */
164: public static function link_to_secure($url, $title = null, $attributes = array())
165: {
166: return static::link($url, $title, $attributes, true);
167: }
168:
169: /**
170: * Generate an HTML link to an asset.
171: *
172: * The application index page will not be added to asset links.
173: *
174: * @param string $url
175: * @param string $title
176: * @param array $attributes
177: * @param bool $https
178: * @return string
179: */
180: public static function link_to_asset($url, $title = null, $attributes = array(), $https = null)
181: {
182: $url = URL::to_asset($url, $https);
183:
184: if (is_null($title)) $title = $url;
185:
186: return '<a href="'.$url.'"'.static::attributes($attributes).'>'.static::entities($title).'</a>';
187: }
188:
189: /**
190: * Generate an HTTPS HTML link to an asset.
191: *
192: * @param string $url
193: * @param string $title
194: * @param array $attributes
195: * @return string
196: */
197: public static function link_to_secure_asset($url, $title = null, $attributes = array())
198: {
199: return static::link_to_asset($url, $title, $attributes, true);
200: }
201:
202: /**
203: * Generate an HTML link to a route.
204: *
205: * An array of parameters may be specified to fill in URI segment wildcards.
206: *
207: * <code>
208: * // Generate a link to the "profile" named route
209: * echo HTML::link_to_route('profile', 'Profile');
210: *
211: * // Generate a link to the "profile" route and add some parameters
212: * echo HTML::link_to_route('profile', 'Profile', array('taylor'));
213: * </code>
214: *
215: * @param string $name
216: * @param string $title
217: * @param array $parameters
218: * @param array $attributes
219: * @return string
220: */
221: public static function link_to_route($name, $title = null, $parameters = array(), $attributes = array())
222: {
223: return static::link(URL::to_route($name, $parameters), $title, $attributes);
224: }
225:
226: /**
227: * Generate an HTML link to a controller action.
228: *
229: * An array of parameters may be specified to fill in URI segment wildcards.
230: *
231: * <code>
232: * // Generate a link to the "home@index" action
233: * echo HTML::link_to_action('home@index', 'Home');
234: *
235: * // Generate a link to the "user@profile" route and add some parameters
236: * echo HTML::link_to_action('user@profile', 'Profile', array('taylor'));
237: * </code>
238: *
239: * @param string $action
240: * @param string $title
241: * @param array $parameters
242: * @param array $attributes
243: * @return string
244: */
245: public static function link_to_action($action, $title = null, $parameters = array(), $attributes = array())
246: {
247: return static::link(URL::to_action($action, $parameters), $title, $attributes);
248: }
249:
250: /**
251: * Generate an HTML link to a different language
252: *
253: * @param string $language
254: * @param string $title
255: * @param array $attributes
256: * @return string
257: */
258: public static function link_to_language($language, $title = null, $attributes = array())
259: {
260: return static::link(URL::to_language($language), $title, $attributes);
261: }
262:
263: /**
264: * Generate an HTML mailto link.
265: *
266: * The E-Mail address will be obfuscated to protect it from spam bots.
267: *
268: * @param string $email
269: * @param string $title
270: * @param array $attributes
271: * @return string
272: */
273: public static function mailto($email, $title = null, $attributes = array())
274: {
275: $email = static::email($email);
276:
277: if (is_null($title)) $title = $email;
278:
279: $email = 'mailto:'.$email;
280:
281: return '<a href="'.$email.'"'.static::attributes($attributes).'>'.static::entities($title).'</a>';
282: }
283:
284: /**
285: * Obfuscate an e-mail address to prevent spam-bots from sniffing it.
286: *
287: * @param string $email
288: * @return string
289: */
290: public static function email($email)
291: {
292: return str_replace('@', '@', static::obfuscate($email));
293: }
294:
295: /**
296: * Generate an HTML image element.
297: *
298: * @param string $url
299: * @param string $alt
300: * @param array $attributes
301: * @return string
302: */
303: public static function image($url, $alt = '', $attributes = array())
304: {
305: $attributes['alt'] = $alt;
306:
307: return '<img src="'.URL::to_asset($url).'"'.static::attributes($attributes).'>';
308: }
309:
310: /**
311: * Generate an ordered list of items.
312: *
313: * @param array $list
314: * @param array $attributes
315: * @return string
316: */
317: public static function ol($list, $attributes = array())
318: {
319: return static::listing('ol', $list, $attributes);
320: }
321:
322: /**
323: * Generate an un-ordered list of items.
324: *
325: * @param array $list
326: * @param array $attributes
327: * @return string
328: */
329: public static function ul($list, $attributes = array())
330: {
331: return static::listing('ul', $list, $attributes);
332: }
333:
334: /**
335: * Generate an ordered or un-ordered list.
336: *
337: * @param string $type
338: * @param array $list
339: * @param array $attributes
340: * @return string
341: */
342: private static function listing($type, $list, $attributes = array())
343: {
344: $html = '';
345:
346: if (count($list) == 0) return $html;
347:
348: foreach ($list as $key => $value)
349: {
350: // If the value is an array, we will recurse the function so that we can
351: // produce a nested list within the list being built. Of course, nested
352: // lists may exist within nested lists, etc.
353: if (is_array($value))
354: {
355: if (is_int($key))
356: {
357: $html .= static::listing($type, $value);
358: }
359: else
360: {
361: $html .= '<li>'.$key.static::listing($type, $value).'</li>';
362: }
363: }
364: else
365: {
366: $html .= '<li>'.static::entities($value).'</li>';
367: }
368: }
369:
370: return '<'.$type.static::attributes($attributes).'>'.$html.'</'.$type.'>';
371: }
372:
373: /**
374: * Generate a definition list.
375: *
376: * @param array $list
377: * @param array $attributes
378: * @return string
379: */
380: public static function dl($list, $attributes = array())
381: {
382: $html = '';
383:
384: if (count($list) == 0) return $html;
385:
386: foreach ($list as $term => $description)
387: {
388: $html .= '<dt>'.static::entities($term).'</dt>';
389: $html .= '<dd>'.static::entities($description).'</dd>';
390: }
391:
392: return '<dl'.static::attributes($attributes).'>'.$html.'</dl>';
393: }
394:
395: /**
396: * Build a list of HTML attributes from an array.
397: *
398: * @param array $attributes
399: * @return string
400: */
401: public static function attributes($attributes)
402: {
403: $html = array();
404:
405: foreach ((array) $attributes as $key => $value)
406: {
407: // For numeric keys, we will assume that the key and the value are the
408: // same, as this will convert HTML attributes such as "required" that
409: // may be specified as required="required", etc.
410: if (is_numeric($key)) $key = $value;
411:
412: if ( ! is_null($value))
413: {
414: $html[] = $key.'="'.static::entities($value).'"';
415: }
416: }
417:
418: return (count($html) > 0) ? ' '.implode(' ', $html) : '';
419: }
420:
421: /**
422: * Obfuscate a string to prevent spam-bots from sniffing it.
423: *
424: * @param string $value
425: * @return string
426: */
427: protected static function obfuscate($value)
428: {
429: $safe = '';
430:
431: foreach (str_split($value) as $letter)
432: {
433: // To properly obfuscate the value, we will randomly convert each
434: // letter to its entity or hexadecimal representation, keeping a
435: // bot from sniffing the randomly obfuscated letters.
436: switch (rand(1, 3))
437: {
438: case 1:
439: $safe .= '&#'.ord($letter).';';
440: break;
441:
442: case 2:
443: $safe .= '&#x'.dechex(ord($letter)).';';
444: break;
445:
446: case 3:
447: $safe .= $letter;
448: }
449: }
450:
451: return $safe;
452: }
453:
454: /**
455: * Get the appliction.encoding without needing to request it from Config::get() each time.
456: *
457: * @return string
458: */
459: protected static function encoding()
460: {
461: return static::$encoding ?: static::$encoding = Config::get('application.encoding');
462: }
463:
464: /**
465: * Dynamically handle calls to custom macros.
466: *
467: * @param string $method
468: * @param array $parameters
469: * @return mixed
470: */
471: public static function __callStatic($method, $parameters)
472: {
473: if (isset(static::$macros[$method]))
474: {
475: return call_user_func_array(static::$macros[$method], $parameters);
476: }
477:
478: throw new \Exception("Method [$method] does not exist.");
479: }
480:
481: }
482: