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