1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8//this script may only be included - so its better to die if called directly.
9if (strpos($_SERVER["SCRIPT_NAME"], basename(__FILE__)) !== false) {
10	header("location: index.php");
11	exit;
12}
13
14/*
15 * smarty_function_icon: Display a Tiki icon, using theme icons if they exists
16 *
17 * params will be used as params for the HTML tag (e.g. border, class, ...), except special params starting with '_' :
18 *  - _id: [deprecated] short name (i.e. 'page_edit') or relative file path (i.e. 'img/icons/page_edit.png').
19 *          Will not work with iconsets.
20 *  - name: name of icon from themes/base_files/iconsets file, which allows for choosing different iconsets.
21 *          Use instead of _id.
22 *  - size:  size of icon when name is used
23 *  - style:  style supported by the current iconset, e.g. for FA5: default, outline, light (pro only), brands
24 *  - class: set custom class (otherwise default classes are applied). When using icon sets, this class will apply to
25 *          anchor element
26 *  - iclass: set custom class for the icon itself (not the link)
27 *  - ititle: set custom title for the icon itself (not the link)
28 *  - istyle: set custom style for the icon itself (not the link)
29 *  - _type: type of URL to use (e.g. 'absolute_uri', 'absolute_path'). Defaults to a relative URL.
30 *  - _tag: type of HTML tag to use (e.g. 'img', 'input_image'). Defaults to 'img' tag.
31 *  - _notag: if set to 'y', will only return the URL (which also handles theme icons).
32 *  - _menu_text: if set to 'y', will use the 'title' argument as text after the icon and place the whole
33 *						content between div tags with a 'icon_menu' class (not compatible with '_notag' param set to 'y').
34 *  - _menu_icon: if set to 'n', will not show icon image when _menu_text is 'y'.
35 *  - _confirm: text to use in a popup requesting the user to confirm its action (yet only available with javascript)
36 *  - _defaultdir: directory to use when the _id param does not include the path
37 *  - _extension: Filename extension - default 'png'
38 */
39function smarty_function_icon($params, $smarty)
40{
41	if (! is_array($params)) {
42		$params = [];
43	}
44
45	global $prefs, $tc_theme, $tc_theme_option, $url_path, $base_url, $tikipath, $iconset;
46	$cachelib = TikiLib::lib('cache');
47
48	if (empty($tc_theme)) {
49		$current_theme = ! empty($prefs['theme']) ? $prefs['theme'] : '';
50		$current_theme_option = isset($prefs['theme_option']) ? $prefs['theme_option'] : '';
51	} else {
52		$current_theme = $tc_theme;
53		$current_theme_option = ! empty($tc_theme_option) ? $tc_theme_option : '';
54	}
55
56	if (isset($params['_type'])) {
57		if ($params['_type'] === 'absolute_uri') {
58			$params['path_prefix'] = $base_url;
59		} elseif ($params['_type'] === 'absolute_path') {
60			$params['path_prefix'] = $url_path;
61		}
62	}
63
64	$serialized_params = serialize(array_merge($params, [$current_theme, $current_theme_option, isset($_SERVER['HTTPS'])]));
65	$cache_key = TikiLib::contextualizeKey('icons_' . '_' . md5($serialized_params), 'language', 'external');
66	if ($cached = $cachelib->getCached($cache_key)) {
67		return $cached;
68	}
69
70	$basedirs = ['img/icons', 'img/icons/mime'];
71	$icons_extension = empty($params['_extension']) ? '.png' : '.' . $params['_extension'];
72	$tag = 'img';
73	$notag = false;
74	$default_class = 'icon';
75	$default_width = 16;
76	$default_height = 16;
77	$menu_text = false;
78	$menu_icon = false;
79	$confirm = '';
80	$html = '';
81
82	if (empty($params['_id'])) {
83		if (isset($params['_defaultdir']) && $params['_defaultdir'] == 'img/icons/large') {
84			$params['_id'] = 'green_question48x48';
85		} else {
86			$params['_id'] = 'green_question';
87		}
88	}
89	if (! empty($params['_defaultdir'])) {
90		array_unshift($basedirs, $params['_defaultdir']);
91		if ($params['_defaultdir'] == 'img/icons/large') {
92			$default_width = $default_height = ( strpos($params['_id'], '48x48') !== false ) ? 48 : 32;
93		}
94	}
95	// ICONSET START, work-in-progress, more information: dev.tiki.org/icons. $iconset array is prepared by lib/setup/theme.php
96	// N.B. In some contexts such as the console $iconset may not be set up
97	if (! empty($params['name']) && empty($params['_tag']) && ! empty($iconset)) {
98		$name = $params['name'];
99		$html = $iconset->getHtml($name, $params);
100		$menu_text = (isset($params['_menu_text']) && $params['_menu_text'] == 'y');
101		if (! empty($params['href']) || ! empty($params['title']) || $menu_text) {
102			/* Generate a link for the icon if href or title (for tips) parameter is set.
103			 * This will produce a link element (<a>) around the icon.
104			 * If you want a button element (<button>), use the {button} smarty_tiki function */
105
106			//collect link components
107			if (! empty($params['title'])) { //add title if not empty
108				$a_title = $params['title'];
109			} elseif (! empty($params['alt'])) {
110				$a_title = $params['alt'];
111			} else {
112				$a_title = '';
113			}
114			if (! empty($a_title)) {
115				$title_attr = $menu_text ? '' : 'title="' . $a_title . '"';
116			} else {
117				$title_attr = '';
118			}
119			if (isset($params['class'])) { //if set, use these classes instead of the default bootstrap
120				$a_class = $params['class'];
121			} else {
122				$a_class = 'btn btn-link'; //the default classes to be used
123			}
124
125			if (! empty($params['href'])) { //use href if not empty
126				$a_href = 'href="' . $params['href'] . '"';
127			} else {
128				$a_href = '';
129			}
130
131			if (isset($params['data-toggle'])) { //add data-toggle if set
132				$a_datatoggle = 'data-toggle="' . $params['data-toggle'] . '"';
133			} else {
134				$a_datatoggle = '';
135			}
136
137			if (isset($params['onclick'])) { //add onclick if set
138				$a_onclick = 'onclick="' . $params['onclick'] . '"';
139			} elseif (isset($params['_confirm'])) {
140				$a_onclick = 'onclick="return confirm(\'' . $params['_confirm'] . '\');"';
141			} else {
142				$a_onclick = '';
143			}
144
145			//assemble the link from the components
146			if ($menu_text) {
147				$icon = isset($params['_menu_icon']) && $params['_menu_icon'] === 'y' ? $html : '';
148				$html = '<div class="iconmenu">' . $icon . '<span class="iconmenutext"> ' . $a_title . '</span></div>';
149			} else {
150				$html = "<a class='$a_class' $title_attr $a_href $a_datatoggle $a_onclick>$html</a>";
151			}
152		}
153		//return the icon
154		return $html;
155	} //ICONSET END
156
157	// Handle _ids that contains the real filename and path
158	if (strpos($params['_id'], '/') !== false || strpos($params['_id'], '.') !== false) {
159		if (($icons_basedir = dirname($params['_id'])) == '') {
160			$icons_basedir = $basedirs[0];
161		}
162
163		$icons_basedir .= '/';
164
165		if (($pos = strrpos($params['_id'], '.')) !== false) {
166			$icons_extension = substr($params['_id'], $pos);
167		}
168
169		$params['_id'] = preg_replace(
170			'/^' . str_replace('/', '\/', $icons_basedir) . '|' . $icons_extension . '$/',
171			'',
172			$params['_id']
173		);
174	} else {
175		$icons_basedir = $basedirs[0] . '/';
176	}
177
178	if (! preg_match('/^[a-z0-9_-]+$/i', $params['_id'])) {
179		return;
180	}
181
182
183	// Include smarty functions used below
184	$smarty->loadPlugin('smarty_function_html_image');
185
186	// auto-detect 'alt' param if not set
187	if (! isset($params['alt'])) {
188		$alt_pos = ( ($alt_pos = strrpos($params['_id'], '_')) === false ) ? 0 : $alt_pos + 1;
189		$params['alt'] = tra(ucfirst(substr($params['_id'], $alt_pos)));
190	}
191
192	// handle special params and clean unrecognized params
193	foreach ($params as $k => $v) {
194		if ($k[0] == '_') {
195			switch ($k) {
196				case '_id':
197					$img_file = $v . $icons_extension;
198					$v = $icons_basedir . $img_file;
199					$themelib = TikiLib::lib('theme');
200					$v2 = $themelib->get_theme_path($current_theme, $current_theme_option, $img_file, 'icons/');
201
202					if (! empty($v2)) {
203						$params['file'] = $v2;
204					} else {
205						$params['file'] = $v;
206					}
207					break;
208
209				case '_notag':
210					$notag = ($v == 'y');
211					break;
212
213				case '_menu_text':
214					$menu_text = ($v == 'y');
215					$menu_icon = ( isset($params['_menu_icon']) && $params['_menu_icon'] == 'y' );
216					break;
217
218				case '_tag':
219					$tag = $v;
220					break;
221
222				case '_confirm':
223					if ($prefs['javascript_enabled'] == 'y') {
224						$params['onclick'] = "return confirm('" . str_replace("'", "\'", $v) . "');";
225					}
226					break;
227			}
228
229			unset($params[$k]);
230		}
231	}
232
233	// default values for some params
234
235	if (isset($params['path_prefix'])) {
236		$params['basedir'] = $tikipath;
237		$params['file'] = '/' . $params['file'];
238	}
239
240	if ($tag == 'img' && is_readable($params['file'])) {
241		$dim = getimagesize($params['file']);
242
243		if (! isset($params['width'])) {
244			$params['width'] = $dim[0] ? $dim[0] : $default_width;
245		}
246		if (! isset($params['height'])) {
247			$params['height'] = $dim[1] ? $dim[1] : $default_height;
248		}
249	}
250
251	if ($notag) {
252		$html = (isset($params['path_prefix']) ? $params['path_prefix'] : '') . $params['file'];
253	} else {
254		// use 'alt' as 'title' if not set
255		if (! isset($params['title'])) {
256			$params['title'] = $params['alt'];
257		}
258		// use default class if not set
259		if (! isset($params['class'])) {
260			$params['class'] = $default_class;
261		}
262
263		// remove empty arguments
264		foreach ($params as $k => $v) {
265			if ($v == '') {
266				unset($params[$k]);
267			}
268		}
269
270		// No need to add a title on a menu icon since there will be the same text just after the icon
271		if ($menu_text) {
272			$menu_text_val = $params['title'];
273			unset($params['title']);
274		}
275
276		if ($tag != 'img') {
277			$params['src'] = TikiLib::tikiUrlOpt($params['file']);
278			unset($params['file']);
279			foreach ($params as $k => $v) {
280				$html .= ' ' . htmlspecialchars($k, ENT_QUOTES, 'UTF-8') . '="' . htmlspecialchars($v, ENT_QUOTES, 'UTF-8') . '"';
281			}
282		}
283
284		if (! empty($params['file'])) {
285			$headerlib = TikiLib::lib('header');
286			$params['file'] = $headerlib->convert_cdn($params['file']);
287			$params['file'] = TikiLib::tikiUrlOpt($params['file']);
288		}
289
290		switch ($tag) {
291			case 'input_image':
292				$html = '<input type="image"' . $html . ' />';
293				break;
294			case 'img':
295			default:
296				try {
297					$html = smarty_function_html_image($params, $smarty->getEmptyInternalTemplate());
298				} catch (Exception $e) {
299					$html = '<span class="icon error" title="' . tra('Error:') . ' ' . $e->getMessage() . '">?</span>';
300				}
301		}
302
303		if ($tag != 'img') {
304			// Add a span tag to be able to apply a CSS style on hover for the icon
305			$html = "<span>$html</span>";
306		}
307
308		if ($menu_text) {
309			if (! $menu_icon) {
310				$html = '';
311			}
312			$html = '<div class="iconmenu">' . $html . '<span class="iconmenutext"> ' . $menu_text_val . '</span></div>';
313		}
314	}
315
316	$cachelib->cacheItem($cache_key, $html);
317	return $html;
318}
319