[TASK] Consolidate regexp for utf8 and non-utf8 file systems
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Utility / IconUtility.php
1 <?php
2 namespace TYPO3\CMS\Backend\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Core\Utility\GeneralUtility;
31 use TYPO3\CMS\Core\Versioning\VersionState;
32
33 /**
34 * Contains class for icon generation in the backend
35 * This library has functions that returns - and if necessary creates - the icon for an element in TYPO3
36 *
37 * Expects global vars:
38 * - $BACK_PATH
39 * - PATH_typo3
40 * - $TCA, $PAGES_TYPES
41 *
42 *
43 * Notes:
44 * These functions are strongly related to the interface of TYPO3.
45 * The class is included in eg. init.php
46 * Static class, functions called without making a class instance.
47 *
48 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
49 */
50 class IconUtility {
51
52 static public $fileSpriteIconNames = array(
53 'htm' => 'mimetypes-text-html',
54 'html' => 'mimetypes-text-html',
55 'css' => 'mimetypes-text-css',
56 'js' => 'mimetypes-text-js',
57 'csv' => 'mimetypes-text-csv',
58 'php' => 'mimetypes-text-php',
59 'php6' => 'mimetypes-text-php',
60 'php5' => 'mimetypes-text-php',
61 'php4' => 'mimetypes-text-php',
62 'php3' => 'mimetypes-text-php',
63 'inc' => 'mimetypes-text-php',
64 'ts' => 'mimetypes-text-ts',
65 'txt' => 'mimetypes-text-text',
66 'class' => 'mimetypes-text-text',
67 'tmpl' => 'mimetypes-text-text',
68 'jpg' => 'mimetypes-media-image',
69 'jpeg' => 'mimetypes-media-image',
70 'gif' => 'mimetypes-media-image',
71 'png' => 'mimetypes-media-image',
72 'bmp' => 'mimetypes-media-image',
73 'tif' => 'mimetypes-media-image',
74 'tga' => 'mimetypes-media-image',
75 'psd' => 'mimetypes-media-image',
76 'eps' => 'mimetypes-media-image',
77 'avi' => 'mimetypes-media-video',
78 'mpg' => 'mimetypes-media-video',
79 'mpeg' => 'mimetypes-media-video',
80 'mov' => 'mimetypes-media-video',
81 'wav' => 'mimetypes-media-audio',
82 'mp3' => 'mimetypes-media-audio',
83 'mid' => 'mimetypes-media-audio',
84 'swf' => 'mimetypes-media-flash',
85 'swa' => 'mimetypes-media-flash',
86 'exe' => 'mimetypes-executable-executable',
87 'com' => 'mimetypes-executable-executable',
88 't3x' => 'mimetypes-compressed',
89 't3d' => 'mimetypes-compressed',
90 'zip' => 'mimetypes-compressed',
91 'tgz' => 'mimetypes-compressed',
92 'gz' => 'mimetypes-compressed',
93 'pdf' => 'mimetypes-pdf',
94 'doc' => 'mimetypes-word',
95 'dot' => 'mimetypes-word',
96 'docm' => 'mimetypes-word',
97 'docx' => 'mimetypes-word',
98 'dotm' => 'mimetypes-word',
99 'dotx' => 'mimetypes-word',
100 'sxw' => 'mimetypes-word',
101 'rtf' => 'mimetypes-word',
102 'xls' => 'mimetypes-excel',
103 'xlsm' => 'mimetypes-excel',
104 'xlsx' => 'mimetypes-excel',
105 'xltm' => 'mimetypes-excel',
106 'xltx' => 'mimetypes-excel',
107 'sxc' => 'mimetypes-excel',
108 'pps' => 'mimetypes-powerpoint',
109 'ppsx' => 'mimetypes-powerpoint',
110 'ppt' => 'mimetypes-powerpoint',
111 'pptm' => 'mimetypes-powerpoint',
112 'pptx' => 'mimetypes-powerpoint',
113 'potm' => 'mimetypes-powerpoint',
114 'potx' => 'mimetypes-powerpoint',
115 'mount' => 'apps-filetree-mount',
116 'folder' => 'apps-filetree-folder-default',
117 'default' => 'mimetypes-other-other'
118 );
119
120 /**
121 * Returns an icon image tag, 18x16 pixels, based on input information.
122 * This function is recommended to use in your backend modules.
123 *
124 * @param string $table The table name
125 * @param array $row The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
126 * @param string $backPath The backpath to the main TYPO3 directory (relative path back to PATH_typo3)
127 * @param string $params Additional attributes for the image tag
128 * @param boolean $shaded If set, the icon will be grayed/shaded
129 * @return string <img>-tag
130 * @see getIcon()
131 * @deprecated since TYPO3 6.1 will be removed in 7.0, should not be used anymore as only sprite icons are used since TYPO3 4.4
132 */
133 static public function getIconImage($table, $row = array(), $backPath, $params = '', $shaded = FALSE) {
134 GeneralUtility::logDeprecatedFunction();
135
136 $str = '<img' . self::skinImg($backPath, self::getIcon($table, $row, $shaded), 'width="18" height="16"') . (trim($params) ? ' ' . trim($params) : '');
137 if (!stristr($str, 'alt="')) {
138 $str .= ' alt=""';
139 }
140 $str .= ' />';
141 return $str;
142 }
143
144 /**
145 * Creates the icon for input table/row
146 * Returns filename for the image icon, relative to PATH_typo3
147 *
148 * @param string $table The table name
149 * @param array $row The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
150 * @param boolean $shaded If set, the icon will be grayed/shaded
151 * @return string Icon filename
152 * @see getIconImage()
153 */
154 static public function getIcon($table, $row = array(), $shaded = FALSE) {
155 // Flags
156 // If set, then the usergroup number will NOT be printed unto the icon. NOTICE.
157 // The icon is generated only if a default icon for groups is not found... So effectively this is ineffective.
158 $doNotRenderUserGroupNumber = TRUE;
159 // Shadow
160 if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
161 switch (VersionState::cast($row['t3ver_state'])) {
162 case new VersionState(VersionState::NEW_PLACEHOLDER):
163 return 'gfx/i/shadow_hide.png';
164 break;
165 case new VersionState(VersionState::DELETE_PLACEHOLDER):
166 return 'gfx/i/shadow_delete.png';
167 break;
168 case new VersionState(VersionState::MOVE_PLACEHOLDER):
169 return 'gfx/i/shadow_moveto_plh.png';
170 break;
171 case new VersionState(VersionState::MOVE_POINTER):
172 return 'gfx/i/shadow_moveto_pointer.png';
173 break;
174 }
175 }
176 // First, find the icon file name. This can depend on configuration in TCA, field values and more:
177 if ($table == 'pages') {
178 $iconfile = $GLOBALS['PAGES_TYPES'][$row['doktype']]['icon'];
179 if (!$iconfile) {
180 $iconfile = $GLOBALS['PAGES_TYPES']['default']['icon'];
181 }
182 } else {
183 if (!($iconfile = $GLOBALS['TCA'][$table]['ctrl']['typeicons'][$row[$GLOBALS['TCA'][$table]['ctrl']['typeicon_column']]])) {
184 $iconfile = $GLOBALS['TCA'][$table]['ctrl']['iconfile'] ?: $table . '.gif';
185 }
186 }
187 // Setting path of iconfile if not already set. Default is "gfx/i/"
188 if (!strstr($iconfile, '/')) {
189 $iconfile = 'gfx/i/' . $iconfile;
190 }
191 // Setting the absolute path where the icon should be found as a file:
192 if (substr($iconfile, 0, 3) == '../') {
193 $absfile = PATH_site . substr($iconfile, 3);
194 } else {
195 $absfile = PATH_typo3 . $iconfile;
196 }
197 // Initializing variables, all booleans except otherwise stated:
198 $hidden = FALSE;
199 $timing = FALSE;
200 $futuretiming = FALSE;
201 // In fact an integer value
202 $user = FALSE;
203 $deleted = FALSE;
204 // Set, if a page-record (only pages!) has the extend-to-subpages flag set.
205 $protectSection = FALSE;
206 $noIconFound = $row['_NO_ICON_FOUND'] ? TRUE : FALSE;
207 // + $shaded which is also boolean!
208 // Icon state based on "enableFields":
209 if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
210 $enCols = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
211 // If "hidden" is enabled:
212 if ($enCols['disabled']) {
213 if ($row[$enCols['disabled']]) {
214 $hidden = TRUE;
215 }
216 }
217 // If a "starttime" is set and higher than current time:
218 if ($enCols['starttime']) {
219 if ($GLOBALS['EXEC_TIME'] < (int)$row[$enCols['starttime']]) {
220 $timing = TRUE;
221 // And if "endtime" is NOT set:
222 if ((int)$row[$enCols['endtime']] === 0) {
223 $futuretiming = TRUE;
224 }
225 }
226 }
227 // If an "endtime" is set:
228 if ($enCols['endtime']) {
229 if ((int)$row[$enCols['endtime']] > 0) {
230 if ((int)$row[$enCols['endtime']] < $GLOBALS['EXEC_TIME']) {
231 // End-timing applies at this point.
232 $timing = TRUE;
233 } else {
234 // End-timing WILL apply in the future for this element.
235 $futuretiming = TRUE;
236 }
237 }
238 }
239 // If a user-group field is set:
240 if ($enCols['fe_group']) {
241 $user = $row[$enCols['fe_group']];
242 if ($user && $doNotRenderUserGroupNumber) {
243 $user = 100;
244 }
245 }
246 }
247 // If "deleted" flag is set (only when listing records which are also deleted!)
248 if ($col = $row[$GLOBALS['TCA'][$table]['ctrl']['delete']]) {
249 $deleted = TRUE;
250 }
251 // Detecting extendToSubpages (for pages only)
252 if ($table == 'pages' && $row['extendToSubpages'] && ($hidden || $timing || $futuretiming || $user)) {
253 $protectSection = TRUE;
254 }
255 // If ANY of the booleans are set it means we have to alter the icon:
256 if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
257 $flags = '';
258 $string = '';
259 if ($deleted) {
260 $string = 'deleted';
261 $flags = 'd';
262 } elseif ($noIconFound) {
263 // This is ONLY for creating icons with "?" on easily...
264 $string = 'no_icon_found';
265 $flags = 'x';
266 } else {
267 if ($hidden) {
268 $string .= 'hidden';
269 }
270 if ($timing) {
271 $string .= 'timing';
272 }
273 if (!$string && $futuretiming) {
274 $string = 'futuretiming';
275 }
276 $flags .= ($hidden ? 'h' : '') . ($timing ? 't' : '') . ($futuretiming ? 'f' : '') . ($user ? 'u' : '') . ($protectSection ? 'p' : '') . ($shaded ? 's' : '');
277 }
278 // Create tagged icon file name:
279 $iconFileName_stateTagged = preg_replace('/.([[:alnum:]]+)$/', '__' . $flags . '.\\1', basename($iconfile));
280 // Check if tagged icon file name exists (a tagged icon means the icon base name with the flags added between body and extension of the filename, prefixed with underscore)
281 if (@is_file((dirname($absfile) . '/' . $iconFileName_stateTagged)) || @is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . '/' . dirname($iconfile) . '/' . $iconFileName_stateTagged))) {
282 // Look for [iconname]_xxxx.[ext]
283 return dirname($iconfile) . '/' . $iconFileName_stateTagged;
284 } else {
285 // Otherwise, create the icon:
286 $theRes = self::makeIcon($GLOBALS['BACK_PATH'] . $iconfile, $string, $user, $protectSection, $absfile, $iconFileName_stateTagged);
287 return $theRes;
288 }
289 } else {
290 return $iconfile;
291 }
292 }
293
294 /**
295 * Returns the src=... for the input $src value OR any alternative found in $TBE_STYLES['skinImg']
296 * Used for skinning the TYPO3 backend with an alternative set of icons
297 *
298 * @param string $backPath Current backpath to PATH_typo3 folder
299 * @param string $src Icon file name relative to PATH_typo3 folder
300 * @param string $wHattribs Default width/height, defined like 'width="12" height="14"'
301 * @param integer $outputMode Mode: 0 (zero) is default and returns src/width/height. 1 returns value of src+backpath, 2 returns value of w/h.
302 * @return string Returns ' src="[backPath][src]" [wHattribs]'
303 * @see skinImgFile()
304 */
305 static public function skinImg($backPath, $src, $wHattribs = '', $outputMode = 0) {
306 static $cachedSkinImages = array();
307 $imageId = md5($backPath . $src . $wHattribs . $outputMode);
308 if (isset($cachedSkinImages[$imageId])) {
309 return $cachedSkinImages[$imageId];
310 }
311 // Setting source key. If the icon is refered to inside an extension, we homogenize the prefix to "ext/":
312 $srcKey = preg_replace('/^(\\.\\.\\/typo3conf\\/ext|sysext|ext)\\//', 'ext/', $src);
313 // LOOKING for alternative icons:
314 if ($GLOBALS['TBE_STYLES']['skinImg'][$srcKey]) {
315 // Slower or faster with is_array()? Could be used.
316 list($src, $wHattribs) = $GLOBALS['TBE_STYLES']['skinImg'][$srcKey];
317 } elseif ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']) {
318 // Otherwise, test if auto-detection is enabled:
319 // Search for alternative icon automatically:
320 $fExt = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['forceFileExtension'];
321 $scaleFactor = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] ?: 1;
322 // Scaling factor
323 $lookUpName = $fExt ? preg_replace('/\\.[[:alnum:]]+$/', '', $srcKey) . '.' . $fExt : $srcKey;
324 // Set filename to look for
325 if ($fExt && !@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
326 // Fallback to original filename if icon with forced extension doesn't exists
327 $lookUpName = $srcKey;
328 }
329 // If file is found:
330 if (@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
331 // If there is a file...
332 $iInfo = @getimagesize(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName));
333 // Get width/height:
334 // Set $src and $wHattribs:
335 $src = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'] . $lookUpName;
336 $wHattribs = 'width="' . round($iInfo[0] * $scaleFactor) . '" height="' . round($iInfo[1] * $scaleFactor) . '"';
337 }
338 // In any case, set currect src / wHattrib - this way we make sure that an entry IS found next time we hit the function,
339 // regardless of whether it points to a alternative icon or just the current.
340 $GLOBALS['TBE_STYLES']['skinImg'][$srcKey] = array($src, $wHattribs);
341 }
342 // Rendering disabled (greyed) icons using _i (inactive) as name suffix ("_d" is already used)
343 $matches = array();
344 $srcBasename = basename($src);
345 if (preg_match('/(.*)_i(\\....)$/', $srcBasename, $matches)) {
346 $temp_path = dirname(PATH_thisScript) . '/';
347 if (!@is_file(($temp_path . $backPath . $src))) {
348 $srcOrg = preg_replace('/_i' . preg_quote($matches[2], '/') . '$/', $matches[2], $src);
349 $src = self::makeIcon($backPath . $srcOrg, 'disabled', 0, FALSE, $temp_path . $backPath . $srcOrg, $srcBasename);
350 }
351 }
352 // Return icon source/wHattributes:
353 $output = '';
354 switch ($outputMode) {
355 case 0:
356 $output = ' src="' . $backPath . $src . '" ' . $wHattribs;
357 break;
358 case 1:
359 $output = $backPath . $src;
360 break;
361 case 2:
362 $output = $wHattribs;
363 break;
364 }
365 $cachedSkinImages[$imageId] = $output;
366 return $output;
367 }
368
369 /***********************************
370 *
371 * Other functions
372 *
373 ***********************************/
374 /**
375 * Creates the icon file for the function getIcon()
376 *
377 * @param string $iconfile Original unprocessed Icon file, relative path to PATH_typo3
378 * @param string $mode Mode string, eg. "deleted" or "futuretiming" determining how the icon will look
379 * @param integer $user The number of the fe_group record uid if applicable
380 * @param boolean $protectSection Flag determines if the protected-section icon should be applied.
381 * @param string $absFile Absolute path to file from which to create the icon.
382 * @param string $iconFileName_stateTagged The filename that this icon should have had, basically [icon base name]_[flags].[extension] - used for part of temporary filename
383 * @return string Filename relative to PATH_typo3
384 * @access private
385 */
386 static public function makeIcon($iconfile, $mode, $user, $protectSection, $absFile, $iconFileName_stateTagged) {
387 $iconFileName = 'icon_' . GeneralUtility::shortMD5(($iconfile . '|' . $mode . '|-' . $user . '|' . $protectSection)) . '_' . $iconFileName_stateTagged . '.' . ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif');
388 $mainpath = '../typo3temp/' . $iconFileName;
389 $path = PATH_site . 'typo3temp/' . $iconFileName;
390 if (file_exists(PATH_typo3 . 'icons/' . $iconFileName)) {
391 // Returns if found in typo3/icons/
392 return 'icons/' . $iconFileName;
393 } elseif (file_exists($path)) {
394 // Returns if found in ../typo3temp/icons/
395 return $mainpath;
396 } else {
397 // Makes icon:
398 if (file_exists($absFile)) {
399 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
400 // Create image pointer, if possible
401 $im = self::imagecreatefrom($absFile);
402 if ($im < 0) {
403 return $iconfile;
404 }
405 // Converting to gray scale, dimming the icon:
406 if ($mode == 'disabled' or $mode != 'futuretiming' && $mode != 'no_icon_found' && !(!$mode && $user)) {
407 $totalImageColors = ImageColorsTotal($im);
408 for ($c = 0; $c < $totalImageColors; $c++) {
409 $cols = ImageColorsForIndex($im, $c);
410 $newcol = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
411 $lighten = $mode == 'disabled' ? 2.5 : 2;
412 $newcol = round(255 - (255 - $newcol) / $lighten);
413 ImageColorSet($im, $c, $newcol, $newcol, $newcol);
414 }
415 }
416 // Applying user icon, if there are access control on the item:
417 if ($user) {
418 if ($user < 100) {
419 // Apply user number only if lower than 100
420 $black = ImageColorAllocate($im, 0, 0, 0);
421 imagefilledrectangle($im, 0, 0, $user > 10 ? 9 : 5, 8, $black);
422 $white = ImageColorAllocate($im, 255, 255, 255);
423 imagestring($im, 1, 1, 1, $user, $white);
424 }
425 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_group.gif');
426 if ($ol_im < 0) {
427 return $iconfile;
428 }
429 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
430 }
431 // Applying overlay based on mode:
432 if ($mode) {
433 unset($ol_im);
434 switch ($mode) {
435 case 'deleted':
436 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_deleted.gif');
437 break;
438 case 'futuretiming':
439 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_timing.gif');
440 break;
441 case 'timing':
442 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_timing.gif');
443 break;
444 case 'hiddentiming':
445 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_hidden_timing.gif');
446 break;
447 case 'no_icon_found':
448 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_no_icon_found.gif');
449 break;
450 case 'disabled':
451 // is already greyed - nothing more
452 $ol_im = 0;
453 break;
454 case 'hidden':
455
456 default:
457 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_hidden.gif');
458 }
459 if ($ol_im < 0) {
460 return $iconfile;
461 }
462 if ($ol_im) {
463 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
464 }
465 }
466 // Protect-section icon:
467 if ($protectSection) {
468 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_sub5.gif');
469 if ($ol_im < 0) {
470 return $iconfile;
471 }
472 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
473 }
474 // Create the image as file, destroy GD image and return:
475 @self::imagemake($im, $path);
476 GeneralUtility::gif_compress($path, 'IM');
477 ImageDestroy($im);
478 return $mainpath;
479 } else {
480 return $iconfile;
481 }
482 } else {
483 return $GLOBALS['BACK_PATH'] . 'gfx/fileicons/default.gif';
484 }
485 }
486 }
487
488 /**
489 * The necessity of using this function for combining two images if GD is version 2 is that
490 * GD2 cannot manage to combine two indexed-color images without totally spoiling everything.
491 * In class \TYPO3\CMS\Core\Imaging\GraphicalFunctions this was solved by combining the images
492 * onto a first created true color image.
493 * However it has turned out that this method will not work if the indexed png-files contains transparency.
494 * So I had to turn my attention to ImageMagick - my 'enemy of death'.
495 * And so it happend - ImageMagick is now used to combine my two indexed-color images with transparency. And that works.
496 * Of course it works only if ImageMagick is able to create valid png-images - which you cannot be sure of with older versions (still 5+)
497 * The only drawback is (apparently) that IM creates true-color png's. The transparency of these will not be shown by MSIE on windows at this time (although it's straight 0%/100% transparency!) and the file size may be larger.
498 *
499 * @param resource $destinationImage Destination image
500 * @param resource $sourceImage Source image
501 * @param integer $destinationX Destination x-coordinate
502 * @param integer $destinationY Destination y-coordinate
503 * @param integer $sourceX Source x-coordinate
504 * @param integer $sourceY Source y-coordinate
505 * @param integer $destinationWidth Destination width
506 * @param integer $destinationHeight Destination height
507 * @param integer $sourceWidth Source width
508 * @param integer $sourceHeight Source height
509 * @return void
510 * @access private
511 * @see \TYPO3\CMS\Core\Imaging\GraphicalFunctions::imagecopyresized()
512 */
513 static public function imagecopyresized(&$destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight) {
514 imagecopyresized($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight);
515 }
516
517 /**
518 * Create new image pointer from input file (either gif/png, in case the wrong format it is converted by \TYPO3\CMS\Core\Utility\GeneralUtility::read_png_gif())
519 *
520 * @param string $file Absolute filename of the image file from which to start the icon creation.
521 * @return mixed If success, image pointer, otherwise "-1
522 * @access private
523 * @see \TYPO3\CMS\Core\Utility\GeneralUtility::read_png_gif
524 */
525 static public function imagecreatefrom($file) {
526 $file = GeneralUtility::read_png_gif($file, $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']);
527 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
528 return $file ? imagecreatefrompng($file) : -1;
529 } else {
530 return $file ? imagecreatefromgif($file) : -1;
531 }
532 }
533
534 /**
535 * Write the icon in $im pointer to $path
536 *
537 * @param pointer $im Pointer to GDlib image resource
538 * @param string $path Absolute path to the filename in which to write the icon.
539 * @return void
540 * @access private
541 */
542 static public function imagemake($im, $path) {
543 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
544 @ImagePng($im, $path);
545 } else {
546 @ImageGif($im, $path);
547 }
548 if (@is_file($path)) {
549 GeneralUtility::fixPermissions($path);
550 }
551 }
552
553 /**********************************************
554 * SPRITE ICON API
555 *
556 * The Sprite Icon API helps you to quickly get the HTML for any icon you want
557 * this is typically wrapped in a <span> tag with corresponding CSS classes that
558 * will be responsible for the
559 *
560 * There are four ways to use this API:
561 *
562 * 1) for any given TCA record
563 * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForRecord('pages', $row);
564 *
565 * 2) for any given File of Folder object
566 * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForResource($fileOrFolderObject);
567 *
568 * 3) for any given file
569 * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForFile('myimage.png');
570 *
571 * 4) for any other icon you know the name
572 * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open');
573 *
574 **********************************************/
575 /**
576 * This generic method is used throughout the TYPO3 Backend to show icons in any variation which are not
577 * bound to any resource object (see getSpriteIconForResource) or database record (see getSpriteIconForRecord)
578 *
579 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
580 * already to have a pre-defined background image, and the correct background-position to show
581 * the necessary icon.
582 *
583 * @param string $iconName The name of the icon to fetch
584 * @param array $options An associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
585 * @param array $overlays An associative array with the icon-name as key, and the options for this overlay as an array again (see the parameter $options again)
586 * @return string The full HTML tag (usually a <span>)
587 * @access public
588 */
589 static public function getSpriteIcon($iconName, array $options = array(), array $overlays = array()) {
590 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
591 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
592 // Deal with the overlays
593 if (count($overlays)) {
594 foreach ($overlays as $overlayIconName => $overlayOptions) {
595 $overlayOptions['html'] = $innerHtml;
596 $overlayOptions['class'] = (isset($overlayOptions['class']) ? $overlayOptions['class'] . ' ' : '') . 't3-icon-overlay';
597 $innerHtml = self::getSpriteIcon($overlayIconName, $overlayOptions);
598 }
599 }
600 // Check if whished icon is available
601 $iconName = in_array($iconName, $GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable']) || $iconName == 'empty-empty' ? $iconName : 'status-status-icon-missing';
602 // Create the CSS class
603 $options['class'] = self::getSpriteIconClasses($iconName) . (isset($options['class']) ? ' ' . $options['class'] : '');
604 unset($options['html']);
605 unset($options['tagName']);
606 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
607 }
608
609 /**
610 * This method is used throughout the TYPO3 Backend to show icons for a file type
611 *
612 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
613 * already to have a pre-defined background image, and the correct background-position to show
614 * the necessary icon.
615 *
616 * @param string $fileExtension The name of the icon to fetch, can be a file extension, full file path or one of the special keywords "folder" or "mount
617 * @param array $options An associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
618 * @return string The full HTML tag (usually a <span>)
619 * @access public
620 */
621 static public function getSpriteIconForFile($fileExtension, array $options = array()) {
622 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
623 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
624 // Create the CSS class
625 $options['class'] = self::mapFileExtensionToSpriteIconClass($fileExtension) . (isset($options['class']) ? ' ' . $options['class'] : '');
626 unset($options['html']);
627 unset($options['tagName']);
628 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
629 }
630
631 /**
632 * Generates the spriteicon css classes name for a given path or fileExtension
633 * usually called from getSpriteIconForFile or ExtJs Provider
634 *
635 * @param string $fileExtension FileExtension can be jpg, gif etc, but also be 'mount' or 'folder', but can also be a full path which will be resolved then
636 * @return string The string of the CSS class, see \TYPO3\CMS\Backend\Utility\IconUtility::$fileSpriteIconNames
637 * @access private
638 */
639 static public function mapFileExtensionToSpriteIconClass($fileExtension) {
640 return self::getSpriteIconClasses(self::mapFileExtensionToSpriteIconName($fileExtension));
641 }
642
643 /**
644 * Generates the spriteicon name for a given path or fileExtension
645 * usually called from mapFileExtensionToSpriteIconClass and tceforms
646 *
647 * @param string $fileExtension FileExtension can be jpg, gif etc, but also be 'mount' or 'folder', but can also be a full path which will be resolved then
648 * @return string The string of the CSS class, see \TYPO3\CMS\Backend\Utility\IconUtility::$fileSpriteIconNames
649 * @access private
650 */
651 static public function mapFileExtensionToSpriteIconName($fileExtension) {
652 // If the file is a whole file with name etc (mainly, if it has a "." or a "/"),
653 // then it is checked whether it is a valid directory
654 if (strpos($fileExtension, '.') !== FALSE || strpos($fileExtension, '/') !== FALSE) {
655 // Check if it is a directory
656 $filePath = dirname(GeneralUtility::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $fileExtension;
657 $path = GeneralUtility::resolveBackPath($filePath);
658 if (is_dir($path) || substr($fileExtension, -1) === '/' || substr($fileExtension, -1) === '\\') {
659 $fileExtension = 'folder';
660 } else {
661 if (($pos = strrpos($fileExtension, '.')) !== FALSE) {
662 $fileExtension = strtolower(substr($fileExtension, $pos + 1));
663 } else {
664 $fileExtension = 'default';
665 }
666 }
667 }
668 // If the file extension is not valid
669 // then use the default one
670 if (!isset(self::$fileSpriteIconNames[$fileExtension])) {
671 $fileExtension = 'default';
672 }
673 $iconName = self::$fileSpriteIconNames[$fileExtension];
674 return $iconName;
675 }
676
677 /**
678 * This method is used throughout the TYPO3 Backend to show icons for a DB record
679 *
680 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
681 * already to have a pre-defined background image, and the correct background-position to show
682 * the necessary icon.
683 *
684 * @param string $table The TCA table name
685 * @param array $row The DB record of the TCA table
686 * @param array $options An associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
687 * @return string The full HTML tag (usually a <span>)
688 * @access public
689 */
690 static public function getSpriteIconForRecord($table, array $row, array $options = array()) {
691 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
692 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
693 // Overlay this record icon with the status of the row
694 $overlaySpriteIconName = self::mapRecordOverlayToSpriteIconName($table, $row);
695 if ($overlaySpriteIconName) {
696 $overlayOptions = array(
697 'html' => $innerHtml,
698 'class' => 't3-icon-overlay'
699 );
700 $innerHtml = self::getSpriteIcon($overlaySpriteIconName, $overlayOptions);
701 }
702 // Fetch the name for the CSS class, based on the $row
703 $options['class'] = self::mapRecordTypeToSpriteIconClass($table, $row) . (isset($options['class']) ? ' ' . $options['class'] : '');
704 unset($options['html']);
705 unset($options['tagName']);
706 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
707 }
708
709 /**
710 * This method is used throughout the TYPO3 Backend to show icons for files and folders
711 *
712 * The method takes care of the translation of file extension to proper icon and for folders
713 * it will return the icon depending on the role of the folder.
714 *
715 * If the given resource is a folder there are some additional options that can be used:
716 * - mount-root => TRUE (to indicate this is the root of a mount)
717 * - folder-open => TRUE (to indicate that the folder is opened in the file tree)
718 *
719 * There is a hook in place to manipulate the icon name and overlays.
720 *
721 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
722 * @param array $options An associative array with additional options and attributes for the tag. See self::getSpriteIcon()
723 * @param array $overlays An associative array with the icon-name as key, and the options for this overlay as an array again (see the parameter $options again)
724 * @return string
725 * @throws \UnexpectedValueException
726 */
727 static public function getSpriteIconForResource(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, array $options = array(), array $overlays = array()) {
728 // Folder
729 if ($resource instanceof \TYPO3\CMS\Core\Resource\FolderInterface) {
730 // non browsable storage
731 if ($resource->getStorage()->isBrowsable() === FALSE && !empty($options['mount-root'])) {
732 $iconName = 'apps-filetree-folder-locked';
733 // storage root
734 } elseif ($resource->getStorage()->getRootLevelFolder()->getIdentifier() === $resource->getIdentifier()) {
735 $iconName = 'apps-filetree-root';
736 // user/group mount root
737 } elseif (!empty($options['mount-root'])) {
738 $iconName = 'apps-filetree-mount';
739 } else {
740
741 // in folder tree view $options['folder-open'] can define a open folder icon
742 if (!empty($options['folder-open'])) {
743 $iconName = 'apps-filetree-folder-opened';
744 } else {
745 $iconName = 'apps-filetree-folder-default';
746 }
747
748 $role = $resource->getRole();
749 if ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_TEMPORARY) {
750 $iconName = 'apps-filetree-folder-temp';
751 } elseif ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_RECYCLER) {
752 $iconName = 'apps-filetree-folder-recycler';
753 }
754
755 // if locked add overlay
756 if ($resource instanceof \TYPO3\CMS\Core\Resource\InaccessibleFolder) {
757 $overlays['status-overlay-locked'] = array();
758 }
759 }
760 // File
761 } else {
762 $iconName = self::mapFileExtensionToSpriteIconName($resource->getExtension());
763
764 if ($resource instanceof \TYPO3\CMS\Core\Resource\File && $resource->isMissing()) {
765 $overlays['status-overlay-missing'] = array();
766 }
767 }
768
769 // Hook: allow some other process to influence the choice of icon and overlays
770 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideResourceIcon'])) {
771 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideResourceIcon'] as $classRef) {
772 $hookObject = GeneralUtility::getUserObj($classRef);
773 if (!$hookObject instanceof IconUtilityOverrideResourceIconHookInterface) {
774 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Backend\\Utility\\IconUtilityOverrideResourceIconHookInterface', 1393574895);
775 }
776 $hookObject->overrideResourceIcon($resource, $iconName, $options, $overlays);
777 }
778 }
779
780 unset($options['mount-root']);
781 unset($options['folder-open']);
782 return self::getSpriteIcon($iconName, $options, $overlays);
783 }
784
785 /**
786 * this helper functions looks up the column that is used for the type of
787 * the chosen TCA table. And then fetches the corresponding class
788 * based on the chosen iconsprite class in this TCA
789 * The TCA looks up
790 * - [ctrl][typeicon_column]
791 * -
792 * This method solely takes care of the type of this record, not any
793 * statuses, used for overlays.
794 * You should not use this directly besides if you need classes for ExtJS iconCls.
795 *
796 * see ext:core/Configuration/TCA/pages.php for an example with the TCA table "pages"
797 *
798 * @param string $table The TCA table
799 * @param array $row The selected record
800 * @return string The CSS class for the sprite icon of that DB record
801 * @access private
802 */
803 static public function mapRecordTypeToSpriteIconClass($table, array $row) {
804 return self::getSpriteIconClasses(self::mapRecordTypeToSpriteIconName($table, $row));
805 }
806
807 /**
808 * this helper functions looks up the column that is used for the type of
809 * the chosen TCA table. And then fetches the corresponding iconname
810 * based on the chosen iconsprite class in this TCA
811 * The TCA looks up
812 * - [ctrl][typeicon_column]
813 * -
814 * This method solely takes care of the type of this record, not any
815 * statuses, used for overlays.
816 * You should not use this directly besides if you need it in tceforms/core classes
817 *
818 * see ext:core/Configuration/TCA/pages.php for an example with the TCA table "pages"
819 *
820 * @param string $tableThe TCA table
821 * @param array $row The selected record
822 * @return string The CSS class for the sprite icon of that DB record
823 * @access private
824 */
825 static public function mapRecordTypeToSpriteIconName($table, array $row) {
826 $recordType = array();
827 $ref = NULL;
828 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_column'])) {
829 $column = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
830 if (isset($row[$column])) {
831 $recordType[1] = $row[$column];
832 } else {
833 $recordType[1] = 'default';
834 }
835 // Workaround to give nav_hide pages a complete different icon
836 // Although it's not a separate doctype
837 // and to give root-pages an own icon
838 if ($table === 'pages') {
839 if ($row['nav_hide']) {
840 $recordType[2] = $recordType[1] . '-hideinmenu';
841 }
842 if ($row['is_siteroot']) {
843 $recordType[3] = $recordType[1] . '-root';
844 }
845 if ($row['module']) {
846 $recordType[4] = 'contains-' . $row['module'];
847 }
848 }
849 if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
850 foreach ($recordType as $key => $type) {
851 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type])) {
852 $recordType[$key] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type];
853 } else {
854 unset($recordType[$key]);
855 }
856 }
857 $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
858 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask'])) {
859 $recordType[5] = str_replace('###TYPE###', $row[$column], $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask']);
860 }
861 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'])) {
862 $parameters = array('row' => $row);
863 $recordType[6] = GeneralUtility::callUserFunction($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'], $parameters, $ref);
864 }
865 } else {
866 foreach ($recordType as &$type) {
867 $type = 'tcarecords-' . $table . '-' . $type;
868 }
869 unset($type);
870 $recordType[0] = 'tcarecords-' . $table . '-default';
871 }
872 } else {
873 if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
874 $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
875 } else {
876 $recordType[0] = 'tcarecords-' . $table . '-default';
877 }
878 }
879 krsort($recordType);
880 if (is_array($GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
881 foreach ($recordType as $iconName) {
882 if (in_array($iconName, $GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
883 return $iconName;
884 }
885 }
886 }
887 return 'status-status-icon-missing';
888 }
889
890 /**
891 * this helper functions checks if the DB record ($row) has any special status
892 * based on the TCA settings like hidden, starttime etc, and then returns a specific
893 * Sprite icon class for the overlay of this DB record
894 * This method solely takes care of the overlay of this record, not any type
895 *
896 * Please note that this only returns one overlay, one status, that is prioritized
897 * by $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayPriorities']
898 * We wanted to not have these icons blown over by tons of overlays, so this is limited
899 * to just one.
900 *
901 * see ext:core/Configuration/DefaultConfiguration.php for the default options, you will find
902 * $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayNames'] that shows
903 * the list of CSS classes that will be used for the sprites, mapped to the statuses here
904 *
905 * @param string $table The TCA table
906 * @param array $row The selected record
907 * @return string The CSS class for the sprite icon of that DB record
908 * @access private
909 */
910 static public function mapRecordOverlayToSpriteIconName($table, array $row) {
911 $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
912 // Calculate for a given record the actual visibility at the moment
913 $status = array(
914 'hidden' => FALSE,
915 'starttime' => FALSE,
916 'endtime' => FALSE,
917 'futureendtime' => FALSE,
918 'fe_group' => FALSE,
919 'deleted' => FALSE,
920 'protectedSection' => FALSE,
921 'nav_hide' => $row['nav_hide'] ? TRUE : FALSE,
922 'noIconFound' => $row['_NO_ICON_FOUND'] ? TRUE : FALSE
923 );
924 // Icon state based on "enableFields":
925 if (is_array($tcaCtrl['enablecolumns'])) {
926 $enCols = $tcaCtrl['enablecolumns'];
927 // If "hidden" is enabled:
928 if ($tcaCtrl['enablecolumns']['disabled'] && $row[$tcaCtrl['enablecolumns']['disabled']]) {
929 $status['hidden'] = TRUE;
930 }
931 // If a "starttime" is set and higher than current time:
932 if ($tcaCtrl['enablecolumns']['starttime'] && $GLOBALS['EXEC_TIME'] < (int)$row[$tcaCtrl['enablecolumns']['starttime']]) {
933 $status['starttime'] = TRUE;
934 }
935 // If an "endtime" is set
936 if ($tcaCtrl['enablecolumns']['endtime']) {
937 if ((int)$row[$tcaCtrl['enablecolumns']['endtime']] > 0) {
938 if ((int)$row[$tcaCtrl['enablecolumns']['endtime']] < $GLOBALS['EXEC_TIME']) {
939 // End-timing applies at this point.
940 $status['endtime'] = TRUE;
941 } else {
942 // End-timing WILL apply in the future for this element.
943 $status['futureendtime'] = TRUE;
944 }
945 }
946 }
947 // If a user-group field is set
948 if ($tcaCtrl['enablecolumns']['fe_group'] && $row[$tcaCtrl['enablecolumns']['fe_group']]) {
949 $status['fe_group'] = TRUE;
950 }
951 }
952 // If "deleted" flag is set (only when listing records which are also deleted!)
953 if ($row[$tcaCtrl['delete']]) {
954 $status['deleted'] = TRUE;
955 }
956 // Detecting extendToSubpages (for pages only)
957 if ($table == 'pages' && $row['extendToSubpages']) {
958 $status['protectedSection'] = TRUE;
959 }
960 // Hook: allow some other process to influence the choice of icon overlay
961 // The method called receives the table name, the current row and the current status array as parameters
962 // The status array should be passed as a reference and in order to be modified within the hook
963 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideIconOverlay'])) {
964 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideIconOverlay'] as $classRef) {
965 $hookObject = GeneralUtility::getUserObj($classRef);
966 if (method_exists($hookObject, 'overrideIconOverlay')) {
967 $hookObject->overrideIconOverlay($table, $row, $status);
968 }
969 }
970 }
971 // Now only show the status with the highest priority
972 $priorities = $GLOBALS['TBE_STYLES']['spriteIconApi']['spriteIconRecordOverlayPriorities'];
973 $iconName = '';
974 if (is_array($priorities)) {
975 foreach ($priorities as $priority) {
976 if ($status[$priority]) {
977 $iconName = $GLOBALS['TBE_STYLES']['spriteIconApi']['spriteIconRecordOverlayNames'][$priority];
978 break;
979 }
980 }
981 }
982 return $iconName;
983 }
984
985 /**
986 * generic method to create the final CSS classes based on the sprite icon name
987 * with the base class and splits the name into parts
988 * is usually called by the methods that are responsible for fetching the names
989 * out of the file name, or the record type
990 *
991 * @param string $name Iconname like 'actions-document-new'
992 * @return string A list of all CSS classes needed for the HTML tag
993 */
994 static public function getSpriteIconClasses($iconName) {
995 $cssClasses = ($baseCssClass = 't3-icon');
996 $parts = explode('-', $iconName);
997 if (count($parts) > 1) {
998 // Will be something like "t3-icon-actions"
999 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0]);
1000 // Will be something like "t3-icon-actions-document"
1001 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0] . '-' . $parts[1]);
1002 // Will be something like "t3-icon-document-new"
1003 $cssClasses .= ' ' . ($baseCssClass . '-' . substr($iconName, (strlen($parts[0]) + 1)));
1004 }
1005 return $cssClasses;
1006 }
1007
1008 /**
1009 * low level function that generates the HTML tag for the sprite icon
1010 * is usually called by the three API classes (getSpriteIcon, getSpriteIconForFile, getSpriteIconForRecord)
1011 * it does not care about classes or anything else, but just plainly builds the HTML tag
1012 *
1013 * @param array $tagAttributes An associative array of additional tagAttributes for the HTML tag
1014 * @param string $innerHtml The content within the tag, a "&nbsp;" by default
1015 * @param string $tagName The name of the HTML element that should be used (span by default)
1016 * @return string The sprite html icon tag
1017 */
1018 static protected function buildSpriteHtmlIconTag(array $tagAttributes, $innerHtml = NULL, $tagName = NULL) {
1019 $innerHtml = $innerHtml === NULL ? '&nbsp;' : $innerHtml;
1020 $tagName = $tagName === NULL ? 'span' : $tagName;
1021 $attributes = '';
1022 foreach ($tagAttributes as $attribute => $value) {
1023 $attributes .= ' ' . htmlspecialchars($attribute) . '="' . htmlspecialchars($value) . '"';
1024 }
1025 return '<' . $tagName . $attributes . '>' . $innerHtml . '</' . $tagName . '>';
1026 }
1027
1028 }