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