[BUGFIX] lineNumber count in Template Analyzer
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / TypoScript / ExtendedTemplateService.php
1 <?php
2 namespace TYPO3\CMS\Core\TypoScript;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2013 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Backend\Utility\BackendUtility;
31 use TYPO3\CMS\Core\Utility\GeneralUtility;
32
33 /**
34 * TSParser extension class to TemplateService
35 * Contains functions for the TS module in TYPO3 backend
36 *
37 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
38 */
39 class ExtendedTemplateService extends \TYPO3\CMS\Core\TypoScript\TemplateService {
40
41 // This string is used to indicate the point in a template from where the editable constants are listed. Any vars before this point (if it exists though) is regarded as default values.
42 /**
43 * @todo Define visibility
44 */
45 public $edit_divider = '###MOD_TS:EDITABLE_CONSTANTS###';
46
47 /**
48 * @todo Define visibility
49 */
50 public $HTMLcolorList = 'aqua,beige,black,blue,brown,fuchsia,gold,gray,green,lime,maroon,navy,olive,orange,purple,red,silver,tan,teal,turquoise,yellow,white';
51
52 // internal
53 /**
54 * @todo Define visibility
55 */
56 public $categories = array(
57 'basic' => array(),
58 // Constants of superior importance for the template-layout. This is dimensions, imagefiles and enabling of various features. The most basic constants, which you would almost always want to configure.
59 'menu' => array(),
60 // Menu setup. This includes fontfiles, sizes, background images. Depending on the menutype.
61 'content' => array(),
62 // All constants related to the display of pagecontent elements
63 'page' => array(),
64 // General configuration like metatags, link targets
65 'advanced' => array(),
66 // Advanced functions, which are used very seldomly.
67 'all' => array()
68 );
69
70 // This will be filled with the available categories of the current template.
71 /**
72 * @todo Define visibility
73 */
74 public $subCategories = array(
75 // Standard categories:
76 'enable' => array('Enable features', 'a'),
77 'dims' => array('Dimensions, widths, heights, pixels', 'b'),
78 'file' => array('Files', 'c'),
79 'typo' => array('Typography', 'd'),
80 'color' => array('Colors', 'e'),
81 'links' => array('Links and targets', 'f'),
82 'language' => array('Language specific constants', 'g'),
83 // subcategories based on the default content elements
84 'cheader' => array('Content: \'Header\'', 'ma'),
85 'cheader_g' => array('Content: \'Header\', Graphical', 'ma'),
86 'ctext' => array('Content: \'Text\'', 'mb'),
87 'cimage' => array('Content: \'Image\'', 'md'),
88 'cbullets' => array('Content: \'Bullet list\'', 'me'),
89 'ctable' => array('Content: \'Table\'', 'mf'),
90 'cuploads' => array('Content: \'Filelinks\'', 'mg'),
91 'cmultimedia' => array('Content: \'Multimedia\'', 'mh'),
92 'cmedia' => array('Content: \'Media\'', 'mr'),
93 'cmailform' => array('Content: \'Form\'', 'mi'),
94 'csearch' => array('Content: \'Search\'', 'mj'),
95 'clogin' => array('Content: \'Login\'', 'mk'),
96 'cmenu' => array('Content: \'Menu/Sitemap\'', 'mm'),
97 'cshortcut' => array('Content: \'Insert records\'', 'mn'),
98 'clist' => array('Content: \'List of records\'', 'mo'),
99 'chtml' => array('Content: \'HTML\'', 'mq')
100 );
101
102 /**
103 * @todo Define visibility
104 */
105 public $backend_info = 1;
106
107 // Tsconstanteditor
108 /**
109 * @todo Define visibility
110 */
111 public $ext_inBrace = 0;
112
113 // Tsbrowser
114 /**
115 * @todo Define visibility
116 */
117 public $tsbrowser_searchKeys = array();
118
119 /**
120 * @todo Define visibility
121 */
122 public $tsbrowser_depthKeys = array();
123
124 /**
125 * @todo Define visibility
126 */
127 public $constantMode = '';
128
129 /**
130 * @todo Define visibility
131 */
132 public $regexMode = '';
133
134 /**
135 * @todo Define visibility
136 */
137 public $fixedLgd = '';
138
139 /**
140 * @todo Define visibility
141 */
142 public $resourceCheck = 0;
143
144 /**
145 * @todo Define visibility
146 */
147 public $ext_lineNumberOffset = 0;
148
149 /**
150 * @todo Define visibility
151 */
152 public $ext_localGfxPrefix = '';
153
154 /**
155 * @todo Define visibility
156 */
157 public $ext_localWebGfxPrefix = '';
158
159 /**
160 * @todo Define visibility
161 */
162 public $ext_expandAllNotes = 0;
163
164 /**
165 * @todo Define visibility
166 */
167 public $ext_noPMicons = 0;
168
169 /**
170 * @todo Define visibility
171 */
172 public $ext_noSpecialCharsOnLabels = 0;
173
174 /**
175 * @todo Define visibility
176 */
177 public $ext_listOfTemplatesArr = array();
178
179 /**
180 * @todo Define visibility
181 */
182 public $ext_lineNumberOffset_mode = '';
183
184 // Dont change...
185 /**
186 * @todo Define visibility
187 */
188 public $ext_dontCheckIssetValues = 0;
189
190 /**
191 * @todo Define visibility
192 */
193 public $ext_printAll = 0;
194
195 /**
196 * @todo Define visibility
197 */
198 public $ext_CEformName = 'forms[0]';
199
200 /**
201 * @todo Define visibility
202 */
203 public $doNotSortCategoriesBeforeMakingForm = FALSE;
204
205 // Ts analyzer
206 /**
207 * @todo Define visibility
208 */
209 public $templateTitles = array();
210
211 /**
212 * @var array|NULL
213 */
214 protected $lnToScript = NULL;
215
216 /**
217 * This flattens a hierarchical setuparray to $this->flatSetup
218 * The original function fetched the resource-file if any ('file.'). This functions doesn't.
219 *
220 * @param [type] $setupArray: ...
221 * @param [type] $prefix: ...
222 * @param [type] $resourceFlag: ...
223 * @return [type] ...
224 * @todo Define visibility
225 */
226 public function flattenSetup($setupArray, $prefix, $resourceFlag) {
227 if (is_array($setupArray)) {
228 // Setting absolute prefixed path for relative resources.
229 $this->getFileName_backPath = PATH_site;
230 foreach ($setupArray as $key => $val) {
231 // We don't want 'TSConstantEditor' in the flattend setup.
232 if ($prefix || substr($key, 0, 16) != 'TSConstantEditor') {
233 if (is_array($val)) {
234 $this->flattenSetup($val, $prefix . $key, $key == 'file.');
235 } elseif ($resourceFlag && $this->resourceCheck) {
236 $this->flatSetup[$prefix . $key] = $this->getFileName($val);
237 if ($this->removeFromGetFilePath && substr($this->flatSetup[$prefix . $key], 0, strlen($this->removeFromGetFilePath)) == $this->removeFromGetFilePath) {
238 $this->flatSetup[$prefix . $key] = substr($this->flatSetup[$prefix . $key], strlen($this->removeFromGetFilePath));
239 }
240 } else {
241 $this->flatSetup[$prefix . $key] = $val;
242 }
243 }
244 }
245 }
246 }
247
248 /**
249 * [Describe function...]
250 *
251 * @param [type] $all: ...
252 * @return [type] ...
253 * @todo Define visibility
254 */
255 public function substituteConstants($all) {
256 $this->Cmarker = substr(md5(uniqid('')), 0, 6);
257 return preg_replace_callback('/\\{\\$(.[^}]+)\\}/', array($this, 'substituteConstantsCallBack'), $all);
258 }
259
260 /**
261 * Call back method for preg_replace_callback in substituteConstants
262 *
263 * @param array $matches Regular expression matches
264 * @return string Replacement
265 * @see substituteConstants()
266 * @todo Define visibility
267 */
268 public function substituteConstantsCallBack($matches) {
269 switch ($this->constantMode) {
270 case 'const':
271 $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? '##' . $this->Cmarker . '_B##' . $matches[0] . '##' . $this->Cmarker . '_E##' : $matches[0];
272 break;
273 case 'subst':
274 $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? '##' . $this->Cmarker . '_B##' . $this->flatSetup[$matches[1]] . '##' . $this->Cmarker . '_E##' : $matches[0];
275 break;
276 case 'untouched':
277 $ret_val = $matches[0];
278 break;
279 default:
280 $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? $this->flatSetup[$matches[1]] : $matches[0];
281 }
282 return $ret_val;
283 }
284
285 /**
286 * [Describe function...]
287 *
288 * @param [type] $all: ...
289 * @return [type] ...
290 * @todo Define visibility
291 */
292 public function substituteCMarkers($all) {
293 switch ($this->constantMode) {
294 case 'const':
295 case 'subst':
296 $all = str_replace(
297 array('##' . $this->Cmarker . '_B##', '##' . $this->Cmarker . '_E##'),
298 array('<font color="green"><strong>', '</strong></font>'),
299 $all
300 );
301 break;
302 default:
303 }
304 return $all;
305 }
306
307 /**
308 * Parses the constants in $this->const with respect to the constant-editor in this module.
309 * In particular comments in the code are registered and the edit_divider is taken into account.
310 *
311 * @return [type] ...
312 * @todo Define visibility
313 */
314 public function generateConfig_constants() {
315 // These vars are also set lateron...
316 $this->setup['resources'] = $this->resources;
317 $this->setup['sitetitle'] = $this->sitetitle;
318 // Parse constants
319 $constants = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\Parser\\TypoScriptParser');
320 // Register comments!
321 $constants->regComments = 1;
322 $constants->setup = $this->const;
323 $constants->setup = $this->mergeConstantsFromPageTSconfig($constants->setup);
324 /** @var $matchObj \TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching\ConditionMatcher */
325 $matchObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Configuration\\TypoScript\\ConditionMatching\\ConditionMatcher');
326 // Matches ALL conditions in TypoScript
327 $matchObj->setSimulateMatchResult(TRUE);
328 $c = 0;
329 $cc = count($this->constants);
330 foreach ($this->constants as $str) {
331 $c++;
332 if ($c == $cc) {
333 if (strstr($str, $this->edit_divider)) {
334 $parts = explode($this->edit_divider, $str, 2);
335 $str = $parts[1];
336 $constants->parse($parts[0], $matchObj);
337 }
338 $this->flatSetup = array();
339 $this->flattenSetup($constants->setup, '', '');
340 $defaultConstants = $this->flatSetup;
341 }
342 $constants->parse($str, $matchObj);
343 }
344 $this->flatSetup = array();
345 $this->flattenSetup($constants->setup, '', '');
346 $this->setup['constants'] = $constants->setup;
347 return $this->ext_compareFlatSetups($defaultConstants);
348 }
349
350 /**
351 * [Describe function...]
352 *
353 * @param [type] $theSetup: ...
354 * @param [type] $theKey: ...
355 * @return [type] ...
356 * @todo Define visibility
357 */
358 public function ext_getSetup($theSetup, $theKey) {
359 $parts = explode('.', $theKey, 2);
360 if ((string)$parts[0] !== '' && is_array($theSetup[$parts[0] . '.'])) {
361 if (trim($parts[1]) !== '') {
362 return $this->ext_getSetup($theSetup[$parts[0] . '.'], trim($parts[1]));
363 } else {
364 return array($theSetup[$parts[0] . '.'], $theSetup[$parts[0]]);
365 }
366 } else {
367 if (trim($theKey) !== '') {
368 return array(array(), $theSetup[$theKey]);
369 } else {
370 return array($theSetup, '');
371 }
372 }
373 }
374
375 /**
376 * [Describe function...]
377 *
378 * @param [type] $arr: ...
379 * @param [type] $depth_in: ...
380 * @param [type] $depthData: ...
381 * @param [type] $parentType: ...
382 * @param [type] $parentValue: ...
383 * @param boolean $alphaSort sorts the array keys / tree by alphabet when set to 1
384 * @return [type] ...
385 * @todo Define visibility
386 */
387 public function ext_getObjTree($arr, $depth_in, $depthData, $parentType = '', $parentValue = '', $alphaSort = '0') {
388 $HTML = '';
389 $a = 0;
390 if ($alphaSort == '1') {
391 ksort($arr);
392 }
393 $keyArr_num = array();
394 $keyArr_alpha = array();
395 foreach ($arr as $key => $value) {
396 // Don't do anything with comments / linenumber registrations...
397 if (substr($key, -2) != '..') {
398 $key = preg_replace('/\\.$/', '', $key);
399 if (substr($key, -1) != '.') {
400 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($key)) {
401 $keyArr_num[$key] = $arr[$key];
402 } else {
403 $keyArr_alpha[$key] = $arr[$key];
404 }
405 }
406 }
407 }
408 ksort($keyArr_num);
409 $keyArr = $keyArr_num + $keyArr_alpha;
410 $c = count($keyArr);
411 if ($depth_in) {
412 $depth_in = $depth_in . '.';
413 }
414 foreach ($keyArr as $key => $value) {
415 $a++;
416 $depth = $depth_in . $key;
417 // This excludes all constants starting with '_' from being shown.
418 if ($this->bType != 'const' || substr($depth, 0, 1) != '_') {
419 $goto = substr(md5($depth), 0, 6);
420 $deeper = is_array($arr[$key . '.']) && ($this->tsbrowser_depthKeys[$depth] || $this->ext_expandAllNotes) ? 1 : 0;
421 $PM = 'join';
422 $LN = $a == $c ? 'blank' : 'line';
423 $BTM = $a == $c ? 'bottom' : '';
424 $PM = is_array($arr[$key . '.']) && !$this->ext_noPMicons ? ($deeper ? 'minus' : 'plus') : 'join';
425 $HTML .= $depthData;
426 $theIcon = '<img src="' . $GLOBALS['BACK_PATH'] . 'gfx/ol/' . $PM . $BTM . '.gif" width="18" height="16" align="top" border="0" alt="" />';
427 if ($PM == 'join') {
428 $HTML .= $theIcon;
429 } else {
430 $urlParameters = array(
431 'id' => $GLOBALS['SOBE']->id,
432 'tsbr[' . $depth . ']' => $deeper ? 0 : 1
433 );
434 if (GeneralUtility::_GP('breakPointLN')) {
435 $urlParameters['breakPointLN'] = GeneralUtility::_GP('breakPointLN');
436 }
437 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters) . '#' . $goto;
438 $HTML .= '<a name="' . $goto . '" href="' . htmlspecialchars($aHref) . '">' . $theIcon . '</a>';
439 }
440 $label = $key;
441 // Read only...
442 if (GeneralUtility::inList('types,resources,sitetitle', $depth) && $this->bType == 'setup') {
443 $label = '<font color="#666666">' . $label . '</font>';
444 } else {
445 if ($this->linkObjects) {
446 $urlParameters = array(
447 'id' => $GLOBALS['SOBE']->id,
448 'sObj' => $depth
449 );
450 if (GeneralUtility::_GP('breakPointLN')) {
451 $urlParameters['breakPointLN'] = GeneralUtility::_GP('breakPointLN');
452 }
453 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
454 if ($this->bType != 'const') {
455 $ln = is_array($arr[$key . '.ln..']) ? 'Defined in: ' . $this->lineNumberToScript($arr[($key . '.ln..')]) : 'N/A';
456 } else {
457 $ln = '';
458 }
459 if ($this->tsbrowser_searchKeys[$depth] & 4) {
460 $label = '<strong><font color="red">' . $label . '</font></strong>';
461 }
462 // The key has matched the search string
463 $label = '<a href="' . htmlspecialchars($aHref) . '" title="' . htmlspecialchars($ln) . '">' . $label . '</a>';
464 }
465 }
466 $HTML .= '[' . $label . ']';
467 if (isset($arr[$key])) {
468 $theValue = $arr[$key];
469 if ($this->fixedLgd) {
470 $imgBlocks = ceil(1 + strlen($depthData) / 77);
471 $lgdChars = 68 - ceil(strlen(('[' . $key . ']')) * 0.8) - $imgBlocks * 3;
472 $theValue = $this->ext_fixed_lgd($theValue, $lgdChars);
473 }
474 // The value has matched the search string
475 if ($this->tsbrowser_searchKeys[$depth] & 2) {
476 $HTML .= '&nbsp;=&nbsp;<strong><font color="red">' . $this->makeHtmlspecialchars($theValue) . '</font></strong>';
477 } else {
478 $HTML .= '&nbsp;=&nbsp;<strong>' . $this->makeHtmlspecialchars($theValue) . '</strong>';
479 }
480 if ($this->ext_regComments && isset($arr[$key . '..'])) {
481 $comment = $arr[$key . '..'];
482 // Skip INCLUDE_TYPOSCRIPT comments, they are almost useless
483 if (!preg_match('/### <INCLUDE_TYPOSCRIPT:.*/', $comment)) {
484 // Remove linebreaks, replace with ' '
485 $comment = preg_replace('/[\\r\\n]/', ' ', $comment);
486 // Remove # and * if more than twice in a row
487 $comment = preg_replace('/[#\\*]{2,}/', '', $comment);
488 // Replace leading # (just if it exists) and add it again. Result: Every comment should be prefixed by a '#'.
489 $comment = preg_replace('/^[#\\*\\s]+/', '# ', $comment);
490 // Masking HTML Tags: Replace < with &lt; and > with &gt;
491 $comment = $this->makeHtmlspecialchars($comment);
492 $HTML .= ' <span class="comment">' . trim($comment) . '</span>';
493 }
494 }
495 }
496 $HTML .= '<br />';
497 if ($deeper) {
498 $HTML .= $this->ext_getObjTree($arr[$key . '.'], $depth, $depthData . '<img src="' . $GLOBALS['BACK_PATH'] . 'gfx/ol/' . $LN . '.gif" width="18" height="16" align="top" alt="" />', '', $arr[$key], $alphaSort);
499 }
500 }
501 }
502 return $HTML;
503 }
504
505 /**
506 * Find the originating template name for an array of line numbers (TypoScript setup only!)
507 * Given an array of linenumbers the method will try to find the corresponding template where this line originated
508 * The linenumber indicates the *last* lineNumber that is part of the template
509 *
510 * lineNumbers are in sync with the calculated lineNumbers '.ln..' in TypoScriptParser
511 *
512 * @param array $lnArr Array with linenumbers (might have some extra symbols, for example for unsetting) to be processed
513 * @return array The same array where each entry has been prepended by the template title if available
514 * @todo Define visibility
515 */
516 public function lineNumberToScript(array $lnArr) {
517 // On the first call, construct the lnToScript array.
518 if (!is_array($this->lnToScript)) {
519 $this->lnToScript = array();
520
521 // aggregatedTotalLineCount
522 $c = 0;
523 foreach ($this->hierarchyInfo as $templateNumber => $info) {
524 // hierarchyInfo has the number of lines in configLines, but unfortunatly this value
525 // was calculated *before* processing of any INCLUDE instructions
526 // for some yet unknown reason we have to add an extra +2 offset
527 $linecountAfterIncludeProcessing = substr_count($this->config[$templateNumber], LF) + 2;
528 $c += $linecountAfterIncludeProcessing;
529 $this->lnToScript[$c] = $info['title'];
530 }
531 }
532
533 foreach ($lnArr as $k => $ln) {
534 foreach ($this->lnToScript as $endLn => $title) {
535 if ($endLn >= intval($ln)) {
536 $lnArr[$k] = '"' . $title . '", ' . $ln;
537 break;
538 }
539 }
540 }
541
542 return implode('; ', $lnArr);
543 }
544
545 /**
546 * [Describe function...]
547 *
548 * @param [type] $theValue: ...
549 * @return [type] ...
550 * @todo Define visibility
551 */
552 public function makeHtmlspecialchars($theValue) {
553 return $this->ext_noSpecialCharsOnLabels ? $theValue : htmlspecialchars($theValue);
554 }
555
556 /**
557 * [Describe function...]
558 *
559 * @param [type] $arr: ...
560 * @param [type] $depth_in: ...
561 * @param [type] $searchString: ...
562 * @param [type] $keyArray: ...
563 * @return [type] ...
564 * @todo Define visibility
565 */
566 public function ext_getSearchKeys($arr, $depth_in, $searchString, $keyArray) {
567 $keyArr = array();
568 foreach ($arr as $key => $value) {
569 $key = preg_replace('/\\.$/', '', $key);
570 if (substr($key, -1) != '.') {
571 $keyArr[$key] = 1;
572 }
573 }
574 $c = count($keyArr);
575 if ($depth_in) {
576 $depth_in = $depth_in . '.';
577 }
578 foreach ($keyArr as $key => $value) {
579 $depth = $depth_in . $key;
580 $deeper = is_array($arr[$key . '.']);
581 if ($this->regexMode) {
582 // The value has matched
583 if (preg_match('/' . $searchString . '/', $arr[$key])) {
584 $this->tsbrowser_searchKeys[$depth] += 2;
585 }
586 // The key has matched
587 if (preg_match('/' . $searchString . '/', $key)) {
588 $this->tsbrowser_searchKeys[$depth] += 4;
589 }
590 // Just open this subtree if the parent key has matched the search
591 if (preg_match('/' . $searchString . '/', $depth_in)) {
592 $this->tsbrowser_searchKeys[$depth] = 1;
593 }
594 } else {
595 // The value has matched
596 if (stristr($arr[$key], $searchString)) {
597 $this->tsbrowser_searchKeys[$depth] += 2;
598 }
599 // The key has matches
600 if (stristr($key, $searchString)) {
601 $this->tsbrowser_searchKeys[$depth] += 4;
602 }
603 // Just open this subtree if the parent key has matched the search
604 if (stristr($depth_in, $searchString)) {
605 $this->tsbrowser_searchKeys[$depth] = 1;
606 }
607 }
608 if ($deeper) {
609 $cS = count($this->tsbrowser_searchKeys);
610 $keyArray = $this->ext_getSearchKeys($arr[$key . '.'], $depth, $searchString, $keyArray);
611 if ($cS != count($this->tsbrowser_searchKeys)) {
612 $keyArray[$depth] = 1;
613 }
614 }
615 }
616 return $keyArray;
617 }
618
619 /**
620 * [Describe function...]
621 *
622 * @param [type] $pid: ...
623 * @return [type] ...
624 * @todo Define visibility
625 */
626 public function ext_getRootlineNumber($pid) {
627 if ($pid && is_array($GLOBALS['rootLine'])) {
628 foreach ($GLOBALS['rootLine'] as $key => $val) {
629 if ($val['uid'] == $pid) {
630 return $key;
631 }
632 }
633 }
634 }
635
636 /**
637 * [Describe function...]
638 *
639 * @param [type] $arr: ...
640 * @param [type] $depthData: ...
641 * @param [type] $keyArray: ...
642 * @param [type] $first: ...
643 * @return [type] ...
644 * @todo Define visibility
645 */
646 public function ext_getTemplateHierarchyArr($arr, $depthData, $keyArray, $first = 0) {
647 $keyArr = array();
648 foreach ($arr as $key => $value) {
649 $key = preg_replace('/\\.$/', '', $key);
650 if (substr($key, -1) != '.') {
651 $keyArr[$key] = 1;
652 }
653 }
654 $a = 0;
655 $c = count($keyArr);
656 static $i = 0;
657 foreach ($keyArr as $key => $value) {
658 $HTML = '';
659 $a++;
660 $deeper = is_array($arr[$key . '.']);
661 $row = $arr[$key];
662 $PM = 'join';
663 $LN = $a == $c ? 'blank' : 'line';
664 $BTM = $a == $c ? 'top' : '';
665 $PM = 'join';
666 $HTML .= $depthData;
667 $alttext = '[' . $row['templateID'] . ']';
668 $alttext .= $row['pid'] ? ' - ' . BackendUtility::getRecordPath($row['pid'], $GLOBALS['SOBE']->perms_clause, 20) : '';
669 $icon = substr($row['templateID'], 0, 3) == 'sys' ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForRecord('sys_template', $row, array('title' => $alttext)) : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('mimetypes-x-content-template-static', array('title' => $alttext));
670 if (in_array($row['templateID'], $this->clearList_const) || in_array($row['templateID'], $this->clearList_setup)) {
671 $urlParameters = array(
672 'id' => $GLOBALS['SOBE']->id,
673 'template' => $row['templateID']
674 );
675 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
676 $A_B = '<a href="' . htmlspecialchars($aHref) . '">';
677 $A_E = '</a>';
678 if (GeneralUtility::_GP('template') == $row['templateID']) {
679 $A_B = '<strong>' . $A_B;
680 $A_E .= '</strong>';
681 }
682 } else {
683 $A_B = '';
684 $A_E = '';
685 }
686 $HTML .= ($first ? '' : '<img src="' . $GLOBALS['BACK_PATH'] . 'gfx/ol/' . $PM . $BTM . '.gif" width="18" height="16" align="top" border="0" alt="" />') . $icon . $A_B . htmlspecialchars(GeneralUtility::fixed_lgd_cs($row['title'], $GLOBALS['BE_USER']->uc['titleLen'])) . $A_E . '&nbsp;&nbsp;';
687 $RL = $this->ext_getRootlineNumber($row['pid']);
688 $keyArray[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
689 <td nowrap="nowrap">' . $HTML . '</td>
690 <td align="center">' . ($row['root'] ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-status-checked') : '') . '&nbsp;&nbsp;</td>
691 <td align="center">' . ($row['clConf'] ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-status-checked') : '') . '&nbsp;&nbsp;' . '</td>
692 <td align="center">' . ($row['clConst'] ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('status-status-checked') : '') . '&nbsp;&nbsp;' . '</td>
693 <td align="center">' . ($row['pid'] ? $row['pid'] : '') . '</td>
694 <td align="center">' . ((string)$RL !== '' ? $RL : '') . '</td>
695 <td>' . ($row['next'] ? '&nbsp;' . $row['next'] . '&nbsp;&nbsp;' : '') . '</td>
696 </tr>';
697 if ($deeper) {
698 $keyArray = $this->ext_getTemplateHierarchyArr($arr[$key . '.'], $depthData . ($first ? '' : '<img src="' . $GLOBALS['BACK_PATH'] . 'gfx/ol/' . $LN . '.gif" width="18" height="16" align="top" />'), $keyArray);
699 }
700 }
701 return $keyArray;
702 }
703
704 /**
705 * Processes the flat array from TemplateService->hierarchyInfo
706 * and turns it into a hierachical array to show dependencies (used by TemplateAnalyzer)
707 *
708 * @param array $depthDataArr (empty array on external call)
709 * @param integer &$pointer Element number (1! to count()) of $this->hierarchyInfo that should be processed.
710 *
711 * @return array Processed hierachyInfo.
712 */
713 public function ext_process_hierarchyInfo(array $depthDataArr, &$pointer) {
714 $parent = $this->hierarchyInfo[$pointer - 1]['templateParent'];
715 while ($pointer > 0 && $this->hierarchyInfo[$pointer - 1]['templateParent'] == $parent) {
716 $pointer--;
717 $row = $this->hierarchyInfo[$pointer];
718 $depthDataArr[$row['templateID']] = $row;
719 $depthDataArr[$row['templateID']]['bgcolor_setup'] = isset($this->clearList_setup_temp[$row['templateID']]) ? ' class="bgColor5"' : '';
720 $depthDataArr[$row['templateID']]['bgcolor_const'] = isset($this->clearList_const_temp[$row['templateID']]) ? ' class="bgColor5"' : '';
721 unset($this->clearList_setup_temp[$row['templateID']]);
722 unset($this->clearList_const_temp[$row['templateID']]);
723 $this->templateTitles[$row['templateID']] = $row['title'];
724 if ($row['templateID'] == $this->hierarchyInfo[$pointer - 1]['templateParent']) {
725 $depthDataArr[$row['templateID'] . '.'] = $this->ext_process_hierarchyInfo(array(), $pointer);
726 }
727 }
728 return $depthDataArr;
729 }
730
731 /**
732 * Get formatted HTML output for TypoScript either with Syntaxhiglighting or in plain mode
733 *
734 * @param array $config Array with simple strings of typoscript code.
735 * @param boolean $lineNumbers Prepend linNumbers to each line.
736 * @param boolean $comments Enable including comments in output.
737 * @param boolean $crop Enable cropping of long lines.
738 * @param boolean $syntaxHL Enrich output with syntaxhighlighting.
739 * @param integer $syntaxHLBlockmode
740 *
741 * @return string
742 *
743 * @todo Define visibility
744 */
745 public function ext_outputTS(
746 array $config, $lineNumbers = FALSE, $comments = FALSE, $crop = FALSE, $syntaxHL = FALSE, $syntaxHLBlockmode = 0
747 ) {
748 $all = '';
749 foreach ($config as $str) {
750 $all .= '[GLOBAL]' . LF . $str;
751 }
752 if ($syntaxHL) {
753 $tsparser = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\Parser\\TypoScriptParser');
754 $tsparser->lineNumberOffset = $this->ext_lineNumberOffset + 1;
755 $tsparser->parentObject = $this;
756 return $tsparser->doSyntaxHighlight($all, $lineNumbers ? array($this->ext_lineNumberOffset + 1) : '', $syntaxHLBlockmode);
757 } else {
758 return $this->ext_formatTS($all, $lineNumbers, $comments, $crop);
759 }
760 }
761
762 /**
763 * Returns a new string of max. $chars length
764 * If the string is longer, it will be truncated and prepended with '...'
765 * $chars must be an integer of at least 4
766 *
767 * @param [type] $string: ...
768 * @param [type] $chars: ...
769 * @return [type] ...
770 * @todo Define visibility
771 */
772 public function ext_fixed_lgd($string, $chars) {
773 if ($chars >= 4) {
774 if (strlen($string) > $chars) {
775 if (strlen($string) > 24 && substr($string, 0, 12) == '##' . $this->Cmarker . '_B##') {
776 return '##' . $this->Cmarker . '_B##' . GeneralUtility::fixed_lgd_cs(substr($string, 12, -12), ($chars - 3)) . '##' . $this->Cmarker . '_E##';
777 } else {
778 return GeneralUtility::fixed_lgd_cs($string, $chars - 3);
779 }
780 }
781 }
782 return $string;
783 }
784
785 /**
786 * [Describe function...]
787 *
788 * @param integer $lineNumber Line Number
789 * @param [type] $str: ...
790 * @return string
791 * @todo Define visibility
792 */
793 public function ext_lnBreakPointWrap($lineNumber, $str) {
794 return '<a href="#" id="line-' . $lineNumber . '" onClick="return brPoint(' . $lineNumber . ',' . ($this->ext_lineNumberOffset_mode == 'setup' ? 1 : 0) . ');">' . $str . '</a>';
795 }
796
797 /**
798 * [Describe function...]
799 *
800 * @param [type] $input: ...
801 * @param [type] $ln: ...
802 * @param [type] $comments: ...
803 * @param [type] $crop: ...
804 * @return [type] ...
805 * @todo Define visibility
806 */
807 public function ext_formatTS($input, $ln, $comments = 1, $crop = 0) {
808 $cArr = explode(LF, $input);
809 $n = ceil(log10(count($cArr) + $this->ext_lineNumberOffset));
810 $lineNum = '';
811 foreach ($cArr as $k => $v) {
812 $lln = $k + $this->ext_lineNumberOffset + 1;
813 if ($ln) {
814 $lineNum = $this->ext_lnBreakPointWrap($lln, str_replace(' ', '&nbsp;', sprintf(('% ' . $n . 'd'), $lln))) . ': ';
815 }
816 $v = htmlspecialchars($v);
817 if ($crop) {
818 $v = $this->ext_fixed_lgd($v, $ln ? 71 : 77);
819 }
820 $cArr[$k] = $lineNum . str_replace(' ', '&nbsp;', $v);
821 $firstChar = substr(trim($v), 0, 1);
822 if ($firstChar == '[') {
823 $cArr[$k] = '<font color="green"><strong>' . $cArr[$k] . '</strong></font>';
824 } elseif ($firstChar == '/' || $firstChar == '#') {
825 if ($comments) {
826 $cArr[$k] = '<span class="typo3-dimmed">' . $cArr[$k] . '</span>';
827 } else {
828 unset($cArr[$k]);
829 }
830 }
831 }
832 $output = implode($cArr, '<br />') . '<br />';
833 return $output;
834 }
835
836 /**
837 * [Describe function...]
838 *
839 * @param [type] $id: ...
840 * @param [type] $template_uid: ...
841 * @return [type] ...
842 * @todo Define visibility
843 */
844 public function ext_getFirstTemplate($id, $template_uid = 0) {
845 // Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
846 if (intval($id)) {
847 if ($template_uid) {
848 $addC = ' AND uid=' . $template_uid;
849 }
850 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid=' . intval($id) . $addC . ' ' . $this->whereClause, '', 'sorting', '1');
851 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
852 BackendUtility::workspaceOL('sys_template', $row);
853 $GLOBALS['TYPO3_DB']->sql_free_result($res);
854 // Returns the template row if found.
855 return $row;
856 }
857 }
858
859 /**
860 * [Describe function...]
861 *
862 * @param [type] $id: ...
863 * @return [type] ...
864 * @todo Define visibility
865 */
866 public function ext_getAllTemplates($id) {
867 // Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
868 if (intval($id)) {
869 $outRes = array();
870 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_template', 'pid=' . intval($id) . ' ' . $this->whereClause, '', 'sorting');
871 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
872 BackendUtility::workspaceOL('sys_template', $row);
873 if (is_array($row)) {
874 $outRes[] = $row;
875 }
876 }
877 $GLOBALS['TYPO3_DB']->sql_free_result($res);
878 // Returns the template rows in an array.
879 return $outRes;
880 }
881 }
882
883 /**
884 * This function compares the flattened constants (default and all).
885 * Returns an array with the constants from the whole template which may be edited by the module.
886 *
887 * @param [type] $default: ...
888 * @return [type] ...
889 * @todo Define visibility
890 */
891 public function ext_compareFlatSetups($default) {
892 $editableComments = array();
893 foreach ($this->flatSetup as $const => $value) {
894 if (substr($const, -2) != '..' && isset($this->flatSetup[$const . '..'])) {
895 $comment = trim($this->flatSetup[$const . '..']);
896 $c_arr = explode(LF, $comment);
897 foreach ($c_arr as $k => $v) {
898 $line = trim(preg_replace('/^[#\\/]*/', '', $v));
899 if ($line) {
900 $parts = explode(';', $line);
901 foreach ($parts as $par) {
902 if (strstr($par, '=')) {
903 $keyValPair = explode('=', $par, 2);
904 switch (trim(strtolower($keyValPair[0]))) {
905 case 'type':
906 // Type:
907 $editableComments[$const]['type'] = trim($keyValPair[1]);
908 break;
909 case 'cat':
910 // List of categories.
911 $catSplit = explode('/', strtolower($keyValPair[1]));
912 $editableComments[$const]['cat'] = trim($catSplit[0]);
913 // This is the subcategory. Must be a key in $this->subCategories[]. catSplit[2] represents the search-order within the subcat.
914 $catSplit[1] = trim($catSplit[1]);
915 if ($catSplit[1] && isset($this->subCategories[$catSplit[1]])) {
916 $editableComments[$const]['subcat_name'] = $catSplit[1];
917 $editableComments[$const]['subcat'] = $this->subCategories[$catSplit[1]][1] . '/' . $catSplit[1] . '/' . trim($catSplit[2]) . 'z';
918 } else {
919 $editableComments[$const]['subcat'] = 'x' . '/' . trim($catSplit[2]) . 'z';
920 }
921 break;
922 case 'label':
923 // Label
924 $editableComments[$const]['label'] = trim($keyValPair[1]);
925 break;
926 case 'customsubcategory':
927 // Custom subCategory label
928 $customSubcategory = explode('=', $keyValPair[1], 2);
929 if (trim($customSubcategory[0])) {
930 $subCategoryKey = strtolower($customSubcategory[0]);
931 $this->subCategories[$subCategoryKey][0] = $GLOBALS['LANG']->sL($customSubcategory[1]);
932 }
933 break;
934 }
935 }
936 }
937 }
938 }
939 }
940 if (isset($editableComments[$const])) {
941 $editableComments[$const]['name'] = $const;
942 $editableComments[$const]['value'] = trim($value);
943 if (isset($default[$const])) {
944 $editableComments[$const]['default_value'] = trim($default[$const]);
945 }
946 }
947 }
948 return $editableComments;
949 }
950
951 /**
952 * [Describe function...]
953 *
954 * @param [type] $editConstArray: ...
955 * @return [type] ...
956 * @todo Define visibility
957 */
958 public function ext_categorizeEditableConstants($editConstArray) {
959 // Runs through the available constants and fills the $this->categories array with pointers and priority-info
960 foreach ($editConstArray as $constName => $constData) {
961 if (!$constData['type']) {
962 $constData['type'] = 'string';
963 }
964 $cats = explode(',', $constData['cat']);
965 // if = only one category, while allows for many. We have agreed on only one category is the most basic way...
966 foreach ($cats as $theCat) {
967 $theCat = trim($theCat);
968 if ($theCat) {
969 $this->categories[$theCat][$constName] = $constData['subcat'];
970 }
971 }
972 }
973 }
974
975 /**
976 * [Describe function...]
977 *
978 * @return [type] ...
979 * @todo Define visibility
980 */
981 public function ext_getCategoryLabelArray() {
982 // Returns array used for labels in the menu.
983 $retArr = array();
984 foreach ($this->categories as $k => $v) {
985 if (count($v)) {
986 $retArr[$k] = strtoupper($k) . ' (' . count($v) . ')';
987 }
988 }
989 return $retArr;
990 }
991
992 /**
993 * [Describe function...]
994 *
995 * @param [type] $type: ...
996 * @return [type] ...
997 * @todo Define visibility
998 */
999 public function ext_getTypeData($type) {
1000 $retArr = array();
1001 $type = trim($type);
1002 if (!$type) {
1003 $retArr['type'] = 'string';
1004 } else {
1005 $m = strcspn($type, ' [');
1006 $retArr['type'] = strtolower(substr($type, 0, $m));
1007 if (GeneralUtility::inList('int,options,file,boolean,offset,user', $retArr['type'])) {
1008 $p = trim(substr($type, $m));
1009 $reg = array();
1010 preg_match('/\\[(.*)\\]/', $p, $reg);
1011 $p = trim($reg[1]);
1012 if ($p) {
1013 $retArr['paramstr'] = $p;
1014 switch ($retArr['type']) {
1015 case 'int':
1016 if (substr($retArr['paramstr'], 0, 1) == '-') {
1017 $retArr['params'] = GeneralUtility::intExplode('-', substr($retArr['paramstr'], 1));
1018 $retArr['params'][0] = intval('-' . $retArr['params'][0]);
1019 } else {
1020 $retArr['params'] = GeneralUtility::intExplode('-', $retArr['paramstr']);
1021 }
1022 $retArr['paramstr'] = $retArr['params'][0] . ' - ' . $retArr['params'][1];
1023 break;
1024 case 'options':
1025 $retArr['params'] = explode(',', $retArr['paramstr']);
1026 break;
1027 }
1028 }
1029 }
1030 }
1031 return $retArr;
1032 }
1033
1034 /**
1035 * [Describe function...]
1036 *
1037 * @param [type] $category: ...
1038 * @return [type] ...
1039 * @todo Define visibility
1040 */
1041 public function ext_getTSCE_config($category) {
1042 $catConf = $this->setup['constants']['TSConstantEditor.'][$category . '.'];
1043 $out = array();
1044 if (is_array($catConf)) {
1045 foreach ($catConf as $key => $val) {
1046 switch ($key) {
1047 case 'image':
1048 $out['imagetag'] = $this->ext_getTSCE_config_image($catConf['image']);
1049 break;
1050 case 'description':
1051
1052 case 'bulletlist':
1053
1054 case 'header':
1055 $out[$key] = $val;
1056 break;
1057 default:
1058 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($key)) {
1059 $constRefs = explode(',', $val);
1060 foreach ($constRefs as $const) {
1061 $const = trim($const);
1062 if ($const && $const <= 20) {
1063 $out['constants'][$const] .= $this->ext_getKeyImage($key);
1064 }
1065 }
1066 }
1067 }
1068 }
1069 }
1070 $this->helpConfig = $out;
1071 }
1072
1073 /**
1074 * [Describe function...]
1075 *
1076 * @param [type] $key: ...
1077 * @return [type] ...
1078 * @todo Define visibility
1079 */
1080 public function ext_getKeyImage($key) {
1081 return '<img src="' . $this->ext_localWebGfxPrefix . 'gfx/' . $key . '.gif" align="top" hspace=2>';
1082 }
1083
1084 /**
1085 * [Describe function...]
1086 *
1087 * @param [type] $imgConf: ...
1088 * @return [type] ...
1089 * @todo Define visibility
1090 */
1091 public function ext_getTSCE_config_image($imgConf) {
1092 if (substr($imgConf, 0, 4) == 'gfx/') {
1093 $iFile = $this->ext_localGfxPrefix . $imgConf;
1094 $tFile = $this->ext_localWebGfxPrefix . $imgConf;
1095 } elseif (substr($imgConf, 0, 4) == 'EXT:') {
1096 $iFile = GeneralUtility::getFileAbsFileName($imgConf);
1097 if ($iFile) {
1098 $f = \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($iFile);
1099 $tFile = $GLOBALS['BACK_PATH'] . '../' . $f;
1100 }
1101 }
1102 $imageInfo = @getImagesize($iFile);
1103 return '<img src="' . $tFile . '" ' . $imageInfo[3] . '>';
1104 }
1105
1106 /**
1107 * [Describe function...]
1108 *
1109 * @param [type] $params: ...
1110 * @return [type] ...
1111 * @todo Define visibility
1112 */
1113 public function ext_fNandV($params) {
1114 $fN = 'data[' . $params['name'] . ']';
1115 $fV = $params['value'];
1116 // Values entered from the constantsedit cannot be constants! 230502; removed \{ and set {
1117 if (preg_match('/^{[\\$][a-zA-Z0-9\\.]*}$/', trim($fV), $reg)) {
1118 $fV = '';
1119 }
1120 $fV = htmlspecialchars($fV);
1121 return array($fN, $fV, $params);
1122 }
1123
1124 /**
1125 * This functions returns the HTML-code that creates the editor-layout of the module.
1126 *
1127 * @param [type] $theConstants: ...
1128 * @param [type] $category: ...
1129 * @return [type] ...
1130 * @todo Define visibility
1131 */
1132 public function ext_printFields($theConstants, $category) {
1133 reset($theConstants);
1134 $output = '<script type="text/javascript" src="' . $GLOBALS['BACK_PATH'] . 'js/constantEditor.js"></script>
1135 ';
1136 $subcat = '';
1137 if (is_array($this->categories[$category])) {
1138 $help = $this->helpConfig;
1139 if (!$this->doNotSortCategoriesBeforeMakingForm) {
1140 asort($this->categories[$category]);
1141 }
1142 foreach ($this->categories[$category] as $name => $type) {
1143 $params = $theConstants[$name];
1144 if (is_array($params)) {
1145 if ($subcat != $params['subcat_name']) {
1146 $subcat = $params['subcat_name'];
1147 $subcat_name = $params['subcat_name'] ? $this->subCategories[$params['subcat_name']][0] : 'Others';
1148 $output .= '<h3 class="typo3-tstemplate-ceditor-subcat">' . $subcat_name . '</h3>';
1149 }
1150 $label = $GLOBALS['LANG']->sL($params['label']);
1151 $label_parts = explode(':', $label, 2);
1152 if (count($label_parts) == 2) {
1153 $head = trim($label_parts[0]);
1154 $body = trim($label_parts[1]);
1155 } else {
1156 $head = trim($label_parts[0]);
1157 $body = '';
1158 }
1159 if (strlen($head) > 35) {
1160 if (!$body) {
1161 $body = $head;
1162 }
1163 $head = GeneralUtility::fixed_lgd_cs($head, 35);
1164 }
1165 $typeDat = $this->ext_getTypeData($params['type']);
1166 $checked = '';
1167 $p_field = '';
1168 $raname = substr(md5($params['name']), 0, 10);
1169 $aname = '\'' . $raname . '\'';
1170 list($fN, $fV, $params) = $this->ext_fNandV($params);
1171 switch ($typeDat['type']) {
1172 case 'int':
1173
1174 case 'int+':
1175 $p_field = '<input id="' . $fN . '" type="text" name="' . $fN . '" value="' . $fV . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(5) . ' onChange="uFormUrl(' . $aname . ')" />';
1176 if ($typeDat['paramstr']) {
1177 $p_field .= ' Range: ' . $typeDat['paramstr'];
1178 } elseif ($typeDat['type'] == 'int+') {
1179 $p_field .= ' Range: 0 - ';
1180 } else {
1181 $p_field .= ' (Integer)';
1182 }
1183 break;
1184 case 'color':
1185 $colorNames = explode(',', ',' . $this->HTMLcolorList);
1186 $p_field = '';
1187 foreach ($colorNames as $val) {
1188 $sel = '';
1189 if ($val == strtolower($params['value'])) {
1190 $sel = ' selected';
1191 }
1192 $p_field .= '<option value="' . htmlspecialchars($val) . '"' . $sel . '>' . $val . '</option>';
1193 }
1194 $p_field = '<select id="select-' . $fN . '" rel="' . $fN . '" name="C' . $fN . '" class="typo3-tstemplate-ceditor-color-select" onChange="uFormUrl(' . $aname . ');">' . $p_field . '</select>';
1195 $p_field .= '<input type="text" id="input-' . $fN . '" rel="' . $fN . '" name="' . $fN . '" class="typo3-tstemplate-ceditor-color-input" value="' . $fV . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(7) . ' onChange="uFormUrl(' . $aname . ')" />';
1196 break;
1197 case 'wrap':
1198 $wArr = explode('|', $fV);
1199 $p_field = '<input type="text" id="' . $fN . '" name="' . $fN . '" value="' . $wArr[0] . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(29) . ' onChange="uFormUrl(' . $aname . ')" />';
1200 $p_field .= ' | ';
1201 $p_field .= '<input type="text" name="W' . $fN . '" value="' . $wArr[1] . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(15) . ' onChange="uFormUrl(' . $aname . ')" />';
1202 break;
1203 case 'offset':
1204 $wArr = explode(',', $fV);
1205 $labels = GeneralUtility::trimExplode(',', $typeDat['paramstr']);
1206 $p_field = ($labels[0] ? $labels[0] : 'x') . ':<input type="text" name="' . $fN . '" value="' . $wArr[0] . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(4) . ' onChange="uFormUrl(' . $aname . ')" />';
1207 $p_field .= ' , ';
1208 $p_field .= ($labels[1] ? $labels[1] : 'y') . ':<input type="text" name="W' . $fN . '" value="' . $wArr[1] . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(4) . ' onChange="uFormUrl(' . $aname . ')" />';
1209 $labelsCount = count($labels);
1210 for ($aa = 2; $aa < $labelsCount; $aa++) {
1211 if ($labels[$aa]) {
1212 $p_field .= ' , ' . $labels[$aa] . ':<input type="text" name="W' . $aa . $fN . '" value="' . $wArr[$aa] . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth(4) . ' onChange="uFormUrl(' . $aname . ')" />';
1213 } else {
1214 $p_field .= '<input type="hidden" name="W' . $aa . $fN . '" value="' . $wArr[$aa] . '" />';
1215 }
1216 }
1217 break;
1218 case 'options':
1219 if (is_array($typeDat['params'])) {
1220 $p_field = '';
1221 foreach ($typeDat['params'] as $val) {
1222 $vParts = explode('=', $val, 2);
1223 $label = $vParts[0];
1224 $val = isset($vParts[1]) ? $vParts[1] : $vParts[0];
1225 // option tag:
1226 $sel = '';
1227 if ($val == $params['value']) {
1228 $sel = ' selected';
1229 }
1230 $p_field .= '<option value="' . htmlspecialchars($val) . '"' . $sel . '>' . $GLOBALS['LANG']->sL($label) . '</option>';
1231 }
1232 $p_field = '<select id="' . $fN . '" name="' . $fN . '" onChange="uFormUrl(' . $aname . ')">' . $p_field . '</select>';
1233 }
1234 break;
1235 case 'boolean':
1236 $p_field = '<input type="hidden" name="' . $fN . '" value="0" />';
1237 $sel = '';
1238 if ($fV) {
1239 $sel = ' checked';
1240 }
1241 $p_field .= '<input id="' . $fN . '" type="checkbox" name="' . $fN . '" value="' . ($typeDat['paramstr'] ? $typeDat['paramstr'] : 1) . '"' . $sel . ' onClick="uFormUrl(' . $aname . ')" />';
1242 break;
1243 case 'comment':
1244 $p_field = '<input type="hidden" name="' . $fN . '" value="#" />';
1245 $sel = '';
1246 if (!$fV) {
1247 $sel = ' checked';
1248 }
1249 $p_field .= '<input id="' . $fN . '" type="checkbox" name="' . $fN . '" value=""' . $sel . ' onClick="uFormUrl(' . $aname . ')" />';
1250 break;
1251 case 'file':
1252 $p_field = '<option value=""></option>';
1253 $theImage = '';
1254 // extensionlist
1255 $extList = $typeDat['paramstr'];
1256 $p_field = '<option value="">(' . $extList . ')</option>';
1257 if ($extList == 'IMAGE_EXT') {
1258 $extList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
1259 }
1260 if (trim($params['value'])) {
1261 $val = $params['value'];
1262 $p_field .= '<option value=""></option>';
1263 $p_field .= '<option value="' . htmlspecialchars($val) . '" selected>' . $val . '</option>';
1264 }
1265 $p_field = '<select id="' . $fN . '" name="' . $fN . '" onChange="uFormUrl(' . $aname . ')">' . $p_field . '</select>';
1266 $p_field .= $theImage;
1267 break;
1268 case 'user':
1269 $userFunction = $typeDat['paramstr'];
1270 $userFunctionParams = array('fieldName' => $fN, 'fieldValue' => $fV);
1271 $p_field = GeneralUtility::callUserFunction($userFunction, $userFunctionParams, $this, '');
1272 break;
1273 case 'small':
1274
1275 default:
1276 $fwidth = $typeDat['type'] == 'small' ? 10 : 46;
1277 $p_field = '<input id="' . $fN . '" type="text" name="' . $fN . '" value="' . $fV . '"' . $GLOBALS['TBE_TEMPLATE']->formWidth($fwidth) . ' onChange="uFormUrl(' . $aname . ')" />';
1278 }
1279 // Define default names and IDs
1280 $userTyposcriptID = 'userTS-' . $params['name'];
1281 $defaultTyposcriptID = 'defaultTS-' . $params['name'];
1282 $checkboxName = 'check[' . $params['name'] . ']';
1283 $checkboxID = $checkboxName;
1284 // Handle type=color specially
1285 if ($typeDat['type'] == 'color' && substr($params['value'], 0, 2) != '{$') {
1286 $color = '<div id="colorbox-' . $fN . '" class="typo3-tstemplate-ceditor-colorblock" style="background-color:' . $params['value'] . ';">&nbsp;</div>';
1287 } else {
1288 $color = '';
1289 }
1290 if (!$this->ext_dontCheckIssetValues) {
1291 // Set the default styling options
1292 if (isset($this->objReg[$params['name']])) {
1293 $checkboxValue = 'checked';
1294 $userTyposcriptStyle = '';
1295 $defaultTyposcriptStyle = 'style="display:none;"';
1296 } else {
1297 $checkboxValue = '';
1298 $userTyposcriptStyle = 'style="display:none;"';
1299 $defaultTyposcriptStyle = '';
1300 }
1301 $deleteIconHTML = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-edit-undo', array(
1302 'class' => 'typo3-tstemplate-ceditor-control undoIcon',
1303 'alt' => 'Revert to default Constant',
1304 'title' => 'Revert to default Constant',
1305 'rel' => $params['name']
1306 ));
1307 $editIconHTML = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-document-open', array(
1308 'class' => 'typo3-tstemplate-ceditor-control editIcon',
1309 'alt' => 'Edit this Constant',
1310 'title' => 'Edit this Constant',
1311 'rel' => $params['name']
1312 ));
1313 $constantCheckbox = '<input type="hidden" name="' . $checkboxName . '" id="' . $checkboxID . '" value="' . $checkboxValue . '"/>';
1314 // If there's no default value for the field, use a static label.
1315 if (!$params['default_value']) {
1316 $params['default_value'] = '[Empty]';
1317 }
1318 $constantDefaultRow = '<div class="typo3-tstemplate-ceditor-row" id="' . $defaultTyposcriptID . '" ' . $defaultTyposcriptStyle . '>' . $editIconHTML . htmlspecialchars($params['default_value']) . $color . '</div>';
1319 }
1320 $constantEditRow = '<div class="typo3-tstemplate-ceditor-row" id="' . $userTyposcriptID . '" ' . $userTyposcriptStyle . '>' . $deleteIconHTML . $p_field . $color . '</div>';
1321 $constantLabel = '<dt class="typo3-tstemplate-ceditor-label">' . htmlspecialchars($head) . '</dt>';
1322 $constantName = '<dt class="typo3-dimmed">[' . $params['name'] . ']</dt>';
1323 $constantDescription = $body ? '<dd>' . htmlspecialchars($body) . '</dd>' : '';
1324 $constantData = '<dd>' . $constantCheckbox . $constantEditRow . $constantDefaultRow . '</dd>';
1325 $output .= '<a name="' . $raname . '"></a>' . $help['constants'][$params['name']];
1326 $output .= '<dl class="typo3-tstemplate-ceditor-constant">' . $constantLabel . $constantName . $constantDescription . $constantData . '</dl>';
1327 } else {
1328 debug('Error. Constant did not exist. Should not happen.');
1329 }
1330 }
1331 }
1332 return $output;
1333 }
1334
1335 /***************************
1336 *
1337 * Processing input values
1338 *
1339 ***************************/
1340 /**
1341 * @param [type] $constants: ...
1342 * @return [type] ...
1343 * @todo Define visibility
1344 */
1345 public function ext_regObjectPositions($constants) {
1346 // This runs through the lines of the constants-field of the active template and registers the constants-names
1347 // and linepositions in an array, $this->objReg
1348 $this->raw = explode(LF, $constants);
1349 $this->rawP = 0;
1350 // Resetting the objReg if the divider is found!!
1351 $this->objReg = array();
1352 $this->ext_regObjects('');
1353 }
1354
1355 /**
1356 * [Describe function...]
1357 *
1358 * @param [type] $pre: ...
1359 * @return [type] ...
1360 * @todo Define visibility
1361 */
1362 public function ext_regObjects($pre) {
1363 // Works with regObjectPositions. "expands" the names of the TypoScript objects
1364 while (isset($this->raw[$this->rawP])) {
1365 $line = ltrim($this->raw[$this->rawP]);
1366 if (strstr($line, $this->edit_divider)) {
1367 // Resetting the objReg if the divider is found!!
1368 $this->objReg = array();
1369 }
1370 $this->rawP++;
1371 if ($line) {
1372 if (substr($line, 0, 1) == '[') {
1373
1374 } elseif (strcspn($line, '}#/') != 0) {
1375 $varL = strcspn($line, ' {=<');
1376 $var = substr($line, 0, $varL);
1377 $line = ltrim(substr($line, $varL));
1378 switch (substr($line, 0, 1)) {
1379 case '=':
1380 $this->objReg[$pre . $var] = $this->rawP - 1;
1381 break;
1382 case '{':
1383 $this->ext_inBrace++;
1384 $this->ext_regObjects($pre . $var . '.');
1385 break;
1386 }
1387 $this->lastComment = '';
1388 } elseif (substr($line, 0, 1) == '}') {
1389 $this->lastComment = '';
1390 $this->ext_inBrace--;
1391 if ($this->ext_inBrace < 0) {
1392 $this->ext_inBrace = 0;
1393 } else {
1394 break;
1395 }
1396 }
1397 }
1398 }
1399 }
1400
1401 /**
1402 * [Describe function...]
1403 *
1404 * @param [type] $key: ...
1405 * @param [type] $var: ...
1406 * @return [type] ...
1407 * @todo Define visibility
1408 */
1409 public function ext_putValueInConf($key, $var) {
1410 // Puts the value $var to the TypoScript value $key in the current lines of the templates.
1411 // If the $key is not found in the template constants field, a new line is inserted in the bottom.
1412 $theValue = ' ' . trim($var);
1413 if (isset($this->objReg[$key])) {
1414 $lineNum = $this->objReg[$key];
1415 $parts = explode('=', $this->raw[$lineNum], 2);
1416 if (count($parts) == 2) {
1417 $parts[1] = $theValue;
1418 }
1419 $this->raw[$lineNum] = implode($parts, '=');
1420 } else {
1421 $this->raw[] = $key . ' =' . $theValue;
1422 }
1423 $this->changed = 1;
1424 }
1425
1426 /**
1427 * [Describe function...]
1428 *
1429 * @param [type] $key: ...
1430 * @return [type] ...
1431 * @todo Define visibility
1432 */
1433 public function ext_removeValueInConf($key) {
1434 // Removes the value in the configuration
1435 if (isset($this->objReg[$key])) {
1436 $lineNum = $this->objReg[$key];
1437 unset($this->raw[$lineNum]);
1438 }
1439 $this->changed = 1;
1440 }
1441
1442 /**
1443 * [Describe function...]
1444 *
1445 * @param [type] $arr: ...
1446 * @param [type] $settings: ...
1447 * @return [type] ...
1448 * @todo Define visibility
1449 */
1450 public function ext_depthKeys($arr, $settings) {
1451 $tsbrArray = array();
1452 foreach ($arr as $theK => $theV) {
1453 $theKeyParts = explode('.', $theK);
1454 $depth = '';
1455 $c = count($theKeyParts);
1456 $a = 0;
1457 foreach ($theKeyParts as $p) {
1458 $a++;
1459 $depth .= ($depth ? '.' : '') . $p;
1460 $tsbrArray[$depth] = $c == $a ? $theV : 1;
1461 }
1462 }
1463 // Modify settings
1464 foreach ($tsbrArray as $theK => $theV) {
1465 if ($theV) {
1466 $settings[$theK] = 1;
1467 } else {
1468 unset($settings[$theK]);
1469 }
1470 }
1471 return $settings;
1472 }
1473
1474 /**
1475 * [Describe function...]
1476 *
1477 * @param [type] $http_post_vars: ...
1478 * @param array (not used anymore)
1479 * @param [type] $theConstants: ...
1480 * @param [type] $tplRow: ...
1481 * @return [type] ...
1482 * @todo Define visibility
1483 */
1484 public function ext_procesInput($http_post_vars, $http_post_files, $theConstants, $tplRow) {
1485 $data = $http_post_vars['data'];
1486 $check = $http_post_vars['check'];
1487 $Wdata = $http_post_vars['Wdata'];
1488 $W2data = $http_post_vars['W2data'];
1489 $W3data = $http_post_vars['W3data'];
1490 $W4data = $http_post_vars['W4data'];
1491 $W5data = $http_post_vars['W5data'];
1492 if (is_array($data)) {
1493 foreach ($data as $key => $var) {
1494 if (isset($theConstants[$key])) {
1495 // If checkbox is set, update the value
1496 if ($this->ext_dontCheckIssetValues || isset($check[$key])) {
1497 // Exploding with linebreak, just to make sure that no multiline input is given!
1498 list($var) = explode(LF, $var);
1499 $typeDat = $this->ext_getTypeData($theConstants[$key]['type']);
1500 switch ($typeDat['type']) {
1501 case 'int':
1502 if ($typeDat['paramstr']) {
1503 $var = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($var, $typeDat['params'][0], $typeDat['params'][1]);
1504 } else {
1505 $var = intval($var);
1506 }
1507 break;
1508 case 'int+':
1509 $var = max(0, intval($var));
1510 break;
1511 case 'color':
1512 $col = array();
1513 if ($var && !GeneralUtility::inList($this->HTMLcolorList, strtolower($var))) {
1514 $var = preg_replace('/[^A-Fa-f0-9]*/', '', $var);
1515 $useFulHex = strlen($var) > 3;
1516 $col[] = HexDec(substr($var, 0, 1));
1517 $col[] = HexDec(substr($var, 1, 1));
1518 $col[] = HexDec(substr($var, 2, 1));
1519 if ($useFulHex) {
1520 $col[] = HexDec(substr($var, 3, 1));
1521 $col[] = HexDec(substr($var, 4, 1));
1522 $col[] = HexDec(substr($var, 5, 1));
1523 }
1524 $var = substr(('0' . DecHex($col[0])), -1) . substr(('0' . DecHex($col[1])), -1) . substr(('0' . DecHex($col[2])), -1);
1525 if ($useFulHex) {
1526 $var .= substr(('0' . DecHex($col[3])), -1) . substr(('0' . DecHex($col[4])), -1) . substr(('0' . DecHex($col[5])), -1);
1527 }
1528 $var = '#' . strtoupper($var);
1529 }
1530 break;
1531 case 'comment':
1532 if ($var) {
1533 $var = '#';
1534 } else {
1535 $var = '';
1536 }
1537 break;
1538 case 'wrap':
1539 if (isset($Wdata[$key])) {
1540 $var .= '|' . $Wdata[$key];
1541 }
1542 break;
1543 case 'offset':
1544 if (isset($Wdata[$key])) {
1545 $var = intval($var) . ',' . intval($Wdata[$key]);
1546 if (isset($W2data[$key])) {
1547 $var .= ',' . intval($W2data[$key]);
1548 if (isset($W3data[$key])) {
1549 $var .= ',' . intval($W3data[$key]);
1550 if (isset($W4data[$key])) {
1551 $var .= ',' . intval($W4data[$key]);
1552 if (isset($W5data[$key])) {
1553 $var .= ',' . intval($W5data[$key]);
1554 }
1555 }
1556 }
1557 }
1558 }
1559 break;
1560 case 'boolean':
1561 if ($var) {
1562 $var = $typeDat['paramstr'] ? $typeDat['paramstr'] : 1;
1563 }
1564 break;
1565 }
1566 if ($this->ext_printAll || (string)$theConstants[$key]['value'] !== (string)$var) {
1567 // Put value in, if changed.
1568 $this->ext_putValueInConf($key, $var);
1569 }
1570 // Remove the entry because it has been "used"
1571 unset($check[$key]);
1572 } else {
1573 $this->ext_removeValueInConf($key);
1574 }
1575 }
1576 }
1577 }
1578 // Remaining keys in $check indicates fields that are just clicked "on" to be edited. Therefore we get the default value and puts that in the template as a start...
1579 if (!$this->ext_dontCheckIssetValues && is_array($check)) {
1580 foreach ($check as $key => $var) {
1581 if (isset($theConstants[$key])) {
1582 $dValue = $theConstants[$key]['default_value'];
1583 $this->ext_putValueInConf($key, $dValue);
1584 }
1585 }
1586 }
1587 }
1588
1589 /**
1590 * [Describe function...]
1591 *
1592 * @param [type] $id: ...
1593 * @param [type] $perms_clause: ...
1594 * @return [type] ...
1595 * @todo Define visibility
1596 */
1597 public function ext_prevPageWithTemplate($id, $perms_clause) {
1598 $rootLine = BackendUtility::BEgetRootLine($id, $perms_clause ? ' AND ' . $perms_clause : '');
1599 foreach ($rootLine as $p) {
1600 if ($this->ext_getFirstTemplate($p['uid'])) {
1601 return $p;
1602 }
1603 }
1604 }
1605
1606 }