[TASK] Remove function index
[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 $summary = trim(htmlspecialchars($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_summary')));
131 $useTfoot = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_tfoot'));
132 $headerPos = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_headerpos');
133 $noStyles = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_nostyles');
134 $tableClass = $this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'acctables_tableclass');
135
136 $delimiter = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'tableparsing_delimiter','s_parsing'));
137 if ($delimiter) {
138 $delimiter = chr(intval($delimiter));
139 } else {
140 $delimiter = '|';
141 }
142 $quotedInput = trim($this->pi_getFFvalue($this->cObj->data['pi_flexform'], 'tableparsing_quote','s_parsing'));
143 if ($quotedInput) {
144 $quotedInput = chr(intval($quotedInput));
145 } else {
146 $quotedInput = '';
147 }
148
149 // generate id prefix for accessible header
150 $headerScope = ($headerPos=='top'?'col':'row');
151 $headerIdPrefix = $headerScope.$this->cObj->data['uid'].'-';
152
153 // Split into single lines (will become table-rows):
154 $rows = t3lib_div::trimExplode(LF,$content);
155 reset($rows);
156
157 // Find number of columns to render:
158 $cols = t3lib_div::intInRange($this->cObj->data['cols']?$this->cObj->data['cols']:count(explode($delimiter,current($rows))),0,100);
159
160 // Traverse rows (rendering the table here)
161 $rCount = count($rows);
162 foreach($rows as $k => $v) {
163 $cells = explode($delimiter,$v);
164 $newCells=array();
165 for($a=0;$a<$cols;$a++) {
166 // remove quotes if needed
167 if ($quotedInput && substr($cells[$a],0,1) == $quotedInput && substr($cells[$a],-1,1) == $quotedInput) {
168 $cells[$a] = substr($cells[$a],1,-1);
169 }
170
171 if (!strcmp(trim($cells[$a]),'')) $cells[$a]='&nbsp;';
172 $cellAttribs = ($noStyles?'':($a>0 && ($cols-1)==$a) ? ' class="td-last td-'.$a.'"' : ' class="td-'.$a.'"');
173 if (($headerPos == 'top' && !$k) || ($headerPos == 'left' && !$a)) {
174 $scope = ' scope="'.$headerScope.'"';
175 $scope .= ' id="'.$headerIdPrefix.(($headerScope=='col')?$a:$k).'"';
176
177 $newCells[$a] = '
178 <th'.$cellAttribs.$scope.'>'.$this->cObj->stdWrap($cells[$a],$conf['innerStdWrap.']).'</th>';
179 } else {
180 if (empty($headerPos)) {
181 $accessibleHeader = '';
182 } else {
183 $accessibleHeader = ' headers="'.$headerIdPrefix.(($headerScope=='col')?$a:$k).'"';
184 }
185 $newCells[$a] = '
186 <td'.$cellAttribs.$accessibleHeader.'>'.$this->cObj->stdWrap($cells[$a],$conf['innerStdWrap.']).'</td>';
187 }
188 }
189 if (!$noStyles) {
190 $oddEven = $k%2 ? 'tr-odd' : 'tr-even';
191 $rowAttribs = ($k>0 && ($rCount-1)==$k) ? ' class="'.$oddEven.' tr-last"' : ' class="'.$oddEven.' tr-'.$k.'"';
192 }
193 $rows[$k]='
194 <tr'.$rowAttribs.'>'.implode('',$newCells).'
195 </tr>';
196 }
197
198 $addTbody = 0;
199 $tableContents = '';
200 if ($caption) {
201 $tableContents .= '
202 <caption>'.$caption.'</caption>';
203 }
204 if ($headerPos == 'top' && $rows[0]) {
205 $tableContents .= '<thead>'. $rows[0] .'
206 </thead>';
207 unset($rows[0]);
208 $addTbody = 1;
209 }
210 if ($useTfoot) {
211 $tableContents .= '
212 <tfoot>'.$rows[$rCount-1].'</tfoot>';
213 unset($rows[$rCount-1]);
214 $addTbody = 1;
215 }
216 $tmpTable = implode('',$rows);
217 if ($addTbody) {
218 $tmpTable = '<tbody>'.$tmpTable.'</tbody>';
219 }
220 $tableContents .= $tmpTable;
221
222 // Set header type:
223 $type = intval($this->cObj->data['layout']);
224
225 // Table tag params.
226 $tableTagParams = $this->getTableAttributes($conf,$type);
227 if (!$noStyles) {
228 $tableTagParams['class'] = 'contenttable contenttable-'.$type.($tableClass?' '.$tableClass:'');
229 } elseif ($tableClass) {
230 $tableTagParams['class'] = $tableClass;
231 }
232
233
234 // Compile table output:
235 $out = '
236 <table '.t3lib_div::implodeAttributes($tableTagParams).($summary?' summary="'.$summary.'"':'').'>'. // Omitted xhtmlSafe argument TRUE - none of the values will be needed to be converted anyways, no need to spend processing time on that.
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
265 $out = '';
266
267 // Set layout type:
268 $type = intval($this->cObj->data['layout']);
269
270 // see if the file path variable is set, this takes precedence
271 $filePathConf = $this->cObj->stdWrap($conf['filePath'], $conf['filePath.']);
272 if ($filePathConf) {
273 $fileList = $this->cObj->filelist($filePathConf);
274 list($path) = explode('|', $filePathConf);
275 } else {
276 // Get the list of files from the field
277 $field = (trim($conf['field']) ? trim($conf['field']) : 'media');
278 $fileList = $this->cObj->data[$field];
279 t3lib_div::loadTCA('tt_content');
280 $path = 'uploads/media/';
281 if (is_array($GLOBALS['TCA']['tt_content']['columns'][$field]) && !empty($GLOBALS['TCA']['tt_content']['columns'][$field]['config']['uploadfolder'])) {
282 // in TCA-Array folders are saved without trailing slash, so $path.$fileName won't work
283 $path = $GLOBALS['TCA']['tt_content']['columns'][$field]['config']['uploadfolder'] .'/';
284 }
285 }
286 $path = trim($path);
287
288 // Explode into an array:
289 $fileArray = t3lib_div::trimExplode(',',$fileList,1);
290
291 // If there were files to list...:
292 if (count($fileArray)) {
293
294 // Get the descriptions for the files (if any):
295 $descriptions = t3lib_div::trimExplode(LF,$this->cObj->data['imagecaption']);
296
297 // Adding hardcoded TS to linkProc configuration:
298 $conf['linkProc.']['path.']['current'] = 1;
299 $conf['linkProc.']['icon'] = 1; // Always render icon - is inserted by PHP if needed.
300 $conf['linkProc.']['icon.']['wrap'] = ' | //**//'; // Temporary, internal split-token!
301 $conf['linkProc.']['icon_link'] = 1; // ALways link the icon
302 $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.
303 if ($conf['labelStdWrap.']) {
304 $conf['linkProc.']['labelStdWrap.'] = $conf['labelStdWrap.'];
305 }
306 if ($conf['useSpacesInLinkText'] || $conf['stripFileExtensionFromLinkText']) {
307 $conf['linkProc.']['removePrependedNumbers'] = 0;
308 }
309
310 // Traverse the files found:
311 $filesData = array();
312 foreach($fileArray as $key => $fileName) {
313 $absPath = t3lib_div::getFileAbsFileName($path.$fileName);
314 if (@is_file($absPath)) {
315 $fI = pathinfo($fileName);
316 $filesData[$key] = array();
317
318 $filesData[$key]['filename'] = $fileName;
319 $filesData[$key]['path'] = $path;
320 $filesData[$key]['filesize'] = filesize($absPath);
321 $filesData[$key]['fileextension'] = strtolower($fI['extension']);
322 $filesData[$key]['description'] = trim($descriptions[$key]);
323
324 $this->cObj->setCurrentVal($path);
325 $GLOBALS['TSFE']->register['ICON_REL_PATH'] = $path.$fileName;
326 $GLOBALS['TSFE']->register['filename'] = $filesData[$key]['filename'];
327 $GLOBALS['TSFE']->register['path'] = $filesData[$key]['path'];
328 $GLOBALS['TSFE']->register['fileSize'] = $filesData[$key]['filesize'];
329 $GLOBALS['TSFE']->register['fileExtension'] = $filesData[$key]['fileextension'];
330 $GLOBALS['TSFE']->register['description'] = $filesData[$key]['description'];
331 $filesData[$key]['linkedFilenameParts']
332 = $this->beautifyFileLink(
333 explode(
334 '//**//',
335 $this->cObj->filelink(
336 $fileName, $conf['linkProc.']
337 )
338 ),
339 $fileName,
340 $conf['useSpacesInLinkText'],
341 $conf['stripFileExtensionFromLinkText']
342 );
343 }
344 }
345
346 // optionSplit applied to conf to allow differnt settings per file
347 $splitConf = $GLOBALS['TSFE']->tmpl->splitConfArray($conf, count($filesData));
348
349 // Now, lets render the list!
350 $outputEntries = array();
351 foreach($filesData as $key => $fileData) {
352 $GLOBALS['TSFE']->register['linkedIcon'] = $fileData['linkedFilenameParts'][0];
353 $GLOBALS['TSFE']->register['linkedLabel'] = $fileData['linkedFilenameParts'][1];
354 $GLOBALS['TSFE']->register['filename'] = $fileData['filename'];
355 $GLOBALS['TSFE']->register['path'] = $fileData['path'];
356 $GLOBALS['TSFE']->register['description'] = $fileData['description'];
357 $GLOBALS['TSFE']->register['fileSize'] = $fileData['filesize'];
358 $GLOBALS['TSFE']->register['fileExtension'] = $fileData['fileextension'];
359 $outputEntries[] = $this->cObj->cObjGetSingle($splitConf[$key]['itemRendering'], $splitConf[$key]['itemRendering.']);
360 }
361
362 if (isset($conf['outerWrap'])) {
363 // Wrap around the whole content
364 $outerWrap = $conf['outerWrap'];
365 } else {
366 // Table tag params
367 $tableTagParams = $this->getTableAttributes($conf,$type);
368 $tableTagParams['class'] = 'csc-uploads csc-uploads-'.$type;
369 $outerWrap = '<table ' . t3lib_div::implodeAttributes($tableTagParams) . '>|</table>';
370 }
371
372 // Compile it all into table tags:
373 $out = $this->cObj->wrap(implode('', $outputEntries), $outerWrap);
374 }
375
376 // Calling stdWrap:
377 if ($conf['stdWrap.']) {
378 $out = $this->cObj->stdWrap($out, $conf['stdWrap.']);
379 }
380
381 // Return value
382 return $out;
383 }
384 }
385
386 /**
387 * returns an array containing width relations for $colCount columns.
388 *
389 * tries to use "colRelations" setting given by TS.
390 * uses "1:1" column relations by default.
391 *
392 * @param array $conf TS configuration for img
393 * @param int $colCount number of columns
394 * @return array
395 */
396 protected function getImgColumnRelations($conf, $colCount) {
397 $relations = array();
398 $equalRelations= array_fill(0, $colCount, 1);
399 $colRelationsTypoScript = trim($this->cObj->stdWrap($conf['colRelations'], $conf['colRelations.']));
400
401 if ($colRelationsTypoScript) {
402 // try to use column width relations given by TS
403 $relationParts = explode(':', $colRelationsTypoScript);
404 // enough columns defined?
405 if (count($relationParts) >= $colCount) {
406 $out = array();
407 for ($a = 0; $a < $colCount; $a++) {
408 $currentRelationValue = intval($relationParts[$a]);
409 if ($currentRelationValue >= 1) {
410 $out[$a] = $currentRelationValue;
411 } else {
412 t3lib_div::devLog('colRelations used with a value smaller than 1 therefore colRelations setting is ignored.', $this->extKey, 2);
413 unset($out);
414 break;
415 }
416 }
417 if (max($out) / min($out) <= 10) {
418 $relations = $out;
419 } else {
420 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);
421 }
422 }
423 }
424 return $relations ? $relations : $equalRelations;
425 }
426
427 /**
428 * returns an array containing the image widths for an image row with $colCount columns.
429 *
430 * @param array $conf TS configuration of img
431 * @param int $colCount number of columns
432 * @param int $netW max usable width for images (without spaces and borders)
433 * @return array
434 */
435 protected function getImgColumnWidths($conf, $colCount, $netW) {
436 $columnWidths = array();
437 $colRelations = $this->getImgColumnRelations($conf, $colCount);
438
439 $accumWidth = 0;
440 $accumDesiredWidth = 0;
441 $relUnitCount = array_sum($colRelations);
442
443 for ($a = 0; $a < $colCount; $a++) {
444 $availableWidth = $netW - $accumWidth; // this much width is available for the remaining images in this row (int)
445 $desiredWidth = $netW / $relUnitCount * $colRelations[$a]; // theoretical width of resized image. (float)
446 $accumDesiredWidth += $desiredWidth; // add this width. $accumDesiredWidth becomes the desired horizontal position
447 // calculate width by comparing actual and desired horizontal position.
448 // this evenly distributes rounding errors across all images in this row.
449 $suggestedWidth = round($accumDesiredWidth - $accumWidth);
450 $finalImgWidth = (int) min($availableWidth, $suggestedWidth); // finalImgWidth may not exceed $availableWidth
451 $accumWidth += $finalImgWidth;
452 $columnWidths[$a] = $finalImgWidth;
453 }
454 return $columnWidths;
455 }
456
457 /**
458 * Rendering the IMGTEXT content element, called from TypoScript (tt_content.textpic.20)
459 *
460 * @param string Content input. Not used, ignore.
461 * @param array TypoScript configuration. See TSRef "IMGTEXT". This function aims to be compatible.
462 * @return string HTML output.
463 * @access private
464 * @coauthor Ernesto Baschny <ernst@cron-it.de>
465 */
466 function render_textpic($content, $conf) {
467 // Look for hook before running default code for function
468 if (method_exists($this, 'hookRequest') && $hookObj = $this->hookRequest('render_textpic')) {
469 return $hookObj->render_textpic($content,$conf);
470 }
471
472 $renderMethod = $this->cObj->stdWrap($conf['renderMethod'], $conf['renderMethod.']);
473
474 // Render using the default IMGTEXT code (table-based)
475 if (!$renderMethod || $renderMethod == 'table') {
476 return $this->cObj->IMGTEXT($conf);
477 }
478
479 // Specific configuration for the chosen rendering method
480 if (is_array($conf['rendering.'][$renderMethod . '.'])) {
481 $conf = $this->cObj->joinTSarrays($conf, $conf['rendering.'][$renderMethod . '.']);
482 }
483
484 // Image or Text with Image?
485 if (is_array($conf['text.'])) {
486 $content = $this->cObj->stdWrap($this->cObj->cObjGet($conf['text.'], 'text.'), $conf['text.']);
487 }
488
489 $imgList = trim($this->cObj->stdWrap($conf['imgList'], $conf['imgList.']));
490
491 if (!$imgList) {
492 // No images, that's easy
493 if (is_array($conf['stdWrap.'])) {
494 return $this->cObj->stdWrap($content, $conf['stdWrap.']);
495 }
496 return $content;
497 }
498
499 $imgs = t3lib_div::trimExplode(',', $imgList);
500 $imgStart = intval($this->cObj->stdWrap($conf['imgStart'], $conf['imgStart.']));
501 $imgCount = count($imgs) - $imgStart;
502 $imgMax = intval($this->cObj->stdWrap($conf['imgMax'], $conf['imgMax.']));
503 if ($imgMax) {
504 $imgCount = t3lib_div::intInRange($imgCount, 0, $imgMax); // reduce the number of images.
505 }
506
507 $imgPath = $this->cObj->stdWrap($conf['imgPath'], $conf['imgPath.']);
508
509 // Does we need to render a "global caption" (below the whole image block)?
510 $renderGlobalCaption = !$conf['captionSplit'] && !$conf['imageTextSplit'] && is_array($conf['caption.']);
511 if ($imgCount == 1) {
512 // If we just have one image, the caption relates to the image, so it is not "global"
513 $renderGlobalCaption = FALSE;
514 }
515
516 // Use the calculated information (amount of images, if global caption is wanted) to choose a different rendering method for the images-block
517 $GLOBALS['TSFE']->register['imageCount'] = $imgCount;
518 $GLOBALS['TSFE']->register['renderGlobalCaption'] = $renderGlobalCaption;
519 $fallbackRenderMethod = $this->cObj->cObjGetSingle($conf['fallbackRendering'], $conf['fallbackRendering.']);
520 if ($fallbackRenderMethod && is_array($conf['rendering.'][$fallbackRenderMethod . '.'])) {
521 $conf = $this->cObj->joinTSarrays($conf, $conf['rendering.'][$fallbackRenderMethod . '.']);
522 }
523
524 // Global caption
525 $globalCaption = '';
526 if ($renderGlobalCaption) {
527 $globalCaption = $this->cObj->stdWrap($this->cObj->cObjGet($conf['caption.'], 'caption.'), $conf['caption.']);
528 }
529
530 // Positioning
531 $position = $this->cObj->stdWrap($conf['textPos'], $conf['textPos.']);
532
533 $imagePosition = $position&7; // 0,1,2 = center,right,left
534 $contentPosition = $position&24; // 0,8,16,24 (above,below,intext,intext-wrap)
535 $align = $this->cObj->align[$imagePosition];
536 $textMargin = intval($this->cObj->stdWrap($conf['textMargin'],$conf['textMargin.']));
537 if (!$conf['textMargin_outOfText'] && $contentPosition < 16) {
538 $textMargin = 0;
539 }
540
541 $colspacing = intval($this->cObj->stdWrap($conf['colSpace'], $conf['colSpace.']));
542 $rowspacing = intval($this->cObj->stdWrap($conf['rowSpace'], $conf['rowSpace.']));
543
544 $border = intval($this->cObj->stdWrap($conf['border'], $conf['border.'])) ? 1:0;
545 $borderColor = $this->cObj->stdWrap($conf['borderCol'], $conf['borderCol.']);
546 $borderThickness = intval($this->cObj->stdWrap($conf['borderThick'], $conf['borderThick.']));
547
548 $borderColor = $borderColor?$borderColor:'black';
549 $borderThickness = $borderThickness?$borderThickness:1;
550 $borderSpace = (($conf['borderSpace']&&$border) ? intval($conf['borderSpace']) : 0);
551
552 // Generate cols
553 $cols = intval($this->cObj->stdWrap($conf['cols'],$conf['cols.']));
554 $colCount = ($cols > 1) ? $cols : 1;
555 if ($colCount > $imgCount) {$colCount = $imgCount;}
556 $rowCount = ceil($imgCount / $colCount);
557
558 // Generate rows
559 $rows = intval($this->cObj->stdWrap($conf['rows'],$conf['rows.']));
560 if ($rows>1) {
561 $rowCount = $rows;
562 if ($rowCount > $imgCount) {$rowCount = $imgCount;}
563 $colCount = ($rowCount>1) ? ceil($imgCount / $rowCount) : $imgCount;
564 }
565
566 // Max Width
567 $maxW = intval($this->cObj->stdWrap($conf['maxW'], $conf['maxW.']));
568
569 if ($contentPosition>=16) { // in Text
570 $maxWInText = intval($this->cObj->stdWrap($conf['maxWInText'],$conf['maxWInText.']));
571 if (!$maxWInText) {
572 // If maxWInText is not set, it's calculated to the 50% of the max
573 $maxW = round($maxW/100*50);
574 } else {
575 $maxW = $maxWInText;
576 }
577 }
578
579 // max usuable width for images (without spacers and borders)
580 $netW = $maxW - $colspacing * ($colCount - 1) - $colCount * $border * ($borderThickness + $borderSpace) * 2;
581
582 // Specify the maximum width for each column
583 $columnWidths = $this->getImgColumnWidths($conf, $colCount, $netW);
584
585 $image_compression = intval($this->cObj->stdWrap($conf['image_compression'],$conf['image_compression.']));
586 $image_effects = intval($this->cObj->stdWrap($conf['image_effects'],$conf['image_effects.']));
587 $image_frames = intval($this->cObj->stdWrap($conf['image_frames.']['key'],$conf['image_frames.']['key.']));
588
589 // EqualHeight
590 $equalHeight = intval($this->cObj->stdWrap($conf['equalH'],$conf['equalH.']));
591 if ($equalHeight) {
592 // Initiate gifbuilder object in order to get dimensions AND calculate the imageWidth's
593 $gifCreator = t3lib_div::makeInstance('tslib_gifbuilder');
594 $gifCreator->init();
595 $relations_cols = Array();
596 $imgWidths = array(); // contains the individual width of all images after scaling to $equalHeight
597 for ($a=0; $a<$imgCount; $a++) {
598 $imgKey = $a+$imgStart;
599 $imgInfo = $gifCreator->getImageDimensions($imgPath.$imgs[$imgKey]);
600 $rel = $imgInfo[1] / $equalHeight; // relationship between the original height and the wished height
601 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.
602 $imgWidths[$a] = $imgInfo[0] / $rel;
603 $relations_cols[floor($a/$colCount)] += $imgWidths[$a]; // counts the total width of the row with the new height taken into consideration.
604 }
605 }
606 }
607
608 // Fetches pictures
609 $splitArr = array();
610 $splitArr['imgObjNum'] = $conf['imgObjNum'];
611 $splitArr = $GLOBALS['TSFE']->tmpl->splitConfArray($splitArr, $imgCount);
612
613 $imageRowsFinalWidths = Array(); // contains the width of every image row
614 $imgsTag = array(); // array index of $imgsTag will be the same as in $imgs, but $imgsTag only contains the images that are actually shown
615 $origImages = array();
616 $rowIdx = 0;
617 for ($a=0; $a<$imgCount; $a++) {
618 $imgKey = $a+$imgStart;
619 $totalImagePath = $imgPath.$imgs[$imgKey];
620
621 $GLOBALS['TSFE']->register['IMAGE_NUM'] = $imgKey; // register IMG_NUM is kept for backwards compatibility
622 $GLOBALS['TSFE']->register['IMAGE_NUM_CURRENT'] = $imgKey;
623 $GLOBALS['TSFE']->register['ORIG_FILENAME'] = $totalImagePath;
624
625 $this->cObj->data[$this->cObj->currentValKey] = $totalImagePath;
626 $imgObjNum = intval($splitArr[$a]['imgObjNum']);
627 $imgConf = $conf[$imgObjNum.'.'];
628
629 if ($equalHeight) {
630
631 if ($a % $colCount == 0) {
632 // a new row startsS
633 $accumWidth = 0; // reset accumulated net width
634 $accumDesiredWidth = 0; // reset accumulated desired width
635 $rowTotalMaxW = $relations_cols[$rowIdx];
636 if ($rowTotalMaxW > $netW) {
637 $scale = $rowTotalMaxW / $netW;
638 } else {
639 $scale = 1;
640 }
641 $desiredHeight = $equalHeight / $scale;
642 $rowIdx++;
643 }
644
645 $availableWidth= $netW - $accumWidth; // this much width is available for the remaining images in this row (int)
646 $desiredWidth= $imgWidths[$a] / $scale; // theoretical width of resized image. (float)
647 $accumDesiredWidth += $desiredWidth; // add this width. $accumDesiredWidth becomes the desired horizontal position
648 // calculate width by comparing actual and desired horizontal position.
649 // this evenly distributes rounding errors across all images in this row.
650 $suggestedWidth = round($accumDesiredWidth - $accumWidth);
651 $finalImgWidth = (int) min($availableWidth, $suggestedWidth); // finalImgWidth may not exceed $availableWidth
652 $accumWidth += $finalImgWidth;
653 $imgConf['file.']['width'] = $finalImgWidth;
654 $imgConf['file.']['height'] = round($desiredHeight);
655
656 // other stuff will be calculated accordingly:
657 unset($imgConf['file.']['maxW']);
658 unset($imgConf['file.']['maxH']);
659 unset($imgConf['file.']['minW']);
660 unset($imgConf['file.']['minH']);
661 unset($imgConf['file.']['width.']);
662 unset($imgConf['file.']['maxW.']);
663 unset($imgConf['file.']['maxH.']);
664 unset($imgConf['file.']['minW.']);
665 unset($imgConf['file.']['minH.']);
666 } else {
667 $imgConf['file.']['maxW'] = $columnWidths[($a%$colCount)];
668 }
669
670 $titleInLink = $this->cObj->stdWrap($imgConf['titleInLink'], $imgConf['titleInLink.']);
671 $titleInLinkAndImg = $this->cObj->stdWrap($imgConf['titleInLinkAndImg'], $imgConf['titleInLinkAndImg.']);
672 $oldATagParms = $GLOBALS['TSFE']->ATagParams;
673 if ($titleInLink) {
674 // Title in A-tag instead of IMG-tag
675 $titleText = trim($this->cObj->stdWrap($imgConf['titleText'], $imgConf['titleText.']));
676 if ($titleText) {
677 // This will be used by the IMAGE call later:
678 $GLOBALS['TSFE']->ATagParams .= ' title="'. $titleText .'"';
679 }
680 }
681
682 if ($imgConf || $imgConf['file']) {
683 if ($this->cObj->image_effects[$image_effects]) {
684 $imgConf['file.']['params'] .= ' '.$this->cObj->image_effects[$image_effects];
685 }
686 if ($image_frames) {
687 if (is_array($conf['image_frames.'][$image_frames.'.'])) {
688 $imgConf['file.']['m.'] = $conf['image_frames.'][$image_frames.'.'];
689 }
690 }
691 if ($image_compression && $imgConf['file'] != 'GIFBUILDER') {
692 if ($image_compression == 1) {
693 $tempImport = $imgConf['file.']['import'];
694 $tempImport_dot = $imgConf['file.']['import.'];
695 unset($imgConf['file.']);
696 $imgConf['file.']['import'] = $tempImport;
697 $imgConf['file.']['import.'] = $tempImport_dot;
698 } elseif (isset($this->cObj->image_compression[$image_compression])) {
699 $imgConf['file.']['params'] .= ' '.$this->cObj->image_compression[$image_compression]['params'];
700 $imgConf['file.']['ext'] = $this->cObj->image_compression[$image_compression]['ext'];
701 unset($imgConf['file.']['ext.']);
702 }
703 }
704 if ($titleInLink && ! $titleInLinkAndImg) {
705 // Check if the image will be linked
706 $link = $this->cObj->imageLinkWrap('', $totalImagePath, $imgConf['imageLinkWrap.']);
707 if ($link) {
708 // Title in A-tag only (set above: ATagParams), not in IMG-tag
709 unset($imgConf['titleText']);
710 unset($imgConf['titleText.']);
711 $imgConf['emptyTitleHandling'] = 'removeAttr';
712 }
713 }
714 $imgsTag[$imgKey] = $this->cObj->IMAGE($imgConf);
715 } else {
716 $imgsTag[$imgKey] = $this->cObj->IMAGE(Array('file' => $totalImagePath)); // currentValKey !!!
717 }
718 // Restore our ATagParams
719 $GLOBALS['TSFE']->ATagParams = $oldATagParms;
720 // Store the original filepath
721 $origImages[$imgKey] = $GLOBALS['TSFE']->lastImageInfo;
722
723 if ($GLOBALS['TSFE']->lastImageInfo[0]==0) {
724 $imageRowsFinalWidths[floor($a/$colCount)] += $this->cObj->data['imagewidth'];
725 } else {
726 $imageRowsFinalWidths[floor($a/$colCount)] += $GLOBALS['TSFE']->lastImageInfo[0];
727 }
728
729 }
730 // How much space will the image-block occupy?
731 $imageBlockWidth = max($imageRowsFinalWidths)+ $colspacing*($colCount-1) + $colCount*$border*($borderSpace+$borderThickness)*2;
732 $GLOBALS['TSFE']->register['rowwidth'] = $imageBlockWidth;
733 $GLOBALS['TSFE']->register['rowWidthPlusTextMargin'] = $imageBlockWidth + $textMargin;
734
735 // noRows is in fact just one ROW, with the amount of columns specified, where the images are placed in.
736 // noCols is just one COLUMN, each images placed side by side on each row
737 $noRows = $this->cObj->stdWrap($conf['noRows'],$conf['noRows.']);
738 $noCols = $this->cObj->stdWrap($conf['noCols'],$conf['noCols.']);
739 if ($noRows) {$noCols=0;} // noRows overrides noCols. They cannot exist at the same time.
740
741 $rowCount_temp = 1;
742 $colCount_temp = $colCount;
743 if ($noRows) {
744 $rowCount_temp = $rowCount;
745 $rowCount = 1;
746 }
747 if ($noCols) {
748 $colCount = 1;
749 $columnWidths = array();
750 }
751
752 // Edit icons:
753 if (!is_array($conf['editIcons.'])) {
754 $conf['editIcons.'] = array();
755 }
756 $editIconsHTML = $conf['editIcons']&&$GLOBALS['TSFE']->beUserLogin ? $this->cObj->editIcons('',$conf['editIcons'],$conf['editIcons.']) : '';
757
758 // If noRows, we need multiple imagecolumn wraps
759 $imageWrapCols = 1;
760 if ($noRows) { $imageWrapCols = $colCount; }
761
762 // User wants to separate the rows, but only do that if we do have rows
763 $separateRows = $this->cObj->stdWrap($conf['separateRows'], $conf['separateRows.']);
764 if ($noRows) { $separateRows = 0; }
765 if ($rowCount == 1) { $separateRows = 0; }
766
767 // Apply optionSplit to the list of classes that we want to add to each image
768 $addClassesImage = $conf['addClassesImage'];
769 if ($conf['addClassesImage.']) {
770 $addClassesImage = $this->cObj->stdWrap($addClassesImage, $conf['addClassesImage.']);
771 }
772 $addClassesImageConf = $GLOBALS['TSFE']->tmpl->splitConfArray(array('addClassesImage' => $addClassesImage), $colCount);
773
774 // Render the images
775 $images = '';
776 for ($c = 0; $c < $imageWrapCols; $c++) {
777 $tmpColspacing = $colspacing;
778 if (($c==$imageWrapCols-1 && $imagePosition==2) || ($c==0 && ($imagePosition==1||$imagePosition==0))) {
779 // Do not add spacing after column if we are first column (left) or last column (center/right)
780 $tmpColspacing = 0;
781 }
782
783 $thisImages = '';
784 $allRows = '';
785 $maxImageSpace = 0;
786 for ($i = $c; $i<count($imgsTag); $i=$i+$imageWrapCols) {
787 $imgKey = $i+$imgStart;
788 $colPos = $i%$colCount;
789 if ($separateRows && $colPos == 0) {
790 $thisRow = '';
791 }
792
793 // Render one image
794 if($origImages[$imgKey][0]==0) {
795 $imageSpace=$this->cObj->data['imagewidth'] + $border*($borderSpace+$borderThickness)*2;
796 } else {
797 $imageSpace = $origImages[$imgKey][0] + $border*($borderSpace+$borderThickness)*2;
798 }
799
800 $GLOBALS['TSFE']->register['IMAGE_NUM'] = $imgKey;
801 $GLOBALS['TSFE']->register['IMAGE_NUM_CURRENT'] = $imgKey;
802 $GLOBALS['TSFE']->register['ORIG_FILENAME'] = $origImages[$imgKey]['origFile'];
803 $GLOBALS['TSFE']->register['imagewidth'] = $origImages[$imgKey][0];
804 $GLOBALS['TSFE']->register['imagespace'] = $imageSpace;
805 $GLOBALS['TSFE']->register['imageheight'] = $origImages[$imgKey][1];
806 if ($imageSpace > $maxImageSpace) {
807 $maxImageSpace = $imageSpace;
808 }
809 $thisImage = '';
810 $thisImage .= $this->cObj->stdWrap($imgsTag[$imgKey], $conf['imgTagStdWrap.']);
811
812 if (!$renderGlobalCaption) {
813 $thisImage .= $this->cObj->stdWrap($this->cObj->cObjGet($conf['caption.'], 'caption.'), $conf['caption.']);
814 }
815 if ($editIconsHTML) {
816 $thisImage .= $this->cObj->stdWrap($editIconsHTML, $conf['editIconsStdWrap.']);
817 }
818 $thisImage = $this->cObj->stdWrap($thisImage, $conf['oneImageStdWrap.']);
819 $classes = '';
820 if ($addClassesImageConf[$colPos]['addClassesImage']) {
821 $classes = ' ' . $addClassesImageConf[$colPos]['addClassesImage'];
822 }
823 $thisImage = str_replace('###CLASSES###', $classes, $thisImage);
824
825 if ($separateRows) {
826 $thisRow .= $thisImage;
827 } else {
828 $allRows .= $thisImage;
829 }
830 $GLOBALS['TSFE']->register['columnwidth'] = $maxImageSpace + $tmpColspacing;
831
832
833 // Close this row at the end (colCount), or the last row at the final end
834 if ($separateRows && ($i+1 == count($imgsTag))) {
835 // Close the very last row with either normal configuration or lastRow stdWrap
836 $allRows .= $this->cObj->stdWrap($thisRow, (is_array($conf['imageLastRowStdWrap.']) ? $conf['imageLastRowStdWrap.'] : $conf['imageRowStdWrap.']));
837 } elseif ($separateRows && $colPos == $colCount-1) {
838 $allRows .= $this->cObj->stdWrap($thisRow, $conf['imageRowStdWrap.']);
839 }
840 }
841 if ($separateRows) {
842 $thisImages .= $allRows;
843 } else {
844 $thisImages .= $this->cObj->stdWrap($allRows, $conf['noRowsStdWrap.']);
845 }
846 if ($noRows) {
847 // Only needed to make columns, rather than rows:
848 $images .= $this->cObj->stdWrap($thisImages, $conf['imageColumnStdWrap.']);
849 } else {
850 $images .= $thisImages;
851 }
852 }
853
854 // Add the global caption, if not split
855 if ($globalCaption) {
856 $images .= $globalCaption;
857 }
858
859 // CSS-classes
860 $captionClass = '';
861 $classCaptionAlign = array(
862 'center' => 'csc-textpic-caption-c',
863 'right' => 'csc-textpic-caption-r',
864 'left' => 'csc-textpic-caption-l',
865 );
866 $captionAlign = $this->cObj->stdWrap($conf['captionAlign'], $conf['captionAlign.']);
867 if ($captionAlign) {
868 $captionClass = $classCaptionAlign[$captionAlign];
869 }
870 $borderClass = '';
871 if ($border) {
872 $borderClass = $conf['borderClass'] ? $conf['borderClass'] : 'csc-textpic-border';
873 }
874
875 // Multiple classes with all properties, to be styled in CSS
876 $class = '';
877 $class .= ($borderClass? ' '.$borderClass:'');
878 $class .= ($captionClass? ' '.$captionClass:'');
879 $class .= ($equalHeight? ' csc-textpic-equalheight':'');
880 $addClasses = $this->cObj->stdWrap($conf['addClasses'], $conf['addClasses.']);
881 $class .= ($addClasses ? ' '.$addClasses:'');
882
883 // Do we need a width in our wrap around images?
884 $imgWrapWidth = '';
885 if ($position == 0 || $position == 8) {
886 // For 'center' we always need a width: without one, the margin:auto trick won't work
887 $imgWrapWidth = $imageBlockWidth;
888 }
889 if ($rowCount > 1) {
890 // For multiple rows we also need a width, so that the images will wrap
891 $imgWrapWidth = $imageBlockWidth;
892 }
893 if ($caption) {
894 // If we have a global caption, we need the width so that the caption will wrap
895 $imgWrapWidth = $imageBlockWidth;
896 }
897
898 // Wrap around the whole image block
899 $GLOBALS['TSFE']->register['totalwidth'] = $imgWrapWidth;
900 if ($imgWrapWidth) {
901 $images = $this->cObj->stdWrap($images, $conf['imageStdWrap.']);
902 } else {
903 $images = $this->cObj->stdWrap($images, $conf['imageStdWrapNoWidth.']);
904 }
905
906 $output = $this->cObj->cObjGetSingle($conf['layout'], $conf['layout.']);
907 $output = str_replace('###TEXT###', $content, $output);
908 $output = str_replace('###IMAGES###', $images, $output);
909 $output = str_replace('###CLASSES###', $class, $output);
910
911 if ($conf['stdWrap.']) {
912 $output = $this->cObj->stdWrap($output, $conf['stdWrap.']);
913 }
914
915 return $output;
916 }
917
918
919
920
921
922
923
924
925
926
927
928
929 /************************************
930 *
931 * Helper functions
932 *
933 ************************************/
934
935 /**
936 * Returns a link text string which replaces underscores in filename with
937 * blanks.
938 *
939 * Has the possibility to cut off FileType.
940
941 * @param array $links
942 * array with [0] linked file icon, [1] text link
943 * @param string $fileName
944 * the name of the file to be linked (without path)
945 * @param boolean $useSpaces
946 * whether underscores in the file name should be replaced with spaces
947 * @param boolean $cutFileExtension
948 * whether the file extension should be removed
949 *
950 * @return array modified array with new link text
951 */
952 protected function beautifyFileLink(
953 array $links, $fileName, $useSpaces = FALSE, $cutFileExtension = FALSE
954 ) {
955 $linkText = $fileName;
956 if ($useSpaces) {
957 $linkText = str_replace('_', ' ', $linkText);
958 }
959 if ($cutFileExtension) {
960 $pos = strrpos($linkText, '.');
961 $linkText = substr($linkText, 0, $pos);
962 }
963 $links[1] = str_replace(
964 '>' . $fileName . '<', '>' . $linkText . '<', $links[1]
965 );
966 return $links;
967 }
968
969 /**
970 * Returns table attributes for uploads / tables.
971 *
972 * @param array TypoScript configuration array
973 * @param integer The "layout" type
974 * @return array Array with attributes inside.
975 */
976 function getTableAttributes($conf,$type) {
977
978 // Initializing:
979 $tableTagParams_conf = $conf['tableParams_'.$type.'.'];
980
981 $conf['color.'][200] = '';
982 $conf['color.'][240] = 'black';
983 $conf['color.'][241] = 'white';
984 $conf['color.'][242] = '#333333';
985 $conf['color.'][243] = 'gray';
986 $conf['color.'][244] = 'silver';
987
988 // Create table attributes array:
989 $tableTagParams = array();
990 $tableTagParams['border'] = $this->cObj->data['table_border'] ? intval($this->cObj->data['table_border']) : $tableTagParams_conf['border'];
991 $tableTagParams['cellspacing'] = $this->cObj->data['table_cellspacing'] ? intval($this->cObj->data['table_cellspacing']) : $tableTagParams_conf['cellspacing'];
992 $tableTagParams['cellpadding'] = $this->cObj->data['table_cellpadding'] ? intval($this->cObj->data['table_cellpadding']) : $tableTagParams_conf['cellpadding'];
993 $tableTagParams['bgcolor'] = isset($conf['color.'][$this->cObj->data['table_bgColor']]) ? $conf['color.'][$this->cObj->data['table_bgColor']] : $conf['color.']['default'];
994
995 // Return result:
996 return $tableTagParams;
997 }
998
999 /**
1000 * Returns an object reference to the hook object if any
1001 *
1002 * @param string Name of the function you want to call / hook key
1003 * @return object Hook object, if any. Otherwise NULL.
1004 */
1005 function hookRequest($functionName) {
1006 global $TYPO3_CONF_VARS;
1007
1008 // Hook: menuConfig_preProcessModMenu
1009 if ($TYPO3_CONF_VARS['EXTCONF']['css_styled_content']['pi1_hooks'][$functionName]) {
1010 $hookObj = t3lib_div::getUserObj($TYPO3_CONF_VARS['EXTCONF']['css_styled_content']['pi1_hooks'][$functionName]);
1011 if (method_exists ($hookObj, $functionName)) {
1012 $hookObj->pObj = $this;
1013 return $hookObj;
1014 }
1015 }
1016 }
1017 }
1018
1019
1020
1021 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/css_styled_content/pi1/class.tx_cssstyledcontent_pi1.php'])) {
1022 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/css_styled_content/pi1/class.tx_cssstyledcontent_pi1.php']);
1023 }
1024
1025 ?>