TYPO3  7.6
ExtendedTemplateService.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\TypoScript;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
28 
34 {
41  public $edit_divider = '###MOD_TS:EDITABLE_CONSTANTS###';
42 
46  public $HTMLcolorList = 'aqua,beige,black,blue,brown,fuchsia,gold,gray,green,lime,maroon,navy,olive,orange,purple,red,silver,tan,teal,turquoise,yellow,white';
47 
51  public $categories = array(
52  'basic' => array(),
53  // 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.
54  'menu' => array(),
55  // Menu setup. This includes fontfiles, sizes, background images. Depending on the menutype.
56  'content' => array(),
57  // All constants related to the display of pagecontent elements
58  'page' => array(),
59  // General configuration like metatags, link targets
60  'advanced' => array(),
61  // Advanced functions, which are used very seldomly.
62  'all' => array()
63  );
64 
70  protected $categoryLabels = array();
71 
77  public $subCategories = array(
78  // Standard categories:
79  'enable' => array('Enable features', 'a'),
80  'dims' => array('Dimensions, widths, heights, pixels', 'b'),
81  'file' => array('Files', 'c'),
82  'typo' => array('Typography', 'd'),
83  'color' => array('Colors', 'e'),
84  'links' => array('Links and targets', 'f'),
85  'language' => array('Language specific constants', 'g'),
86  // subcategories based on the default content elements
87  'cheader' => array('Content: \'Header\'', 'ma'),
88  'cheader_g' => array('Content: \'Header\', Graphical', 'ma'),
89  'ctext' => array('Content: \'Text\'', 'mb'),
90  'cimage' => array('Content: \'Image\'', 'md'),
91  'ctextmedia' => array('Content: \'Textmedia\'', 'ml'),
92  'cbullets' => array('Content: \'Bullet list\'', 'me'),
93  'ctable' => array('Content: \'Table\'', 'mf'),
94  'cuploads' => array('Content: \'Filelinks\'', 'mg'),
95  'cmultimedia' => array('Content: \'Multimedia\'', 'mh'),
96  'cmedia' => array('Content: \'Media\'', 'mr'),
97  'cmailform' => array('Content: \'Form\'', 'mi'),
98  'csearch' => array('Content: \'Search\'', 'mj'),
99  'clogin' => array('Content: \'Login\'', 'mk'),
100  'cmenu' => array('Content: \'Menu/Sitemap\'', 'mm'),
101  'cshortcut' => array('Content: \'Insert records\'', 'mn'),
102  'clist' => array('Content: \'List of records\'', 'mo'),
103  'chtml' => array('Content: \'HTML\'', 'mq')
104  );
105 
109  public $backend_info = true;
110 
116  public $ext_inBrace = 0;
117 
123  public $tsbrowser_searchKeys = array();
124 
128  public $tsbrowser_depthKeys = array();
129 
133  public $constantMode = '';
134 
138  public $regexMode = '';
139 
143  public $fixedLgd = '';
144 
149 
153  public $ext_localGfxPrefix = '';
154 
159 
164 
168  public $ext_noPMicons = 0;
169 
176 
180  public $ext_listOfTemplatesArr = array();
181 
186 
193 
197  public $ext_printAll = 0;
198 
202  public $ext_CEformName = 'forms[0]';
203 
208 
214  public $templateTitles = array();
215 
219  protected $lnToScript = null;
220 
225 
230 
234  protected $Cmarker = '';
235 
239  public $bType = '';
240 
244  public $linkObjects = false;
245 
249  public $helpConfig = array();
250 
254  public $changed = false;
255 
259  protected $objReg = array();
260 
264  public $raw = array();
265 
269  public $rawP = 0;
270 
274  public $lastComment = '';
275 
282  public function substituteConstants($all)
283  {
284  $this->Cmarker = substr(md5(uniqid('', true)), 0, 6);
285  return preg_replace_callback('/\\{\\$(.[^}]+)\\}/', array($this, 'substituteConstantsCallBack'), $all);
286  }
287 
295  public function substituteConstantsCallBack($matches)
296  {
297  switch ($this->constantMode) {
298  case 'const':
299  $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? '##' . $this->Cmarker . '_B##' . $matches[0] . '##' . $this->Cmarker . '_E##' : $matches[0];
300  break;
301  case 'subst':
302  $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];
303  break;
304  case 'untouched':
305  $ret_val = $matches[0];
306  break;
307  default:
308  $ret_val = isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? $this->flatSetup[$matches[1]] : $matches[0];
309  }
310  return $ret_val;
311  }
312 
319  public function substituteCMarkers($all)
320  {
321  switch ($this->constantMode) {
322  case 'const':
323  case 'subst':
324  $all = str_replace(
325  array('##' . $this->Cmarker . '_B##', '##' . $this->Cmarker . '_E##'),
326  array('<strong style="color: green;">', '</strong>'),
327  $all
328  );
329  break;
330  default:
331  }
332  return $all;
333  }
334 
341  public function generateConfig_constants()
342  {
343  // These vars are also set lateron...
344  $this->setup['sitetitle'] = $this->sitetitle;
345  // Parse constants
346  $constants = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
347  // Register comments!
348  $constants->regComments = 1;
349  $constants->setup = $this->mergeConstantsFromPageTSconfig(array());
351  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
352  // Matches ALL conditions in TypoScript
353  $matchObj->setSimulateMatchResult(true);
354  $c = 0;
355  $cc = count($this->constants);
356  $defaultConstants = array();
357  foreach ($this->constants as $str) {
358  $c++;
359  if ($c == $cc) {
360  if (strstr($str, $this->edit_divider)) {
361  $parts = explode($this->edit_divider, $str, 2);
362  $str = $parts[1];
363  $constants->parse($parts[0], $matchObj);
364  }
365  $this->flatSetup = array();
366  $this->flattenSetup($constants->setup, '', '');
367  $defaultConstants = $this->flatSetup;
368  }
369  $constants->parse($str, $matchObj);
370  }
371  $this->flatSetup = array();
372  $this->flattenSetup($constants->setup, '', '');
373  $this->setup['constants'] = $constants->setup;
374  return $this->ext_compareFlatSetups($defaultConstants);
375  }
376 
382  public function ext_getSetup($theSetup, $theKey)
383  {
384  $parts = explode('.', $theKey, 2);
385  if ((string)$parts[0] !== '' && is_array($theSetup[$parts[0] . '.'])) {
386  if (trim($parts[1]) !== '') {
387  return $this->ext_getSetup($theSetup[$parts[0] . '.'], trim($parts[1]));
388  } else {
389  return array($theSetup[$parts[0] . '.'], $theSetup[$parts[0]]);
390  }
391  } else {
392  if (trim($theKey) !== '') {
393  return array(array(), $theSetup[$theKey]);
394  } else {
395  return array($theSetup, '');
396  }
397  }
398  }
399 
411  public function ext_getObjTree($arr, $depth_in, $depthData, $parentType = '', $parentValue = '', $alphaSort = '0')
412  {
413  $HTML = '';
414  $a = 0;
415  if ($alphaSort == '1') {
416  ksort($arr);
417  }
418  $keyArr_num = array();
419  $keyArr_alpha = array();
420  foreach ($arr as $key => $value) {
421  // Don't do anything with comments / linenumber registrations...
422  if (substr($key, -2) != '..') {
423  $key = preg_replace('/\\.$/', '', $key);
424  if (substr($key, -1) != '.') {
426  $keyArr_num[$key] = $arr[$key];
427  } else {
428  $keyArr_alpha[$key] = $arr[$key];
429  }
430  }
431  }
432  }
433  ksort($keyArr_num);
434  $keyArr = $keyArr_num + $keyArr_alpha;
435  $c = count($keyArr);
436  if ($depth_in) {
437  $depth_in = $depth_in . '.';
438  }
439  foreach ($keyArr as $key => $value) {
440  $a++;
441  $depth = $depth_in . $key;
442  // This excludes all constants starting with '_' from being shown.
443  if ($this->bType !== 'const' || $depth[0] !== '_') {
444  $goto = substr(md5($depth), 0, 6);
445  $deeper = is_array($arr[$key . '.']) && ($this->tsbrowser_depthKeys[$depth] || $this->ext_expandAllNotes) ? 1 : 0;
446  $LN = $a == $c ? 'blank' : 'line';
447  $BTM = $a == $c ? 'bottom' : '';
448  $PM = is_array($arr[$key . '.']) && !$this->ext_noPMicons ? ($deeper ? 'minus' : 'plus') : 'join';
449  $HTML .= $depthData . '<li>';
450  if ($PM !== 'join') {
451  $urlParameters = array(
452  'id' => $GLOBALS['SOBE']->id,
453  'tsbr[' . $depth . ']' => $deeper ? 0 : 1
454  );
455  if (GeneralUtility::_GP('breakPointLN')) {
456  $urlParameters['breakPointLN'] = GeneralUtility::_GP('breakPointLN');
457  }
458  $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters) . '#' . $goto;
459  $HTML .= '<a class="list-tree-control' . ($PM === 'minus' ? ' list-tree-control-open' : ' list-tree-control-closed') . '" name="' . $goto . '" href="' . htmlspecialchars($aHref) . '"><i class="fa"></i></a>';
460  }
461  $label = $key;
462  // Read only...
463  if (GeneralUtility::inList('types,resources,sitetitle', $depth) && $this->bType == 'setup') {
464  $label = '<span style="color: #666666;">' . $label . '</span>';
465  } else {
466  if ($this->linkObjects) {
467  $urlParameters = array(
468  'id' => $GLOBALS['SOBE']->id,
469  'sObj' => $depth
470  );
471  if (GeneralUtility::_GP('breakPointLN')) {
472  $urlParameters['breakPointLN'] = GeneralUtility::_GP('breakPointLN');
473  }
474  $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
475  if ($this->bType != 'const') {
476  $ln = is_array($arr[$key . '.ln..']) ? 'Defined in: ' . $this->lineNumberToScript($arr[($key . '.ln..')]) : 'N/A';
477  } else {
478  $ln = '';
479  }
480  if ($this->tsbrowser_searchKeys[$depth] & 4) {
481  $label = '<strong class="text-danger">' . $label . '</strong>';
482  }
483  // The key has matched the search string
484  $label = '<a href="' . htmlspecialchars($aHref) . '" title="' . htmlspecialchars($ln) . '">' . $label . '</a>';
485  }
486  }
487  $HTML .= '
488  <span class="list-tree-group">
489  <span class="list-tree-label">[' . $label . ']</span>';
490  if (isset($arr[$key])) {
491  $theValue = $arr[$key];
492  if ($this->fixedLgd) {
493  $imgBlocks = ceil(1 + strlen($depthData) / 77);
494  $lgdChars = 68 - ceil(strlen(('[' . $key . ']')) * 0.8) - $imgBlocks * 3;
495  $theValue = $this->ext_fixed_lgd($theValue, $lgdChars);
496  }
497  // The value has matched the search string
498  if ($this->tsbrowser_searchKeys[$depth] & 2) {
499  $HTML .= ' = <span class="list-tree-value text-danger">' . htmlspecialchars($theValue) . '</span>';
500  } else {
501  $HTML .= ' = <span class="list-tree-value">' . htmlspecialchars($theValue) . '</span>';
502  }
503  if ($this->ext_regComments && isset($arr[$key . '..'])) {
504  $comment = $arr[$key . '..'];
505  // Skip INCLUDE_TYPOSCRIPT comments, they are almost useless
506  if (!preg_match('/### <INCLUDE_TYPOSCRIPT:.*/', $comment)) {
507  // Remove linebreaks, replace with ' '
508  $comment = preg_replace('/[\\r\\n]/', ' ', $comment);
509  // Remove # and * if more than twice in a row
510  $comment = preg_replace('/[#\\*]{2,}/', '', $comment);
511  // Replace leading # (just if it exists) and add it again. Result: Every comment should be prefixed by a '#'.
512  $comment = preg_replace('/^[#\\*\\s]+/', '# ', $comment);
513  // Masking HTML Tags: Replace < with &lt; and > with &gt;
514  $comment = htmlspecialchars($comment);
515  $HTML .= ' <i class="text-muted">' . trim($comment) . '</i>';
516  }
517  }
518  }
519  $HTML .= '</span>';
520  if ($deeper) {
521  $HTML .= $this->ext_getObjTree($arr[$key . '.'], $depth, $depthData, '', $arr[$key], $alphaSort);
522  }
523  }
524  }
525  if ($HTML !== '') {
526  $HTML = '<ul class="list-tree text-monospace">' . $HTML . '</ul>';
527  }
528 
529  return $HTML;
530  }
531 
542  public function lineNumberToScript(array $lnArr)
543  {
544  // On the first call, construct the lnToScript array.
545  if (!is_array($this->lnToScript)) {
546  $this->lnToScript = array();
547 
548  // aggregatedTotalLineCount
549  $c = 0;
550  foreach ($this->hierarchyInfo as $templateNumber => $info) {
551  // hierarchyInfo has the number of lines in configLines, but unfortunatly this value
552  // was calculated *before* processing of any INCLUDE instructions
553  // for some yet unknown reason we have to add an extra +2 offset
554  $linecountAfterIncludeProcessing = substr_count($this->config[$templateNumber], LF) + 2;
555  $c += $linecountAfterIncludeProcessing;
556  $this->lnToScript[$c] = $info['title'];
557  }
558  }
559 
560  foreach ($lnArr as $k => $ln) {
561  foreach ($this->lnToScript as $endLn => $title) {
562  if ($endLn >= (int)$ln) {
563  $lnArr[$k] = '"' . $title . '", ' . $ln;
564  break;
565  }
566  }
567  }
568 
569  return implode('; ', $lnArr);
570  }
571 
577  public function makeHtmlspecialchars($theValue)
578  {
580  return $this->ext_noSpecialCharsOnLabels ? $theValue : htmlspecialchars($theValue);
581  }
582 
591  public function ext_getSearchKeys($arr, $depth_in, $searchString, $keyArray)
592  {
593  $keyArr = array();
594  foreach ($arr as $key => $value) {
595  $key = preg_replace('/\\.$/', '', $key);
596  if (substr($key, -1) != '.') {
597  $keyArr[$key] = 1;
598  }
599  }
600  if ($depth_in) {
601  $depth_in = $depth_in . '.';
602  }
603  $searchPattern = '';
604  if ($this->regexMode) {
605  $searchPattern = '/' . addcslashes($searchString, '/') . '/';
606  $matchResult = @preg_match($searchPattern, '');
607  if ($matchResult === false) {
608  throw new Exception(sprintf('Error evaluating regular expression "%s".', $searchPattern), 1446559458);
609  }
610  }
611  foreach ($keyArr as $key => $value) {
612  $depth = $depth_in . $key;
613  $deeper = is_array($arr[$key . '.']);
614  if ($this->regexMode) {
615  // The value has matched
616  if (preg_match($searchPattern, $arr[$key])) {
617  $this->tsbrowser_searchKeys[$depth] += 2;
618  }
619  // The key has matched
620  if (preg_match($searchPattern, $key)) {
621  $this->tsbrowser_searchKeys[$depth] += 4;
622  }
623  // Just open this subtree if the parent key has matched the search
624  if (preg_match($searchPattern, $depth_in)) {
625  $this->tsbrowser_searchKeys[$depth] = 1;
626  }
627  } else {
628  // The value has matched
629  if (stristr($arr[$key], $searchString)) {
630  $this->tsbrowser_searchKeys[$depth] += 2;
631  }
632  // The key has matches
633  if (stristr($key, $searchString)) {
634  $this->tsbrowser_searchKeys[$depth] += 4;
635  }
636  // Just open this subtree if the parent key has matched the search
637  if (stristr($depth_in, $searchString)) {
638  $this->tsbrowser_searchKeys[$depth] = 1;
639  }
640  }
641  if ($deeper) {
642  $cS = count($this->tsbrowser_searchKeys);
643  $keyArray = $this->ext_getSearchKeys($arr[$key . '.'], $depth, $searchString, $keyArray);
644  if ($cS != count($this->tsbrowser_searchKeys)) {
645  $keyArray[$depth] = 1;
646  }
647  }
648  }
649  return $keyArray;
650  }
651 
656  public function ext_getRootlineNumber($pid)
657  {
658  if ($pid) {
659  foreach ($this->getRootLine() as $key => $val) {
660  if ((int)$val['uid'] === (int)$pid) {
661  return (int)$key;
662  }
663  }
664  }
665  return -1;
666  }
667 
675  public function ext_getTemplateHierarchyArr($arr, $depthData, $keyArray, $first = 0)
676  {
677  $keyArr = array();
678  foreach ($arr as $key => $value) {
679  $key = preg_replace('/\\.$/', '', $key);
680  if (substr($key, -1) != '.') {
681  $keyArr[$key] = 1;
682  }
683  }
684  $a = 0;
685  $c = count($keyArr);
686  static $i = 0;
688  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
689  foreach ($keyArr as $key => $value) {
690  $HTML = '';
691  $a++;
692  $deeper = is_array($arr[$key . '.']);
693  $row = $arr[$key];
694  $LN = $a == $c ? 'blank' : 'line';
695  $BTM = $a == $c ? 'top' : '';
696  $HTML .= $depthData;
697  $alttext = '[' . $row['templateID'] . ']';
698  $alttext .= $row['pid'] ? ' - ' . BackendUtility::getRecordPath($row['pid'], $GLOBALS['SOBE']->perms_clause, 20) : '';
699  $icon = substr($row['templateID'], 0, 3) === 'sys'
700  ? '<span title="' . htmlspecialchars($alttext) . '">' . $iconFactory->getIconForRecord('sys_template', $row, Icon::SIZE_SMALL)->render() . '</span>'
701  : '<span title="' . htmlspecialchars($alttext) . '">' . $iconFactory->getIcon('mimetypes-x-content-template-static', Icon::SIZE_SMALL)->render() . '</span>';
702  if (in_array($row['templateID'], $this->clearList_const) || in_array($row['templateID'], $this->clearList_setup)) {
703  $urlParameters = array(
704  'id' => $GLOBALS['SOBE']->id,
705  'template' => $row['templateID']
706  );
707  $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
708  $A_B = '<a href="' . htmlspecialchars($aHref) . '">';
709  $A_E = '</a>';
710  if (GeneralUtility::_GP('template') == $row['templateID']) {
711  $A_B = '<strong>' . $A_B;
712  $A_E .= '</strong>';
713  }
714  } else {
715  $A_B = '';
716  $A_E = '';
717  }
718  $HTML .= ($first ? '' : '<span class="treeline-icon treeline-icon-join' . $BTM . '"></span>') . $icon . $A_B
719  . htmlspecialchars(GeneralUtility::fixed_lgd_cs($row['title'], $GLOBALS['BE_USER']->uc['titleLen']))
720  . $A_E . '&nbsp;&nbsp;';
721  $RL = $this->ext_getRootlineNumber($row['pid']);
722  $statusCheckedIcon = $iconFactory->getIcon('status-status-checked', Icon::SIZE_SMALL)->render();
723  $keyArray[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
724  <td nowrap="nowrap">' . $HTML . '</td>
725  <td align="center">' . ($row['root'] ? $statusCheckedIcon : '') . '&nbsp;&nbsp;</td>
726  <td align="center">' . ($row['clConf'] ? $statusCheckedIcon : '') . '&nbsp;&nbsp;' . '</td>
727  <td align="center">' . ($row['clConst'] ? $statusCheckedIcon : '') . '&nbsp;&nbsp;' . '</td>
728  <td align="center">' . ($row['pid'] ?: '') . '</td>
729  <td align="center">' . ($RL >= 0 ? $RL : '') . '</td>
730  <td>' . ($row['next'] ? '&nbsp;' . $row['next'] . '&nbsp;&nbsp;' : '') . '</td>
731  </tr>';
732  if ($deeper) {
733  $keyArray = $this->ext_getTemplateHierarchyArr($arr[$key . '.'], $depthData . ($first ? '' : '<span class="treeline-icon treeline-icon-' . $LN . '"></span>'), $keyArray);
734  }
735  }
736  return $keyArray;
737  }
738 
747  public function ext_process_hierarchyInfo(array $depthDataArr, &$pointer)
748  {
749  $parent = $this->hierarchyInfo[$pointer - 1]['templateParent'];
750  while ($pointer > 0 && $this->hierarchyInfo[$pointer - 1]['templateParent'] == $parent) {
751  $pointer--;
752  $row = $this->hierarchyInfo[$pointer];
753  $depthDataArr[$row['templateID']] = $row;
754  $depthDataArr[$row['templateID']]['bgcolor_setup'] = isset($this->clearList_setup_temp[$row['templateID']]) ? ' class="bgColor5"' : '';
755  $depthDataArr[$row['templateID']]['bgcolor_const'] = isset($this->clearList_const_temp[$row['templateID']]) ? ' class="bgColor5"' : '';
756  unset($this->clearList_setup_temp[$row['templateID']]);
757  unset($this->clearList_const_temp[$row['templateID']]);
758  $this->templateTitles[$row['templateID']] = $row['title'];
759  if ($row['templateID'] == $this->hierarchyInfo[$pointer - 1]['templateParent']) {
760  $depthDataArr[$row['templateID'] . '.'] = $this->ext_process_hierarchyInfo(array(), $pointer);
761  }
762  }
763  return $depthDataArr;
764  }
765 
777  public function ext_outputTS(
778  array $config, $lineNumbers = false, $comments = false, $crop = false, $syntaxHL = false, $syntaxHLBlockmode = 0
779  ) {
780  $all = '';
781  foreach ($config as $str) {
782  $all .= '[GLOBAL]' . LF . $str;
783  }
784  if ($syntaxHL) {
785  $tsparser = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
786  $tsparser->lineNumberOffset = $this->ext_lineNumberOffset + 1;
787  $tsparser->parentObject = $this;
788  return $tsparser->doSyntaxHighlight($all, $lineNumbers ? array($this->ext_lineNumberOffset + 1) : '', $syntaxHLBlockmode);
789  } else {
790  return $this->ext_formatTS($all, $lineNumbers, $comments, $crop);
791  }
792  }
793 
803  public function ext_fixed_lgd($string, $chars)
804  {
805  if ($chars >= 4) {
806  if (strlen($string) > $chars) {
807  if (strlen($string) > 24 && substr($string, 0, 12) == '##' . $this->Cmarker . '_B##') {
808  return '##' . $this->Cmarker . '_B##' . GeneralUtility::fixed_lgd_cs(substr($string, 12, -12), ($chars - 3))
809  . '##' . $this->Cmarker . '_E##';
810  } else {
811  return GeneralUtility::fixed_lgd_cs($string, $chars - 3);
812  }
813  }
814  }
815  return $string;
816  }
817 
823  public function ext_lnBreakPointWrap($lineNumber, $str)
824  {
825  return '<a href="#" id="line-' . $lineNumber . '" onClick="return brPoint(' . $lineNumber . ','
826  . ($this->ext_lineNumberOffset_mode == 'setup' ? 1 : 0) . ');">' . $str . '</a>';
827  }
828 
836  public function ext_formatTS($input, $ln, $comments = true, $crop = false)
837  {
838  $cArr = explode(LF, $input);
839  $n = ceil(log10(count($cArr) + $this->ext_lineNumberOffset));
840  $lineNum = '';
841  foreach ($cArr as $k => $v) {
842  $lln = $k + $this->ext_lineNumberOffset + 1;
843  if ($ln) {
844  $lineNum = $this->ext_lnBreakPointWrap($lln, str_replace(' ', '&nbsp;', sprintf(('% ' . $n . 'd'), $lln))) . ': ';
845  }
846  $v = htmlspecialchars($v);
847  if ($crop) {
848  $v = $this->ext_fixed_lgd($v, $ln ? 71 : 77);
849  }
850  $cArr[$k] = $lineNum . str_replace(' ', '&nbsp;', $v);
851  $firstChar = substr(trim($v), 0, 1);
852  if ($firstChar == '[') {
853  $cArr[$k] = '<strong class="text-success">' . $cArr[$k] . '</strong>';
854  } elseif ($firstChar == '/' || $firstChar == '#') {
855  if ($comments) {
856  $cArr[$k] = '<span class="text-muted">' . $cArr[$k] . '</span>';
857  } else {
858  unset($cArr[$k]);
859  }
860  }
861  }
862  $output = implode($cArr, '<br />') . '<br />';
863  return $output;
864  }
865 
871  public function ext_getFirstTemplate($id, $template_uid = 0)
872  {
873  // Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
874  if ((int)$id) {
875  $addC = $template_uid ? ' AND uid=' . (int)$template_uid : '';
876  $where = 'pid=' . (int)$id . $addC . ' ' . $this->whereClause;
877  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'sys_template', $where, '', 'sorting', '1');
878  $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
879  BackendUtility::workspaceOL('sys_template', $row);
880  $this->getDatabaseConnection()->sql_free_result($res);
881  // Returns the template row if found.
882  return $row;
883  }
884  return null;
885  }
886 
891  public function ext_getAllTemplates($id)
892  {
893  if (!$id) {
894  return array();
895  }
896 
897  // Query is taken from the runThroughTemplates($theRootLine) function in the parent class.
898  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'sys_template', 'pid=' . (int)$id . ' ' . $this->whereClause, '', 'sorting');
899 
900  $outRes = array();
901  while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
902  BackendUtility::workspaceOL('sys_template', $row);
903  if (is_array($row)) {
904  $outRes[] = $row;
905  }
906  }
907  $this->getDatabaseConnection()->sql_free_result($res);
908 
909  return $outRes;
910  }
911 
919  public function ext_compareFlatSetups($default)
920  {
921  $editableComments = array();
922  foreach ($this->flatSetup as $const => $value) {
923  if (substr($const, -2) === '..' || !isset($this->flatSetup[$const . '..'])) {
924  continue;
925  }
926  $comment = trim($this->flatSetup[$const . '..']);
927  $c_arr = explode(LF, $comment);
928  foreach ($c_arr as $k => $v) {
929  $line = trim(preg_replace('/^[#\\/]*/', '', $v));
930  if (!$line) {
931  continue;
932  }
933  $parts = explode(';', $line);
934  foreach ($parts as $par) {
935  if (strstr($par, '=')) {
936  $keyValPair = explode('=', $par, 2);
937  switch (trim(strtolower($keyValPair[0]))) {
938  case 'type':
939  // Type:
940  $editableComments[$const]['type'] = trim($keyValPair[1]);
941  break;
942  case 'cat':
943  // List of categories.
944  $catSplit = explode('/', strtolower($keyValPair[1]));
945  $catSplit[0] = trim($catSplit[0]);
946  if (isset($this->categoryLabels[$catSplit[0]])) {
947  $catSplit[0] = $this->categoryLabels[$catSplit[0]];
948  }
949  $editableComments[$const]['cat'] = $catSplit[0];
950  // This is the subcategory. Must be a key in $this->subCategories[].
951  // catSplit[2] represents the search-order within the subcat.
952  $catSplit[1] = trim($catSplit[1]);
953  if ($catSplit[1] && isset($this->subCategories[$catSplit[1]])) {
954  $editableComments[$const]['subcat_name'] = $catSplit[1];
955  $editableComments[$const]['subcat'] = $this->subCategories[$catSplit[1]][1]
956  . '/' . $catSplit[1] . '/' . trim($catSplit[2]) . 'z';
957  } else {
958  $editableComments[$const]['subcat'] = 'x' . '/' . trim($catSplit[2]) . 'z';
959  }
960  break;
961  case 'label':
962  // Label
963  $editableComments[$const]['label'] = trim($keyValPair[1]);
964  break;
965  case 'customcategory':
966  // Custom category label
967  $customCategory = explode('=', $keyValPair[1], 2);
968  if (trim($customCategory[0])) {
969  $categoryKey = strtolower($customCategory[0]);
970  $this->categoryLabels[$categoryKey] = $this->getLanguageService()->sL($customCategory[1]);
971  }
972  break;
973  case 'customsubcategory':
974  // Custom subCategory label
975  $customSubcategory = explode('=', $keyValPair[1], 2);
976  if (trim($customSubcategory[0])) {
977  $subCategoryKey = strtolower($customSubcategory[0]);
978  $this->subCategories[$subCategoryKey][0] = $this->getLanguageService()->sL($customSubcategory[1]);
979  }
980  break;
981  }
982  }
983  }
984  }
985  if (isset($editableComments[$const])) {
986  $editableComments[$const]['name'] = $const;
987  $editableComments[$const]['value'] = trim($value);
988  if (isset($default[$const])) {
989  $editableComments[$const]['default_value'] = trim($default[$const]);
990  }
991  }
992  }
993  return $editableComments;
994  }
995 
1000  public function ext_categorizeEditableConstants($editConstArray)
1001  {
1002  // Runs through the available constants and fills the $this->categories array with pointers and priority-info
1003  foreach ($editConstArray as $constName => $constData) {
1004  if (!$constData['type']) {
1005  $constData['type'] = 'string';
1006  }
1007  $cats = explode(',', $constData['cat']);
1008  // if = only one category, while allows for many. We have agreed on only one category is the most basic way...
1009  foreach ($cats as $theCat) {
1010  $theCat = trim($theCat);
1011  if ($theCat) {
1012  $this->categories[$theCat][$constName] = $constData['subcat'];
1013  }
1014  }
1015  }
1016  }
1017 
1021  public function ext_getCategoryLabelArray()
1022  {
1023  // Returns array used for labels in the menu.
1024  $retArr = array();
1025  foreach ($this->categories as $k => $v) {
1026  if (!empty($v)) {
1027  $retArr[$k] = strtoupper($k) . ' (' . count($v) . ')';
1028  }
1029  }
1030  return $retArr;
1031  }
1032 
1037  public function ext_getTypeData($type)
1038  {
1039  $retArr = array();
1040  $type = trim($type);
1041  if (!$type) {
1042  $retArr['type'] = 'string';
1043  } else {
1044  $m = strcspn($type, ' [');
1045  $retArr['type'] = strtolower(substr($type, 0, $m));
1046  if (GeneralUtility::inList('int,options,file,boolean,offset,user', $retArr['type'])) {
1047  $p = trim(substr($type, $m));
1048  $reg = array();
1049  preg_match('/\\[(.*)\\]/', $p, $reg);
1050  $p = trim($reg[1]);
1051  if ($p) {
1052  $retArr['paramstr'] = $p;
1053  switch ($retArr['type']) {
1054  case 'int':
1055  if ($retArr['paramstr'][0] === '-') {
1056  $retArr['params'] = GeneralUtility::intExplode('-', substr($retArr['paramstr'], 1));
1057  $retArr['params'][0] = (int)('-' . $retArr['params'][0]);
1058  } else {
1059  $retArr['params'] = GeneralUtility::intExplode('-', $retArr['paramstr']);
1060  }
1061  $retArr['paramstr'] = $retArr['params'][0] . ' - ' . $retArr['params'][1];
1062  break;
1063  case 'options':
1064  $retArr['params'] = explode(',', $retArr['paramstr']);
1065  break;
1066  }
1067  }
1068  }
1069  }
1070  return $retArr;
1071  }
1072 
1077  public function ext_getTSCE_config($category)
1078  {
1079  $catConf = $this->setup['constants']['TSConstantEditor.'][$category . '.'];
1080  $out = array();
1081  if (is_array($catConf)) {
1082  foreach ($catConf as $key => $val) {
1083  switch ($key) {
1084  case 'image':
1085  $out['imagetag'] = $this->ext_getTSCE_config_image($catConf['image']);
1086  break;
1087  case 'description':
1088  case 'bulletlist':
1089  case 'header':
1090  $out[$key] = $val;
1091  break;
1092  default:
1094  $constRefs = explode(',', $val);
1095  foreach ($constRefs as $const) {
1096  $const = trim($const);
1097  if ($const) {
1098  $out['constants'][$const] .= '<span class="label label-danger">' . $key . '</span>';
1099  }
1100  }
1101  }
1102  }
1103  }
1104  }
1105  $this->helpConfig = $out;
1106  }
1107 
1113  public function ext_getKeyImage($key)
1114  {
1116  return '<span class="label label-danger">' . $key . '</span>';
1117  }
1118 
1123  public function ext_getTSCE_config_image($imgConf)
1124  {
1125  $iFile = null;
1126  $tFile = null;
1127  if (substr($imgConf, 0, 4) == 'gfx/') {
1128  $iFile = $this->ext_localGfxPrefix . $imgConf;
1129  $tFile = $this->ext_localWebGfxPrefix . $imgConf;
1130  } elseif (substr($imgConf, 0, 4) == 'EXT:') {
1131  $iFile = GeneralUtility::getFileAbsFileName($imgConf);
1132  if ($iFile) {
1133  $f = PathUtility::stripPathSitePrefix($iFile);
1134  $tFile = $GLOBALS['BACK_PATH'] . '../' . $f;
1135  }
1136  }
1137  if ($iFile !== null) {
1138  $imageInfo = @getImagesize($iFile);
1139  return '<img src="' . $tFile . '" ' . $imageInfo[3] . '>';
1140  }
1141  return '';
1142  }
1143 
1148  public function ext_fNandV($params)
1149  {
1150  $fN = 'data[' . $params['name'] . ']';
1151  $idName = str_replace('.', '-', $params['name']);
1152  $fV = $params['value'];
1153  // Values entered from the constantsedit cannot be constants! 230502; removed \{ and set {
1154  if (preg_match('/^{[\\$][a-zA-Z0-9\\.]*}$/', trim($fV), $reg)) {
1155  $fV = '';
1156  }
1157  $fV = htmlspecialchars($fV);
1158  return array($fN, $fV, $params, $idName);
1159  }
1160 
1168  public function ext_printFields($theConstants, $category)
1169  {
1170  reset($theConstants);
1171  $output = '';
1172  $subcat = '';
1173  if (is_array($this->categories[$category])) {
1174  $help = $this->helpConfig;
1175  if (!$this->doNotSortCategoriesBeforeMakingForm) {
1176  asort($this->categories[$category]);
1177  }
1179  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
1180  foreach ($this->categories[$category] as $name => $type) {
1181  $params = $theConstants[$name];
1182  if (is_array($params)) {
1183  if ($subcat != $params['subcat_name']) {
1184  $subcat = $params['subcat_name'];
1185  $subcat_name = $params['subcat_name'] ? $this->subCategories[$params['subcat_name']][0] : 'Others';
1186  $output .= '<h3 class="typo3-tstemplate-ceditor-subcat">' . $subcat_name . '</h3>';
1187  }
1188  $label = $this->getLanguageService()->sL($params['label']);
1189  $label_parts = explode(':', $label, 2);
1190  if (count($label_parts) === 2) {
1191  $head = trim($label_parts[0]);
1192  $body = trim($label_parts[1]);
1193  } else {
1194  $head = trim($label_parts[0]);
1195  $body = '';
1196  }
1197  if (strlen($head) > 35) {
1198  if (!$body) {
1199  $body = $head;
1200  }
1201  $head = GeneralUtility::fixed_lgd_cs($head, 35);
1202  }
1203  $typeDat = $this->ext_getTypeData($params['type']);
1204  $p_field = '';
1205  $raname = substr(md5($params['name']), 0, 10);
1206  $aname = '\'' . $raname . '\'';
1207  list($fN, $fV, $params, $idName) = $this->ext_fNandV($params);
1208  $idName = htmlspecialchars($idName);
1209  $hint = '';
1210  switch ($typeDat['type']) {
1211  case 'int':
1212  case 'int+':
1213  if ($typeDat['paramstr']) {
1214  $hint = ' Range: ' . $typeDat['paramstr'];
1215  } elseif ($typeDat['type'] === 'int+') {
1216  $hint = ' Range: 0 - ';
1217  } else {
1218  $hint = ' (Integer)';
1219  }
1220 
1221  $p_field =
1222  '<input class="form-control" id="' . $idName . '" type="text"'
1223  . ' name="' . $fN . '" value="' . $fV . '"' . ' onChange="uFormUrl(' . $aname . ')" />';
1224  break;
1225  case 'color':
1226  $colorNames = explode(',', ',' . $this->HTMLcolorList);
1227  $p_field = '';
1228  foreach ($colorNames as $val) {
1229  $sel = '';
1230  if ($val == strtolower($params['value'])) {
1231  $sel = ' selected';
1232  }
1233  $p_field .= '<option value="' . htmlspecialchars($val) . '"' . $sel . '>' . $val . '</option>';
1234  }
1235  $p_field = '<select class="form-control t3js-color-select" id="select-' . $idName . '" rel="' . $idName . '" name="C' . $fN . '" onChange="uFormUrl(' . $aname . ');"' . $this->getDocumentTemplate()->formWidth(7) . '>' . $p_field . '</select>';
1236  $p_field .= '<input class="form-control t3js-color-input" type="text" id="input-' . $idName . '" rel="' . $idName . '" name="' . $fN . '" value="' . $fV . '"' . $this->getDocumentTemplate()->formWidth(7) . ' onChange="uFormUrl(' . $aname . ')" />';
1237  break;
1238  case 'wrap':
1239  $wArr = explode('|', $fV);
1240  $p_field = '<input class="form-control" type="text" id="' . $idName . '" name="' . $fN . '" value="' . $wArr[0] . '"' . $this->getDocumentTemplate()->formWidth(29) . ' onChange="uFormUrl(' . $aname . ')" />';
1241  $p_field .= ' | ';
1242  $p_field .= '<input class="form-control" type="text" name="W' . $fN . '" value="' . $wArr[1] . '"' . $this->getDocumentTemplate()->formWidth(15) . ' onChange="uFormUrl(' . $aname . ')" />';
1243  break;
1244  case 'offset':
1245  $wArr = explode(',', $fV);
1246  $labels = GeneralUtility::trimExplode(',', $typeDat['paramstr']);
1247  $p_field = ($labels[0] ? $labels[0] : 'x') . ':<input type="text" name="' . $fN . '" value="' . $wArr[0] . '"' . $this->getDocumentTemplate()->formWidth(4) . ' onChange="uFormUrl(' . $aname . ')" />';
1248  $p_field .= ' , ';
1249  $p_field .= ($labels[1] ? $labels[1] : 'y') . ':<input type="text" name="W' . $fN . '" value="' . $wArr[1] . '"' . $this->getDocumentTemplate()->formWidth(4) . ' onChange="uFormUrl(' . $aname . ')" />';
1250  $labelsCount = count($labels);
1251  for ($aa = 2; $aa < $labelsCount; $aa++) {
1252  if ($labels[$aa]) {
1253  $p_field .= ' , ' . $labels[$aa] . ':<input type="text" name="W' . $aa . $fN . '" value="' . $wArr[$aa] . '"' . $this->getDocumentTemplate()->formWidth(4) . ' onChange="uFormUrl(' . $aname . ')" />';
1254  } else {
1255  $p_field .= '<input type="hidden" name="W' . $aa . $fN . '" value="' . $wArr[$aa] . '" />';
1256  }
1257  }
1258  break;
1259  case 'options':
1260  if (is_array($typeDat['params'])) {
1261  $p_field = '';
1262  foreach ($typeDat['params'] as $val) {
1263  $vParts = explode('=', $val, 2);
1264  $label = $vParts[0];
1265  $val = isset($vParts[1]) ? $vParts[1] : $vParts[0];
1266  // option tag:
1267  $sel = '';
1268  if ($val === $params['value']) {
1269  $sel = ' selected';
1270  }
1271  $p_field .= '<option value="' . htmlspecialchars($val) . '"' . $sel . '>' . $this->getLanguageService()->sL($label) . '</option>';
1272  }
1273  $p_field = '<select class="form-control" id="' . $idName . '" name="' . $fN . '" onChange="uFormUrl(' . $aname . ')">' . $p_field . '</select>';
1274  }
1275  break;
1276  case 'boolean':
1277  $sel = $fV ? 'checked' : '';
1278  $p_field =
1279  '<label class="btn btn-default btn-checkbox">'
1280  . '<input type="hidden" name="' . $fN . '" value="0" />'
1281  . '<input id="' . $idName . '" type="checkbox" name="' . $fN . '" value="' . ($typeDat['paramstr'] ? $typeDat['paramstr'] : 1) . '" ' . $sel . ' onClick="uFormUrl(' . $aname . ')" />'
1282  . '<span class="t3-icon fa"></span>'
1283  . '</label>';
1284  break;
1285  case 'comment':
1286  $sel = $fV ? 'checked' : '';
1287  $p_field =
1288  '<label class="btn btn-default btn-checkbox">'
1289  . '<input type="hidden" name="' . $fN . '" value="#" />'
1290  . '<input id="' . $idName . '" type="checkbox" name="' . $fN . '" value="" ' . $sel . ' onClick="uFormUrl(' . $aname . ')" />'
1291  . '<span class="t3-icon fa"></span>'
1292  . '</label>';
1293  break;
1294  case 'file':
1295  // extensionlist
1296  $extList = $typeDat['paramstr'];
1297  if ($extList === 'IMAGE_EXT') {
1298  $extList = $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'];
1299  }
1300  $p_field = '<option value="">(' . $extList . ')</option>';
1301  if (trim($params['value'])) {
1302  $val = $params['value'];
1303  $p_field .= '<option value=""></option>';
1304  $p_field .= '<option value="' . htmlspecialchars($val) . '" selected>' . $val . '</option>';
1305  }
1306  $p_field = '<select class="form-select" id="' . $idName . '" name="' . $fN . '" onChange="uFormUrl(' . $aname . ')">' . $p_field . '</select>';
1307  break;
1308  case 'user':
1309  $userFunction = $typeDat['paramstr'];
1310  $userFunctionParams = array('fieldName' => $fN, 'fieldValue' => $fV);
1311  $p_field = GeneralUtility::callUserFunction($userFunction, $userFunctionParams, $this, '');
1312  break;
1313  case 'small':
1314 
1315  default:
1316  $p_field = '<input class="form-control" id="' . $idName . '" type="text" name="' . $fN . '" value="' . $fV . '"'
1317  . ' onChange="uFormUrl(' . $aname . ')" />';
1318  }
1319  // Define default names and IDs
1320  $userTyposcriptID = 'userTS-' . $idName;
1321  $defaultTyposcriptID = 'defaultTS-' . $idName;
1322  $checkboxName = 'check[' . $params['name'] . ']';
1323  $checkboxID = 'check-' . $idName;
1324  // Handle type=color specially
1325  if ($typeDat['type'] === 'color' && substr($params['value'], 0, 2) != '{$') {
1326  $appendedGroupAddon = '<span class="input-group-addon colorbox" id="colorbox-' . $idName . '" class="typo3-tstemplate-ceditor-colorblock" style="background-color:' . $params['value'] . ';"></span>';
1327  } else {
1328  $appendedGroupAddon = '';
1329  }
1330  $userTyposcriptStyle = '';
1331  $deleteIconHTML = '';
1332  $constantCheckbox = '';
1333  $constantDefaultRow = '';
1334  if (!$this->ext_dontCheckIssetValues) {
1335  // Set the default styling options
1336  if (isset($this->objReg[$params['name']])) {
1337  $checkboxValue = 'checked';
1338  $defaultTyposcriptStyle = 'style="display:none;"';
1339  } else {
1340  $checkboxValue = '';
1341  $userTyposcriptStyle = 'style="display:none;"';
1342  $defaultTyposcriptStyle = '';
1343  }
1344  $deleteTitle = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.deleteTitle', true);
1345  $deleteIcon = $iconFactory->getIcon('actions-edit-undo', Icon::SIZE_SMALL)->render();
1346  $deleteIconHTML =
1347  '<button type="button" class="btn btn-default t3js-toggle" data-toggle="undo" rel="' . $idName . '">'
1348  . '<span title="' . $deleteTitle . '" alt="' . $deleteTitle . '">'
1349  . $deleteIcon
1350  . '</span>'
1351  . '</button>';
1352  $editTitle = $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.editTitle', true);
1353  $editIcon = $iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render();
1354  $editIconHTML =
1355  '<button type="button" class="btn btn-default t3js-toggle" data-toggle="edit" rel="' . $idName . '">'
1356  . '<span title="' . $editTitle . '" alt="' . $editTitle . '">'
1357  . $editIcon
1358  . '</span>'
1359  . '</button>';
1360  $constantCheckbox = '<input type="hidden" name="' . $checkboxName . '" id="' . $checkboxID . '" value="' . $checkboxValue . '"/>';
1361  // If there's no default value for the field, use a static label.
1362  if (!$params['default_value']) {
1363  $params['default_value'] = '[Empty]';
1364  }
1365  $constantDefaultRow =
1366  '<div class="input-group defaultTS" id="' . $defaultTyposcriptID . '" ' . $defaultTyposcriptStyle . '>'
1367  . '<span class="input-group-btn">' . $editIconHTML . '</span>'
1368  . '<input class="form-control" type="text" placeholder="' . htmlspecialchars($params['default_value']) . '" readonly>'
1369  . $appendedGroupAddon
1370  . '</div>';
1371  }
1372  $constantEditRow =
1373  '<div class="input-group userTS" id="' . $userTyposcriptID . '" ' . $userTyposcriptStyle . '>'
1374  . '<span class="input-group-btn">' . $deleteIconHTML . '</span>'
1375  . $p_field
1376  . $appendedGroupAddon
1377  . '</div>';
1378  $constantLabel = '<label class="t3js-formengine-label"><span>' . htmlspecialchars($head) . '</span></label>';
1379  $constantName = '<span class="help-block">[' . $params['name'] . ']</span>';
1380  $constantDescription = $body ? '<p class="help-block">' . htmlspecialchars($body) . '</p>' : '';
1381  $constantData = '';
1382  if ($hint !== '') {
1383  $constantData .= '<span class="help-block">' . $hint . '</span>';
1384  }
1385  $constantData .=
1386  $constantCheckbox
1387  . $constantEditRow
1388  . $constantDefaultRow;
1389 
1390  $output .=
1391  '<fieldset class="form-section">'
1392  . '<a name="' . $raname . '"></a>' . $help['constants'][$params['name']]
1393  . '<div class="form-group">'
1394  . $constantLabel . $constantName . $constantDescription . $constantData
1395  . '</div>'
1396  . '</fieldset>';
1397  } else {
1398  debug('Error. Constant did not exist. Should not happen.');
1399  }
1400  }
1401  }
1402  return '<div class="tstemplate-constanteditor">' . $output . '</div>';
1403  }
1404 
1405  /***************************
1406  *
1407  * Processing input values
1408  *
1409  ***************************/
1415  {
1416  // This runs through the lines of the constants-field of the active template and registers the constants-names
1417  // and line positions in an array, $this->objReg
1418  $this->raw = explode(LF, $constants);
1419  $this->rawP = 0;
1420  // Resetting the objReg if the divider is found!!
1421  $this->objReg = array();
1422  $this->ext_regObjects('');
1423  }
1424 
1429  public function ext_regObjects($pre)
1430  {
1431  // Works with regObjectPositions. "expands" the names of the TypoScript objects
1432  while (isset($this->raw[$this->rawP])) {
1433  $line = ltrim($this->raw[$this->rawP]);
1434  if (strstr($line, $this->edit_divider)) {
1435  // Resetting the objReg if the divider is found!!
1436  $this->objReg = array();
1437  }
1438  $this->rawP++;
1439  if ($line) {
1440  if ($line[0] === '[') {
1441  } elseif (strcspn($line, '}#/') != 0) {
1442  $varL = strcspn($line, ' {=<');
1443  $var = substr($line, 0, $varL);
1444  $line = ltrim(substr($line, $varL));
1445  switch ($line[0]) {
1446  case '=':
1447  $this->objReg[$pre . $var] = $this->rawP - 1;
1448  break;
1449  case '{':
1450  $this->ext_inBrace++;
1451  $this->ext_regObjects($pre . $var . '.');
1452  break;
1453  }
1454  $this->lastComment = '';
1455  } elseif ($line[0] === '}') {
1456  $this->lastComment = '';
1457  $this->ext_inBrace--;
1458  if ($this->ext_inBrace < 0) {
1459  $this->ext_inBrace = 0;
1460  } else {
1461  break;
1462  }
1463  }
1464  }
1465  }
1466  }
1467 
1473  public function ext_putValueInConf($key, $var)
1474  {
1475  // Puts the value $var to the TypoScript value $key in the current lines of the templates.
1476  // If the $key is not found in the template constants field, a new line is inserted in the bottom.
1477  $theValue = ' ' . trim($var);
1478  if (isset($this->objReg[$key])) {
1479  $lineNum = $this->objReg[$key];
1480  $parts = explode('=', $this->raw[$lineNum], 2);
1481  if (count($parts) === 2) {
1482  $parts[1] = $theValue;
1483  }
1484  $this->raw[$lineNum] = implode($parts, '=');
1485  } else {
1486  $this->raw[] = $key . ' =' . $theValue;
1487  }
1488  $this->changed = true;
1489  }
1490 
1495  public function ext_removeValueInConf($key)
1496  {
1497  // Removes the value in the configuration
1498  if (isset($this->objReg[$key])) {
1499  $lineNum = $this->objReg[$key];
1500  unset($this->raw[$lineNum]);
1501  }
1502  $this->changed = true;
1503  }
1504 
1510  public function ext_depthKeys($arr, $settings)
1511  {
1512  $tsbrArray = array();
1513  foreach ($arr as $theK => $theV) {
1514  $theKeyParts = explode('.', $theK);
1515  $depth = '';
1516  $c = count($theKeyParts);
1517  $a = 0;
1518  foreach ($theKeyParts as $p) {
1519  $a++;
1520  $depth .= ($depth ? '.' : '') . $p;
1521  $tsbrArray[$depth] = $c == $a ? $theV : 1;
1522  }
1523  }
1524  // Modify settings
1525  foreach ($tsbrArray as $theK => $theV) {
1526  if ($theV) {
1527  $settings[$theK] = 1;
1528  } else {
1529  unset($settings[$theK]);
1530  }
1531  }
1532  return $settings;
1533  }
1534 
1544  public function ext_procesInput($http_post_vars, $http_post_files, $theConstants, $tplRow)
1545  {
1546  $data = $http_post_vars['data'];
1547  $check = $http_post_vars['check'];
1548  $Wdata = $http_post_vars['Wdata'];
1549  $W2data = $http_post_vars['W2data'];
1550  $W3data = $http_post_vars['W3data'];
1551  $W4data = $http_post_vars['W4data'];
1552  $W5data = $http_post_vars['W5data'];
1553  if (is_array($data)) {
1554  foreach ($data as $key => $var) {
1555  if (isset($theConstants[$key])) {
1556  // If checkbox is set, update the value
1557  if ($this->ext_dontCheckIssetValues || isset($check[$key])) {
1558  // Exploding with linebreak, just to make sure that no multiline input is given!
1559  list($var) = explode(LF, $var);
1560  $typeDat = $this->ext_getTypeData($theConstants[$key]['type']);
1561  switch ($typeDat['type']) {
1562  case 'int':
1563  if ($typeDat['paramstr']) {
1564  $var = MathUtility::forceIntegerInRange($var, $typeDat['params'][0], $typeDat['params'][1]);
1565  } else {
1566  $var = (int)$var;
1567  }
1568  break;
1569  case 'int+':
1570  $var = max(0, (int)$var);
1571  break;
1572  case 'color':
1573  $col = array();
1574  if ($var && !GeneralUtility::inList($this->HTMLcolorList, strtolower($var))) {
1575  $var = preg_replace('/[^A-Fa-f0-9]*/', '', $var);
1576  $useFulHex = strlen($var) > 3;
1577  $col[] = HexDec($var[0]);
1578  $col[] = HexDec($var[1]);
1579  $col[] = HexDec($var[2]);
1580  if ($useFulHex) {
1581  $col[] = HexDec($var[3]);
1582  $col[] = HexDec($var[4]);
1583  $col[] = HexDec($var[5]);
1584  }
1585  $var = substr(('0' . DecHex($col[0])), -1) . substr(('0' . DecHex($col[1])), -1) . substr(('0' . DecHex($col[2])), -1);
1586  if ($useFulHex) {
1587  $var .= substr(('0' . DecHex($col[3])), -1) . substr(('0' . DecHex($col[4])), -1) . substr(('0' . DecHex($col[5])), -1);
1588  }
1589  $var = '#' . strtoupper($var);
1590  }
1591  break;
1592  case 'comment':
1593  if ($var) {
1594  $var = '#';
1595  } else {
1596  $var = '';
1597  }
1598  break;
1599  case 'wrap':
1600  if (isset($Wdata[$key])) {
1601  $var .= '|' . $Wdata[$key];
1602  }
1603  break;
1604  case 'offset':
1605  if (isset($Wdata[$key])) {
1606  $var = (int)$var . ',' . (int)$Wdata[$key];
1607  if (isset($W2data[$key])) {
1608  $var .= ',' . (int)$W2data[$key];
1609  if (isset($W3data[$key])) {
1610  $var .= ',' . (int)$W3data[$key];
1611  if (isset($W4data[$key])) {
1612  $var .= ',' . (int)$W4data[$key];
1613  if (isset($W5data[$key])) {
1614  $var .= ',' . (int)$W5data[$key];
1615  }
1616  }
1617  }
1618  }
1619  }
1620  break;
1621  case 'boolean':
1622  if ($var) {
1623  $var = $typeDat['paramstr'] ? $typeDat['paramstr'] : 1;
1624  }
1625  break;
1626  }
1627  if ($this->ext_printAll || (string)$theConstants[$key]['value'] !== (string)$var) {
1628  // Put value in, if changed.
1629  $this->ext_putValueInConf($key, $var);
1630  }
1631  // Remove the entry because it has been "used"
1632  unset($check[$key]);
1633  } else {
1634  $this->ext_removeValueInConf($key);
1635  }
1636  }
1637  }
1638  }
1639  // Remaining keys in $check indicates fields that are just clicked "on" to be edited.
1640  // Therefore we get the default value and puts that in the template as a start...
1641  if (!$this->ext_dontCheckIssetValues && is_array($check)) {
1642  foreach ($check as $key => $var) {
1643  if (isset($theConstants[$key])) {
1644  $dValue = $theConstants[$key]['default_value'];
1645  $this->ext_putValueInConf($key, $dValue);
1646  }
1647  }
1648  }
1649  }
1650 
1656  public function ext_prevPageWithTemplate($id, $perms_clause)
1657  {
1658  $rootLine = BackendUtility::BEgetRootLine($id, $perms_clause ? ' AND ' . $perms_clause : '');
1659  foreach ($rootLine as $p) {
1660  if ($this->ext_getFirstTemplate($p['uid'])) {
1661  return $p;
1662  }
1663  }
1664  return array();
1665  }
1666 
1670  protected function getRootLine()
1671  {
1672  return isset($GLOBALS['rootLine']) ? $GLOBALS['rootLine'] : array();
1673  }
1674 
1678  protected function getDatabaseConnection()
1679  {
1680  return $GLOBALS['TYPO3_DB'];
1681  }
1682 
1686  protected function getLanguageService()
1687  {
1688  return $GLOBALS['LANG'];
1689  }
1690 
1694  protected function getDocumentTemplate()
1695  {
1696  return $GLOBALS['TBE_TEMPLATE'];
1697  }
1698 }