TYPO3  7.6
IconUtility.php
Go to the documentation of this file.
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 
22 
39 {
43  public static $fileSpriteIconNames = array(
44  'htm' => 'mimetypes-text-html',
45  'html' => 'mimetypes-text-html',
46  'css' => 'mimetypes-text-css',
47  'js' => 'mimetypes-text-js',
48  'csv' => 'mimetypes-text-csv',
49  'php' => 'mimetypes-text-php',
50  'php6' => 'mimetypes-text-php',
51  'php5' => 'mimetypes-text-php',
52  'php4' => 'mimetypes-text-php',
53  'php3' => 'mimetypes-text-php',
54  'inc' => 'mimetypes-text-php',
55  'ts' => 'mimetypes-text-ts',
56  'txt' => 'mimetypes-text-text',
57  'class' => 'mimetypes-text-text',
58  'tmpl' => 'mimetypes-text-text',
59  'jpg' => 'mimetypes-media-image',
60  'jpeg' => 'mimetypes-media-image',
61  'gif' => 'mimetypes-media-image',
62  'png' => 'mimetypes-media-image',
63  'bmp' => 'mimetypes-media-image',
64  'tif' => 'mimetypes-media-image',
65  'tiff' => 'mimetypes-media-image',
66  'tga' => 'mimetypes-media-image',
67  'psd' => 'mimetypes-media-image',
68  'eps' => 'mimetypes-media-image',
69  'ai' => 'mimetypes-media-image',
70  'svg' => 'mimetypes-media-image',
71  'pcx' => 'mimetypes-media-image',
72  'avi' => 'mimetypes-media-video',
73  'mpg' => 'mimetypes-media-video',
74  'mpeg' => 'mimetypes-media-video',
75  'mov' => 'mimetypes-media-video',
76  'wav' => 'mimetypes-media-audio',
77  'mp3' => 'mimetypes-media-audio',
78  'mid' => 'mimetypes-media-audio',
79  'swf' => 'mimetypes-media-flash',
80  'swa' => 'mimetypes-media-flash',
81  'exe' => 'mimetypes-application',
82  'com' => 'mimetypes-application',
83  't3x' => 'mimetypes-compressed',
84  't3d' => 'mimetypes-compressed',
85  'zip' => 'mimetypes-compressed',
86  'tgz' => 'mimetypes-compressed',
87  'gz' => 'mimetypes-compressed',
88  'pdf' => 'mimetypes-pdf',
89  'doc' => 'mimetypes-word',
90  'dot' => 'mimetypes-word',
91  'docm' => 'mimetypes-word',
92  'docx' => 'mimetypes-word',
93  'dotm' => 'mimetypes-word',
94  'dotx' => 'mimetypes-word',
95  'sxw' => 'mimetypes-word',
96  'rtf' => 'mimetypes-word',
97  'xls' => 'mimetypes-excel',
98  'xlsm' => 'mimetypes-excel',
99  'xlsx' => 'mimetypes-excel',
100  'xltm' => 'mimetypes-excel',
101  'xltx' => 'mimetypes-excel',
102  'sxc' => 'mimetypes-excel',
103  'pps' => 'mimetypes-powerpoint',
104  'ppsx' => 'mimetypes-powerpoint',
105  'ppt' => 'mimetypes-powerpoint',
106  'pptm' => 'mimetypes-powerpoint',
107  'pptx' => 'mimetypes-powerpoint',
108  'potm' => 'mimetypes-powerpoint',
109  'potx' => 'mimetypes-powerpoint',
110  'mount' => 'apps-filetree-mount',
111  'folder' => 'apps-filetree-folder-default',
112  'default' => 'mimetypes-other-other'
113  );
114 
121  protected static $spriteIconCache = array();
122 
133  public static function getIcon($table, $row = array(), $shaded = false)
134  {
136  // Flags
137  // If set, then the usergroup number will NOT be printed unto the icon. NOTICE.
138  // The icon is generated only if a default icon for groups is not found... So effectively this is ineffective.
139  $doNotRenderUserGroupNumber = true;
140  // Shadow
141  if (!empty($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) && !empty($row['t3ver_state'])) {
142  switch (VersionState::cast($row['t3ver_state'])) {
144  return 'gfx/i/shadow_hide.png';
145  break;
147  return 'gfx/i/shadow_delete.png';
148  break;
150  return 'gfx/i/shadow_moveto_plh.png';
151  break;
153  return 'gfx/i/shadow_moveto_pointer.png';
154  break;
155  }
156  }
157  // First, find the icon file name. This can depend on configuration in TCA, field values and more:
158  if ($table === 'pages') {
159  $iconfile = $GLOBALS['PAGES_TYPES'][$row['doktype']]['icon'];
160  if (empty($iconfile)) {
161  $iconfile = $GLOBALS['PAGES_TYPES']['default']['icon'];
162  }
163  }
164 
165  if (empty($iconfile)) {
166  $iconfile = $GLOBALS['TCA'][$table]['ctrl']['iconfile'] ?: $table . '.gif';
167  }
168 
169  // Setting path of iconfile if not already set. Default is "gfx/i/"
170  if (!strstr($iconfile, '/')) {
171  $iconfile = 'gfx/i/' . $iconfile;
172  }
173  // Setting the absolute path where the icon should be found as a file:
174  if (substr($iconfile, 0, 3) == '../') {
175  $absfile = PATH_site . substr($iconfile, 3);
176  } else {
177  $absfile = PATH_typo3 . $iconfile;
178  }
179  // Initializing variables, all booleans except otherwise stated:
180  $hidden = false;
181  $timing = false;
182  $futuretiming = false;
183  // In fact an integer value
184  $user = false;
185  $deleted = false;
186  // Set, if a page-record (only pages!) has the extend-to-subpages flag set.
187  $protectSection = false;
188  $noIconFound = (bool)$row['_NO_ICON_FOUND'];
189  // + $shaded which is also boolean!
190  // Icon state based on "enableFields":
191  if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
192  $enCols = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
193  // If "hidden" is enabled:
194  if ($enCols['disabled']) {
195  if ($row[$enCols['disabled']]) {
196  $hidden = true;
197  }
198  }
199  // If a "starttime" is set and higher than current time:
200  if ($enCols['starttime']) {
201  if ($GLOBALS['EXEC_TIME'] < (int)$row[$enCols['starttime']]) {
202  $timing = true;
203  // And if "endtime" is NOT set:
204  if ((int)$row[$enCols['endtime']] === 0) {
205  $futuretiming = true;
206  }
207  }
208  }
209  // If an "endtime" is set:
210  if ($enCols['endtime']) {
211  if ((int)$row[$enCols['endtime']] > 0) {
212  if ((int)$row[$enCols['endtime']] < $GLOBALS['EXEC_TIME']) {
213  // End-timing applies at this point.
214  $timing = true;
215  } else {
216  // End-timing WILL apply in the future for this element.
217  $futuretiming = true;
218  }
219  }
220  }
221  // If a user-group field is set:
222  if ($enCols['fe_group']) {
223  $user = $row[$enCols['fe_group']];
224  if ($user && $doNotRenderUserGroupNumber) {
225  $user = 100;
226  }
227  }
228  }
229  // If "deleted" flag is set (only when listing records which are also deleted!)
230  if ($col = $row[$GLOBALS['TCA'][$table]['ctrl']['delete']]) {
231  $deleted = true;
232  }
233  // Detecting extendToSubpages (for pages only)
234  if ($table == 'pages' && $row['extendToSubpages'] && ($hidden || $timing || $futuretiming || $user)) {
235  $protectSection = true;
236  }
237  // If ANY of the booleans are set it means we have to alter the icon:
238  if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
239  $flags = '';
240  $string = '';
241  if ($deleted) {
242  $string = 'deleted';
243  $flags = 'd';
244  } elseif ($noIconFound) {
245  // This is ONLY for creating icons with "?" on easily...
246  $string = 'no_icon_found';
247  $flags = 'x';
248  } else {
249  if ($hidden) {
250  $string .= 'hidden';
251  }
252  if ($timing) {
253  $string .= 'timing';
254  }
255  if (!$string && $futuretiming) {
256  $string = 'futuretiming';
257  }
258  $flags .= ($hidden ? 'h' : '') . ($timing ? 't' : '') . ($futuretiming ? 'f' : '') . ($user ? 'u' : '') . ($protectSection ? 'p' : '') . ($shaded ? 's' : '');
259  }
260  // Create tagged icon file name:
261  $iconFileName_stateTagged = preg_replace('/.([[:alnum:]]+)$/', '__' . $flags . '.\\1', basename($iconfile));
262  // 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)
263  if (@is_file((dirname($absfile) . '/' . $iconFileName_stateTagged)) || @is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . '/' . dirname($iconfile) . '/' . $iconFileName_stateTagged))) {
264  // Look for [iconname]_xxxx.[ext]
265  return dirname($iconfile) . '/' . $iconFileName_stateTagged;
266  } else {
267  // Otherwise, create the icon:
268  $theRes = self::makeIcon($GLOBALS['BACK_PATH'] . $iconfile, $string, $user, $protectSection, $absfile, $iconFileName_stateTagged);
269  return $theRes;
270  }
271  } else {
272  return $iconfile;
273  }
274  }
275 
288  public static function skinImg($backPath, $src, $wHattribs = '', $outputMode = 0)
289  {
291  static $cachedSkinImages = array();
292  $imageId = md5($backPath . $src . $wHattribs . $outputMode);
293  if (isset($cachedSkinImages[$imageId])) {
294  return $cachedSkinImages[$imageId];
295  }
296  // Setting source key. If the icon is referred to inside an extension, we homogenize the prefix to "ext/":
297  $srcKey = preg_replace('/^(\\.\\.\\/typo3conf\\/ext|sysext|ext)\\//', 'ext/', $src);
298  // LOOKING for alternative icons:
299  if ($GLOBALS['TBE_STYLES']['skinImg'][$srcKey]) {
300  // Slower or faster with is_array()? Could be used.
301  list($src, $wHattribs) = $GLOBALS['TBE_STYLES']['skinImg'][$srcKey];
302  } elseif ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']) {
303  // Otherwise, test if auto-detection is enabled:
304  // Search for alternative icon automatically:
305  $fExt = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['forceFileExtension'];
306  $scaleFactor = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] ?: 1;
307  // Scaling factor
308  $lookUpName = $fExt ? preg_replace('/\\.[[:alnum:]]+$/', '', $srcKey) . '.' . $fExt : $srcKey;
309  // Set filename to look for
310  if ($fExt && !@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
311  // Fallback to original filename if icon with forced extension doesn't exists
312  $lookUpName = $srcKey;
313  }
314  // If file is found:
315  if (@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
316  // If there is a file...
317  $iInfo = @getimagesize(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName));
318  // Get width/height:
319  // Set $src and $wHattribs:
320  $src = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'] . $lookUpName;
321  $wHattribs = 'width="' . round($iInfo[0] * $scaleFactor) . '" height="' . round($iInfo[1] * $scaleFactor) . '"';
322  }
323  // In any case, set currect src / wHattrib - this way we make sure that an entry IS found next time we hit the function,
324  // regardless of whether it points to an alternative icon or just the current.
325  $GLOBALS['TBE_STYLES']['skinImg'][$srcKey] = array($src, $wHattribs);
326  }
327  // Rendering disabled (greyed) icons using _i (inactive) as name suffix ("_d" is already used)
328  $matches = array();
329  $srcBasename = basename($src);
330  if (preg_match('/(.*)_i(\\....)$/', $srcBasename, $matches)) {
331  $temp_path = dirname(PATH_thisScript) . '/';
332  if (!@is_file(($temp_path . $backPath . $src))) {
333  $srcOrg = preg_replace('/_i' . preg_quote($matches[2], '/') . '$/', $matches[2], $src);
334  $src = self::makeIcon($backPath . $srcOrg, 'disabled', 0, false, $temp_path . $backPath . $srcOrg, $srcBasename);
335  }
336  }
337  // Return icon source/wHattributes:
338  $output = '';
339  switch ($outputMode) {
340  case 0:
341  $output = ' src="' . $backPath . $src . '" ' . $wHattribs;
342  break;
343  case 1:
344  $output = $backPath . $src;
345  break;
346  case 2:
347  $output = $wHattribs;
348  break;
349  }
350  $cachedSkinImages[$imageId] = $output;
351 
352  return $output;
353  }
354 
355  /***********************************
356  *
357  * Other functions
358  *
359  ***********************************/
372  public static function makeIcon($iconfile, $mode, $user, $protectSection, $absFile, $iconFileName_stateTagged)
373  {
374  $iconFileName = GeneralUtility::shortMD5(($iconfile . '|' . $mode . '|-' . $user . '|' . $protectSection)) . '_' . $iconFileName_stateTagged . '.' . ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif');
375  $mainpath = '../typo3temp/Icons/' . $iconFileName;
376  $path = PATH_site . 'typo3temp/Icons/' . $iconFileName;
377  if (file_exists($path)) {
378  // Returns if found in ../typo3temp/Icons/
379  return $mainpath;
380  } else {
381  // Makes icon:
382  if (file_exists($absFile)) {
383  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
384  // Create image pointer, if possible
385  $im = self::imagecreatefrom($absFile);
386  if ($im < 0) {
387  return $iconfile;
388  }
389  // Converting to gray scale, dimming the icon:
390  if ($mode == 'disabled' or $mode != 'futuretiming' && $mode != 'no_icon_found' && !(!$mode && $user)) {
391  $totalImageColors = ImageColorsTotal($im);
392  for ($c = 0; $c < $totalImageColors; $c++) {
393  $cols = ImageColorsForIndex($im, $c);
394  $newcol = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
395  $lighten = $mode == 'disabled' ? 2.5 : 2;
396  $newcol = round(255 - (255 - $newcol) / $lighten);
397  ImageColorSet($im, $c, $newcol, $newcol, $newcol);
398  }
399  }
400  // Applying user icon, if there are access control on the item:
401  if ($user) {
402  if ($user < 100) {
403  // Apply user number only if lower than 100
404  $black = ImageColorAllocate($im, 0, 0, 0);
405  imagefilledrectangle($im, 0, 0, $user > 10 ? 9 : 5, 8, $black);
406  $white = ImageColorAllocate($im, 255, 255, 255);
407  imagestring($im, 1, 1, 1, $user, $white);
408  }
409  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_group.gif');
410  if ($ol_im < 0) {
411  return $iconfile;
412  }
413  self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
414  }
415  // Applying overlay based on mode:
416  if ($mode) {
417  unset($ol_im);
418  switch ($mode) {
419  case 'deleted':
420  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_deleted.gif');
421  break;
422  case 'futuretiming':
423  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_timing.gif');
424  break;
425  case 'timing':
426  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_timing.gif');
427  break;
428  case 'hiddentiming':
429  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_hidden_timing.gif');
430  break;
431  case 'no_icon_found':
432  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_no_icon_found.gif');
433  break;
434  case 'disabled':
435  // is already greyed - nothing more
436  $ol_im = 0;
437  break;
438  case 'hidden':
439 
440  default:
441  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_hidden.gif');
442  }
443  if ($ol_im < 0) {
444  return $iconfile;
445  }
446  if ($ol_im) {
447  self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
448  }
449  }
450  // Protect-section icon:
451  if ($protectSection) {
452  $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/overlay_sub5.gif');
453  if ($ol_im < 0) {
454  return $iconfile;
455  }
456  self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
457  }
458  // Create the image as file, destroy GD image and return:
459  $targetDirectory = dirname($path);
460  if (!@is_dir($targetDirectory)) {
461  GeneralUtility::mkdir($targetDirectory);
462  }
463  @self::imagemake($im, $path);
464  GraphicalFunctions::gifCompress($path, 'IM');
465  ImageDestroy($im);
466 
467  return $mainpath;
468  } else {
469  return $iconfile;
470  }
471  } else {
472  return $GLOBALS['BACK_PATH'] . 'typo3/sysext/backend/Resources/Public/Images/Overlay/default.gif';
473  }
474  }
475  }
476 
502  public static function imagecopyresized(&$destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight)
503  {
504  imagecopyresized($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight);
505  }
506 
515  public static function imagecreatefrom($file)
516  {
517  $file = GraphicalFunctions::readPngGif($file, $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']);
518  if (!$file) {
519  return -1;
520  }
521 
522  return $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? imagecreatefrompng($file) : imagecreatefromgif($file);
523  }
524 
533  public static function imagemake($im, $path)
534  {
535  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
536  @ImagePng($im, $path);
537  } else {
538  @ImageGif($im, $path);
539  }
540  if (@is_file($path)) {
542  }
543  }
544 
545  /**********************************************
546  * SPRITE ICON API
547  *
548  * The Sprite Icon API helps you to quickly get the HTML for any icon you want
549  * this is typically wrapped in a <span> tag with corresponding CSS classes that
550  * will be responsible for the
551  *
552  * There are four ways to use this API:
553  *
554  * 1) for any given TCA record
555  * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForRecord('pages', $row);
556  *
557  * 2) for any given File of Folder object
558  * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForResource($fileOrFolderObject);
559  *
560  * 3) for any given file
561  * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForFile('myimage.png');
562  *
563  * 4) for any other icon you know the name
564  * $spriteIconHtml = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open');
565  *
566  **********************************************/
586  public static function getSpriteIcon($iconName, array $options = array(), array $overlays = array())
587  {
589  // Check if icon can be cached and return cached version if present
590  if (empty($options) && empty($overlays)) {
591  if (isset(static::$spriteIconCache[$iconName])) {
592  return static::$spriteIconCache[$iconName];
593  }
594  $iconIsCacheable = true;
595  } else {
596  $iconIsCacheable = false;
597  }
598 
599  $innerHtml = isset($options['html']) ? $options['html'] : null;
600  $tagName = isset($options['tagName']) ? $options['tagName'] : null;
601 
602  // Deal with the overlays
603  foreach ($overlays as $overlayIconName => $overlayOptions) {
604  $overlayOptions['html'] = $innerHtml;
605  $overlayOptions['class'] = (isset($overlayOptions['class']) ? $overlayOptions['class'] . ' ' : '') . 't3-icon-overlay';
606  $innerHtml = self::getSpriteIcon($overlayIconName, $overlayOptions);
607  }
608 
609  $availableIcons = isset($GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])
610  ? (array)$GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable']
611  : array();
612  if ($iconName !== 'empty-empty' && !in_array($iconName, $availableIcons, true)) {
613  $iconName = 'status-status-icon-missing';
614  }
615 
616  // Create the CSS class
617  $options['class'] = self::getSpriteIconClasses($iconName) . (isset($options['class']) ? ' ' . $options['class'] : '');
618  unset($options['html'], $options['tagName']);
619  $spriteHtml = self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
620 
621  // Store result in cache if possible
622  if ($iconIsCacheable) {
623  static::$spriteIconCache[$iconName] = $spriteHtml;
624  }
625 
626  return $spriteHtml;
627  }
628 
642  public static function getSpriteIconForFile($fileExtension, array $options = null)
643  {
645  if ($options !== null) {
646  GeneralUtility::deprecationLog('The parameter $options of IconUtility::getSpriteIconForFile is not used anymore');
647  }
648  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
649 
650  return $iconFactory->getIconForFileExtension($fileExtension)->render();
651  }
652 
661  public static function mapFileExtensionToSpriteIconClass($fileExtension)
662  {
663  return self::getSpriteIconClasses(self::mapFileExtensionToSpriteIconName($fileExtension));
664  }
665 
674  public static function mapFileExtensionToSpriteIconName($fileExtension)
675  {
676  // If the file is a whole file with name etc (mainly, if it has a "." or a "/"),
677  // then it is checked whether it is a valid directory
678  if (strpos($fileExtension, '.') !== false || strpos($fileExtension, '/') !== false) {
679  // Check if it is a directory
680  $filePath = dirname(GeneralUtility::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $fileExtension;
681  $path = GeneralUtility::resolveBackPath($filePath);
682  if (is_dir($path) || substr($fileExtension, -1) === '/' || substr($fileExtension, -1) === '\\') {
683  $fileExtension = 'folder';
684  } else {
685  if (($pos = strrpos($fileExtension, '.')) !== false) {
686  $fileExtension = strtolower(substr($fileExtension, $pos + 1));
687  } else {
688  $fileExtension = 'default';
689  }
690  }
691  }
692  // If the file extension is not valid
693  // then use the default one
694  if (!isset(self::$fileSpriteIconNames[$fileExtension])) {
695  $fileExtension = 'default';
696  }
697  $iconName = self::$fileSpriteIconNames[$fileExtension];
698 
699  return $iconName;
700  }
701 
716  public static function getSpriteIconForRecord($table, array $row, array $options = null)
717  {
719  if ($options !== null) {
720  GeneralUtility::deprecationLog('The parameter $options of IconUtility::getSpriteIconForRecord is not used anymore');
721  }
722  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
723 
724  return $iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render();
725  }
726 
746  public static function getSpriteIconForResource(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, array $options = array(), array $overlays = null)
747  {
749  if ($overlays !== null) {
750  GeneralUtility::deprecationLog('The parameter $overlays of IconUtility::getSpriteIconForResource is not used anymore');
751  }
752  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
753 
754  return $iconFactory->getIconForResource($resource, Icon::SIZE_SMALL, null, $options)->render();
755  }
756 
776  public static function mapRecordTypeToSpriteIconClass($table, array $row)
777  {
779  return self::getSpriteIconClasses(self::mapRecordTypeToSpriteIconName($table, $row));
780  }
781 
800  public static function mapRecordTypeToSpriteIconName($table, array $row)
801  {
802  $recordType = array();
803  $ref = null;
804  if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_column'])) {
805  $column = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
806  if (isset($row[$column])) {
807  $recordType[1] = $row[$column];
808  } else {
809  $recordType[1] = 'default';
810  }
811  // Workaround to give nav_hide pages a complete different icon
812  // Although it's not a separate doctype
813  // and to give root-pages an own icon
814  if ($table === 'pages') {
815  if ($row['nav_hide']) {
816  $recordType[2] = $recordType[1] . '-hideinmenu';
817  }
818  if ($row['is_siteroot']) {
819  $recordType[3] = $recordType[1] . '-root';
820  }
821  if ($row['module']) {
822  $recordType[4] = 'contains-' . $row['module'];
823  }
824  if ((int)$row['content_from_pid'] > 0) {
825  $recordType[4] = (int)$row['nav_hide'] === 0 ? 'page-contentFromPid' : 'page-contentFromPid-hideinmenu';
826  }
827  }
828  if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
829  foreach ($recordType as $key => $type) {
830  if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type])) {
831  $recordType[$key] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type];
832  } else {
833  unset($recordType[$key]);
834  }
835  }
836  $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
837  if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask'])) {
838  $recordType[5] = str_replace('###TYPE###', $row[$column], $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask']);
839  }
840  if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'])) {
841  $parameters = array('row' => $row);
842  $recordType[6] = GeneralUtility::callUserFunction($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'], $parameters, $ref);
843  }
844  } else {
845  foreach ($recordType as &$type) {
846  $type = 'tcarecords-' . $table . '-' . $type;
847  }
848  unset($type);
849  $recordType[0] = 'tcarecords-' . $table . '-default';
850  }
851  } else {
852  if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
853  $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
854  } else {
855  $recordType[0] = 'tcarecords-' . $table . '-default';
856  }
857  }
858  krsort($recordType);
859  if (is_array($GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
860  foreach ($recordType as $iconName) {
861  if (in_array($iconName, $GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
862  return $iconName;
863  }
864  }
865  }
866 
867  return 'status-status-icon-missing';
868  }
869 
880  public static function getSpriteIconClasses($iconName)
881  {
883  $cssClasses = ($baseCssClass = 't3-icon');
884  $parts = explode('-', $iconName);
885  if (count($parts) > 1) {
886  // Will be something like "t3-icon-actions"
887  $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0]);
888  // Will be something like "t3-icon-actions-document"
889  $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0] . '-' . $parts[1]);
890  // Will be something like "t3-icon-document-new"
891  $cssClasses .= ' ' . ($baseCssClass . '-' . substr($iconName, (strlen($parts[0]) + 1)));
892  }
893 
894  return $cssClasses;
895  }
896 
908  protected static function buildSpriteHtmlIconTag(array $tagAttributes, $innerHtml = null, $tagName = null)
909  {
911 
912  $innerHtml = $innerHtml === null ? ' ' : $innerHtml;
913  $tagName = $tagName === null ? 'span' : $tagName;
914  $attributes = '';
915  foreach ($tagAttributes as $attribute => $value) {
916  $attributes .= ' ' . htmlspecialchars($attribute) . '="' . htmlspecialchars($value) . '"';
917  }
918 
919  return '<' . $tagName . $attributes . '>' . $innerHtml . '</' . $tagName . '>';
920  }
921 }