[TASK] Use strict comparison for strings
[Packages/TYPO3.CMS.git] / typo3 / sysext / css_styled_content / Classes / Controller / CssStyledContentController.php
1 <?php
2 namespace TYPO3\CMS\CssStyledContent\Controller;
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\Utility\GeneralUtility;
18 use TYPO3\CMS\Core\Utility\MathUtility;
19
20 /**
21 * Plugin class - instantiated from TypoScript.
22 * Rendering some content elements from tt_content table.
23 */
24 class CssStyledContentController extends \TYPO3\CMS\Frontend\Plugin\AbstractPlugin
25 {
26 /**
27 * Same as class name
28 *
29 * @var string
30 */
31 public $prefixId = 'tx_cssstyledcontent_pi1';
32
33 /**
34 * Path to this script relative to the extension dir.
35 *
36 * @var string
37 */
38 public $scriptRelPath = 'Classes/Controller/CssStyledContentController.php';
39
40 /**
41 * The extension key
42 *
43 * @var string
44 */
45 public $extKey = 'css_styled_content';
46
47 /**
48 * @var array
49 */
50 public $conf = [];
51
52 /***********************************
53 * Rendering of Content Elements:
54 ***********************************/
55
56 /**
57 * Rendering the "Table" type content element, called from TypoScript (tt_content.table.20)
58 *
59 * @param string $content Content input. Not used, ignore.
60 * @param array $conf TypoScript configuration
61 * @return string HTML output.
62 */
63 public function render_table($content, $conf)
64 {
65 // Look for hook before running default code for function
66 if ($hookObj = $this->hookRequest('render_table')) {
67 return $hookObj->render_table($content, $conf);
68 } else {
69 // Init FlexForm configuration
70 $this->pi_initPIflexForm();
71 // Get bodytext field content
72 $field = isset($conf['field']) && trim($conf['field']) ? trim($conf['field']) : 'bodytext';
73 $content = trim($this->cObj->data[$field]);
74 if ($content === '') {
75 return '';
76 }
77 // get flexform values
78 $caption = trim(htmlspecialchars($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_caption')));
79 $useTfoot = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_tfoot'));
80 $headerPos = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_headerpos');
81 $noStyles = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_nostyles');
82 $tableClass = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_tableclass');
83 $delimiter = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'tableparsing_delimiter', 's_parsing'));
84 if ($delimiter) {
85 $delimiter = chr((int)$delimiter);
86 } else {
87 $delimiter = '|';
88 }
89 $quotedInput = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'tableparsing_quote', 's_parsing'));
90 if ($quotedInput) {
91 $quotedInput = chr((int)$quotedInput);
92 } else {
93 $quotedInput = '';
94 }
95 // Generate id prefix for accessible header
96 $headerScope = $headerPos === 'top' ? 'col' : 'row';
97 $headerIdPrefix = $headerScope . $this->cObj->data['uid'] . '-';
98 // Split into single lines (will become table-rows):
99 $rows = GeneralUtility::trimExplode(LF, $content);
100 reset($rows);
101 // Find number of columns to render:
102 $cols = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(
103 $this->cObj->data['cols'] ? $this->cObj->data['cols'] : count(str_getcsv(current($rows), $delimiter, $quotedInput)),
104 0,
105 100
106 );
107 // Traverse rows (rendering the table here)
108 $rCount = count($rows);
109 foreach ($rows as $k => $v) {
110 $cells = str_getcsv($v, $delimiter, $quotedInput);
111 $newCells = [];
112 for ($a = 0; $a < $cols; $a++) {
113 if (trim($cells[$a]) === '') {
114 $cells[$a] = ' ';
115 }
116 $cells[$a] = preg_replace('|<br */?>|i', LF, $cells[$a]);
117 $cellAttribs = $noStyles ? '' : ($a > 0 && $cols - 1 == $a ? ' class="td-last td-' . $a . '"' : ' class="td-' . $a . '"');
118 if ($headerPos === 'top' && !$k || $headerPos === 'left' && !$a) {
119 $scope = ' scope="' . $headerScope . '"';
120 $scope .= ' id="' . $headerIdPrefix . ($headerScope === 'col' ? $a : $k) . '"';
121 $newCells[$a] = '
122 <th' . $cellAttribs . $scope . '>' . $this->cObj->stdWrap($cells[$a], $conf['innerStdWrap.']) . '</th>';
123 } else {
124 if (empty($headerPos)) {
125 $accessibleHeader = '';
126 } else {
127 $accessibleHeader = ' headers="' . $headerIdPrefix . ($headerScope === 'col' ? $a : $k) . '"';
128 }
129 $newCells[$a] = '
130 <td' . $cellAttribs . $accessibleHeader . '>' . $this->cObj->stdWrap($cells[$a], $conf['innerStdWrap.']) . '</td>';
131 }
132 }
133 if (!$noStyles) {
134 $oddEven = $k % 2 ? 'tr-odd' : 'tr-even';
135 $rowAttribs = $k > 0 && $rCount - 1 == $k ? ' class="' . $oddEven . ' tr-last"' : ' class="' . $oddEven . ' tr-' . $k . '"';
136 }
137 $rows[$k] = '
138 <tr' . $rowAttribs . '>' . implode('', $newCells) . '
139 </tr>';
140 }
141 $addTbody = 0;
142 $tableContents = '';
143 if ($caption) {
144 $tableContents .= '
145 <caption>' . $caption . '</caption>';
146 }
147 if ($headerPos === 'top' && $rows[0]) {
148 $tableContents .= '<thead>' . $rows[0] . '
149 </thead>';
150 unset($rows[0]);
151 $addTbody = 1;
152 }
153 if ($useTfoot) {
154 $tableContents .= '
155 <tfoot>' . $rows[$rCount - 1] . '</tfoot>';
156 unset($rows[$rCount - 1]);
157 $addTbody = 1;
158 }
159 $tmpTable = implode('', $rows);
160 if ($addTbody) {
161 $tmpTable = '<tbody>' . $tmpTable . '</tbody>';
162 }
163 $tableContents .= $tmpTable;
164 // Set header type:
165 $type = (int)$this->cObj->data['layout'];
166 // Table tag params.
167 $tableTagParams = $this->getTableAttributes($conf, $type);
168 if (!$noStyles) {
169 $tableTagParams['class'] = 'contenttable contenttable-' . $type . ($tableClass ? ' ' . $tableClass : '') . $tableTagParams['class'];
170 } elseif ($tableClass) {
171 $tableTagParams['class'] = $tableClass;
172 }
173 // Compile table output:
174 $out = '
175 <table ' . GeneralUtility::implodeAttributes($tableTagParams) . '>' . $tableContents . '
176 </table>';
177 // Return value
178 return $out;
179 }
180 }
181
182 /**
183 * Returns an array containing width relations for $colCount columns.
184 *
185 * Tries to use "colRelations" setting given by TS.
186 * uses "1:1" column relations by default.
187 *
188 * @param array $conf TS configuration for img
189 * @param int $colCount number of columns
190 * @return array
191 */
192 protected function getImgColumnRelations($conf, $colCount)
193 {
194 $relations = [];
195 $equalRelations = array_fill(0, $colCount, 1);
196 $colRelationsTypoScript = trim($this->cObj->stdWrap($conf['colRelations'], $conf['colRelations.']));
197 if ($colRelationsTypoScript) {
198 // Try to use column width relations given by TS
199 $relationParts = explode(':', $colRelationsTypoScript);
200 // Enough columns defined?
201 if (count($relationParts) >= $colCount) {
202 $out = [];
203 for ($a = 0; $a < $colCount; $a++) {
204 $currentRelationValue = (int)$relationParts[$a];
205 if ($currentRelationValue >= 1) {
206 $out[$a] = $currentRelationValue;
207 } else {
208 GeneralUtility::devLog('colRelations used with a value smaller than 1 therefore colRelations setting is ignored.', $this->extKey, 2);
209 unset($out);
210 break;
211 }
212 }
213 if (max($out) / min($out) <= 10) {
214 $relations = $out;
215 } else {
216 GeneralUtility::devLog(
217 'The difference in size between the largest and smallest colRelation was not within' .
218 ' a factor of ten therefore colRelations setting is ignored..',
219 $this->extKey,
220 2
221 );
222 }
223 }
224 }
225 return $relations ?: $equalRelations;
226 }
227
228 /**
229 * Returns an array containing the image widths for an image row with $colCount columns.
230 *
231 * @param array $conf TS configuration of img
232 * @param int $colCount number of columns
233 * @param int $netW max usable width for images (without spaces and borders)
234 * @return array
235 */
236 protected function getImgColumnWidths($conf, $colCount, $netW)
237 {
238 $columnWidths = [];
239 $colRelations = $this->getImgColumnRelations($conf, $colCount);
240 $accumWidth = 0;
241 $accumDesiredWidth = 0;
242 $relUnitCount = array_sum($colRelations);
243 for ($a = 0; $a < $colCount; $a++) {
244 // This much width is available for the remaining images in this row (int)
245 $availableWidth = $netW - $accumWidth;
246 // Theoretical width of resized image. (float)
247 $desiredWidth = $netW / $relUnitCount * $colRelations[$a];
248 // Add this width. $accumDesiredWidth becomes the desired horizontal position
249 $accumDesiredWidth += $desiredWidth;
250 // Calculate width by comparing actual and desired horizontal position.
251 // this evenly distributes rounding errors across all images in this row.
252 $suggestedWidth = round($accumDesiredWidth - $accumWidth);
253 // finalImgWidth may not exceed $availableWidth
254 $finalImgWidth = (int)min($availableWidth, $suggestedWidth);
255 $accumWidth += $finalImgWidth;
256 $columnWidths[$a] = $finalImgWidth;
257 }
258 return $columnWidths;
259 }
260
261 /**
262 * Rendering the text w/ image content element, called from TypoScript (tt_content.textpic.20)
263 *
264 * @param string $content Content input. Not used, ignore.
265 * @param array $conf TypoScript configuration. See TSRef "IMGTEXT". This function aims to be compatible.
266 * @return string HTML output.
267 */
268 public function render_textpic($content, $conf)
269 {
270 // Look for hook before running default code for function
271 if (method_exists($this, 'hookRequest') && ($hookObj = $this->hookRequest('render_textpic'))) {
272 return $hookObj->render_textpic($content, $conf);
273 }
274 $renderMethod = $this->cObj->stdWrap($conf['renderMethod'], $conf['renderMethod.']);
275 // Render using the default IMGTEXT code (table-based)
276 if (!$renderMethod || $renderMethod === 'table') {
277 return $this->cObj->cObjGetSingle('IMGTEXT', $conf);
278 }
279 $restoreRegisters = false;
280 if (isset($conf['preRenderRegisters.'])) {
281 $restoreRegisters = true;
282 $this->cObj->cObjGetSingle('LOAD_REGISTER', $conf['preRenderRegisters.']);
283 }
284 // Specific configuration for the chosen rendering method
285 if (is_array($conf['rendering.'][$renderMethod . '.'])) {
286 $conf = array_replace_recursive($conf, $conf['rendering.'][$renderMethod . '.']);
287 }
288 // Image or Text with Image?
289 if (is_array($conf['text.'])) {
290 $content = $this->cObj->stdWrap($this->cObj->cObjGet($conf['text.'], 'text.'), $conf['text.']);
291 }
292 $imgList = trim($this->cObj->stdWrap($conf['imgList'], $conf['imgList.']));
293 if (!$imgList) {
294 // No images, that's easy
295 if ($restoreRegisters) {
296 $this->cObj->cObjGetSingle('RESTORE_REGISTER', []);
297 }
298 return $content;
299 }
300 $imgs = GeneralUtility::trimExplode(',', $imgList, true);
301 if (empty($imgs)) {
302 // The imgList was not empty but did only contain empty values
303 if ($restoreRegisters) {
304 $this->cObj->cObjGetSingle('RESTORE_REGISTER', []);
305 }
306 return $content;
307 }
308 $imgStart = (int)$this->cObj->stdWrap($conf['imgStart'], $conf['imgStart.']);
309 $imgCount = count($imgs) - $imgStart;
310 $imgMax = (int)$this->cObj->stdWrap($conf['imgMax'], $conf['imgMax.']);
311 if ($imgMax) {
312 $imgCount = MathUtility::forceIntegerInRange($imgCount, 0, $imgMax);
313 }
314 $imgPath = $this->cObj->stdWrap($conf['imgPath'], $conf['imgPath.']);
315 // Does we need to render a "global caption" (below the whole image block)?
316 $renderGlobalCaption = !$conf['captionSplit'] && !$conf['imageTextSplit'] && is_array($conf['caption.']);
317 if ($imgCount == 1) {
318 // If we just have one image, the caption relates to the image, so it is not "global"
319 $renderGlobalCaption = false;
320 }
321 $imgListContainsReferenceUids = (bool)(isset($conf['imgListContainsReferenceUids.'])
322 ? $this->cObj->stdWrap($conf['imgListContainsReferenceUids'], $conf['imgListContainsReferenceUids.'])
323 : $conf['imgListContainsReferenceUids']);
324 // Use the calculated information (amount of images, if global caption is wanted) to choose a different rendering method for the images-block
325 $this->frontendController->register['imageCount'] = $imgCount;
326 $this->frontendController->register['renderGlobalCaption'] = $renderGlobalCaption;
327 $fallbackRenderMethod = '';
328 if ($conf['fallbackRendering']) {
329 $fallbackRenderMethod = $this->cObj->cObjGetSingle($conf['fallbackRendering'], $conf['fallbackRendering.']);
330 }
331 if ($fallbackRenderMethod && is_array($conf['rendering.'][$fallbackRenderMethod . '.'])) {
332 $conf = array_replace_recursive($conf, $conf['rendering.'][$fallbackRenderMethod . '.']);
333 }
334 // Set the accessibility mode which uses a different type of markup, used 4.7+
335 $accessibilityMode = false;
336 if (strpos(strtolower($renderMethod), 'caption') || strpos(strtolower($fallbackRenderMethod), 'caption')) {
337 $accessibilityMode = true;
338 }
339 // Global caption
340 $globalCaption = '';
341 if ($renderGlobalCaption) {
342 $globalCaption = $this->cObj->stdWrap($this->cObj->cObjGet($conf['caption.'], 'caption.'), $conf['caption.']);
343 }
344 // Positioning
345 $position = $this->cObj->stdWrap($conf['textPos'], $conf['textPos.']);
346 // 0,1,2 = center,right,left
347 $imagePosition = $position & 7;
348 // 0,8,16,24 (above,below,intext,intext-wrap)
349 $contentPosition = $position & 24;
350 $textMargin = (int)$this->cObj->stdWrap($conf['textMargin'], $conf['textMargin.']);
351 if (!$conf['textMargin_outOfText'] && $contentPosition < 16) {
352 $textMargin = 0;
353 }
354 $colspacing = (int)$this->cObj->stdWrap($conf['colSpace'], $conf['colSpace.']);
355 $border = (int)$this->cObj->stdWrap($conf['border'], $conf['border.']) ? 1 : 0;
356 $borderThickness = (int)$this->cObj->stdWrap($conf['borderThick'], $conf['borderThick.']);
357 $borderThickness = $borderThickness ?: 1;
358 $borderSpace = $conf['borderSpace'] && $border ? (int)$conf['borderSpace'] : 0;
359 // Generate cols
360 $cols = (int)$this->cObj->stdWrap($conf['cols'], $conf['cols.']);
361 $colCount = $cols > 1 ? $cols : 1;
362 if ($colCount > $imgCount) {
363 $colCount = $imgCount;
364 }
365 $rowCount = ceil($imgCount / $colCount);
366 // Generate rows
367 $rows = (int)$this->cObj->stdWrap($conf['rows'], $conf['rows.']);
368 if ($rows > 1) {
369 $rowCount = $rows;
370 if ($rowCount > $imgCount) {
371 $rowCount = $imgCount;
372 }
373 $colCount = $rowCount > 1 ? ceil($imgCount / $rowCount) : $imgCount;
374 }
375 // Max Width
376 $maxW = (int)$this->cObj->stdWrap($conf['maxW'], $conf['maxW.']);
377 $maxWInText = (int)$this->cObj->stdWrap($conf['maxWInText'], $conf['maxWInText.']);
378 $fiftyPercentWidthInText = round($maxW / 100 * 50);
379 // in Text
380 if ($contentPosition >= 16) {
381 if (!$maxWInText) {
382 // If maxWInText is not set, it's calculated to the 50% of the max
383 $maxW = $fiftyPercentWidthInText;
384 } else {
385 $maxW = $maxWInText;
386 }
387 }
388 // max usuable width for images (without spacers and borders)
389 $netW = $maxW - $colspacing * ($colCount - 1) - $colCount * $border * ($borderThickness + $borderSpace) * 2;
390 // Specify the maximum width for each column
391 $columnWidths = $this->getImgColumnWidths($conf, $colCount, $netW);
392 $image_compression = (int)$this->cObj->stdWrap($conf['image_compression'], $conf['image_compression.']);
393 $image_effects = (int)$this->cObj->stdWrap($conf['image_effects'], $conf['image_effects.']);
394 $image_frames = (int)$this->cObj->stdWrap($conf['image_frames.']['key'], $conf['image_frames.']['key.']);
395 // EqualHeight
396 $equalHeight = (int)$this->cObj->stdWrap($conf['equalH'], $conf['equalH.']);
397 if ($equalHeight) {
398 $relations_cols = [];
399 // contains the individual width of all images after scaling to $equalHeight
400 $imgWidths = [];
401 for ($a = 0; $a < $imgCount; $a++) {
402 $imgKey = $a + $imgStart;
403
404 /** @var $file \TYPO3\CMS\Core\Resource\File */
405 if (MathUtility::canBeInterpretedAsInteger($imgs[$imgKey])) {
406 if ($imgListContainsReferenceUids) {
407 $file = $this->getResourceFactory()->getFileReferenceObject((int)$imgs[$imgKey])->getOriginalFile();
408 } else {
409 $file = $this->getResourceFactory()->getFileObject((int)$imgs[$imgKey]);
410 }
411 } else {
412 $file = $this->getResourceFactory()->getFileObjectFromCombinedIdentifier($imgPath . $imgs[$imgKey]);
413 }
414
415 // relationship between the original height and the wished height
416 $rel = $file->getProperty('height') / $equalHeight;
417 // if relations is zero, then the addition of this value is omitted as the image is not expected to display because of some error.
418 if ($rel) {
419 $imgWidths[$a] = $file->getProperty('width') / $rel;
420 // counts the total width of the row with the new height taken into consideration.
421 $relations_cols[(int)floor($a / $colCount)] += $imgWidths[$a];
422 }
423 }
424 }
425 // Fetches pictures
426 $splitArr = [];
427 $splitArr['imgObjNum'] = $conf['imgObjNum'];
428 $splitArr = $this->frontendController->tmpl->splitConfArray($splitArr, $imgCount);
429 // Contains the width of every image row
430 $imageRowsFinalWidths = [];
431 // Array index of $imgsTag will be the same as in $imgs, but $imgsTag only contains the images that are actually shown
432 $imgsTag = [];
433 $origImages = [];
434 $rowIdx = 0;
435 for ($a = 0; $a < $imgCount; $a++) {
436 $imgKey = $a + $imgStart;
437 // If the image cannot be interpreted as integer (therefore filename and no FAL id), add the image path
438 if (MathUtility::canBeInterpretedAsInteger($imgs[$imgKey])) {
439 $totalImagePath = (int)$imgs[$imgKey];
440 $this->initializeCurrentFileInContentObjectRenderer($totalImagePath, $imgListContainsReferenceUids);
441 } else {
442 $totalImagePath = $imgPath . $imgs[$imgKey];
443 }
444 // register IMG_NUM is kept for backwards compatibility
445 $this->frontendController->register['IMAGE_NUM'] = $imgKey;
446 $this->frontendController->register['IMAGE_NUM_CURRENT'] = $imgKey;
447 $this->frontendController->register['ORIG_FILENAME'] = $totalImagePath;
448 $this->cObj->data[$this->cObj->currentValKey] = $totalImagePath;
449 $imgObjNum = (int)$splitArr[$a]['imgObjNum'];
450 $imgConf = $conf[$imgObjNum . '.'];
451 if ($equalHeight) {
452 if ($a % $colCount == 0) {
453 // A new row starts
454 // Reset accumulated net width
455 $accumWidth = 0;
456 // Reset accumulated desired width
457 $accumDesiredWidth = 0;
458 $rowTotalMaxW = $relations_cols[$rowIdx];
459 if ($rowTotalMaxW > $netW && $netW > 0) {
460 $scale = $rowTotalMaxW / $netW;
461 } else {
462 $scale = 1;
463 }
464 $desiredHeight = $equalHeight / $scale;
465 $rowIdx++;
466 }
467 // This much width is available for the remaining images in this row (int)
468 $availableWidth = $netW - $accumWidth;
469 // Theoretical width of resized image. (float)
470 $desiredWidth = $imgWidths[$a] / $scale;
471 // Add this width. $accumDesiredWidth becomes the desired horizontal position
472 $accumDesiredWidth += $desiredWidth;
473 // Calculate width by comparing actual and desired horizontal position.
474 // this evenly distributes rounding errors across all images in this row.
475 $suggestedWidth = round($accumDesiredWidth - $accumWidth);
476 // finalImgWidth may not exceed $availableWidth
477 $finalImgWidth = (int)min($availableWidth, $suggestedWidth);
478 $accumWidth += $finalImgWidth;
479 $imgConf['file.']['width'] = $finalImgWidth;
480 $imgConf['file.']['height'] = round($desiredHeight);
481 // other stuff will be calculated accordingly:
482 unset($imgConf['file.']['maxW']);
483 unset($imgConf['file.']['maxH']);
484 unset($imgConf['file.']['minW']);
485 unset($imgConf['file.']['minH']);
486 unset($imgConf['file.']['width.']);
487 unset($imgConf['file.']['maxW.']);
488 unset($imgConf['file.']['maxH.']);
489 unset($imgConf['file.']['minW.']);
490 unset($imgConf['file.']['minH.']);
491 } else {
492 $imgConf['file.']['maxW'] = $columnWidths[$a % $colCount];
493 }
494 $titleInLink = $this->cObj->stdWrap($imgConf['titleInLink'], $imgConf['titleInLink.']);
495 $titleInLinkAndImg = $this->cObj->stdWrap($imgConf['titleInLinkAndImg'], $imgConf['titleInLinkAndImg.']);
496 $oldATagParms = $this->frontendController->ATagParams;
497 if ($titleInLink) {
498 // Title in A-tag instead of IMG-tag
499 $titleText = trim($this->cObj->stdWrap($imgConf['titleText'], $imgConf['titleText.']));
500 if ($titleText) {
501 // This will be used by the IMAGE call later:
502 $this->frontendController->ATagParams .= ' title="' . htmlspecialchars($titleText) . '"';
503 }
504 }
505
506 // hook to allow custom rendering of a single element
507 // This hook is needed to render alternative content which is not just a plain image,
508 // like showing other FAL content, like videos, things which need to be embedded as JS, ...
509 $customRendering = '';
510 if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['css_styled_content']['pi1_hooks']['render_singleMediaElement'])
511 && is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['css_styled_content']['pi1_hooks']['render_singleMediaElement'])) {
512 $hookParameters = [
513 'file' => $totalImagePath,
514 'imageConfiguration' => $imgConf
515 ];
516
517 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['css_styled_content']['pi1_hooks']['render_singleMediaElement'] as $reference) {
518 $customRendering = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($reference, $hookParameters, $this);
519 // if there is a renderer found, don't run through the other renderers
520 if (!empty($customRendering)) {
521 break;
522 }
523 }
524 }
525
526 if (!empty($customRendering)) {
527 $imgsTag[$imgKey] = $customRendering;
528 } elseif ($imgConf || $imgConf['file']) {
529 if ($this->cObj->image_effects[$image_effects]) {
530 $imgConf['file.']['params'] .= ' ' . $this->cObj->image_effects[$image_effects];
531 }
532 if ($image_frames) {
533 if (is_array($conf['image_frames.'][$image_frames . '.'])) {
534 $imgConf['file.']['m.'] = $conf['image_frames.'][$image_frames . '.'];
535 }
536 }
537 if ($image_compression && $imgConf['file'] !== 'GIFBUILDER') {
538 if ($image_compression == 1) {
539 $tempImport = $imgConf['file.']['import'];
540 $tempImport_dot = $imgConf['file.']['import.'];
541 $tempTreatIdAsReference = $imgConf['file.']['treatIdAsReference'];
542 unset($imgConf['file.']);
543 $imgConf['file.']['import'] = $tempImport;
544 $imgConf['file.']['import.'] = $tempImport_dot;
545 $imgConf['file.']['treatIdAsReference'] = $tempTreatIdAsReference;
546 } elseif (isset($this->cObj->image_compression[$image_compression])) {
547 $imgConf['file.']['params'] .= ' ' . $this->cObj->image_compression[$image_compression]['params'];
548 $imgConf['file.']['ext'] = $this->cObj->image_compression[$image_compression]['ext'];
549 unset($imgConf['file.']['ext.']);
550 }
551 }
552 if ($titleInLink && !$titleInLinkAndImg) {
553 // Check if the image will be linked
554 $link = $this->cObj->imageLinkWrap('', $this->cObj->getCurrentFile() ?: $totalImagePath, $imgConf['imageLinkWrap.']);
555 if ($link) {
556 // Title in A-tag only (set above: ATagParams), not in IMG-tag
557 unset($imgConf['titleText']);
558 unset($imgConf['titleText.']);
559 $imgConf['emptyTitleHandling'] = 'removeAttr';
560 }
561 }
562 $imgsTag[$imgKey] = $this->cObj->cObjGetSingle('IMAGE', $imgConf);
563 } else {
564 // currentValKey !!!
565 $imgsTag[$imgKey] = $this->cObj->cObjGetSingle('IMAGE', ['file' => $totalImagePath]);
566 }
567 // Restore our ATagParams
568 $this->frontendController->ATagParams = $oldATagParms;
569 // Store the original filepath
570 $origImages[$imgKey] = $this->frontendController->lastImageInfo;
571 if ($this->frontendController->lastImageInfo[0] == 0) {
572 $imageRowsFinalWidths[(int)floor($a / $colCount)] += $this->cObj->data['imagewidth'];
573 } else {
574 $imageRowsFinalWidths[(int)floor($a / $colCount)] += $this->frontendController->lastImageInfo[0];
575 }
576 }
577 // How much space will the image-block occupy?
578 $imageBlockWidth = max($imageRowsFinalWidths) + $colspacing * ($colCount - 1) + $colCount * $border * ($borderSpace + $borderThickness) * 2;
579 $this->frontendController->register['rowwidth'] = $imageBlockWidth;
580 $this->frontendController->register['rowWidthPlusTextMargin'] = $imageBlockWidth + $textMargin;
581 // noRows is in fact just one ROW, with the amount of columns specified, where the images are placed in.
582 // noCols is just one COLUMN, each images placed side by side on each row
583 $noRows = $this->cObj->stdWrap($conf['noRows'], $conf['noRows.']);
584 $noCols = $this->cObj->stdWrap($conf['noCols'], $conf['noCols.']);
585 // noRows overrides noCols. They cannot exist at the same time.
586 if ($noRows) {
587 $noCols = 0;
588 $rowCount = 1;
589 }
590 if ($noCols) {
591 $colCount = 1;
592 }
593 // Edit icons:
594 if (!is_array($conf['editIcons.'])) {
595 $conf['editIcons.'] = [];
596 }
597 $editIconsHTML = $conf['editIcons'] && $this->frontendController->beUserLogin ? $this->cObj->editIcons('', $conf['editIcons'], $conf['editIcons.']) : '';
598 // If noRows, we need multiple imagecolumn wraps
599 $imageWrapCols = 1;
600 if ($noRows) {
601 $imageWrapCols = $colCount;
602 }
603 // User wants to separate the rows, but only do that if we do have rows
604 $separateRows = $this->cObj->stdWrap($conf['separateRows'], $conf['separateRows.']);
605 if ($noRows) {
606 $separateRows = 0;
607 }
608 if ($rowCount == 1) {
609 $separateRows = 0;
610 }
611 if ($accessibilityMode) {
612 $imagesInColumns = round($imgCount / ($rowCount * $colCount), 0, PHP_ROUND_HALF_UP);
613 // Apply optionSplit to the list of classes that we want to add to each column
614 $addClassesCol = $conf['addClassesCol'];
615 if (isset($conf['addClassesCol.'])) {
616 $addClassesCol = $this->cObj->stdWrap($addClassesCol, $conf['addClassesCol.']);
617 }
618 $addClassesColConf = $this->frontendController->tmpl->splitConfArray(['addClassesCol' => $addClassesCol], $colCount);
619 // Apply optionSplit to the list of classes that we want to add to each image
620 $addClassesImage = $conf['addClassesImage'];
621 if (isset($conf['addClassesImage.'])) {
622 $addClassesImage = $this->cObj->stdWrap($addClassesImage, $conf['addClassesImage.']);
623 }
624 $addClassesImageConf = $this->frontendController->tmpl->splitConfArray(['addClassesImage' => $addClassesImage], $imagesInColumns);
625 $rows = [];
626 $currentImage = 0;
627 // Set the class for the caption (split or global)
628 $classCaptionAlign = [
629 'center' => 'csc-textpic-caption-c',
630 'right' => 'csc-textpic-caption-r',
631 'left' => 'csc-textpic-caption-l'
632 ];
633 $captionAlign = $this->cObj->stdWrap($conf['captionAlign'], $conf['captionAlign.']);
634 // Iterate over the rows
635 for ($rowCounter = 1; $rowCounter <= $rowCount; $rowCounter++) {
636 $rowColumns = [];
637 // Iterate over the columns
638 for ($columnCounter = 1; $columnCounter <= $colCount; $columnCounter++) {
639 $columnImages = [];
640 // Iterate over the amount of images allowed in a column
641 for ($imagesCounter = 1; $imagesCounter <= $imagesInColumns; $imagesCounter++) {
642 $image = null;
643 $splitCaption = null;
644 $imageMarkers = ($captionMarkers = []);
645 $single = '&nbsp;';
646 // Set the key of the current image
647 $imageKey = $currentImage + $imgStart;
648 // Register IMAGE_NUM_CURRENT for the caption
649 $this->frontendController->register['IMAGE_NUM_CURRENT'] = $imageKey;
650 $this->cObj->data[$this->cObj->currentValKey] = $origImages[$imageKey]['origFile'];
651 if (MathUtility::canBeInterpretedAsInteger($imgs[$imageKey])) {
652 $this->initializeCurrentFileInContentObjectRenderer((int)$imgs[$imageKey], $imgListContainsReferenceUids);
653 } elseif (!isset($imgs[$imageKey])) {
654 // If not all columns in the last row are filled $imageKey gets larger than
655 // the array. In that case we clear the current file.
656 $this->cObj->setCurrentFile(null);
657 }
658 // Get the image if not an empty cell
659 if (isset($imgsTag[$imageKey])) {
660 $image = $this->cObj->stdWrap($imgsTag[$imageKey], $conf['imgTagStdWrap.']);
661 // Add the edit icons
662 if ($editIconsHTML) {
663 $image .= $this->cObj->stdWrap($editIconsHTML, $conf['editIconsStdWrap.']);
664 }
665 // Wrap the single image
666 $single = $this->cObj->stdWrap($image, $conf['singleStdWrap.']);
667 // Get the caption
668 if (!$renderGlobalCaption) {
669 $imageMarkers['caption'] = $this->cObj->stdWrap($this->cObj->cObjGet($conf['caption.'], 'caption.'), $conf['caption.']);
670 if ($captionAlign) {
671 $captionMarkers['classes'] = ' ' . $classCaptionAlign[$captionAlign];
672 }
673 $imageMarkers['caption'] = $this->cObj->substituteMarkerArray($imageMarkers['caption'], $captionMarkers, '###|###', 1, 1);
674 }
675 if ($addClassesImageConf[$imagesCounter - 1]['addClassesImage']) {
676 $imageMarkers['classes'] = ' ' . $addClassesImageConf[$imagesCounter - 1]['addClassesImage'];
677 }
678 }
679 $columnImages[] = $this->cObj->substituteMarkerArray($single, $imageMarkers, '###|###', 1, 1);
680 $currentImage++;
681 }
682 $rowColumn = $this->cObj->stdWrap(implode(LF, $columnImages), $conf['columnStdWrap.']);
683 // Start filling the markers for columnStdWrap
684 $columnMarkers = [];
685 if ($addClassesColConf[$columnCounter - 1]['addClassesCol']) {
686 $columnMarkers['classes'] = ' ' . $addClassesColConf[$columnCounter - 1]['addClassesCol'];
687 }
688 $rowColumns[] = $this->cObj->substituteMarkerArray($rowColumn, $columnMarkers, '###|###', 1, 1);
689 }
690 if ($noRows) {
691 $rowConfiguration = $conf['noRowsStdWrap.'];
692 } elseif ($rowCounter == $rowCount) {
693 $rowConfiguration = $conf['lastRowStdWrap.'];
694 } else {
695 $rowConfiguration = $conf['rowStdWrap.'];
696 }
697 $row = $this->cObj->stdWrap(implode(LF, $rowColumns), $rowConfiguration);
698 // Start filling the markers for columnStdWrap
699 $rowMarkers = [];
700 $rows[] = $this->cObj->substituteMarkerArray($row, $rowMarkers, '###|###', 1, 1);
701 }
702 $images = $this->cObj->stdWrap(implode(LF, $rows), $conf['allStdWrap.']);
703 // Start filling the markers for allStdWrap
704 $allMarkers = [];
705 $classes = [];
706 // Add the global caption to the allStdWrap marker array if set
707 if ($globalCaption) {
708 $allMarkers['caption'] = $globalCaption;
709 if ($captionAlign) {
710 $classes[] = $classCaptionAlign[$captionAlign];
711 }
712 }
713 // Set the margin for image + text, no wrap always to avoid multiple stylesheets
714 $noWrapMargin = (int)(($maxWInText ? $maxWInText : $fiftyPercentWidthInText) + (int)$this->cObj->stdWrap($conf['textMargin'], $conf['textMargin.']));
715 $this->addPageStyle('.csc-textpic-intext-right-nowrap .csc-textpic-text', 'margin-right: ' . $noWrapMargin . 'px;');
716 $this->addPageStyle('.csc-textpic-intext-left-nowrap .csc-textpic-text', 'margin-left: ' . $noWrapMargin . 'px;');
717 // Beside Text where the image block width is not equal to maxW
718 if ($contentPosition == 24 && $maxW != $imageBlockWidth) {
719 $noWrapMargin = $imageBlockWidth + $textMargin;
720 // Beside Text, Right
721 if ($imagePosition == 1) {
722 $this->addPageStyle('.csc-textpic-intext-right-nowrap-' . $noWrapMargin . ' .csc-textpic-text', 'margin-right: ' . $noWrapMargin . 'px;');
723 $classes[] = 'csc-textpic-intext-right-nowrap-' . $noWrapMargin;
724 } elseif ($imagePosition == 2) {
725 $this->addPageStyle('.csc-textpic-intext-left-nowrap-' . $noWrapMargin . ' .csc-textpic-text', 'margin-left: ' . $noWrapMargin . 'px;');
726 $classes[] = 'csc-textpic-intext-left-nowrap-' . $noWrapMargin;
727 }
728 }
729 // Add the border class if needed
730 if ($border) {
731 $classes[] = $conf['borderClass'] ?: 'csc-textpic-border';
732 }
733 // Add the class for equal height if needed
734 if ($equalHeight) {
735 $classes[] = 'csc-textpic-equalheight';
736 }
737 $addClasses = $this->cObj->stdWrap($conf['addClasses'], $conf['addClasses.']);
738 if ($addClasses) {
739 $classes[] = $addClasses;
740 }
741 if ($classes) {
742 $class = ' ' . implode(' ', $classes);
743 }
744 // Fill the markers for the allStdWrap
745 $images = $this->cObj->substituteMarkerArray($images, $allMarkers, '###|###', 1, 1);
746 } else {
747 // Apply optionSplit to the list of classes that we want to add to each image
748 $addClassesImage = $conf['addClassesImage'];
749 if (isset($conf['addClassesImage.'])) {
750 $addClassesImage = $this->cObj->stdWrap($addClassesImage, $conf['addClassesImage.']);
751 }
752 $addClassesImageConf = $this->frontendController->tmpl->splitConfArray(['addClassesImage' => $addClassesImage], $colCount);
753 // Render the images
754 $images = '';
755 for ($c = 0; $c < $imageWrapCols; $c++) {
756 $tmpColspacing = $colspacing;
757 if ($c == $imageWrapCols - 1 && $imagePosition == 2 || $c == 0 && ($imagePosition == 1 || $imagePosition == 0)) {
758 // Do not add spacing after column if we are first column (left) or last column (center/right)
759 $tmpColspacing = 0;
760 }
761 $thisImages = '';
762 $allRows = '';
763 $maxImageSpace = 0;
764 $imgsTagCount = count($imgsTag);
765 for ($i = $c; $i < $imgsTagCount; $i = $i + $imageWrapCols) {
766 $imgKey = $i + $imgStart;
767 $colPos = $i % $colCount;
768 if ($separateRows && $colPos == 0) {
769 $thisRow = '';
770 }
771 // Render one image
772 if ($origImages[$imgKey][0] == 0) {
773 $imageSpace = $this->cObj->data['imagewidth'] + $border * ($borderSpace + $borderThickness) * 2;
774 } else {
775 $imageSpace = $origImages[$imgKey][0] + $border * ($borderSpace + $borderThickness) * 2;
776 }
777 $this->frontendController->register['IMAGE_NUM'] = $imgKey;
778 $this->frontendController->register['IMAGE_NUM_CURRENT'] = $imgKey;
779 $this->frontendController->register['ORIG_FILENAME'] = $origImages[$imgKey]['origFile'];
780 $this->frontendController->register['imagewidth'] = $origImages[$imgKey][0];
781 $this->frontendController->register['imagespace'] = $imageSpace;
782 $this->frontendController->register['imageheight'] = $origImages[$imgKey][1];
783 if (MathUtility::canBeInterpretedAsInteger($imgs[$imgKey])) {
784 $this->initializeCurrentFileInContentObjectRenderer(intval($imgs[$imgKey]), $imgListContainsReferenceUids);
785 }
786 if ($imageSpace > $maxImageSpace) {
787 $maxImageSpace = $imageSpace;
788 }
789 $thisImage = '';
790 $thisImage .= $this->cObj->stdWrap($imgsTag[$imgKey], $conf['imgTagStdWrap.']);
791 if (!$renderGlobalCaption) {
792 $thisImage .= $this->cObj->stdWrap($this->cObj->cObjGet($conf['caption.'], 'caption.'), $conf['caption.']);
793 }
794 if ($editIconsHTML) {
795 $thisImage .= $this->cObj->stdWrap($editIconsHTML, $conf['editIconsStdWrap.']);
796 }
797 $thisImage = $this->cObj->stdWrap($thisImage, $conf['oneImageStdWrap.']);
798 $classes = '';
799 if ($addClassesImageConf[$colPos]['addClassesImage']) {
800 $classes = ' ' . $addClassesImageConf[$colPos]['addClassesImage'];
801 }
802 $thisImage = str_replace('###CLASSES###', $classes, $thisImage);
803 if ($separateRows) {
804 $thisRow .= $thisImage;
805 } else {
806 $allRows .= $thisImage;
807 }
808 $this->frontendController->register['columnwidth'] = $maxImageSpace + $tmpColspacing;
809 // Close this row at the end (colCount), or the last row at the final end
810 if ($separateRows && $i + 1 === count($imgsTag)) {
811 // Close the very last row with either normal configuration or lastRow stdWrap
812 $allRows .= $this->cObj->stdWrap(
813 $thisRow,
814 is_array($conf['imageLastRowStdWrap.']) ? $conf['imageLastRowStdWrap.'] : $conf['imageRowStdWrap.']
815 );
816 } elseif ($separateRows && $colPos == $colCount - 1) {
817 $allRows .= $this->cObj->stdWrap($thisRow, $conf['imageRowStdWrap.']);
818 }
819 }
820 if ($separateRows) {
821 $thisImages .= $allRows;
822 } else {
823 $thisImages .= $this->cObj->stdWrap($allRows, $conf['noRowsStdWrap.']);
824 }
825 if ($noRows) {
826 // Only needed to make columns, rather than rows:
827 $images .= $this->cObj->stdWrap($thisImages, $conf['imageColumnStdWrap.']);
828 } else {
829 $images .= $thisImages;
830 }
831 }
832 // Add the global caption, if not split
833 if ($globalCaption) {
834 $images .= $globalCaption;
835 }
836 // CSS-classes
837 $captionClass = '';
838 $classCaptionAlign = [
839 'center' => 'csc-textpic-caption-c',
840 'right' => 'csc-textpic-caption-r',
841 'left' => 'csc-textpic-caption-l'
842 ];
843 $captionAlign = $this->cObj->stdWrap($conf['captionAlign'], $conf['captionAlign.']);
844 if ($captionAlign) {
845 $captionClass = $classCaptionAlign[$captionAlign];
846 }
847 $borderClass = '';
848 if ($border) {
849 $borderClass = $conf['borderClass'] ?: 'csc-textpic-border';
850 }
851 // Multiple classes with all properties, to be styled in CSS
852 $class = '';
853 $class .= $borderClass ? ' ' . $borderClass : '';
854 $class .= $captionClass ? ' ' . $captionClass : '';
855 $class .= $equalHeight ? ' csc-textpic-equalheight' : '';
856 $addClasses = $this->cObj->stdWrap($conf['addClasses'], $conf['addClasses.']);
857 $class .= $addClasses ? ' ' . $addClasses : '';
858 // Do we need a width in our wrap around images?
859 $imgWrapWidth = '';
860 if ($position == 0 || $position == 8) {
861 // For 'center' we always need a width: without one, the margin:auto trick won't work
862 $imgWrapWidth = $imageBlockWidth;
863 }
864 if ($rowCount > 1) {
865 // For multiple rows we also need a width, so that the images will wrap
866 $imgWrapWidth = $imageBlockWidth;
867 }
868 if ($globalCaption) {
869 // If we have a global caption, we need the width so that the caption will wrap
870 $imgWrapWidth = $imageBlockWidth;
871 }
872 // Wrap around the whole image block
873 $this->frontendController->register['totalwidth'] = $imgWrapWidth;
874 if ($imgWrapWidth) {
875 $images = $this->cObj->stdWrap($images, $conf['imageStdWrap.']);
876 } else {
877 $images = $this->cObj->stdWrap($images, $conf['imageStdWrapNoWidth.']);
878 }
879 }
880
881 $output = str_replace(
882 [
883 '###TEXT###',
884 '###IMAGES###',
885 '###CLASSES###'
886 ],
887 [
888 $content,
889 $images,
890 $class
891 ],
892 $this->cObj->cObjGetSingle($conf['layout'], $conf['layout.'])
893 );
894
895 if ($restoreRegisters) {
896 $this->cObj->cObjGetSingle('RESTORE_REGISTER', []);
897 }
898
899 return $output;
900 }
901
902 /**
903 * Loads the file / file reference object and sets it in the
904 * currentFile property of the ContentObjectRenderer.
905 *
906 * This makes the file data available during image rendering.
907 *
908 * @param int $fileUid The UID of the file or file reference (depending on $treatAsReference) that should be loaded.
909 * @param bool $treatAsReference If TRUE the given UID will be used to load a file reference otherwise it will be used to load a regular file.
910 * @return void
911 */
912 protected function initializeCurrentFileInContentObjectRenderer($fileUid, $treatAsReference)
913 {
914 $resourceFactory = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
915 if ($treatAsReference) {
916 $imageFile = $resourceFactory->getFileReferenceObject($fileUid);
917 } else {
918 $imageFile = $resourceFactory->getFileObject($fileUid);
919 }
920 $this->cObj->setCurrentFile($imageFile);
921 }
922
923 /***********************************
924 * Rendering of Content Element properties
925 ***********************************/
926
927 /**
928 * Add top or bottom margin to the content element
929 *
930 * Constructs and adds a class to the content element. This class selector
931 * and its declaration are added to the specific page styles.
932 *
933 * @param string $content Content input. Not used, ignore.
934 * @param array $configuration TypoScript configuration
935 * @return string The class name
936 */
937 public function renderSpace($content, array $configuration)
938 {
939 // Look for hook before running default code for function
940 if (method_exists($this, 'hookRequest') && ($hookObject = $this->hookRequest('renderSpace'))) {
941 return $hookObject->renderSpace($content, $configuration);
942 }
943 if (isset($configuration['space']) && in_array($configuration['space'], ['before', 'after'])) {
944 $constant = (int)$configuration['constant'];
945 if ($configuration['space'] === 'before') {
946 $value = $constant + $this->cObj->data['spaceBefore'];
947 $declaration = 'margin-top: ' . $value . 'px !important;';
948 } else {
949 $value = $constant + $this->cObj->data['spaceAfter'];
950 $declaration = 'margin-bottom: ' . $value . 'px !important;';
951 }
952 if (!empty($value)) {
953 if ($configuration['classStdWrap.']) {
954 $className = $this->cObj->stdWrap($value, $configuration['classStdWrap.']);
955 } else {
956 $className = $value;
957 }
958 $selector = '.' . trim($className);
959 $this->addPageStyle($selector, $declaration);
960 return $className;
961 }
962 }
963 }
964
965 /************************************
966 * Helper functions
967 ************************************/
968
969 /**
970 * Returns table attributes for uploads / tables.
971 *
972 * @param array $conf TypoScript configuration array
973 * @param int $type The "layout" type
974 * @return array Array with attributes inside.
975 */
976 public function getTableAttributes($conf, $type)
977 {
978 // Initializing:
979 $tableTagParams_conf = $conf['tableParams_' . $type . '.'];
980 $border = $this->cObj->data['table_border'] ? (int)$this->cObj->data['table_border'] : $tableTagParams_conf['border'];
981 $cellSpacing = $this->cObj->data['table_cellspacing'] ? (int)$this->cObj->data['table_cellspacing'] : $tableTagParams_conf['cellspacing'];
982 $cellPadding = $this->cObj->data['table_cellpadding'] ? (int)$this->cObj->data['table_cellpadding'] : $tableTagParams_conf['cellpadding'];
983 $summary = trim(htmlspecialchars($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_summary')));
984 // Create table attributes and classes array:
985 $tableTagParams = ($classes = []);
986 // Table attributes for all doctypes except HTML5
987 if ($this->frontendController->config['config']['doctype'] !== 'html5') {
988 $tableTagParams['border'] = $border;
989 $tableTagParams['cellspacing'] = $cellSpacing;
990 $tableTagParams['cellpadding'] = $cellPadding;
991 if ($summary) {
992 $tableTagParams['summary'] = $summary;
993 }
994 } else {
995 if ($border) {
996 // Border property has changed, now with class
997 $borderClass = 'contenttable-border-' . $border;
998 $borderDeclaration = 'border-width: ' . $border . 'px; border-style: solid;';
999 $this->addPageStyle('.' . $borderClass, $borderDeclaration);
1000 $classes[] = $borderClass;
1001 }
1002 if ($cellSpacing) {
1003 // Border attribute for HTML5 is 1 when there is cell spacing
1004 $tableTagParams['border'] = 1;
1005 // Use CSS3 border-spacing in class to have cell spacing
1006 $cellSpacingClass = 'contenttable-cellspacing-' . $cellSpacing;
1007 $cellSpacingDeclaration = 'border-spacing: ' . $cellSpacing . 'px;';
1008 $this->addPageStyle('.' . $cellSpacingClass, $cellSpacingDeclaration);
1009 $classes[] = $cellSpacingClass;
1010 }
1011 if ($cellPadding) {
1012 // Cell padding property has changed, now with class
1013 $cellPaddingClass = 'contenttable-cellpadding-' . $cellPadding;
1014 $cellSpacingSelector = '.' . $cellPaddingClass . ' td, .' . $cellPaddingClass . ' th';
1015 $cellPaddingDeclaration = 'padding: ' . $cellPadding . 'px;';
1016 $this->addPageStyle($cellSpacingSelector, $cellPaddingDeclaration);
1017 $classes[] = $cellPaddingClass;
1018 }
1019 }
1020 // Background color is class
1021 if (isset($conf['color.'][$this->cObj->data['table_bgColor']]) && !empty($conf['color.'][$this->cObj->data['table_bgColor']])) {
1022 $classes[] = 'contenttable-color-' . $this->cObj->data['table_bgColor'];
1023 }
1024 if (!empty($classes)) {
1025 $tableTagParams['class'] = ' ' . implode(' ', $classes);
1026 }
1027 // Return result:
1028 return $tableTagParams;
1029 }
1030
1031 /**
1032 * Add a style to the page, specific for this page
1033 *
1034 * The selector can be a contextual selector, like '#id .class p'
1035 * The presence of the selector is checked to avoid multiple entries of the
1036 * same selector.
1037 *
1038 * @param string $selector The selector
1039 * @param string $declaration The declaration
1040 * @return void
1041 */
1042 protected function addPageStyle($selector, $declaration)
1043 {
1044 if (!isset($this->frontendController->tmpl->setup['plugin.']['tx_cssstyledcontent.']['_CSS_PAGE_STYLE'])) {
1045 $this->frontendController->tmpl->setup['plugin.']['tx_cssstyledcontent.']['_CSS_PAGE_STYLE'] = [];
1046 }
1047 if (!isset($this->frontendController->tmpl->setup['plugin.']['tx_cssstyledcontent.']['_CSS_PAGE_STYLE'][$selector])) {
1048 $this->frontendController->tmpl->setup['plugin.']['tx_cssstyledcontent.']['_CSS_PAGE_STYLE'][$selector] = TAB . $selector . ' { ' . $declaration . ' }';
1049 }
1050 }
1051
1052 /**
1053 * Returns an object reference to the hook object if any
1054 *
1055 * @param string $functionName Name of the function you want to call / hook key
1056 * @return object|NULL Hook object, if any. Otherwise NULL.
1057 */
1058 public function hookRequest($functionName)
1059 {
1060 // Hook: menuConfig_preProcessModMenu
1061 if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['css_styled_content']['pi1_hooks'][$functionName]) {
1062 $hookObj = GeneralUtility::getUserObj($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['css_styled_content']['pi1_hooks'][$functionName]);
1063 if (method_exists($hookObj, $functionName)) {
1064 $hookObj->pObj = $this;
1065 return $hookObj;
1066 }
1067 }
1068 }
1069
1070 /**
1071 * Get the ResourceFactory
1072 *
1073 * @return \TYPO3\CMS\Core\Resource\ResourceFactory
1074 */
1075 protected function getResourceFactory()
1076 {
1077 return \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
1078 }
1079 }