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