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