[TASK] Render Resources using SVG in IconFactory
[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 $iconfile = $GLOBALS['TCA'][$table]['ctrl']['iconfile'] ?: $table . '.gif';
161 }
162 // Setting path of iconfile if not already set. Default is "gfx/i/"
163 if (!strstr($iconfile, '/')) {
164 $iconfile = 'gfx/i/' . $iconfile;
165 }
166 // Setting the absolute path where the icon should be found as a file:
167 if (substr($iconfile, 0, 3) == '../') {
168 $absfile = PATH_site . substr($iconfile, 3);
169 } else {
170 $absfile = PATH_typo3 . $iconfile;
171 }
172 // Initializing variables, all booleans except otherwise stated:
173 $hidden = FALSE;
174 $timing = FALSE;
175 $futuretiming = FALSE;
176 // In fact an integer value
177 $user = FALSE;
178 $deleted = FALSE;
179 // Set, if a page-record (only pages!) has the extend-to-subpages flag set.
180 $protectSection = FALSE;
181 $noIconFound = (bool)$row['_NO_ICON_FOUND'];
182 // + $shaded which is also boolean!
183 // Icon state based on "enableFields":
184 if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
185 $enCols = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
186 // If "hidden" is enabled:
187 if ($enCols['disabled']) {
188 if ($row[$enCols['disabled']]) {
189 $hidden = TRUE;
190 }
191 }
192 // If a "starttime" is set and higher than current time:
193 if ($enCols['starttime']) {
194 if ($GLOBALS['EXEC_TIME'] < (int)$row[$enCols['starttime']]) {
195 $timing = TRUE;
196 // And if "endtime" is NOT set:
197 if ((int)$row[$enCols['endtime']] === 0) {
198 $futuretiming = TRUE;
199 }
200 }
201 }
202 // If an "endtime" is set:
203 if ($enCols['endtime']) {
204 if ((int)$row[$enCols['endtime']] > 0) {
205 if ((int)$row[$enCols['endtime']] < $GLOBALS['EXEC_TIME']) {
206 // End-timing applies at this point.
207 $timing = TRUE;
208 } else {
209 // End-timing WILL apply in the future for this element.
210 $futuretiming = TRUE;
211 }
212 }
213 }
214 // If a user-group field is set:
215 if ($enCols['fe_group']) {
216 $user = $row[$enCols['fe_group']];
217 if ($user && $doNotRenderUserGroupNumber) {
218 $user = 100;
219 }
220 }
221 }
222 // If "deleted" flag is set (only when listing records which are also deleted!)
223 if ($col = $row[$GLOBALS['TCA'][$table]['ctrl']['delete']]) {
224 $deleted = TRUE;
225 }
226 // Detecting extendToSubpages (for pages only)
227 if ($table == 'pages' && $row['extendToSubpages'] && ($hidden || $timing || $futuretiming || $user)) {
228 $protectSection = TRUE;
229 }
230 // If ANY of the booleans are set it means we have to alter the icon:
231 if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
232 $flags = '';
233 $string = '';
234 if ($deleted) {
235 $string = 'deleted';
236 $flags = 'd';
237 } elseif ($noIconFound) {
238 // This is ONLY for creating icons with "?" on easily...
239 $string = 'no_icon_found';
240 $flags = 'x';
241 } else {
242 if ($hidden) {
243 $string .= 'hidden';
244 }
245 if ($timing) {
246 $string .= 'timing';
247 }
248 if (!$string && $futuretiming) {
249 $string = 'futuretiming';
250 }
251 $flags .= ($hidden ? 'h' : '') . ($timing ? 't' : '') . ($futuretiming ? 'f' : '') . ($user ? 'u' : '') . ($protectSection ? 'p' : '') . ($shaded ? 's' : '');
252 }
253 // Create tagged icon file name:
254 $iconFileName_stateTagged = preg_replace('/.([[:alnum:]]+)$/', '__' . $flags . '.\\1', basename($iconfile));
255 // 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)
256 if (@is_file((dirname($absfile) . '/' . $iconFileName_stateTagged)) || @is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . '/' . dirname($iconfile) . '/' . $iconFileName_stateTagged))) {
257 // Look for [iconname]_xxxx.[ext]
258 return dirname($iconfile) . '/' . $iconFileName_stateTagged;
259 } else {
260 // Otherwise, create the icon:
261 $theRes = self::makeIcon($GLOBALS['BACK_PATH'] . $iconfile, $string, $user, $protectSection, $absfile, $iconFileName_stateTagged);
262 return $theRes;
263 }
264 } else {
265 return $iconfile;
266 }
267 }
268
269 /**
270 * Returns the src=... for the input $src value OR any alternative found in $TBE_STYLES['skinImg']
271 * Used for skinning the TYPO3 backend with an alternative set of icons
272 *
273 * @param string $backPath Current backpath to PATH_typo3 folder
274 * @param string $src Icon file name relative to PATH_typo3 folder
275 * @param string $wHattribs Default width/height, defined like 'width="12" height="14"'
276 * @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.
277 * @return string Returns ' src="[backPath][src]" [wHattribs]'
278 * @see skinImgFile()
279 */
280 static public function skinImg($backPath, $src, $wHattribs = '', $outputMode = 0) {
281 static $cachedSkinImages = array();
282 $imageId = md5($backPath . $src . $wHattribs . $outputMode);
283 if (isset($cachedSkinImages[$imageId])) {
284 return $cachedSkinImages[$imageId];
285 }
286 // Setting source key. If the icon is referred to inside an extension, we homogenize the prefix to "ext/":
287 $srcKey = preg_replace('/^(\\.\\.\\/typo3conf\\/ext|sysext|ext)\\//', 'ext/', $src);
288 // LOOKING for alternative icons:
289 if ($GLOBALS['TBE_STYLES']['skinImg'][$srcKey]) {
290 // Slower or faster with is_array()? Could be used.
291 list($src, $wHattribs) = $GLOBALS['TBE_STYLES']['skinImg'][$srcKey];
292 } elseif ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']) {
293 // Otherwise, test if auto-detection is enabled:
294 // Search for alternative icon automatically:
295 $fExt = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['forceFileExtension'];
296 $scaleFactor = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] ?: 1;
297 // Scaling factor
298 $lookUpName = $fExt ? preg_replace('/\\.[[:alnum:]]+$/', '', $srcKey) . '.' . $fExt : $srcKey;
299 // Set filename to look for
300 if ($fExt && !@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
301 // Fallback to original filename if icon with forced extension doesn't exists
302 $lookUpName = $srcKey;
303 }
304 // If file is found:
305 if (@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
306 // If there is a file...
307 $iInfo = @getimagesize(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName));
308 // Get width/height:
309 // Set $src and $wHattribs:
310 $src = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'] . $lookUpName;
311 $wHattribs = 'width="' . round($iInfo[0] * $scaleFactor) . '" height="' . round($iInfo[1] * $scaleFactor) . '"';
312 }
313 // In any case, set currect src / wHattrib - this way we make sure that an entry IS found next time we hit the function,
314 // regardless of whether it points to an alternative icon or just the current.
315 $GLOBALS['TBE_STYLES']['skinImg'][$srcKey] = array($src, $wHattribs);
316 }
317 // Rendering disabled (greyed) icons using _i (inactive) as name suffix ("_d" is already used)
318 $matches = array();
319 $srcBasename = basename($src);
320 if (preg_match('/(.*)_i(\\....)$/', $srcBasename, $matches)) {
321 $temp_path = dirname(PATH_thisScript) . '/';
322 if (!@is_file(($temp_path . $backPath . $src))) {
323 $srcOrg = preg_replace('/_i' . preg_quote($matches[2], '/') . '$/', $matches[2], $src);
324 $src = self::makeIcon($backPath . $srcOrg, 'disabled', 0, FALSE, $temp_path . $backPath . $srcOrg, $srcBasename);
325 }
326 }
327 // Return icon source/wHattributes:
328 $output = '';
329 switch ($outputMode) {
330 case 0:
331 $output = ' src="' . $backPath . $src . '" ' . $wHattribs;
332 break;
333 case 1:
334 $output = $backPath . $src;
335 break;
336 case 2:
337 $output = $wHattribs;
338 break;
339 }
340 $cachedSkinImages[$imageId] = $output;
341
342 return $output;
343 }
344
345 /***********************************
346 *
347 * Other functions
348 *
349 ***********************************/
350 /**
351 * Creates the icon file for the function getIcon()
352 *
353 * @param string $iconfile Original unprocessed Icon file, relative path to PATH_typo3
354 * @param string $mode Mode string, eg. "deleted" or "futuretiming" determining how the icon will look
355 * @param int $user The number of the fe_group record uid if applicable
356 * @param bool $protectSection Flag determines if the protected-section icon should be applied.
357 * @param string $absFile Absolute path to file from which to create the icon.
358 * @param string $iconFileName_stateTagged The filename that this icon should have had, basically [icon base name]_[flags].[extension] - used for part of temporary filename
359 * @return string Filename relative to PATH_typo3
360 * @access private
361 */
362 static public function makeIcon($iconfile, $mode, $user, $protectSection, $absFile, $iconFileName_stateTagged) {
363 $iconFileName = GeneralUtility::shortMD5(($iconfile . '|' . $mode . '|-' . $user . '|' . $protectSection)) . '_' . $iconFileName_stateTagged . '.' . ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif');
364 $mainpath = '../typo3temp/Icons/' . $iconFileName;
365 $path = PATH_site . 'typo3temp/Icons/' . $iconFileName;
366 if (file_exists($path)) {
367 // Returns if found in ../typo3temp/Icons/
368 return $mainpath;
369 } else {
370 // Makes icon:
371 if (file_exists($absFile)) {
372 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
373 // Create image pointer, if possible
374 $im = self::imagecreatefrom($absFile);
375 if ($im < 0) {
376 return $iconfile;
377 }
378 // Converting to gray scale, dimming the icon:
379 if ($mode == 'disabled' or $mode != 'futuretiming' && $mode != 'no_icon_found' && !(!$mode && $user)) {
380 $totalImageColors = ImageColorsTotal($im);
381 for ($c = 0; $c < $totalImageColors; $c++) {
382 $cols = ImageColorsForIndex($im, $c);
383 $newcol = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
384 $lighten = $mode == 'disabled' ? 2.5 : 2;
385 $newcol = round(255 - (255 - $newcol) / $lighten);
386 ImageColorSet($im, $c, $newcol, $newcol, $newcol);
387 }
388 }
389 // Applying user icon, if there are access control on the item:
390 if ($user) {
391 if ($user < 100) {
392 // Apply user number only if lower than 100
393 $black = ImageColorAllocate($im, 0, 0, 0);
394 imagefilledrectangle($im, 0, 0, $user > 10 ? 9 : 5, 8, $black);
395 $white = ImageColorAllocate($im, 255, 255, 255);
396 imagestring($im, 1, 1, 1, $user, $white);
397 }
398 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_group.gif');
399 if ($ol_im < 0) {
400 return $iconfile;
401 }
402 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
403 }
404 // Applying overlay based on mode:
405 if ($mode) {
406 unset($ol_im);
407 switch ($mode) {
408 case 'deleted':
409 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_deleted.gif');
410 break;
411 case 'futuretiming':
412 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_timing.gif');
413 break;
414 case 'timing':
415 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_timing.gif');
416 break;
417 case 'hiddentiming':
418 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_hidden_timing.gif');
419 break;
420 case 'no_icon_found':
421 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_no_icon_found.gif');
422 break;
423 case 'disabled':
424 // is already greyed - nothing more
425 $ol_im = 0;
426 break;
427 case 'hidden':
428
429 default:
430 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_hidden.gif');
431 }
432 if ($ol_im < 0) {
433 return $iconfile;
434 }
435 if ($ol_im) {
436 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
437 }
438 }
439 // Protect-section icon:
440 if ($protectSection) {
441 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_sub5.gif');
442 if ($ol_im < 0) {
443 return $iconfile;
444 }
445 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
446 }
447 // Create the image as file, destroy GD image and return:
448 $targetDirectory = dirname($path);
449 if (!@is_dir($targetDirectory)) {
450 GeneralUtility::mkdir($targetDirectory);
451 }
452 @self::imagemake($im, $path);
453 GraphicalFunctions::gifCompress($path, 'IM');
454 ImageDestroy($im);
455
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 happened - 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 * @return string The full HTML tag (usually a <span>)
569 * @access public
570 */
571 static public function getSpriteIcon($iconName, array $options = array(), array $overlays = array()) {
572 // Check if icon can be cached and return cached version if present
573 if (empty($options) && empty($overlays)) {
574 if (isset(static::$spriteIconCache[$iconName])) {
575 return static::$spriteIconCache[$iconName];
576 }
577 $iconIsCacheable = TRUE;
578 } else {
579 $iconIsCacheable = FALSE;
580 }
581
582 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
583 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
584
585 // Deal with the overlays
586 foreach ($overlays as $overlayIconName => $overlayOptions) {
587 $overlayOptions['html'] = $innerHtml;
588 $overlayOptions['class'] = (isset($overlayOptions['class']) ? $overlayOptions['class'] . ' ' : '') . 't3-icon-overlay';
589 $innerHtml = self::getSpriteIcon($overlayIconName, $overlayOptions);
590 }
591
592 $availableIcons = isset($GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])
593 ? (array)$GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable']
594 : array();
595 if ($iconName !== 'empty-empty' && !in_array($iconName, $availableIcons, TRUE)) {
596 $iconName = 'status-status-icon-missing';
597 }
598
599 // Create the CSS class
600 $options['class'] = self::getSpriteIconClasses($iconName) . (isset($options['class']) ? ' ' . $options['class'] : '');
601 unset($options['html'], $options['tagName']);
602 $spriteHtml = self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
603
604 // Store result in cache if possible
605 if ($iconIsCacheable) {
606 static::$spriteIconCache[$iconName] = $spriteHtml;
607 }
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
678 return $iconName;
679 }
680
681 /**
682 * This method is used throughout the TYPO3 Backend to show icons for a DB record
683 *
684 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
685 * already to have a pre-defined background image, and the correct background-position to show
686 * the necessary icon.
687 *
688 * @param string $table The TCA table name
689 * @param array $row The DB record of the TCA table
690 * @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)
691 * @return string The full HTML tag (usually a <span>)
692 * @access public
693 */
694 static public function getSpriteIconForRecord($table, array $row, array $options = array()) {
695 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
696 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
697 // Overlay this record icon with the status of the row
698 $overlaySpriteIconName = self::mapRecordOverlayToSpriteIconName($table, $row);
699 if ($overlaySpriteIconName) {
700 $overlayOptions = array(
701 'html' => $innerHtml,
702 'class' => 't3-icon-overlay'
703 );
704 $innerHtml = self::getSpriteIcon($overlaySpriteIconName, $overlayOptions);
705 }
706 // Fetch the name for the CSS class, based on the $row
707 $options['class'] = self::mapRecordTypeToSpriteIconClass($table, $row) . (isset($options['class']) ? ' ' . $options['class'] : '');
708 unset($options['html']);
709 unset($options['tagName']);
710 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
711 }
712
713 /**
714 * This method is used throughout the TYPO3 Backend to show icons for files and folders
715 *
716 * The method takes care of the translation of file extension to proper icon and for folders
717 * it will return the icon depending on the role of the folder.
718 *
719 * If the given resource is a folder there are some additional options that can be used:
720 * - mount-root => TRUE (to indicate this is the root of a mount)
721 * - folder-open => TRUE (to indicate that the folder is opened in the file tree)
722 *
723 * There is a hook in place to manipulate the icon name and overlays.
724 *
725 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
726 * @param array $options An associative array with additional options and attributes for the tag. See self::getSpriteIcon()
727 * @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)
728 * @return string
729 * @throws \UnexpectedValueException
730 */
731 static public function getSpriteIconForResource(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, array $options = array(), array $overlays = array()) {
732 // Folder
733 if ($resource instanceof \TYPO3\CMS\Core\Resource\FolderInterface) {
734 $iconName = NULL;
735 $role = $resource->getRole();
736 // non browsable storage
737 if ($resource->getStorage()->isBrowsable() === FALSE && !empty($options['mount-root'])) {
738 $iconName = 'apps-filetree-folder-locked';
739 } else {
740 // storage root
741 if ($resource->getStorage()->getRootLevelFolder()->getIdentifier() === $resource->getIdentifier()) {
742 $iconName = 'apps-filetree-root';
743 }
744
745
746 // user/group mount root
747 if (!empty($options['mount-root'])) {
748 $iconName = 'apps-filetree-mount';
749 if ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_READONLY_MOUNT) {
750 $overlays['status-overlay-locked'] = array();
751 } elseif ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_USER_MOUNT) {
752 $overlays['status-overlay-access-restricted'] = array();
753 }
754 }
755
756 if ($iconName === NULL) {
757 // in folder tree view $options['folder-open'] can define an open folder icon
758 if (!empty($options['folder-open'])) {
759 $iconName = 'apps-filetree-folder-opened';
760 } else {
761 $iconName = 'apps-filetree-folder-default';
762 }
763
764 if ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_TEMPORARY) {
765 $iconName = 'apps-filetree-folder-temp';
766 } elseif ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_RECYCLER) {
767 $iconName = 'apps-filetree-folder-recycler';
768 }
769 }
770
771 // if locked add overlay
772 if ($resource instanceof \TYPO3\CMS\Core\Resource\InaccessibleFolder ||
773 !$resource->getStorage()->isBrowsable() ||
774 !$resource->getStorage()->checkFolderActionPermission('add', $resource)
775 ) {
776 $overlays['status-overlay-locked'] = array();
777 }
778 }
779
780
781
782 // File
783 } else {
784 $iconName = self::mapFileExtensionToSpriteIconName($resource->getExtension());
785
786 if ($resource instanceof \TYPO3\CMS\Core\Resource\File && $resource->isMissing()) {
787 $overlays['status-overlay-missing'] = array();
788 }
789 }
790
791 // Hook: allow some other process to influence the choice of icon and overlays
792 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideResourceIcon'])) {
793 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideResourceIcon'] as $classRef) {
794 $hookObject = GeneralUtility::getUserObj($classRef);
795 if (!$hookObject instanceof IconUtilityOverrideResourceIconHookInterface) {
796 throw new \UnexpectedValueException('$hookObject must implement interface ' . \TYPO3\CMS\Backend\Utility\IconUtilityOverrideResourceIconHookInterface::class, 1393574895);
797 }
798 $hookObject->overrideResourceIcon($resource, $iconName, $options, $overlays);
799 }
800 }
801
802 unset($options['mount-root']);
803 unset($options['folder-open']);
804 return self::getSpriteIcon($iconName, $options, $overlays);
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 class
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 classes for ExtJS iconCls.
817 *
818 * see ext:core/Configuration/TCA/pages.php for an example with the TCA table "pages"
819 *
820 * @param string $table The 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 mapRecordTypeToSpriteIconClass($table, array $row) {
826 return self::getSpriteIconClasses(self::mapRecordTypeToSpriteIconName($table, $row));
827 }
828
829 /**
830 * this helper functions looks up the column that is used for the type of
831 * the chosen TCA table. And then fetches the corresponding iconname
832 * based on the chosen iconsprite class in this TCA
833 * The TCA looks up
834 * - [ctrl][typeicon_column]
835 * -
836 * This method solely takes care of the type of this record, not any
837 * statuses, used for overlays.
838 * You should not use this directly besides if you need it in tceforms/core classes
839 *
840 * see ext:core/Configuration/TCA/pages.php for an example with the TCA table "pages"
841 *
842 * @param string $table The TCA table
843 * @param array $row The selected record
844 * @return string The CSS class for the sprite icon of that DB record
845 * @access private
846 */
847 static public function mapRecordTypeToSpriteIconName($table, array $row) {
848 $recordType = array();
849 $ref = NULL;
850 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_column'])) {
851 $column = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
852 if (isset($row[$column])) {
853 $recordType[1] = $row[$column];
854 } else {
855 $recordType[1] = 'default';
856 }
857 // Workaround to give nav_hide pages a complete different icon
858 // Although it's not a separate doctype
859 // and to give root-pages an own icon
860 if ($table === 'pages') {
861 if ($row['nav_hide']) {
862 $recordType[2] = $recordType[1] . '-hideinmenu';
863 }
864 if ($row['is_siteroot']) {
865 $recordType[3] = $recordType[1] . '-root';
866 }
867 if ($row['module']) {
868 $recordType[4] = 'contains-' . $row['module'];
869 }
870 if ((int)$row['content_from_pid'] > 0) {
871 $recordType[4] = (int)$row['nav_hide'] === 0 ? 'page-contentFromPid' : 'page-contentFromPid-hideinmenu';
872 }
873 }
874 if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
875 foreach ($recordType as $key => $type) {
876 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type])) {
877 $recordType[$key] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type];
878 } else {
879 unset($recordType[$key]);
880 }
881 }
882 $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
883 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask'])) {
884 $recordType[5] = str_replace('###TYPE###', $row[$column], $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask']);
885 }
886 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'])) {
887 $parameters = array('row' => $row);
888 $recordType[6] = GeneralUtility::callUserFunction($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'], $parameters, $ref);
889 }
890 } else {
891 foreach ($recordType as &$type) {
892 $type = 'tcarecords-' . $table . '-' . $type;
893 }
894 unset($type);
895 $recordType[0] = 'tcarecords-' . $table . '-default';
896 }
897 } else {
898 if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
899 $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
900 } else {
901 $recordType[0] = 'tcarecords-' . $table . '-default';
902 }
903 }
904 krsort($recordType);
905 if (is_array($GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
906 foreach ($recordType as $iconName) {
907 if (in_array($iconName, $GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
908 return $iconName;
909 }
910 }
911 }
912
913 return 'status-status-icon-missing';
914 }
915
916 /**
917 * this helper functions checks if the DB record ($row) has any special status
918 * based on the TCA settings like hidden, starttime etc, and then returns a specific
919 * Sprite icon class for the overlay of this DB record
920 * This method solely takes care of the overlay of this record, not any type
921 *
922 * Please note that this only returns one overlay, one status, that is prioritized
923 * by $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayPriorities']
924 * We wanted to not have these icons blown over by tons of overlays, so this is limited
925 * to just one.
926 *
927 * see ext:core/Configuration/DefaultConfiguration.php for the default options, you will find
928 * $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayNames'] that shows
929 * the list of CSS classes that will be used for the sprites, mapped to the statuses here
930 *
931 * @param string $table The TCA table
932 * @param array $row The selected record
933 * @return string The CSS class for the sprite icon of that DB record
934 * @access private
935 */
936 static public function mapRecordOverlayToSpriteIconName($table, array $row) {
937 $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
938 // Calculate for a given record the actual visibility at the moment
939 $status = array(
940 'hidden' => FALSE,
941 'starttime' => FALSE,
942 'endtime' => FALSE,
943 'futureendtime' => FALSE,
944 'fe_group' => FALSE,
945 'deleted' => FALSE,
946 'protectedSection' => FALSE,
947 'nav_hide' => (bool)$row['nav_hide'],
948 'noIconFound' => (bool)$row['_NO_ICON_FOUND']
949 );
950 // Icon state based on "enableFields":
951 if (is_array($tcaCtrl['enablecolumns'])) {
952 $enCols = $tcaCtrl['enablecolumns'];
953 // If "hidden" is enabled:
954 if ($tcaCtrl['enablecolumns']['disabled'] && $row[$tcaCtrl['enablecolumns']['disabled']]) {
955 $status['hidden'] = TRUE;
956 }
957 // If a "starttime" is set and higher than current time:
958 if ($tcaCtrl['enablecolumns']['starttime'] && $GLOBALS['EXEC_TIME'] < (int)$row[$tcaCtrl['enablecolumns']['starttime']]) {
959 $status['starttime'] = TRUE;
960 }
961 // If an "endtime" is set
962 if ($tcaCtrl['enablecolumns']['endtime']) {
963 if ((int)$row[$tcaCtrl['enablecolumns']['endtime']] > 0) {
964 if ((int)$row[$tcaCtrl['enablecolumns']['endtime']] < $GLOBALS['EXEC_TIME']) {
965 // End-timing applies at this point.
966 $status['endtime'] = TRUE;
967 } else {
968 // End-timing WILL apply in the future for this element.
969 $status['futureendtime'] = TRUE;
970 }
971 }
972 }
973 // If a user-group field is set
974 if ($tcaCtrl['enablecolumns']['fe_group'] && $row[$tcaCtrl['enablecolumns']['fe_group']]) {
975 $status['fe_group'] = TRUE;
976 }
977 }
978 // If "deleted" flag is set (only when listing records which are also deleted!)
979 if ($row[$tcaCtrl['delete']]) {
980 $status['deleted'] = TRUE;
981 }
982 // Detecting extendToSubpages (for pages only)
983 if ($table == 'pages' && $row['extendToSubpages']) {
984 $status['protectedSection'] = TRUE;
985 }
986 // Hook: allow some other process to influence the choice of icon overlay
987 // The method called receives the table name, the current row and the current status array as parameters
988 // The status array should be passed as a reference and in order to be modified within the hook
989 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideIconOverlay'])) {
990 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideIconOverlay'] as $classRef) {
991 $hookObject = GeneralUtility::getUserObj($classRef);
992 if (method_exists($hookObject, 'overrideIconOverlay')) {
993 $hookObject->overrideIconOverlay($table, $row, $status);
994 }
995 }
996 }
997 // Now only show the status with the highest priority
998 $priorities = $GLOBALS['TBE_STYLES']['spriteIconApi']['spriteIconRecordOverlayPriorities'];
999 $iconName = '';
1000 if (is_array($priorities)) {
1001 foreach ($priorities as $priority) {
1002 if ($status[$priority]) {
1003 $iconName = $GLOBALS['TBE_STYLES']['spriteIconApi']['spriteIconRecordOverlayNames'][$priority];
1004 break;
1005 }
1006 }
1007 }
1008
1009 return $iconName;
1010 }
1011
1012 /**
1013 * generic method to create the final CSS classes based on the sprite icon name
1014 * with the base class and splits the name into parts
1015 * is usually called by the methods that are responsible for fetching the names
1016 * out of the file name, or the record type
1017 *
1018 * @param string $iconName Iconname like 'actions-document-new'
1019 * @return string A list of all CSS classes needed for the HTML tag
1020 */
1021 static public function getSpriteIconClasses($iconName) {
1022 $cssClasses = ($baseCssClass = 't3-icon');
1023 $parts = explode('-', $iconName);
1024 if (count($parts) > 1) {
1025 // Will be something like "t3-icon-actions"
1026 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0]);
1027 // Will be something like "t3-icon-actions-document"
1028 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0] . '-' . $parts[1]);
1029 // Will be something like "t3-icon-document-new"
1030 $cssClasses .= ' ' . ($baseCssClass . '-' . substr($iconName, (strlen($parts[0]) + 1)));
1031 }
1032 static::emitBuildSpriteIconClassesSignal($iconName, $cssClasses);
1033
1034 return $cssClasses;
1035 }
1036
1037 /**
1038 * low level function that generates the HTML tag for the sprite icon
1039 * is usually called by the three API classes (getSpriteIcon, getSpriteIconForFile, getSpriteIconForRecord)
1040 * it does not care about classes or anything else, but just plainly builds the HTML tag
1041 *
1042 * @param array $tagAttributes An associative array of additional tagAttributes for the HTML tag
1043 * @param string $innerHtml The content within the tag, a "&nbsp;" by default
1044 * @param string $tagName The name of the HTML element that should be used (span by default)
1045 * @return string The sprite html icon tag
1046 */
1047 static protected function buildSpriteHtmlIconTag(array $tagAttributes, $innerHtml = NULL, $tagName = NULL) {
1048 list($tagAttributes, $innerHtml, $tagName) = static::emitBuildSpriteHtmlIconTagSignal($tagAttributes, $innerHtml, $tagName);
1049
1050 $innerHtml = $innerHtml === NULL ? ' ' : $innerHtml;
1051 $tagName = $tagName === NULL ? 'span' : $tagName;
1052 $attributes = '';
1053 foreach ($tagAttributes as $attribute => $value) {
1054 $attributes .= ' ' . htmlspecialchars($attribute) . '="' . htmlspecialchars($value) . '"';
1055 }
1056
1057 return '<' . $tagName . $attributes . '>' . $innerHtml . '</' . $tagName . '>';
1058 }
1059
1060 /**
1061 * @param array $tagAttributes An associative array of additional tagAttributes for the HTML tag
1062 * @param string $innerHtml The content within the tag, NULL by default
1063 * @param string $tagName The name of the HTML element that should be used (span by default), NULL by default
1064 * @return array
1065 */
1066 static protected function emitBuildSpriteHtmlIconTagSignal(array $tagAttributes, $innerHtml, $tagName) {
1067 return static::getSignalSlotDispatcher()->dispatch(\TYPO3\CMS\Backend\Utility\IconUtility::class, 'buildSpriteHtmlIconTag', array($tagAttributes, $innerHtml, $tagName));
1068 }
1069
1070 /**
1071 * Emits a signal right after the CSS classes are built. This is useful if somebody only
1072 * fetches the CSS classes via IconUtility and not the whole sprite span tag.
1073 *
1074 * @param string $iconName The name of the icon
1075 * @param string $cssClasses the CSS classes to be used as a string
1076 */
1077 static protected function emitBuildSpriteIconClassesSignal($iconName, &$cssClasses) {
1078 static::getSignalSlotDispatcher()->dispatch(\TYPO3\CMS\Backend\Utility\IconUtility::class, 'buildSpriteIconClasses', array($iconName, &$cssClasses));
1079 }
1080
1081 /**
1082 * Get the SignalSlot dispatcher
1083 *
1084 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
1085 */
1086 static protected function getSignalSlotDispatcher() {
1087 return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
1088 }
1089
1090 }