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