RHtml::link()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 8
rs 10
cc 2
nc 2
nop 3
1
<?php
2
/**
3
 * @package     Redcore
4
 * @subpackage  HTML
5
 *
6
 * @copyright   Copyright (C) 2008 - 2021 redWEB.dk. All rights reserved.
7
 * @license     GNU General Public License version 2 or later, see LICENSE.
8
 */
9
10
defined('JPATH_REDCORE') or die;
11
12
JLoader::import('joomla.environment.browser');
13
JLoader::import('joomla.filesystem.file');
14
JLoader::import('joomla.filesystem.path');
15
JLoader::import('joomla.utilities.arrayhelper');
16
17
use Joomla\Utilities\ArrayHelper;
18
19
/**
20
 * Utility class for all HTML drawing classes
21
 *
22
 * @package     Redcore
23
 * @subpackage  HTML
24
 * @since       1.0
25
 */
26
abstract class RHtml
27
{
28
	/**
29
	 * Option values related to the generation of HTML output. Recognized
30
	 * options are:
31
	 *     fmtDepth, integer. The current indent depth.
32
	 *     fmtEol, string. The end of line string, default is linefeed.
33
	 *     fmtIndent, string. The string to use for indentation, default is
34
	 *     tab.
35
	 *
36
	 * @var    array
37
	 * @since  1.0
38
	 */
39
	public static $formatOptions = array('format.depth' => 0, 'format.eol' => "\n", 'format.indent' => "\t");
40
41
	/**
42
	 * An array to hold included paths
43
	 *
44
	 * @var    array
45
	 * @since  1.0
46
	 */
47
	protected static $includePaths = array();
48
49
	/**
50
	 * An array to hold method references
51
	 *
52
	 * @var    array
53
	 * @since  1.0
54
	 */
55
	protected static $registry = array();
56
57
	/**
58
	 * Method to extract a key
59
	 *
60
	 * @param   string  $key  The name of helper method to load, (prefix).(class).function
61
	 *                        prefix and class are optional and can be used to load custom html helpers.
62
	 *
63
	 * @return  array  Contains lowercase key, prefix, file, function.
64
	 *
65
	 * @since   1.0
66
	 */
67
	protected static function extract($key)
68
	{
69
		$key = preg_replace('#[^A-Z0-9_\.]#i', '', $key);
70
71
		// Check to see whether we need to load a helper file
72
		$parts = explode('.', $key);
73
74
		$prefix = (count($parts) == 3 ? array_shift($parts) : 'JHtml');
75
		$file = (count($parts) == 2 ? array_shift($parts) : '');
76
		$func = array_shift($parts);
77
78
		return array(strtolower($prefix . '.' . $file . '.' . $func), $prefix, $file, $func);
79
	}
80
81
	/**
82
	 * Class loader method
83
	 *
84
	 * Additional arguments may be supplied and are passed to the sub-class.
85
	 * Additional include paths are also able to be specified for third-party use
86
	 *
87
	 * @param   string  $key  The name of helper method to load, (prefix).(class).function
88
	 *                        prefix and class are optional and can be used to load custom
89
	 *                        html helpers.
90
	 *
91
	 * @return  mixed  JHtml::call($function, $args) or False on error
92
	 *
93
	 * @since   1.0
94
	 * @throws  InvalidArgumentException
95
	 */
96
	public static function _($key)
97
	{
98
		list($key, $prefix, $file, $func) = static::extract($key);
99
100
		if (array_key_exists($key, static::$registry))
101
		{
102
			$function = static::$registry[$key];
103
			$args = func_get_args();
104
105
			// Remove function name from arguments
106
			array_shift($args);
107
108
			return static::call($function, $args);
109
		}
110
111
		$className = $prefix . ucfirst($file);
112
113
		if (!class_exists($className))
114
		{
115
			$path = JPath::find(static::$includePaths, strtolower($file) . '.php');
116
117
			if (!$path)
118
			{
119
				throw new InvalidArgumentException(sprintf('%s %s not found.', $prefix, $file), 500);
120
			}
121
122
			JLoader::register($className, $path);
123
124
			if (!class_exists($className))
125
			{
126
				throw new InvalidArgumentException(sprintf('%s not found.', $className), 500);
127
			}
128
		}
129
130
		$toCall = array($className, $func);
131
132
		if (!is_callable($toCall))
133
		{
134
			throw new InvalidArgumentException(sprintf('%s::%s not found.', $className, $func), 500);
135
		}
136
137
		static::register($key, $toCall);
0 ignored issues
show
Bug introduced by
$toCall of type array<integer,mixed|string> is incompatible with the type string expected by parameter $function of RHtml::register(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

137
		static::register($key, /** @scrutinizer ignore-type */ $toCall);
Loading history...
138
		$args = func_get_args();
139
140
		// Remove function name from arguments
141
		array_shift($args);
142
143
		return static::call($toCall, $args);
144
	}
145
146
	/**
147
	 * Registers a function to be called with a specific key
148
	 *
149
	 * @param   string  $key       The name of the key
150
	 * @param   string  $function  Function or method
151
	 *
152
	 * @return  boolean  True if the function is callable
153
	 *
154
	 * @since   1.0
155
	 */
156
	public static function register($key, $function)
157
	{
158
		list($key) = static::extract($key);
159
160
		if (is_callable($function))
161
		{
162
			static::$registry[$key] = $function;
163
164
			return true;
165
		}
166
167
		return false;
168
	}
169
170
	/**
171
	 * Removes a key for a method from registry.
172
	 *
173
	 * @param   string  $key  The name of the key
174
	 *
175
	 * @return  boolean  True if a set key is unset
176
	 *
177
	 * @since   1.0
178
	 */
179
	public static function unregister($key)
180
	{
181
		list($key) = static::extract($key);
182
183
		if (isset(static::$registry[$key]))
184
		{
185
			unset(static::$registry[$key]);
186
187
			return true;
188
		}
189
190
		return false;
191
	}
192
193
	/**
194
	 * Test if the key is registered.
195
	 *
196
	 * @param   string  $key  The name of the key
197
	 *
198
	 * @return  boolean  True if the key is registered.
199
	 *
200
	 * @since   1.0
201
	 */
202
	public static function isRegistered($key)
203
	{
204
		list($key) = static::extract($key);
205
206
		return isset(static::$registry[$key]);
207
	}
208
209
	/**
210
	 * Function caller method
211
	 *
212
	 * @param   callable  $function  Function or method to call
213
	 * @param   array     $args      Arguments to be passed to function
214
	 *
215
	 * @return  mixed   Function result or false on error.
216
	 *
217
	 * @see     http://php.net/manual/en/function.call-user-func-array.php
218
	 * @since   1.0
219
	 * @throws  InvalidArgumentException
220
	 */
221
	protected static function call($function, $args)
222
	{
223
		if (!is_callable($function))
224
		{
225
			throw new InvalidArgumentException('Function not supported', 500);
226
		}
227
228
		// PHP 5.3 workaround
229
		$temp = array();
230
231
		foreach ($args as &$arg)
232
		{
233
			$temp[] = &$arg;
234
		}
235
236
		return call_user_func_array($function, $temp);
237
	}
238
239
	/**
240
	 * Write a <a></a> element
241
	 *
242
	 * @param   string  $url      The relative URL to use for the href attribute
243
	 * @param   string  $text     The target attribute to use
244
	 * @param   array   $attribs  An associative array of attributes to add
245
	 *
246
	 * @return  string  <a></a> string
247
	 *
248
	 * @since   1.0
249
	 */
250
	public static function link($url, $text, $attribs = null)
251
	{
252
		if (is_array($attribs))
253
		{
254
			$attribs = ArrayHelper::toString($attribs);
255
		}
256
257
		return '<a href="' . $url . '" ' . $attribs . '>' . $text . '</a>';
258
	}
259
260
	/**
261
	 * Write a <iframe></iframe> element
262
	 *
263
	 * @param   string  $url       The relative URL to use for the src attribute.
264
	 * @param   string  $name      The target attribute to use.
265
	 * @param   array   $attribs   An associative array of attributes to add.
266
	 * @param   string  $noFrames  The message to display if the iframe tag is not supported.
267
	 *
268
	 * @return  string  <iframe></iframe> element or message if not supported.
269
	 *
270
	 * @since   1.0
271
	 */
272
	public static function iframe($url, $name, $attribs = null, $noFrames = '')
273
	{
274
		if (is_array($attribs))
275
		{
276
			$attribs = ArrayHelper::toString($attribs);
277
		}
278
279
		return '<iframe src="' . $url . '" ' . $attribs . ' name="' . $name . '">' . $noFrames . '</iframe>';
280
	}
281
282
	/**
283
	 * Include version with MD5SUM file in path.
284
	 *
285
	 * @param   string  $path  Folder name to search into (images, css, js, ...).
286
	 *
287
	 * @return  string  Query string to add.
288
	 *
289
	 * @since   3.7.0
290
	 *
291
	 * @deprecated   4.0  Usage of MD5SUM files is deprecated, use version instead.
292
	 */
293
	protected static function getMd5Version($path)
294
	{
295
		$md5 = dirname($path) . '/MD5SUM';
296
297
		if (file_exists($md5))
298
		{
299
			JLog::add('Usage of MD5SUM files is deprecated, use version instead.', JLog::WARNING, 'deprecated');
300
301
			return '?' . file_get_contents($md5);
302
		}
303
304
		return '';
305
	}
306
307
	/**
308
	 * Compute the files to be included
309
	 *
310
	 * @param   string   $folder          folder name to search into (images, css, js, ...).
311
	 * @param   string   $file            path to file.
312
	 * @param   boolean  $relative        path to file is relative to /media folder  (and searches in template).
313
	 * @param   boolean  $detect_browser  detect browser to include specific browser files.
314
	 * @param   boolean  $detect_debug    detect debug to include compressed files if debug is on.
315
	 *
316
	 * @return  array    files to be included.
317
	 *
318
	 * @see     JBrowser
319
	 * @since   1.0
320
	 */
321
	protected static function includeRelativeFiles($folder, $file, $relative, $detect_browser, $detect_debug)
322
	{
323
		// If http is present in filename
324
		if (strpos($file, 'http') === 0 || strpos($file, '//') === 0)
325
		{
326
			$includes = array($file);
327
		}
328
		else
329
		{
330
			// Extract extension and strip the file
331
			$strip = JFile::stripExt($file);
332
			$ext   = JFile::getExt($file);
333
334
			// Prepare array of files
335
			$includes = array();
336
337
			// Detect browser and compute potential files
338
			if ($detect_browser)
339
			{
340
				$navigator = JBrowser::getInstance();
341
				$browser = $navigator->getBrowser();
342
				$major = $navigator->getMajor();
343
				$minor = $navigator->getMinor();
344
345
				// Try to include files named filename.ext, filename_browser.ext, filename_browser_major.ext, filename_browser_major_minor.ext
346
				// where major and minor are the browser version names
347
				$potential = array($strip, $strip . '_' . $browser,  $strip . '_' . $browser . '_' . $major,
348
					$strip . '_' . $browser . '_' . $major . '_' . $minor);
349
			}
350
			else
351
			{
352
				$potential = array($strip);
353
			}
354
355
			// If relative search in template directory or media directory
356
			if ($relative)
357
			{
358
				// Get the template
359
				$template = JFactory::getApplication()->getTemplate();
360
361
				// For each potential files
362
				foreach ($potential as $strip)
363
				{
364
					$files = array();
365
366
					// Detect debug mode
367
					if ($detect_debug && JFactory::getConfig()->get('debug'))
368
					{
369
						/*
370
						 * Detect if we received a file in the format name.min.ext
371
						 * If so, strip the .min part out, otherwise append -uncompressed
372
						 */
373
						if (strlen($strip) > 4 && preg_match('#\.min$#', $strip))
374
						{
375
							$files[] = preg_replace('#\.min$#', '.', $strip) . $ext;
376
						}
377
						else
378
						{
379
							$files[] = $strip . '-uncompressed.' . $ext;
380
						}
381
					}
382
383
					$files[] = $strip . '.' . $ext;
384
385
					/*
386
					 * Loop on 1 or 2 files and break on first found.
387
					 * Add the content of the MD5SUM file located in the same folder to url to ensure cache browser refresh
388
					 * This MD5SUM file must represent the signature of the folder content
389
					 */
390
					foreach ($files as $file)
0 ignored issues
show
introduced by
$file is overwriting one of the parameters of this function.
Loading history...
391
					{
392
						// If the file is in the template folder
393
						$path = JPATH_THEMES . "/$template/$folder/$file";
394
395
						if (file_exists($path))
396
						{
397
							$includes[] = JUri::base(true) . "/templates/$template/$folder/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

397
							$includes[] = JUri::base(true) . "/templates/$template/$folder/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
398
399
							break;
400
						}
401
						else
402
						{
403
							// If the file contains any /: it can be in an media extension subfolder
404
							if (strpos($file, '/'))
405
							{
406
								// Divide the file extracting the extension as the first part before /
407
								list($extension, $file) = explode('/', $file, 2);
408
409
								// If the file yet contains any /: it can be a plugin
410
								if (strpos($file, '/'))
411
								{
412
									// Divide the file extracting the element as the first part before /
413
									list($element, $file) = explode('/', $file, 2);
414
415
									// Try to deal with plugins group in the media folder
416
									$path = JPATH_ROOT . "/media/$extension/$element/$folder/$file";
417
418
									if (file_exists($path))
419
									{
420
										$includes[] = JUri::root(true) . "/media/$extension/$element/$folder/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

420
										$includes[] = JUri::root(true) . "/media/$extension/$element/$folder/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
421
422
										break;
423
									}
424
425
									// Try to deal with classical file in a a media subfolder called element
426
									$path = JPATH_ROOT . "/media/$extension/$folder/$element/$file";
427
428
									if (file_exists($path))
429
									{
430
										$includes[] = JUri::root(true) . "/media/$extension/$folder/$element/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

430
										$includes[] = JUri::root(true) . "/media/$extension/$folder/$element/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
431
432
										break;
433
									}
434
435
									// Try to deal with classical file in a a media subfolder where pointer actually points
436
									$path = JPATH_ROOT . "/media/$extension/$element/$file";
437
438
									if (file_exists($path))
439
									{
440
										$includes[] = JUri::root(true) . "/media/$extension/$element/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

440
										$includes[] = JUri::root(true) . "/media/$extension/$element/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
441
442
										break;
443
									}
444
445
									// Try to deal with system files in the template folder
446
									$path = JPATH_THEMES . "/$template/$folder/system/$element/$file";
447
448
									if (file_exists($path))
449
									{
450
										$includes[] = JUri::root(true) . "/templates/$template/$folder/system/$element/$file"
451
											. static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

451
											. /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
452
453
										break;
454
									}
455
456
									// Try to deal with system files in the media folder
457
									$path = JPATH_ROOT . "/media/system/$folder/$element/$file";
458
459
									if (file_exists($path))
460
									{
461
										$includes[] = JUri::root(true) . "/media/system/$folder/$element/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

461
										$includes[] = JUri::root(true) . "/media/system/$folder/$element/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
462
463
										break;
464
									}
465
								}
466
								else
467
								{
468
									// Try to deals in the extension media folder
469
									$path = JPATH_ROOT . "/media/$extension/$folder/$file";
470
471
									if (file_exists($path))
472
									{
473
										$includes[] = JUri::root(true) . "/media/$extension/$folder/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

473
										$includes[] = JUri::root(true) . "/media/$extension/$folder/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
474
475
										break;
476
									}
477
478
									// Try to deal with system files in the template folder
479
									$path = JPATH_THEMES . "/$template/$folder/system/$file";
480
481
									if (file_exists($path))
482
									{
483
										$includes[] = JUri::root(true) . "/templates/$template/$folder/system/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

483
										$includes[] = JUri::root(true) . "/templates/$template/$folder/system/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
484
485
										break;
486
									}
487
488
									// Try to deal with system files in the media folder
489
									$path = JPATH_ROOT . "/media/system/$folder/$file";
490
491
									if (file_exists($path))
492
									{
493
										$includes[] = JUri::root(true) . "/media/system/$folder/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

493
										$includes[] = JUri::root(true) . "/media/system/$folder/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
494
495
										break;
496
									}
497
								}
498
							}
499
							// Try to deal with system files in the media folder
500
							else
501
							{
502
								$path = JPATH_ROOT . "/media/system/$folder/$file";
503
504
								if (file_exists($path))
505
								{
506
									$includes[] = JUri::root(true) . "/media/system/$folder/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

506
									$includes[] = JUri::root(true) . "/media/system/$folder/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
507
508
									break;
509
								}
510
							}
511
						}
512
					}
513
				}
514
			}
515
			// If not relative and http is not present in filename
516
			else
517
			{
518
				foreach ($potential as $strip)
519
				{
520
					$files = array();
521
522
					// Detect debug mode
523
					if ($detect_debug && JFactory::getConfig()->get('debug'))
524
					{
525
						/*
526
						 * Detect if we received a file in the format name.min.ext
527
						 * If so, strip the .min part out, otherwise append -uncompressed
528
						 */
529
						if (strlen($strip) > 4 && preg_match('#\.min$#', $strip))
530
						{
531
							$files[] = preg_replace('#\.min$#', '.', $strip) . $ext;
532
						}
533
						else
534
						{
535
							$files[] = $strip . '-uncompressed.' . $ext;
536
						}
537
					}
538
539
					$files[] = $strip . '.' . $ext;
540
541
					/*
542
					 * Loop on 1 or 2 files and break on first found.
543
					 * Add the content of the MD5SUM file located in the same folder to url to ensure cache browser refresh
544
					 * This MD5SUM file must represent the signature of the folder content
545
					 */
546
					foreach ($files as $file)
0 ignored issues
show
introduced by
$file is overwriting one of the parameters of this function.
Loading history...
547
					{
548
						$path = JPATH_ROOT . "/$file";
549
550
						if (file_exists($path))
551
						{
552
							$includes[] = JUri::root(true) . "/$file" . static::getMd5Version($path);
0 ignored issues
show
Deprecated Code introduced by
The function RHtml::getMd5Version() has been deprecated: 4.0 Usage of MD5SUM files is deprecated, use version instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

552
							$includes[] = JUri::root(true) . "/$file" . /** @scrutinizer ignore-deprecated */ static::getMd5Version($path);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
553
554
							break;
555
						}
556
					}
557
				}
558
			}
559
		}
560
561
		return $includes;
562
	}
563
564
	/**
565
	 * Write a `<img>` element
566
	 *
567
	 * @param   string        $file        The relative or absolute URL to use for the src attribute.
568
	 * @param   string        $alt         The alt text.
569
	 * @param   array|string  $attribs     Attributes to be added to the `<img>` element
570
	 * @param   boolean       $relative    Flag if the path to the file is relative to the /media folder (and searches in template).
571
	 * @param   integer       $returnPath  Defines the return value for the method:
572
	 *                                     -1: Returns a `<img>` tag without looking for relative files
573
	 *                                     0: Returns a `<img>` tag while searching for relative files
574
	 *                                     1: Returns the file path to the image while searching for relative files
575
	 *
576
	 * @return  string
577
	 *
578
	 * @since   1.5
579
	 */
580
	public static function image($file, $alt, $attribs = null, $relative = false, $returnPath = 0)
581
	{
582
		$returnPath = (int) $returnPath;
583
584
		if ($returnPath !== -1)
585
		{
586
			$includes = static::includeRelativeFiles('images', $file, $relative, false, false);
587
			$file = count($includes) ? $includes[0] : null;
588
		}
589
590
		// If only path is required
591
		if ($returnPath)
592
		{
593
			return $file;
594
		}
595
596
		return '<img src="' . $file . '" alt="' . $alt . '" ' . trim((is_array($attribs) ? ArrayHelper::toString($attribs) : $attribs) . ' /') . '>';
597
	}
598
599
	/**
600
	 * Write a <link rel="stylesheet" style="text/css" /> element
601
	 *
602
	 * @param   string   $file            path to file
603
	 * @param   array    $attribs         attributes to be added to the stylesheet
604
	 * @param   boolean  $relative        path to file is relative to /media folder
605
	 * @param   boolean  $path_only       return the path to the file only
606
	 * @param   boolean  $detect_browser  detect browser to include specific browser css files
607
	 *                                    will try to include file, file_*browser*, file_*browser*_*major*, file_*browser*_*major*_*minor*
608
	 *                                    <table>
609
	 *                                       <tr><th>Navigator</th>                  <th>browser</th>	<th>major.minor</th></tr>
610
	 *
611
	 *                                       <tr><td>Safari 3.0.x</td>               <td>konqueror</td>	<td>522.x</td></tr>
612
	 *                                       <tr><td>Safari 3.1.x and 3.2.x</td>     <td>konqueror</td>	<td>525.x</td></tr>
613
	 *                                       <tr><td>Safari 4.0 to 4.0.2</td>        <td>konqueror</td>	<td>530.x</td></tr>
614
	 *                                       <tr><td>Safari 4.0.3 to 4.0.4</td>      <td>konqueror</td>	<td>531.x</td></tr>
615
	 *                                       <tr><td>iOS 4.0 Safari</td>             <td>konqueror</td>	<td>532.x</td></tr>
616
	 *                                       <tr><td>Safari 5.0</td>                 <td>konqueror</td>	<td>533.x</td></tr>
617
	 *
618
	 *                                       <tr><td>Google Chrome 1.0</td>          <td>konqueror</td>	<td>528.x</td></tr>
619
	 *                                       <tr><td>Google Chrome 2.0</td>          <td>konqueror</td>	<td>530.x</td></tr>
620
	 *                                       <tr><td>Google Chrome 3.0 and 4.x</td>  <td>konqueror</td>	<td>532.x</td></tr>
621
	 *                                       <tr><td>Google Chrome 5.0</td>          <td>konqueror</td>	<td>533.x</td></tr>
622
	 *
623
	 *                                       <tr><td>Internet Explorer 5.5</td>      <td>msie</td>		<td>5.5</td></tr>
624
	 *                                       <tr><td>Internet Explorer 6.x</td>      <td>msie</td>		<td>6.x</td></tr>
625
	 *                                       <tr><td>Internet Explorer 7.x</td>      <td>msie</td>		<td>7.x</td></tr>
626
	 *                                       <tr><td>Internet Explorer 8.x</td>      <td>msie</td>		<td>8.x</td></tr>
627
	 *
628
	 *                                       <tr><td>Firefox</td>                    <td>mozilla</td>	<td>5.0</td></tr>
629
	 *                                    </table>
630
	 *                                    a lot of others
631
	 * @param   boolean  $detect_debug    detect debug to search for compressed files if debug is on
632
	 *
633
	 * @return  mixed  nothing if $path_only is false, null, path or array of path if specific css browser files were detected
634
	 *
635
	 * @see     JBrowser
636
	 * @since   1.0
637
	 */
638
	public static function stylesheet($file, $attribs = array(), $relative = false, $path_only = false, $detect_browser = true, $detect_debug = true)
639
	{
640
		$includes = static::includeRelativeFiles('css', $file, $relative, $detect_browser, $detect_debug);
641
642
		// If only path is required
643
		if ($path_only)
644
		{
645
			if (count($includes) == 0)
646
			{
647
				return null;
648
			}
649
			elseif (count($includes) == 1)
650
			{
651
				return $includes[0];
652
			}
653
			else
654
			{
655
				return $includes;
656
			}
657
		}
658
		else
659
			// If inclusion is required
660
		{
661
			$document = JFactory::getDocument();
662
663
			foreach ($includes as $include)
664
			{
665
				$document->addStylesheet($include, 'text/css', null, $attribs);
0 ignored issues
show
Deprecated Code introduced by
The function JDocument::addStyleSheet() has been deprecated: 4.0 The (url, mime, media, attribs) method signature is deprecated, use (url, options, attributes) instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

665
				/** @scrutinizer ignore-deprecated */ $document->addStylesheet($include, 'text/css', null, $attribs);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
666
			}
667
		}
668
	}
669
670
	/**
671
	 * Write a <script></script> element
672
	 *
673
	 * @param   string   $file            path to file.
674
	 * @param   boolean  $framework       load the JS framework.
675
	 * @param   boolean  $relative        path to file is relative to /media folder.
676
	 * @param   boolean  $path_only       return the path to the file only.
677
	 * @param   boolean  $detect_browser  detect browser to include specific browser js files.
678
	 * @param   boolean  $detect_debug    detect debug to search for compressed files if debug is on.
679
	 *
680
	 * @return  mixed  nothing if $path_only is false, null, path or array of path if specific js browser files were detected.
681
	 *
682
	 * @see     JHtml::stylesheet
683
	 * @since   1.0
684
	 */
685
	public static function script($file, $framework = false, $relative = false, $path_only = false, $detect_browser = true, $detect_debug = true)
686
	{
687
		// Include MooTools framework
688
		if ($framework)
689
		{
690
			static::_('behavior.framework');
691
		}
692
693
		$includes = static::includeRelativeFiles('js', $file, $relative, $detect_browser, $detect_debug);
694
695
		// If only path is required
696
		if ($path_only)
697
		{
698
			if (count($includes) == 0)
699
			{
700
				return null;
701
			}
702
			elseif (count($includes) == 1)
703
			{
704
				return $includes[0];
705
			}
706
			else
707
			{
708
				return $includes;
709
			}
710
		}
711
		else
712
			// If inclusion is required
713
		{
714
			$document = JFactory::getDocument();
715
716
			foreach ($includes as $include)
717
			{
718
				$document->addScript($include);
0 ignored issues
show
Deprecated Code introduced by
The function JDocument::addScript() has been deprecated: 4.0 The (url, mime, defer, async) method signature is deprecated, use (url, options, attributes) instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

718
				/** @scrutinizer ignore-deprecated */ $document->addScript($include);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
719
			}
720
		}
721
	}
722
723
	/**
724
	 * Set format related options.
725
	 *
726
	 * Updates the formatOptions array with all valid values in the passed
727
	 * array. See {@see JHtml::$formatOptions} for details.
728
	 *
729
	 * @param   array  $options  Option key/value pairs.
730
	 *
731
	 * @return  void
732
	 *
733
	 * @since   1.0
734
	 */
735
	public static function setFormatOptions($options)
736
	{
737
		foreach ($options as $key => $val)
738
		{
739
			if (isset(static::$formatOptions[$key]))
740
			{
741
				static::$formatOptions[$key] = $val;
742
			}
743
		}
744
	}
745
746
	/**
747
	 * Returns formated date according to a given format and time zone.
748
	 *
749
	 * @param   string   $input      String in a format accepted by date(), defaults to "now".
750
	 * @param   string   $format     The date format specification string (see {@link PHP_MANUAL#date}).
751
	 * @param   mixed    $tz         Time zone to be used for the date.  Special cases: boolean true for user
752
	 *                               setting, boolean false for server setting.
753
	 * @param   boolean  $gregorian  True to use Gregorian calendar.
754
	 *
755
	 * @return  string    A date translated by the given format and time zone.
756
	 *
757
	 * @see     strftime
758
	 * @since   1.0
759
	 */
760
	public static function date($input = 'now', $format = null, $tz = true, $gregorian = false)
761
	{
762
		// Get some system objects.
763
		$config = JFactory::getConfig();
764
		$user = JFactory::getUser();
765
766
		// UTC date converted to user time zone.
767
		if ($tz === true)
768
		{
769
			// Get a date object based on UTC.
770
			$date = JFactory::getDate($input, 'UTC');
771
772
			// Set the correct time zone based on the user configuration.
773
			$date->setTimezone($user->getTimezone());
774
		}
775
		// UTC date converted to server time zone.
776
		elseif ($tz === false)
777
		{
778
			// Get a date object based on UTC.
779
			$date = JFactory::getDate($input, 'UTC');
780
781
			// Set the correct time zone based on the server configuration.
782
			$date->setTimezone(new DateTimeZone($config->get('offset')));
783
		}
784
		// No date conversion.
785
		elseif ($tz === null)
786
		{
787
			$date = JFactory::getDate($input);
788
		}
789
		// UTC date converted to given time zone.
790
		else
791
		{
792
			// Get a date object based on UTC.
793
			$date = JFactory::getDate($input, 'UTC');
794
795
			// Set the correct time zone based on the server configuration.
796
			$date->setTimezone(new DateTimeZone($tz));
797
		}
798
799
		// If no format is given use the default locale based format.
800
		if (!empty($format))
801
		{
802
			$format = JText::_('DATE_FORMAT_LC1');
803
		}
804
		// $format is an existing language key
805
		elseif (JFactory::getLanguage()->hasKey($format))
806
		{
807
			$format = JText::_($format);
808
		}
809
810
		if ($gregorian)
811
		{
812
			return $date->format($format, true);
813
		}
814
815
		return $date->calendar($format, true);
816
	}
817
818
	/**
819
	 * Creates a tooltip with an image as button
820
	 *
821
	 * @param   string  $tooltip  The tip string.
822
	 * @param   mixed   $title    The title of the tooltip or an associative array with keys contained in
823
	 *                            {'title','image','text','href','alt'} and values corresponding to parameters of the same name.
824
	 * @param   string  $image    The image for the tip, if no text is provided.
825
	 * @param   string  $text     The text for the tip.
826
	 * @param   string  $href     An URL that will be used to create the link.
827
	 * @param   string  $alt      The alt attribute for img tag.
828
	 * @param   string  $class    CSS class for the tool tip.
829
	 *
830
	 * @return  string
831
	 *
832
	 * @since   1.0
833
	 */
834
	public static function tooltip($tooltip, $title = '', $image = 'tooltip.png', $text = '', $href = '', $alt = 'Tooltip', $class = 'hasTooltip')
835
	{
836
		if (is_array($title))
837
		{
838
			foreach (array('image', 'text', 'href', 'alt', 'class') as $param)
839
			{
840
				if (isset($title[$param]))
841
				{
842
					$$param = $title[$param];
843
				}
844
			}
845
846
			if (isset($title['title']))
847
			{
848
				$title = $title['title'];
849
			}
850
			else
851
			{
852
				$title = '';
853
			}
854
		}
855
856
		if (!$text)
857
		{
858
			$alt = htmlspecialchars($alt, ENT_COMPAT, 'UTF-8');
859
			$text = static::image($image, $alt, null, true);
860
		}
861
862
		if ($href)
863
		{
864
			$tip = '<a href="' . $href . '">' . $text . '</a>';
865
		}
866
		else
867
		{
868
			$tip = $text;
869
		}
870
871
		if ($class == 'hasTip')
872
		{
873
			// Still using MooTools tooltips!
874
			$tooltip = htmlspecialchars($tooltip, ENT_COMPAT, 'UTF-8');
875
876
			if ($title)
877
			{
878
				$title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');
879
				$tooltip = $title . '::' . $tooltip;
880
			}
881
		}
882
		else
883
		{
884
			$tooltip = self::tooltipText($title, $tooltip, 0);
885
		}
886
887
		return '<span class="' . $class . '" title="' . $tooltip . '">' . $tip . '</span>';
888
	}
889
890
	/**
891
	 * Converts a double colon seperated string or 2 separate strings to a string ready for bootstrap tooltips
892
	 *
893
	 * @param   string  $title      The title of the tooltip (or combined '::' separated string).
894
	 * @param   string  $content    The content to tooltip.
895
	 * @param   int     $translate  If true will pass texts through JText.
896
	 * @param   int     $escape     If true will pass texts through htmlspecialchars.
897
	 *
898
	 * @return  string  The tooltip string
899
	 *
900
	 * @since   1.0
901
	 */
902
	public static function tooltipText($title = '', $content = '', $translate = 1, $escape = 1)
903
	{
904
		// Initialise return value.
905
		$result = '';
906
907
		// Don't process empty strings
908
		if ($content != '' || $title != '')
909
		{
910
			// Split title into title and content if the title contains '::' (old Mootools format).
911
			if ($content == '' && !(strpos($title, '::') === false))
912
			{
913
				list($title, $content) = explode('::', $title, 2);
914
			}
915
916
			// Pass texts through JText if required.
917
			if ($translate)
918
			{
919
				$title = JText::_($title);
920
				$content = JText::_($content);
921
			}
922
923
			// Use only the content if no title is given.
924
			if ($title == '')
925
			{
926
				$result = $content;
927
			}
928
			// Use only the title, if title and text are the same.
929
			elseif ($title == $content)
930
			{
931
				$result = '<strong>' . $title . '</strong>';
932
			}
933
			// Use a formatted string combining the title and content.
934
			elseif ($content != '')
935
			{
936
				$result = '<strong>' . $title . '</strong><br />' . $content;
937
			}
938
			else
939
			{
940
				$result = $title;
941
			}
942
943
			// Escape everything, if required.
944
			if ($escape)
945
			{
946
				$result = htmlspecialchars($result);
947
			}
948
		}
949
950
		return $result;
951
	}
952
953
	/**
954
	 * Displays a calendar control field
955
	 *
956
	 * @param   string  $value    The date value
957
	 * @param   string  $name     The name of the text field
958
	 * @param   string  $id       The id of the text field
959
	 * @param   string  $format   The date format
960
	 * @param   mixed   $attribs  Additional HTML attributes
961
	 *                            The array can have the following keys:
962
	 *                            readonly      Sets the readonly parameter for the input tag
963
	 *                            disabled      Sets the disabled parameter for the input tag
964
	 *                            autofocus     Sets the autofocus parameter for the input tag
965
	 *                            autocomplete  Sets the autocomplete parameter for the input tag
966
	 *                            filter        Sets the filter for the input tag
967
	 *
968
	 * @return  string  HTML markup for a calendar field
969
	 *
970
	 * @since   1.5
971
	 *
972
	 */
973
	public static function calendar($value, $name, $id, $format = '%Y-%m-%d', $attribs = array())
974
	{
975
		$tag       = JFactory::getLanguage()->getTag();
976
		$calendar  = JFactory::getLanguage()->getCalendar();
977
		$direction = strtolower(JFactory::getDocument()->getDirection());
978
979
		// Get the appropriate file for the current language date helper
980
		$helperPath = 'system/fields/calendar-locales/date/gregorian/date-helper.min.js';
981
982
		if (!empty($calendar) && is_dir(JPATH_ROOT . '/media/system/js/fields/calendar-locales/date/' . strtolower($calendar)))
983
		{
984
			$helperPath = 'system/fields/calendar-locales/date/' . strtolower($calendar) . '/date-helper.min.js';
985
		}
986
987
		// Get the appropriate locale file for the current language
988
		$localesPath = 'system/fields/calendar-locales/en.js';
989
990
		if (is_file(JPATH_ROOT . '/media/system/js/fields/calendar-locales/' . strtolower($tag) . '.js'))
991
		{
992
			$localesPath = 'system/fields/calendar-locales/' . strtolower($tag) . '.js';
993
		}
994
		elseif (is_file(JPATH_ROOT . '/media/system/js/fields/calendar-locales/' . strtolower(substr($tag, 0, -3)) . '.js'))
995
		{
996
			$localesPath = 'system/fields/calendar-locales/' . strtolower(substr($tag, 0, -3)) . '.js';
997
		}
998
999
		$readonly     = isset($attribs['readonly']) && $attribs['readonly'] == 'readonly';
1000
		$disabled     = isset($attribs['disabled']) && $attribs['disabled'] == 'disabled';
1001
		$autocomplete = isset($attribs['autocomplete']) && $attribs['autocomplete'] == '';
1002
		$autofocus    = isset($attribs['autofocus']) && $attribs['autofocus'] == '';
1003
		$required     = isset($attribs['required']) && $attribs['required'] == '';
1004
		$filter       = isset($attribs['filter']) && $attribs['filter'] == '';
1005
		$todayBtn     = isset($attribs['todayBtn']) ? $attribs['todayBtn'] : true;
1006
		$weekNumbers  = isset($attribs['weekNumbers']) ? $attribs['weekNumbers'] : false;
1007
		$showTime     = isset($attribs['showTime']) ? $attribs['showTime'] : false;
1008
		$fillTable    = isset($attribs['fillTable']) ? $attribs['fillTable'] : true;
1009
		$timeFormat   = isset($attribs['timeFormat']) ? $attribs['timeFormat'] : 24;
1010
		$singleHeader = isset($attribs['singleHeader']) ? $attribs['singleHeader'] : false;
1011
		$hint         = isset($attribs['placeholder']) ? $attribs['placeholder'] : '';
1012
		$class        = isset($attribs['class']) ? $attribs['class'] : '';
1013
		$onchange     = isset($attribs['onChange']) ? $attribs['onChange'] : '';
1014
1015
		$showTime     = ($showTime) ? "1" : "0";
1016
		$todayBtn     = ($todayBtn) ? "1" : "0";
1017
		$weekNumbers  = ($weekNumbers) ? "1" : "0";
1018
		$fillTable    = ($fillTable) ? "1" : "0";
1019
		$singleHeader = ($singleHeader) ? "1" : "0";
1020
1021
		// Format value when not nulldate ('0000-00-00 00:00:00'), otherwise blank it as it would result in 1970-01-01.
1022
		if ($value && $value != JFactory::getDbo()->getNullDate() && strtotime($value) !== false)
1023
		{
1024
			$tz = date_default_timezone_get();
1025
			date_default_timezone_set('UTC');
1026
			$inputvalue = strftime($format, strtotime($value));
1027
			date_default_timezone_set($tz);
1028
		}
1029
		else
1030
		{
1031
			$inputvalue = '';
1032
		}
1033
1034
		$data = array(
1035
			'id'           => $id,
1036
			'name'         => $name,
1037
			'class'        => $class,
1038
			'value'        => $inputvalue,
1039
			'format'       => $format,
1040
			'filter'       => $filter,
1041
			'required'     => $required,
1042
			'readonly'     => $readonly,
1043
			'disabled'     => $disabled,
1044
			'hint'         => $hint,
1045
			'autofocus'    => $autofocus,
1046
			'autocomplete' => $autocomplete,
1047
			'todaybutton'  => $todayBtn,
1048
			'weeknumbers'  => $weekNumbers,
1049
			'showtime'     => $showTime,
1050
			'filltable'    => $fillTable,
1051
			'timeformat'   => $timeFormat,
1052
			'singleheader' => $singleHeader,
1053
			'tag'          => $tag,
1054
			'helperPath'   => $helperPath,
1055
			'localesPath'  => $localesPath,
1056
			'direction'    => $direction,
1057
			'onchange'     => $onchange,
1058
		);
1059
1060
		return JLayoutHelper::render('joomla.form.field.calendar', $data, null, null);
1061
	}
1062
1063
	/**
1064
	 * Add a directory where JHtml should search for helpers. You may
1065
	 * either pass a string or an array of directories.
1066
	 *
1067
	 * @param   string  $path  A path to search.
1068
	 *
1069
	 * @return  array  An array with directory elements
1070
	 *
1071
	 * @since   1.0
1072
	 */
1073
	public static function addIncludePath($path = '')
1074
	{
1075
		// Force path to array
1076
		settype($path, 'array');
1077
1078
		// Loop through the path directories
1079
		foreach ($path as $dir)
1080
		{
1081
			if (!empty($dir) && !in_array($dir, static::$includePaths))
1082
			{
1083
				array_unshift(static::$includePaths, JPath::clean($dir));
1084
			}
1085
		}
1086
1087
		return static::$includePaths;
1088
	}
1089
1090
	/**
1091
	 * Internal method to get a JavaScript object notation string from an array
1092
	 *
1093
	 * @param   array  $array  The array to convert to JavaScript object notation
1094
	 *
1095
	 * @return  string  JavaScript object notation representation of the array
1096
	 *
1097
	 * @since   3.0
1098
	 * @deprecated  4.0 Use `json_encode()` or `Joomla\Registry\Registry::toString('json')` instead
1099
	 */
1100
	public static function getJSObject(array $array = array())
1101
	{
1102
		JLog::add(
1103
			__METHOD__ . " is deprecated. Use json_encode() or \\Joomla\\Registry\\Registry::toString('json') instead.",
1104
			JLog::WARNING,
1105
			'deprecated'
1106
		);
1107
1108
		$elements = array();
1109
1110
		foreach ($array as $k => $v)
1111
		{
1112
			// Don't encode either of these types
1113
			if (is_null($v) || is_resource($v))
1114
			{
1115
				continue;
1116
			}
1117
1118
			// Safely encode as a Javascript string
1119
			$key = json_encode((string) $k);
1120
1121
			if (is_bool($v))
1122
			{
1123
				$elements[] = $key . ': ' . ($v ? 'true' : 'false');
1124
			}
1125
			elseif (is_numeric($v))
1126
			{
1127
				$elements[] = $key . ': ' . ($v + 0);
1128
			}
1129
			elseif (is_string($v))
1130
			{
1131
				if (strpos($v, '\\') === 0)
1132
				{
1133
					// Items such as functions and JSON objects are prefixed with \, strip the prefix and don't encode them
1134
					$elements[] = $key . ': ' . substr($v, 1);
1135
				}
1136
				else
1137
				{
1138
					// The safest way to insert a string
1139
					$elements[] = $key . ': ' . json_encode((string) $v);
1140
				}
1141
			}
1142
			else
1143
			{
1144
				$elements[] = $key . ': ' . json_encode(is_object($v) ? get_object_vars($v) : $v);
1145
			}
1146
		}
1147
1148
		return '{' . implode(',', $elements) . '}';
1149
	}
1150
}
1151