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