[TASK] Call explicit render() on icon objects
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / Wizard / TableController.php
1 <?php
2 namespace TYPO3\CMS\Backend\Controller\Wizard;
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 Psr\Http\Message\ServerRequestInterface;
18 use Psr\Http\Message\ResponseInterface;
19 use TYPO3\CMS\Backend\Template\DocumentTemplate;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
22 use TYPO3\CMS\Core\DataHandling\DataHandler;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\Imaging\IconFactory;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\CMS\Core\Utility\HttpUtility;
27 use TYPO3\CMS\Core\Utility\MathUtility;
28 use TYPO3\CMS\Core\Utility\StringUtility;
29
30 /**
31 * Script Class for rendering the Table Wizard
32 */
33 class TableController extends AbstractWizardController {
34
35 /**
36 * Document template object
37 *
38 * @var DocumentTemplate
39 */
40 public $doc;
41
42 /**
43 * Content accumulation for the module.
44 *
45 * @var string
46 */
47 public $content;
48
49 /**
50 * If TRUE, <input> fields are shown instead of textareas.
51 *
52 * @var bool
53 */
54 public $inputStyle = FALSE;
55
56 /**
57 * If set, the string version of the content is interpreted/written as XML
58 * instead of the original line-based kind. This variable still needs binding
59 * to the wizard parameters - but support is ready!
60 *
61 * @var int
62 */
63 public $xmlStorage = 0;
64
65 /**
66 * Number of new rows to add in bottom of wizard
67 *
68 * @var int
69 */
70 public $numNewRows = 1;
71
72 /**
73 * Name of field in parent record which MAY contain the number of columns for the table
74 * here hardcoded to the value of tt_content. Should be set by FormEngine parameters (from P)
75 *
76 * @var string
77 */
78 public $colsFieldName = 'cols';
79
80 /**
81 * Wizard parameters, coming from FormEngine linking to the wizard.
82 *
83 * @var array
84 */
85 public $P;
86
87 /**
88 * The array which is constantly submitted by the multidimensional form of this wizard.
89 *
90 * @var array
91 */
92 public $TABLECFG;
93
94 /**
95 * Table parsing
96 * quoting of table cells
97 *
98 * @var string
99 */
100 public $tableParsing_quote;
101
102 /**
103 * delimiter between table cells
104 *
105 * @var string
106 */
107 public $tableParsing_delimiter;
108
109 /**
110 * @var IconFactory
111 */
112 protected $iconFactory;
113
114 /**
115 * Constructor
116 */
117 public function __construct() {
118 $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
119 $this->getLanguageService()->includeLLFile('EXT:lang/locallang_wizards.xlf');
120 $GLOBALS['SOBE'] = $this;
121
122 $this->init();
123 }
124
125 /**
126 * Initialization of the class
127 *
128 * @return void
129 */
130 protected function init() {
131 // GPvars:
132 $this->P = GeneralUtility::_GP('P');
133 $this->TABLECFG = GeneralUtility::_GP('TABLE');
134 // Setting options:
135 $this->xmlStorage = $this->P['params']['xmlOutput'];
136 $this->numNewRows = MathUtility::forceIntegerInRange($this->P['params']['numNewRows'], 1, 50, 5);
137 // Textareas or input fields:
138 $this->inputStyle = isset($this->TABLECFG['textFields']) ? (bool)$this->TABLECFG['textFields'] : TRUE;
139 // Document template object:
140 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
141 $this->doc->setModuleTemplate('EXT:backend/Resources/Private/Templates/wizard_table.html');
142 // Setting form tag:
143 list($rUri) = explode('#', GeneralUtility::getIndpEnv('REQUEST_URI'));
144 $this->doc->form = '<form action="' . htmlspecialchars($rUri) . '" method="post" name="wizardForm">';
145 $this->tableParsing_delimiter = '|';
146 $this->tableParsing_quote = '';
147 }
148
149 /**
150 * Injects the request object for the current request or subrequest
151 * As this controller goes only through the main() method, it is rather simple for now
152 *
153 * @param ServerRequestInterface $request
154 * @param ResponseInterface $response
155 * @return ResponseInterface
156 */
157 public function mainAction(ServerRequestInterface $request, ResponseInterface $response) {
158 $this->main();
159 $response->getBody()->write($this->content);
160 return $response;
161 }
162
163 /**
164 * Main function, rendering the table wizard
165 *
166 * @return void
167 */
168 public function main() {
169 if ($this->P['table'] && $this->P['field'] && $this->P['uid']) {
170 $this->content .= $this->doc->section($this->getLanguageService()->getLL('table_title'), $this->tableWizard(), 0, 1);
171 } else {
172 $this->content .= $this->doc->section($this->getLanguageService()->getLL('table_title'), '<span class="text-danger">' . $this->getLanguageService()->getLL('table_noData', TRUE) . '</span>', 0, 1);
173 }
174 // Setting up the buttons and markers for docHeader
175 $docHeaderButtons = $this->getButtons();
176 $markers['CSH'] = $docHeaderButtons['csh'];
177 $markers['CONTENT'] = $this->content;
178 // Build the <body> for the module
179 $this->content = $this->doc->startPage('Table');
180 $this->content .= $this->doc->moduleBody(array(), $docHeaderButtons, $markers);
181 $this->content .= $this->doc->endPage();
182 $this->content = $this->doc->insertStylesAndJS($this->content);
183 }
184
185 /**
186 * Outputting the accumulated content to screen
187 *
188 * @return void
189 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use mainAction() instead
190 */
191 public function printContent() {
192 GeneralUtility::logDeprecatedFunction();
193 echo $this->content;
194 }
195
196 /**
197 * Create the panel of buttons for submitting the form or otherwise perform operations.
198 *
199 * @return array All available buttons as an associative array
200 */
201 protected function getButtons() {
202 $buttons = array(
203 'csh' => '',
204 'csh_buttons' => '',
205 'close' => '',
206 'save' => '',
207 'save_close' => '',
208 'reload' => ''
209 );
210 if ($this->P['table'] && $this->P['field'] && $this->P['uid']) {
211 // CSH
212 $buttons['csh'] = BackendUtility::cshItem('xMOD_csh_corebe', 'wizard_table_wiz');
213 // CSH Buttons
214 $buttons['csh_buttons'] = BackendUtility::cshItem('xMOD_csh_corebe', 'wizard_table_wiz_buttons');
215 // Close
216 $title = 'title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', TRUE) . '"';
217 $buttons['close'] = '<a href="#" onclick="' . htmlspecialchars(('jumpToUrl(' . GeneralUtility::quoteJSvalue(GeneralUtility::sanitizeLocalUrl($this->P['returnUrl'])) . '); return false;')) . '" ' . $title . '>' . $this->iconFactory->getIcon('actions-document-close', Icon::SIZE_SMALL)->render() . '</a>';
218 // Save
219 $buttons['save'] = '<button class="c-inputButton" name="savedok" value="1" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc', TRUE) . '">'
220 . $this->iconFactory->getIcon('actions-document-save', Icon::SIZE_SMALL)->render()
221 . '</button>';
222 // Save & Close
223 $buttons['save_close'] = '<button class="c-inputButton" name="saveandclosedok" value="1" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc', TRUE) . '">'
224 . $this->iconFactory->getIcon('actions-document-save-close', Icon::SIZE_SMALL)->render()
225 . '</button>';
226 // Reload
227 $buttons['reload'] = '<button class="c-inputButton" name="_refresh" value="1" title="' . $this->getLanguageService()->getLL('forms_refresh', TRUE) . '">'
228 . $this->iconFactory->getIcon('actions-refresh', Icon::SIZE_SMALL)->render()
229 . '</button>';
230 }
231 return $buttons;
232 }
233
234 /**
235 * Draws the table wizard content
236 *
237 * @return string HTML content for the form.
238 * @throws \RuntimeException
239 */
240 public function tableWizard() {
241 if (!$this->checkEditAccess($this->P['table'], $this->P['uid'])) {
242 throw new \RuntimeException('Wizard Error: No access', 1349692692);
243 }
244 // First, check the references by selecting the record:
245 $row = BackendUtility::getRecord($this->P['table'], $this->P['uid']);
246 if (!is_array($row)) {
247 throw new \RuntimeException('Wizard Error: No reference to record', 1294587125);
248 }
249 // This will get the content of the form configuration code field to us - possibly cleaned up,
250 // saved to database etc. if the form has been submitted in the meantime.
251 $tableCfgArray = $this->getConfigCode($row);
252 // Generation of the Table Wizards HTML code:
253 $content = $this->getTableHTML($tableCfgArray);
254 // Return content:
255 return $content;
256 }
257
258 /*
259 *
260 * Helper functions
261 *
262 */
263
264 /**
265 * Will get and return the configuration code string
266 * Will also save (and possibly redirect/exit) the content if a save button has been pressed
267 *
268 * @param array $row Current parent record row
269 * @return array Table config code in an array
270 * @internal
271 */
272 public function getConfigCode($row) {
273 // Get delimiter settings
274 $flexForm = GeneralUtility::xml2array($row['pi_flexform']);
275 if (is_array($flexForm)) {
276 $this->tableParsing_quote = $flexForm['data']['s_parsing']['lDEF']['tableparsing_quote']['vDEF'] ? chr((int)$flexForm['data']['s_parsing']['lDEF']['tableparsing_quote']['vDEF']) : '';
277 $this->tableParsing_delimiter = $flexForm['data']['s_parsing']['lDEF']['tableparsing_delimiter']['vDEF'] ? chr((int)$flexForm['data']['s_parsing']['lDEF']['tableparsing_delimiter']['vDEF']) : '|';
278 }
279 // If some data has been submitted, then construct
280 if (isset($this->TABLECFG['c'])) {
281 // Process incoming:
282 $this->changeFunc();
283 // Convert to string (either line based or XML):
284 if ($this->xmlStorage) {
285 // Convert the input array to XML:
286 $bodyText = GeneralUtility::array2xml_cs($this->TABLECFG['c'], 'T3TableWizard');
287 // Setting cfgArr directly from the input:
288 $configuration = $this->TABLECFG['c'];
289 } else {
290 // Convert the input array to a string of configuration code:
291 $bodyText = $this->cfgArray2CfgString($this->TABLECFG['c']);
292 // Create cfgArr from the string based configuration - that way it is cleaned up and any incompatibilities will be removed!
293 $configuration = $this->cfgString2CfgArray($bodyText, $row[$this->colsFieldName]);
294 }
295 // If a save button has been pressed, then save the new field content:
296 if ($_POST['savedok'] || $_POST['saveandclosedok']) {
297 // Get DataHandler object:
298 /** @var DataHandler $dataHandler */
299 $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
300 $dataHandler->stripslashes_values = FALSE;
301 // Put content into the data array:
302 $data = array();
303 if ($this->P['flexFormPath']) {
304 // Current value of flexForm path:
305 $currentFlexFormData = GeneralUtility::xml2array($row[$this->P['field']]);
306 /** @var FlexFormTools $flexFormTools */
307 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
308 $flexFormTools->setArrayValueByPath($this->P['flexFormPath'], $currentFlexFormData, $bodyText);
309 $data[$this->P['table']][$this->P['uid']][$this->P['field']] = $currentFlexFormData;
310 } else {
311 $data[$this->P['table']][$this->P['uid']][$this->P['field']] = $bodyText;
312 }
313 // Perform the update:
314 $dataHandler->start($data, array());
315 $dataHandler->process_datamap();
316 // If the save/close button was pressed, then redirect the screen:
317 if ($_POST['saveandclosedok']) {
318 HttpUtility::redirect(GeneralUtility::sanitizeLocalUrl($this->P['returnUrl']));
319 }
320 }
321 } else {
322 // If nothing has been submitted, load the $bodyText variable from the selected database row:
323 if ($this->xmlStorage) {
324 $configuration = GeneralUtility::xml2array($row[$this->P['field']]);
325 } else {
326 if ($this->P['flexFormPath']) {
327 // Current value of flexForm path:
328 $currentFlexFormData = GeneralUtility::xml2array($row[$this->P['field']]);
329 /** @var FlexFormTools $flexFormTools */
330 $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
331 $configuration = $flexFormTools->getArrayValueByPath($this->P['flexFormPath'], $currentFlexFormData);
332 $configuration = $this->cfgString2CfgArray($configuration, 0);
333 } else {
334 // Regular line based table configuration:
335 $configuration = $this->cfgString2CfgArray($row[$this->P['field']], $row[$this->colsFieldName]);
336 }
337 }
338 $configuration = is_array($configuration) ? $configuration : array();
339 }
340 return $configuration;
341 }
342
343 /**
344 * Creates the HTML for the Table Wizard:
345 *
346 * @param array $configuration Table config array
347 * @return string HTML for the table wizard
348 * @internal
349 */
350 public function getTableHTML($configuration) {
351 // Traverse the rows:
352 $tRows = array();
353 $k = 0;
354 $countLines = count($configuration);
355 foreach ($configuration as $cellArr) {
356 if (is_array($cellArr)) {
357 // Initialize:
358 $cells = array();
359 $a = 0;
360 // Traverse the columns:
361 foreach ($cellArr as $cellContent) {
362 if ($this->inputStyle) {
363 $cells[] = '<input class="form-control" type="text"' . $this->doc->formWidth(20) . ' name="TABLE[c][' . ($k + 1) * 2 . '][' . ($a + 1) * 2 . ']" value="' . htmlspecialchars($cellContent) . '" />';
364 } else {
365 $cellContent = preg_replace('/<br[ ]?[\\/]?>/i', LF, $cellContent);
366 $cells[] = '<textarea class="form-control" ' . $this->doc->formWidth(20) . ' rows="6" name="TABLE[c][' . ($k + 1) * 2 . '][' . ($a + 1) * 2 . ']">' . htmlspecialchars($cellContent) . '</textarea>';
367 }
368 // Increment counter:
369 $a++;
370 }
371 // CTRL panel for a table row (move up/down/around):
372 $onClick = 'document.wizardForm.action+=' . GeneralUtility::quoteJSvalue('#ANC_' . (($k + 1) * 2 - 2)) . ';';
373 $onClick = ' onclick="' . htmlspecialchars($onClick) . '"';
374 $ctrl = '';
375 if ($k !== 0) {
376 $ctrl .= '<button class="btn btn-default" name="TABLE[row_up][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_up', TRUE) . '"'. $onClick . '><span class="t3-icon fa fa-fw fa-angle-up"></span></button>';
377 } else {
378 $ctrl .= '<button class="btn btn-default" name="TABLE[row_bottom][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_bottom', TRUE) . '"'. $onClick . '><span class="t3-icon fa fa-fw fa-angle-double-down"></span></button>';
379 }
380 if ($k + 1 !== $countLines) {
381 $ctrl .= '<button class="btn btn-default" name="TABLE[row_down][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_down', TRUE) . '"'. $onClick . '><span class="t3-icon fa fa-fw fa-angle-down"></span></button>';
382 } else {
383 $ctrl .= '<button class="btn btn-default" name="TABLE[row_top][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_top', TRUE) . '"'. $onClick . '><span class="t3-icon fa fa-fw fa-angle-double-up"></span></button>';
384 }
385 $ctrl .= '<button class="btn btn-default" name="TABLE[row_remove][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_removeRow', TRUE) . '"'. $onClick . '><span class="t3-icon fa fa-fw fa-trash"></span></button>';
386 $ctrl .= '<button class="btn btn-default" name="TABLE[row_add][' . ($k + 1) * 2 . ']" title="' . $this->getLanguageService()->getLL('table_addRow', TRUE) . '"'. $onClick . '><span class="t3-icon fa fa-fw fa-plus"></span></button>';
387 $tRows[] = '
388 <tr>
389 <td>
390 <a name="ANC_' . ($k + 1) * 2 . '"></a>
391 <span class="btn-group' . ($this->inputStyle ? '' : '-vertical') . '">' . $ctrl . '</span>
392 </td>
393 <td>' . implode('</td>
394 <td>', $cells) . '</td>
395 </tr>';
396 // Increment counter:
397 $k++;
398 }
399 }
400 // CTRL panel for a table column (move left/right/around/delete)
401 $cells = array();
402 $cells[] = '';
403 // Finding first row:
404 $firstRow = reset($configuration);
405 if (is_array($firstRow)) {
406 $cols = count($firstRow);
407 for ($a = 1; $a <= $cols; $a++) {
408 $b = $a * 2;
409 $ctrl = '';
410 if ($a !== 1) {
411 $ctrl .= '<button class="btn btn-default" name="TABLE[col_left][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_left', TRUE) . '"><span class="t3-icon fa fa-fw fa-angle-left"></span></button>';
412 } else {
413 $ctrl .= '<button class="btn btn-default" name="TABLE[col_end][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_end', TRUE) . '"><span class="t3-icon fa fa-fw fa-angle-double-right"></span></button>';
414 }
415 if ($a != $cols) {
416 $ctrl .= '<button class="btn btn-default" name="TABLE[col_right][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_right', TRUE) . '"><span class="t3-icon fa fa-fw fa-angle-right"></span></button>';
417 } else {
418 $ctrl .= '<button class="btn btn-default" name="TABLE[col_start][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_start', TRUE) . '"><span class="t3-icon fa fa-fw fa-angle-double-left"></span></button>';
419 }
420 $ctrl .= '<button class="btn btn-default" name="TABLE[col_remove][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_removeColumn', TRUE) . '"><span class="t3-icon fa fa-fw fa-trash"></span></button>';
421 $ctrl .= '<button class="btn btn-default" name="TABLE[col_add][' . $b . ']" title="' . $this->getLanguageService()->getLL('table_addColumn', TRUE) . '"><span class="t3-icon fa fa-fw fa-plus"></span></button>';
422 $cells[] = '<span class="btn-group">' . $ctrl . '</span>';
423 }
424 $tRows[] = '
425 <tfoot>
426 <tr>
427 <td>' . implode('</td>
428 <td>', $cells) . '</td>
429 </tr>
430 </tfoot>';
431 }
432 $content = '';
433 // Implode all table rows into a string, wrapped in table tags.
434 $content .= '
435
436 <!-- Table wizard -->
437 <div class="table-fit table-fit-inline-block">
438 <table id="typo3-tablewizard" class="table table-center">
439 ' . implode('', $tRows) . '
440 </table>
441 </div>';
442 // Input type checkbox:
443 $content .= '
444
445 <!-- Input mode check box: -->
446 <div class="checkbox">
447 <input type="hidden" name="TABLE[textFields]" value="0" />
448 <label for="textFields">
449 <input type="checkbox" name="TABLE[textFields]" id="textFields" value="1"' . ($this->inputStyle ? ' checked="checked"' : '') . ' />
450 ' . $this->getLanguageService()->getLL('table_smallFields') . '
451 </label>
452 </div>';
453 return $content;
454 }
455
456 /**
457 * Detects if a control button (up/down/around/delete) has been pressed for an item and accordingly it will manipulate the internal TABLECFG array
458 *
459 * @return void
460 * @internal
461 */
462 public function changeFunc() {
463 if ($this->TABLECFG['col_remove']) {
464 $kk = key($this->TABLECFG['col_remove']);
465 $cmd = 'col_remove';
466 } elseif ($this->TABLECFG['col_add']) {
467 $kk = key($this->TABLECFG['col_add']);
468 $cmd = 'col_add';
469 } elseif ($this->TABLECFG['col_start']) {
470 $kk = key($this->TABLECFG['col_start']);
471 $cmd = 'col_start';
472 } elseif ($this->TABLECFG['col_end']) {
473 $kk = key($this->TABLECFG['col_end']);
474 $cmd = 'col_end';
475 } elseif ($this->TABLECFG['col_left']) {
476 $kk = key($this->TABLECFG['col_left']);
477 $cmd = 'col_left';
478 } elseif ($this->TABLECFG['col_right']) {
479 $kk = key($this->TABLECFG['col_right']);
480 $cmd = 'col_right';
481 } elseif ($this->TABLECFG['row_remove']) {
482 $kk = key($this->TABLECFG['row_remove']);
483 $cmd = 'row_remove';
484 } elseif ($this->TABLECFG['row_add']) {
485 $kk = key($this->TABLECFG['row_add']);
486 $cmd = 'row_add';
487 } elseif ($this->TABLECFG['row_top']) {
488 $kk = key($this->TABLECFG['row_top']);
489 $cmd = 'row_top';
490 } elseif ($this->TABLECFG['row_bottom']) {
491 $kk = key($this->TABLECFG['row_bottom']);
492 $cmd = 'row_bottom';
493 } elseif ($this->TABLECFG['row_up']) {
494 $kk = key($this->TABLECFG['row_up']);
495 $cmd = 'row_up';
496 } elseif ($this->TABLECFG['row_down']) {
497 $kk = key($this->TABLECFG['row_down']);
498 $cmd = 'row_down';
499 } else {
500 $kk = '';
501 $cmd = '';
502 }
503 if ($cmd && MathUtility::canBeInterpretedAsInteger($kk)) {
504 if (StringUtility::beginsWith($cmd, 'row_')) {
505 switch ($cmd) {
506 case 'row_remove':
507 unset($this->TABLECFG['c'][$kk]);
508 break;
509 case 'row_add':
510 for ($a = 1; $a <= $this->numNewRows; $a++) {
511 // Checking if set: The point is that any new row between existing rows
512 // will be TRUE after one row is added while if rows are added in the bottom
513 // of the table there will be no existing rows to stop the addition of new rows
514 // which means it will add up to $this->numNewRows rows then.
515 if (!isset($this->TABLECFG['c'][($kk + $a)])) {
516 $this->TABLECFG['c'][$kk + $a] = array();
517 } else {
518 break;
519 }
520 }
521 break;
522 case 'row_top':
523 $this->TABLECFG['c'][1] = $this->TABLECFG['c'][$kk];
524 unset($this->TABLECFG['c'][$kk]);
525 break;
526 case 'row_bottom':
527 $this->TABLECFG['c'][10000000] = $this->TABLECFG['c'][$kk];
528 unset($this->TABLECFG['c'][$kk]);
529 break;
530 case 'row_up':
531 $this->TABLECFG['c'][$kk - 3] = $this->TABLECFG['c'][$kk];
532 unset($this->TABLECFG['c'][$kk]);
533 break;
534 case 'row_down':
535 $this->TABLECFG['c'][$kk + 3] = $this->TABLECFG['c'][$kk];
536 unset($this->TABLECFG['c'][$kk]);
537 break;
538 }
539 ksort($this->TABLECFG['c']);
540 }
541 if (StringUtility::beginsWith($cmd, 'col_')) {
542 foreach ($this->TABLECFG['c'] as $cAK => $value) {
543 switch ($cmd) {
544 case 'col_remove':
545 unset($this->TABLECFG['c'][$cAK][$kk]);
546 break;
547 case 'col_add':
548 $this->TABLECFG['c'][$cAK][$kk + 1] = '';
549 break;
550 case 'col_start':
551 $this->TABLECFG['c'][$cAK][1] = $this->TABLECFG['c'][$cAK][$kk];
552 unset($this->TABLECFG['c'][$cAK][$kk]);
553 break;
554 case 'col_end':
555 $this->TABLECFG['c'][$cAK][1000000] = $this->TABLECFG['c'][$cAK][$kk];
556 unset($this->TABLECFG['c'][$cAK][$kk]);
557 break;
558 case 'col_left':
559 $this->TABLECFG['c'][$cAK][$kk - 3] = $this->TABLECFG['c'][$cAK][$kk];
560 unset($this->TABLECFG['c'][$cAK][$kk]);
561 break;
562 case 'col_right':
563 $this->TABLECFG['c'][$cAK][$kk + 3] = $this->TABLECFG['c'][$cAK][$kk];
564 unset($this->TABLECFG['c'][$cAK][$kk]);
565 break;
566 }
567 ksort($this->TABLECFG['c'][$cAK]);
568 }
569 }
570 }
571 // Convert line breaks to <br /> tags:
572 foreach ($this->TABLECFG['c'] as $a => $value) {
573 foreach ($this->TABLECFG['c'][$a] as $b => $value2) {
574 $this->TABLECFG['c'][$a][$b] = str_replace(LF, '<br />', str_replace(CR, '', $this->TABLECFG['c'][$a][$b]));
575 }
576 }
577 }
578
579 /**
580 * Converts the input array to a configuration code string
581 *
582 * @param array $cfgArr Array of table configuration (follows the input structure from the table wizard POST form)
583 * @return string The array converted into a string with line-based configuration.
584 * @see cfgString2CfgArray()
585 */
586 public function cfgArray2CfgString($cfgArr) {
587 $inLines = array();
588 // Traverse the elements of the table wizard and transform the settings into configuration code.
589 foreach ($cfgArr as $valueA) {
590 $thisLine = array();
591 foreach ($valueA as $valueB) {
592 $thisLine[] = $this->tableParsing_quote . str_replace($this->tableParsing_delimiter, '', $valueB) . $this->tableParsing_quote;
593 }
594 $inLines[] = implode($this->tableParsing_delimiter, $thisLine);
595 }
596 // Finally, implode the lines into a string:
597 return implode(LF, $inLines);
598 }
599
600 /**
601 * Converts the input configuration code string into an array
602 *
603 * @param string $configurationCode Configuration code
604 * @param int $columns Default number of columns
605 * @return array Configuration array
606 * @see cfgArray2CfgString()
607 */
608 public function cfgString2CfgArray($configurationCode, $columns) {
609 // Explode lines in the configuration code - each line is a table row.
610 $tableLines = explode(LF, $configurationCode);
611 // Setting number of columns
612 // auto...
613 if (!$columns && trim($tableLines[0])) {
614 $columns = count(explode($this->tableParsing_delimiter, $tableLines[0]));
615 }
616 $columns = $columns ?: 4;
617 // Traverse the number of table elements:
618 $configurationArray = array();
619 foreach ($tableLines as $key => $value) {
620 // Initialize:
621 $valueParts = explode($this->tableParsing_delimiter, $value);
622 // Traverse columns:
623 for ($a = 0; $a < $columns; $a++) {
624 if ($this->tableParsing_quote && $valueParts[$a][0] === $this->tableParsing_quote && substr($valueParts[$a], -1, 1) === $this->tableParsing_quote) {
625 $valueParts[$a] = substr(trim($valueParts[$a]), 1, -1);
626 }
627 $configurationArray[$key][$a] = $valueParts[$a];
628 }
629 }
630 return $configurationArray;
631 }
632
633 }