[TASK] BACK_PATH BE controller
[Packages/TYPO3.CMS.git] / typo3 / sysext / tstemplate / Classes / Controller / TypoScriptTemplateModuleController.php
1 <?php
2 namespace TYPO3\CMS\Tstemplate\Controller;
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
17 use TYPO3\CMS\Backend\Module\BaseScriptClass;
18 use TYPO3\CMS\Backend\Template\DocumentTemplate;
19 use TYPO3\CMS\Core\DataHandling\DataHandler;
20 use TYPO3\CMS\Core\Imaging\Icon;
21 use TYPO3\CMS\Core\Imaging\IconFactory;
22 use TYPO3\CMS\Core\Messaging\FlashMessage;
23 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Backend\Utility\BackendUtility;
26 use TYPO3\CMS\Backend\Utility\IconUtility;
27 use TYPO3\CMS\Core\Utility\MathUtility;
28 use TYPO3\CMS\Extbase\Object\ObjectManager;
29 use TYPO3\CMS\Fluid\View\StandaloneView;
30 use TYPO3\CMS\Fluid\ViewHelpers\Be\InfoboxViewHelper;
31
32 /**
33 * Module: TypoScript Tools
34 *
35 * $TYPO3_CONF_VARS["MODS"]["web_ts"]["onlineResourceDir"] = Directory of default resources. Eg. "fileadmin/res/" or so.
36 */
37 class TypoScriptTemplateModuleController extends BaseScriptClass {
38
39 /**
40 * @var string
41 */
42 public $perms_clause;
43
44 /**
45 * @var string
46 */
47 public $e;
48
49 /**
50 * @var string
51 */
52 public $sObj;
53
54 /**
55 * @var string
56 */
57 public $edit;
58
59 /**
60 * @var string
61 */
62 public $textExtensions = 'html,htm,txt,css,tmpl,inc,js';
63
64 /**
65 * @var string
66 */
67 public $modMenu_type = '';
68
69 /**
70 * @var string
71 */
72 public $modMenu_dontValidateList = '';
73
74 /**
75 * @var string
76 */
77 public $modMenu_setDefaultList = '';
78
79 /**
80 * @var array
81 */
82 public $pageinfo = array();
83
84 /**
85 * @var bool
86 */
87 public $access = FALSE;
88
89 /**
90 * The name of the module
91 *
92 * @var string
93 */
94 protected $moduleName = 'web_ts';
95
96 /**
97 * @var IconFactory
98 */
99 protected $iconFactory;
100
101 /**
102 * Constructor
103 */
104 public function __construct() {
105 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
106 $this->getLanguageService()->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang.xlf');
107
108 $this->MCONF = array(
109 'name' => $this->moduleName
110 );
111 }
112
113 /**
114 * Init
115 *
116 * @return void
117 */
118 public function init() {
119 parent::init();
120 $this->id = (int)GeneralUtility::_GP('id');
121 $this->e = GeneralUtility::_GP('e');
122 $this->sObj = GeneralUtility::_GP('sObj');
123 $this->edit = GeneralUtility::_GP('edit');
124 $this->perms_clause = $this->getBackendUser()->getPagePermsClause(1);
125 }
126
127 /**
128 * Clear cache
129 *
130 * @return void
131 */
132 public function clearCache() {
133 if (GeneralUtility::_GP('clear_all_cache')) {
134 /** @var DataHandler $tce */
135 $tce = GeneralUtility::makeInstance(DataHandler::class);
136 $tce->stripslashes_values = FALSE;
137 $tce->start(array(), array());
138 $tce->clear_cacheCmd('all');
139 }
140 }
141
142 /**
143 * Main
144 *
145 * @return void
146 */
147 public function main() {
148 // Template markers
149 $markers = array(
150 'CSH' => '',
151 'FUNC_MENU' => '',
152 'CONTENT' => ''
153 );
154
155 // Access check...
156 // The page will show only if there is a valid page and if this page may be viewed by the user
157 $this->pageinfo = BackendUtility::readPageAccess($this->id, $this->perms_clause);
158 $this->access = is_array($this->pageinfo);
159
160 /** @var DocumentTemplate doc */
161 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
162 $this->doc->setModuleTemplate('EXT:tstemplate/Resources/Private/Templates/tstemplate.html');
163 $this->doc->addStyleSheet('module', 'sysext/tstemplate/Resources/Public/Css/styles.css');
164
165 $lang = $this->getLanguageService();
166
167 if ($this->id && $this->access) {
168 $urlParameters = array(
169 'id' => $this->id,
170 'template' => 'all'
171 );
172 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
173 $this->doc->form = '<form action="' . htmlspecialchars($aHref) . '" method="post" enctype="multipart/form-data" name="editForm" class="form">';
174
175 // JavaScript
176 $this->doc->JScode = '
177 <script language="javascript" type="text/javascript">
178 function uFormUrl(aname) {
179 document.forms[0].action = ' . GeneralUtility::quoteJSvalue(($aHref . '#'), TRUE) . '+aname;
180 }
181 function brPoint(lnumber,t) {
182 window.location.href = ' . GeneralUtility::quoteJSvalue(($aHref . '&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateObjectBrowserModuleFunctionController&SET[ts_browser_type]='), TRUE) . '+(t?"setup":"const")+"&breakPointLN="+lnumber;
183 return false;
184 }
185 </script>
186 ';
187 $this->doc->postCode = '
188 <script language="javascript" type="text/javascript">
189 if (top.fsMod) top.fsMod.recentIds["web"] = ' . $this->id . ';
190 </script>
191 ';
192 $this->doc->inDocStylesArray[] = '
193 TABLE#typo3-objectBrowser { width: 100%; margin-bottom: 24px; }
194 TABLE#typo3-objectBrowser A { text-decoration: none; }
195 TABLE#typo3-objectBrowser .comment { color: maroon; font-weight: bold; }
196 .ts-typoscript { width: 100%; }
197 .tsob-search-submit {margin-left: 3px; margin-right: 3px;}
198 .tst-analyzer-options { margin:5px 0; }
199 ';
200 // Setting up the context sensitive menu:
201 $this->doc->getContextMenuCode();
202 // Build the modulle content
203 $this->content = $this->doc->header($lang->getLL('moduleTitle'));
204 $this->extObjContent();
205 // Setting up the buttons and markers for docheader
206 $docHeaderButtons = $this->getButtons();
207 $markers['FUNC_MENU'] = BackendUtility::getFuncMenu($this->id, 'SET[function]', $this->MOD_SETTINGS['function'], $this->MOD_MENU['function']);
208 $markers['CONTENT'] = $this->content;
209 } else {
210 // Template pages:
211 $records = $this->getDatabaseConnection()->exec_SELECTgetRows(
212 'pages.uid, count(*) AS count, max(sys_template.root) AS root_max_val, min(sys_template.root) AS root_min_val',
213 'pages,sys_template',
214 'pages.uid=sys_template.pid'
215 . BackendUtility::deleteClause('pages')
216 . BackendUtility::versioningPlaceholderClause('pages')
217 . BackendUtility::deleteClause('sys_template')
218 . BackendUtility::versioningPlaceholderClause('sys_template'),
219 'pages.uid',
220 'pages.pid, pages.sorting'
221 );
222 $pArray = array();
223 foreach ($records as $record) {
224 $this->setInPageArray($pArray, BackendUtility::BEgetRootLine($record['uid'], 'AND 1=1'), $record);
225 }
226
227 $table = '<div class="table-fit"><table class="table table-striped table-hover" id="ts-overview">' .
228 '<thead>' .
229 '<tr>' .
230 '<th>' . $lang->getLL('pageName') . '</th>' .
231 '<th>' . $lang->getLL('templates') . '</th>' .
232 '<th>' . $lang->getLL('isRoot') . '</th>' .
233 '<th>' . $lang->getLL('isExt') . '</th>' .
234 '</tr>' .
235 '</thead>' .
236 '<tbody>' . implode('', $this->renderList($pArray)) . '</tbody>' .
237 '</table></div>';
238
239 $this->content = $this->doc->header($lang->getLL('moduleTitle'));
240 $this->content .= $this->doc->section('', '<p class="lead">' . $lang->getLL('overview') . '</p>' . $table);
241
242 // RENDER LIST of pages with templates, END
243 // Setting up the buttons and markers for docheader
244 $docHeaderButtons = $this->getButtons();
245 $markers['CONTENT'] = $this->content;
246 }
247
248 // Build the <body> for the module
249 $this->content = $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
250 // Renders the module page
251 $this->content = $this->doc->render('Template Tools', $this->content);
252 }
253
254 /**
255 * Print content
256 *
257 * @return void
258 */
259 public function printContent() {
260 echo $this->content;
261 }
262
263 /**
264 * Create the panel of buttons for submitting the form or otherwise perform operations.
265 *
266 * @return array All available buttons as an assoc. array
267 */
268 protected function getButtons() {
269 $buttons = array(
270 'back' => '',
271 'close' => '',
272 'new' => '',
273 'save' => '',
274 'save_close' => '',
275 'view' => '',
276 'shortcut' => ''
277 );
278
279 $lang = $this->getLanguageService();
280
281 if ($this->id && $this->access) {
282 // View page
283 $buttons['view'] = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($this->pageinfo['uid'], '', BackendUtility::BEgetRootLine($this->pageinfo['uid']))) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
284 if ($this->extClassConf['name'] == TypoScriptTemplateInformationModuleFunctionController::class) {
285 // NEW button
286 $urlParameters = array(
287 'id' => $this->id,
288 'template' => 'all',
289 'createExtension' => 'new'
290 );
291 $buttons['new'] = '<a href="' . htmlspecialchars(BackendUtility::getModuleUrl('web_ts', $urlParameters)) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:db_new.php.pagetitle', TRUE) . '">' . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL) . '</a>';
292 if (!empty($this->e) && !GeneralUtility::_POST('saveclose')) {
293 // no NEW-button while edit
294 $buttons['new'] = '';
295 // SAVE button
296 $buttons['save'] = '<button type="submit" class="c-inputButton" name="submit">'
297 . IconUtility::getSpriteIcon('actions-document-save', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE)))
298 . '</button>';
299 // SAVE AND CLOSE button
300 $buttons['save_close'] = '<button type="submit" class="c-inputButton" name="saveclose">'
301 . IconUtility::getSpriteIcon('actions-document-save-close', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', TRUE)))
302 . '</button>';
303 // CLOSE button
304 $url = BackendUtility::getModuleUrl('web_ts', array('id' => $this->id));
305 $buttons['close'] = '<a href="' . htmlspecialchars($url) . '" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-close') .'</a>';
306 }
307 } elseif ($this->extClassConf['name'] === TypoScriptTemplateConstantEditorModuleFunctionController::class && !empty($this->MOD_MENU['constant_editor_cat'])) {
308 // SAVE button
309 $buttons['save'] = '<button class="c-inputButton" name="submit">'
310 . IconUtility::getSpriteIcon('actions-document-save', array('title' => $lang->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE)))
311 . '</button>';
312 } elseif ($this->extClassConf['name'] === TypoScriptTemplateObjectBrowserModuleFunctionController::class) {
313 if (!empty($this->sObj)) {
314 // BACK
315 $urlParameters = array(
316 'id' => $this->id
317 );
318 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
319 $buttons['back'] = '<a href="' . htmlspecialchars($aHref) . '" class="typo3-goBack" title="' . $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.goBack', TRUE) . '">' . IconUtility::getSpriteIcon('actions-view-go-back') . '</a>';
320 }
321 }
322 // Shortcut
323 if ($this->getBackendUser()->mayMakeShortcut()) {
324 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id, edit_record, pointer, new_unique_uid, search_field, search_levels, showLimit', implode(',', array_keys($this->MOD_MENU)), $this->MCONF['name']);
325 }
326 } else {
327 // Shortcut
328 if ($this->getBackendUser()->mayMakeShortcut()) {
329 $buttons['shortcut'] = $this->doc->makeShortcutIcon('id', '', $this->MCONF['name']);
330 }
331 }
332 return $buttons;
333 }
334
335 // OTHER FUNCTIONS:
336 /**
337 * Wrap title for link in template
338 *
339 * @param string $title
340 * @param string $onlyKey
341 * @return string
342 */
343 public function linkWrapTemplateTitle($title, $onlyKey = '') {
344 $urlParameters = array(
345 'id' => $this->id
346 );
347 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
348 if ($onlyKey) {
349 $title = '<a href="' . htmlspecialchars(($aHref . '&e[' . $onlyKey . ']=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
350 } else {
351 $title = '<a href="' . htmlspecialchars(($aHref . '&e[constants]=1&e[config]=1&SET[function]=TYPO3\\CMS\\Tstemplate\\Controller\\TypoScriptTemplateInformationModuleFunctionController')) . '">' . htmlspecialchars($title) . '</a>';
352 }
353 return $title;
354 }
355
356 /**
357 * No template
358 *
359 * @param int $newStandardTemplate
360 * @return string
361 */
362 public function noTemplate($newStandardTemplate = 0) {
363 // Defined global here!
364 /** @var ExtendedTemplateService $tmpl */
365 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
366 $GLOBALS['tmpl'] = $tmpl;
367
368 // Do not log time-performance information
369 $tmpl->tt_track = FALSE;
370 $tmpl->init();
371
372 $lang = $this->getLanguageService();
373
374 $title = $lang->getLL('noTemplate');
375 $message = '<p>' . $lang->getLL('noTemplateDescription') . '<br />' . $lang->getLL('createTemplateToEditConfiguration') . '</p>';
376
377 $view = GeneralUtility::makeInstance(StandaloneView::class);
378 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:tstemplate/Resources/Private/Templates/InfoBox.html'));
379 $view->assignMultiple(array(
380 'title' => $title,
381 'message' => $message,
382 'state' => InfoboxViewHelper::STATE_INFO
383 ));
384 $theOutput = $view->render();
385
386 // New standard?
387 if ($newStandardTemplate) {
388 // Hook to change output, implemented for statictemplates
389 if (isset(
390 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView']
391 )) {
392 $selector = '';
393 $staticsText = '';
394 $reference = array(
395 'selectorHtml' => &$selector,
396 'staticsText' => &$staticsText
397 );
398 GeneralUtility::callUserFunction(
399 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateView'],
400 $reference,
401 $this
402 );
403 $selector = $reference['selectorHtml'];
404 $staticsText = $reference['staticsText'];
405 } else {
406 $selector = '<input type="hidden" name="createStandard" value="" />';
407 $staticsText = '';
408 }
409 // Extension?
410 $theOutput .= $this->doc->section(
411 $lang->getLL('newWebsite') . $staticsText,
412 '<p>' . $lang->getLL('newWebsiteDescription') . '</p>' . $selector . '<input class="btn btn-primary" type="submit" name="newWebsite" value="' . $lang->getLL('newWebsiteAction') . '" />',
413 0, 1);
414 }
415 // Extension?
416 $theOutput .= $this->doc->section(
417 $lang->getLL('extTemplate'),
418 '<p>' . $lang->getLL('extTemplateDescription') . '</p>' . '<input class="btn btn-default" type="submit" name="createExtension" value="' . $lang->getLL('extTemplateAction') . '" />',
419 0, 1);
420 // Go to first appearing...
421 $first = $tmpl->ext_prevPageWithTemplate($this->id, $this->perms_clause);
422 if ($first) {
423 $urlParameters = array(
424 'id' => $first['uid']
425 );
426 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
427 $theOutput .= $this->doc->section(
428 $lang->getLL('goToClosest'),
429 sprintf('<p>' . $lang->getLL('goToClosestDescription') . '</p>%s' . $lang->getLL('goToClosestAction') . '%s', htmlspecialchars($first['title']), $first['uid'], '<a class="btn btn-default" href="' . htmlspecialchars($aHref) . '">', '</a>'),
430 0, 1);
431 }
432 return $theOutput;
433 }
434
435 /**
436 * Render template menu
437 *
438 * @return string
439 */
440 public function templateMenu() {
441 /** @var ExtendedTemplateService $tmpl */
442 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
443 $GLOBALS['tmpl'] = $tmpl;
444
445 // Do not log time-performance information
446 $tmpl->tt_track = FALSE;
447 $tmpl->init();
448
449 $all = $tmpl->ext_getAllTemplates($this->id, $this->perms_clause);
450 if (count($all) > 1) {
451 $this->MOD_MENU['templatesOnPage'] = array();
452 foreach ($all as $d) {
453 $this->MOD_MENU['templatesOnPage'][$d['uid']] = $d['title'];
454 }
455 }
456 $this->MOD_SETTINGS = BackendUtility::getModuleData($this->MOD_MENU, GeneralUtility::_GP('SET'), $this->MCONF['name'], $this->modMenu_type, $this->modMenu_dontValidateList, $this->modMenu_setDefaultList);
457 return BackendUtility::getFuncMenu($this->id, 'SET[templatesOnPage]', $this->MOD_SETTINGS['templatesOnPage'], $this->MOD_MENU['templatesOnPage']);
458 }
459
460 /**
461 * Create template
462 *
463 * @param int $id
464 * @param int $actTemplateId
465 * @return string
466 */
467 public function createTemplate($id, $actTemplateId = 0) {
468 $recData = array();
469 /** @var DataHandler $tce */
470 $tce = GeneralUtility::makeInstance(DataHandler::class);
471 $tce->stripslashes_values = FALSE;
472
473 if (GeneralUtility::_GP('createExtension') || GeneralUtility::_GP('createExtension_x')) {
474 $recData['sys_template']['NEW'] = array(
475 'pid' => $actTemplateId ? -1 * $actTemplateId : $id,
476 'title' => '+ext'
477 );
478 $tce->start($recData, array());
479 $tce->process_datamap();
480 } elseif (GeneralUtility::_GP('newWebsite')) {
481 // Hook to handle row data, implemented for statictemplates
482 if (isset(
483 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler']
484 )) {
485 $reference = array(
486 'recData' => &$recData,
487 'id' => $id,
488 );
489 GeneralUtility::callUserFunction(
490 $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][TypoScriptTemplateModuleController::class]['newStandardTemplateHandler'],
491 $reference,
492 $this
493 );
494 $recData = $reference['recData'];
495 } else {
496 $recData['sys_template']['NEW'] = array(
497 'pid' => $id,
498 'title' => $this->getLanguageService()->getLL('titleNewSite'),
499 'sorting' => 0,
500 'root' => 1,
501 'clear' => 3,
502 'config' => '
503 # Default PAGE object:
504 page = PAGE
505 page.10 = TEXT
506 page.10.value = HELLO WORLD!
507 '
508 );
509 }
510 $tce->start($recData, array());
511 $tce->process_datamap();
512 $tce->clear_cacheCmd('all');
513 }
514 return $tce->substNEWwithIDs['NEW'];
515 }
516
517 // RENDER LIST of pages with templates, BEGIN
518 /**
519 * Set page in array
520 *
521 * @param array $pArray
522 * @param array $rlArr
523 * @param array $row
524 * @return void
525 */
526 public function setInPageArray(&$pArray, $rlArr, $row) {
527 ksort($rlArr);
528 reset($rlArr);
529 if (!$rlArr[0]['uid']) {
530 array_shift($rlArr);
531 }
532 $cEl = current($rlArr);
533 $pArray[$cEl['uid']] = htmlspecialchars($cEl['title']);
534 array_shift($rlArr);
535 if (!empty($rlArr)) {
536 if (!isset($pArray[($cEl['uid'] . '.')])) {
537 $pArray[$cEl['uid'] . '.'] = array();
538 }
539 $this->setInPageArray($pArray[$cEl['uid'] . '.'], $rlArr, $row);
540 } else {
541 $pArray[$cEl['uid'] . '_'] = $row;
542 }
543 }
544
545 /**
546 * Render the list
547 *
548 * @param array $pArray
549 * @param array $lines
550 * @param int $c
551 * @return array
552 */
553 public function renderList($pArray, $lines = array(), $c = 0) {
554 static $i;
555
556 if (!is_array($pArray)) {
557 return $lines;
558 }
559
560 foreach ($pArray as $k => $v) {
561 if (MathUtility::canBeInterpretedAsInteger($k)) {
562 if (isset($pArray[$k . '_'])) {
563 $lines[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
564 <td nowrap><span style="width: 1px; height: 1px; display:inline-block; margin-left: ' . $c * 20 . 'px"></span>' . '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('id' => $k))) . '">' . IconUtility::getSpriteIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $k), array('title' => ('ID: ' . $k))) . GeneralUtility::fixed_lgd_cs($pArray[$k], 30) . '</a></td>
565 <td>' . $pArray[($k . '_')]['count'] . '</td>
566 <td>' . ($pArray[$k . '_']['root_max_val'] > 0 ? IconUtility::getSpriteIcon('status-status-checked') : '&nbsp;') . '</td>
567 <td>' . ($pArray[$k . '_']['root_min_val'] == 0 ? IconUtility::getSpriteIcon('status-status-checked') : '&nbsp;') . '</td>
568 </tr>';
569 } else {
570 $lines[] = '<tr class="' . ($i++ % 2 == 0 ? 'bgColor4' : 'bgColor6') . '">
571 <td nowrap><span style="width: 1px; height: 1px; display:inline-block; margin-left: ' . $c * 20 . 'px"></span>' . IconUtility::getSpriteIconForRecord('pages', BackendUtility::getRecordWSOL('pages', $k)) . GeneralUtility::fixed_lgd_cs($pArray[$k], 30) . '</td>
572 <td></td>
573 <td></td>
574 <td></td>
575 </tr>';
576 }
577 $lines = $this->renderList($pArray[$k . '.'], $lines, $c + 1);
578 }
579 }
580 return $lines;
581 }
582
583 }