102 $GLOBALS[
'LANG']->includeLLFile(
'EXT:lang/locallang_wizards.xlf');
118 $this->xmlStorage = $this->P[
'params'][
'xmlOutput'];
121 $this->inputStyle = isset($this->TABLECFG[
'textFields']) ? $this->TABLECFG[
'textFields'] : 1;
124 $this->doc->backPath =
$GLOBALS[
'BACK_PATH'];
125 $this->doc->setModuleTemplate(
'EXT:backend/Resources/Private/Templates/wizard_table.html');
128 $this->doc->form =
'<form action="' . htmlspecialchars($rUri) .
'" method="post" name="wizardForm">';
129 $this->tableParsing_delimiter =
'|';
130 $this->tableParsing_quote =
'';
139 if ($this->P[
'table'] && $this->P[
'field'] && $this->P[
'uid']) {
140 $this->content .= $this->doc->section(
$GLOBALS[
'LANG']->getLL(
'table_title'), $this->
tableWizard(), 0, 1);
142 $this->content .= $this->doc->section(
$GLOBALS[
'LANG']->getLL(
'table_title'),
'<span class="typo3-red">' .
$GLOBALS[
'LANG']->getLL(
'table_noData', TRUE) .
'</span>', 0, 1);
146 $markers[
'CSH'] = $docHeaderButtons[
'csh'];
149 $this->content = $this->doc->startPage(
'Table');
150 $this->content .= $this->doc->moduleBody($this->pageinfo, $docHeaderButtons, $markers);
151 $this->content .= $this->doc->endPage();
152 $this->content = $this->doc->insertStylesAndJS($this->content);
179 if ($this->P[
'table'] && $this->P[
'field'] && $this->P[
'uid']) {
185 $buttons[
'close'] =
'<a href="#" onclick="' . htmlspecialchars((
'jumpToUrl(unescape(\'' . rawurlencode(
GeneralUtility::sanitizeLocalUrl($this->P[
'returnUrl'])) .
'\'));
return false;
')) . '">' . IconUtility::getSpriteIcon('actions-document-close', array('title' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:rm.closeDoc', TRUE))) . '</a>'; 187 $buttons['save'] = '<input type="image
" class="c-inputButton
" name="savedok
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/savedok.gif') . ' title="' . $GLOBALS['LANG
']->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveDoc
', TRUE) . '" />'; 189 $buttons['save_close'] = '<input type="image
" class="c-inputButton
" name="saveandclosedok
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/saveandclosedok.gif') . ' title="' . $GLOBALS['LANG
']->sL('LLL:EXT:lang/locallang_core.xlf:rm.saveCloseDoc
', TRUE) . '" />'; 191 $buttons['reload'] = '<input type="image
" class="c-inputButton
" name="_refresh
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/refresh_n.gif') . ' title="' . $GLOBALS['LANG
']->getLL('forms_refresh
', TRUE) . '" />'; 202 public function tableWizard() { 203 if (!$this->checkEditAccess($this->P['table'], $this->P['uid'])) { 204 throw new \RuntimeException('Wizard Error: No access', 1349692692); 206 // First, check the references by selecting the record: 207 $row = BackendUtility::getRecord($this->P['table'], $this->P['uid']); 208 if (!is_array($row)) { 209 throw new \RuntimeException('Wizard Error: No reference to record', 1294587125); 211 // This will get the content of the form configuration code field to us - possibly cleaned up, 212 // saved to database etc. if the form has been submitted in the meantime. 213 $tableCfgArray = $this->getConfigCode($row); 214 // Generation of the Table Wizards HTML code: 215 $content = $this->getTableHTML($tableCfgArray, $row); 220 /*************************** 224 ***************************/ 234 public function getConfigCode($row) { 235 // Get delimiter settings 236 $flexForm = GeneralUtility::xml2array($row['pi_flexform']); 237 if (is_array($flexForm)) { 238 $this->tableParsing_quote = $flexForm['data']['s_parsing']['lDEF']['tableparsing_quote']['vDEF'] ? chr((int)$flexForm['data']['s_parsing']['lDEF']['tableparsing_quote']['vDEF']) : ''; 239 $this->tableParsing_delimiter = $flexForm['data']['s_parsing']['lDEF']['tableparsing_delimiter']['vDEF'] ? chr((int)$flexForm['data']['s_parsing']['lDEF']['tableparsing_delimiter']['vDEF']) : '|'; 241 // If some data has been submitted, then construct 242 if (isset($this->TABLECFG['c'])) { 245 // Convert to string (either line based or XML): 246 if ($this->xmlStorage) { 247 // Convert the input array to XML: 248 $bodyText = GeneralUtility::array2xml_cs($this->TABLECFG['c'], 'T3TableWizard'); 249 // Setting cfgArr directly from the input: 250 $cfgArr = $this->TABLECFG['c']; 252 // Convert the input array to a string of configuration code: 253 $bodyText = $this->cfgArray2CfgString($this->TABLECFG['c']); 254 // Create cfgArr from the string based configuration - that way it is cleaned up and any incompatibilities will be removed! 255 $cfgArr = $this->cfgString2CfgArray($bodyText, $row[$this->colsFieldName]); 257 // If a save button has been pressed, then save the new field content: 258 if ($_POST['savedok_x'] || $_POST['saveandclosedok_x']) { 259 // Make TCEmain object: 260 $tce = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\DataHandling\\DataHandler'); 261 $tce->stripslashes_values = 0; 262 // Put content into the data array: 264 $data[$this->P['table']][$this->P['uid']][$this->P['field']] = $bodyText; 265 // Perform the update: 266 $tce->start($data, array()); 267 $tce->process_datamap(); 268 // If the save/close button was pressed, then redirect the screen: 269 if ($_POST['saveandclosedok_x']) { 270 \TYPO3\CMS\Core\Utility\HttpUtility::redirect(GeneralUtility::sanitizeLocalUrl($this->P['returnUrl'])); 274 // If nothing has been submitted, load the $bodyText variable from the selected database row: 275 if ($this->xmlStorage) { 276 $cfgArr = GeneralUtility::xml2array($row[$this->P['field']]); 278 // Regular linebased table configuration: 279 $cfgArr = $this->cfgString2CfgArray($row[$this->P['field']], $row[$this->colsFieldName]); 281 $cfgArr = is_array($cfgArr) ? $cfgArr : array(); 295 public function getTableHTML($cfgArr, $row) { 296 // Traverse the rows: 299 $countLines = count($cfgArr); 300 foreach ($cfgArr as $cellArr) { 301 if (is_array($cellArr)) { 305 // Traverse the columns: 306 foreach ($cellArr as $cellContent) { 307 if ($this->inputStyle) { 308 $cells[] = '<input type="text
"' . $this->doc->formWidth(20) . ' name="TABLE[c][
' . ($k + 1) * 2 . '][
' . ($a + 1) * 2 . ']
" value="' . htmlspecialchars($cellContent) . '" />'; 310 $cellContent = preg_replace('/<br[ ]?[\\/]?>/i', LF, $cellContent); 311 $cells[] = '<textarea ' . $this->doc->formWidth(20) . ' rows="5
" name="TABLE[c][
' . ($k + 1) * 2 . '][
' . ($a + 1) * 2 . ']
">' . GeneralUtility::formatForTextarea($cellContent) . '</textarea>'; 313 // Increment counter: 316 // CTRL panel for a table row (move up/down/around): 317 $onClick = 'document.wizardForm.action+=\'#ANC_' . (($k + 1) * 2 - 2) . '\';'; 318 $onClick = ' onclick="' . htmlspecialchars($onClick) . '"'; 320 $brTag = $this->inputStyle ? '' : '<br />'; 322 $ctrl .= '<input type="image
" name="TABLE[row_up][
' . ($k + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/pil2up.gif', '') . $onClick . ' title="' . $GLOBALS['LANG
']->getLL('table_up
', TRUE) . '" />' . $brTag; 324 $ctrl .= '<input type="image
" name="TABLE[row_bottom][
' . ($k + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/turn_up.gif', '') . $onClick . ' title="' . $GLOBALS['LANG
']->getLL('table_bottom
', TRUE) . '" />' . $brTag; 326 $ctrl .= '<input type="image
" name="TABLE[row_remove][
' . ($k + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/garbage.gif', '') . $onClick . ' title="' . $GLOBALS['LANG
']->getLL('table_removeRow
', TRUE) . '" />' . $brTag; 327 if ($k + 1 != $countLines) { 328 $ctrl .= '<input type="image
" name="TABLE[row_down][
' . ($k + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/pil2down.gif', '') . $onClick . ' title="' . $GLOBALS['LANG
']->getLL('table_down
', TRUE) . '" />' . $brTag; 330 $ctrl .= '<input type="image
" name="TABLE[row_top][
' . ($k + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/turn_down.gif', '') . $onClick . ' title="' . $GLOBALS['LANG
']->getLL('table_top
', TRUE) . '" />' . $brTag; 332 $ctrl .= '<input type="image
" name="TABLE[row_add][
' . ($k + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/add.gif', '') . $onClick . ' title="' . $GLOBALS['LANG
']->getLL('table_addRow
', TRUE) . '" />' . $brTag; 334 <tr class="bgColor4
"> 335 <td class="bgColor5
"><a name="ANC_
' . ($k + 1) * 2 . '"></a><span class="c-wizButtonsV
">' . $ctrl . '</span></td> 336 <td>' . implode('</td> 337 <td>', $cells) . '</td> 339 // Increment counter: 343 // CTRL panel for a table column (move left/right/around/delete) 346 // Finding first row: 347 $firstRow = reset($cfgArr); 348 if (is_array($firstRow)) { 351 $cols = count($firstRow); 352 // Traverse first row: 353 foreach ($firstRow as $temp) { 356 $ctrl .= '<input type="image
" name="TABLE[col_left][
' . ($a + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/pil2left.gif', '') . ' title="' . $GLOBALS['LANG
']->getLL('table_left
', TRUE) . '" />'; 358 $ctrl .= '<input type="image
" name="TABLE[col_end][
' . ($a + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/turn_left.gif', '') . ' title="' . $GLOBALS['LANG
']->getLL('table_end
', TRUE) . '" />'; 360 $ctrl .= '<input type="image
" name="TABLE[col_remove][
' . ($a + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/garbage.gif', '') . ' title="' . $GLOBALS['LANG
']->getLL('table_removeColumn
', TRUE) . '" />'; 361 if ($a + 1 != $cols) { 362 $ctrl .= '<input type="image
" name="TABLE[col_right][
' . ($a + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/pil2right.gif', '') . ' title="' . $GLOBALS['LANG
']->getLL('table_right
', TRUE) . '" />'; 364 $ctrl .= '<input type="image
" name="TABLE[col_start][
' . ($a + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/turn_right.gif', '') . ' title="' . $GLOBALS['LANG
']->getLL('table_start
', TRUE) . '" />'; 366 $ctrl .= '<input type="image
" name="TABLE[col_add][
' . ($a + 1) * 2 . ']
"' . IconUtility::skinImg($this->doc->backPath, 'gfx/add.gif', '') . ' title="' . $GLOBALS['LANG
']->getLL('table_addColumn
', TRUE) . '" />'; 367 $cells[] = '<span class="c-wizButtonsH
">' . $ctrl . '</span>'; 372 <tr class="bgColor5
"> 373 <td align="center
">' . implode('</td> 374 <td align="center
">', $cells) . '</td> 378 // Implode all table rows into a string, wrapped in table tags. 385 <table border="0
" cellpadding="0
" cellspacing="1
" id="typo3-tablewizard
"> 386 ' . implode('', $tRows) . ' 388 // Input type checkbox: 392 Input mode check box: 394 <div id="c-inputMode
"> 395 ' . '<input type="hidden
" name="TABLE[textFields]
" value="0
" />' . '<input type="checkbox
" name="TABLE[textFields]
" id="textFields
" value="1
"' . ($this->inputStyle ? ' checked="checked
"' : '') . ' /> <label for="textFields
">' . $GLOBALS['LANG']->getLL('table_smallFields') . '</label> 411 public function changeFunc() { 412 if ($this->TABLECFG['col_remove']) { 413 $kk = key($this->TABLECFG['col_remove']); 415 } elseif ($this->TABLECFG['col_add']) { 416 $kk = key($this->TABLECFG['col_add']); 418 } elseif ($this->TABLECFG['col_start']) { 419 $kk = key($this->TABLECFG['col_start']); 421 } elseif ($this->TABLECFG['col_end']) { 422 $kk = key($this->TABLECFG['col_end']); 424 } elseif ($this->TABLECFG['col_left']) { 425 $kk = key($this->TABLECFG['col_left']); 427 } elseif ($this->TABLECFG['col_right']) { 428 $kk = key($this->TABLECFG['col_right']); 430 } elseif ($this->TABLECFG['row_remove']) { 431 $kk = key($this->TABLECFG['row_remove']); 433 } elseif ($this->TABLECFG['row_add']) { 434 $kk = key($this->TABLECFG['row_add']); 436 } elseif ($this->TABLECFG['row_top']) { 437 $kk = key($this->TABLECFG['row_top']); 439 } elseif ($this->TABLECFG['row_bottom']) { 440 $kk = key($this->TABLECFG['row_bottom']); 442 } elseif ($this->TABLECFG['row_up']) { 443 $kk = key($this->TABLECFG['row_up']); 445 } elseif ($this->TABLECFG['row_down']) { 446 $kk = key($this->TABLECFG['row_down']); 449 if ($cmd && MathUtility::canBeInterpretedAsInteger($kk)) { 450 if (substr($cmd, 0, 4) == 'row_') { 453 unset($this->TABLECFG['c'][$kk]); 456 for ($a = 1; $a <= $this->numNewRows; $a++) { 457 // Checking if set: The point is that any new row inbetween existing rows 458 // will be TRUE after one row is added while if rows are added in the bottom 459 // of the table there will be no existing rows to stop the addition of new rows 460 // which means it will add up to $this->numNewRows rows then. 461 if (!isset($this->TABLECFG['c'][($kk + $a)])) { 462 $this->TABLECFG['c'][$kk + $a] = array(); 469 $this->TABLECFG['c'][1] = $this->TABLECFG['c'][$kk]; 470 unset($this->TABLECFG['c'][$kk]); 473 $this->TABLECFG['c'][10000000] = $this->TABLECFG['c'][$kk]; 474 unset($this->TABLECFG['c'][$kk]); 477 $this->TABLECFG['c'][$kk - 3] = $this->TABLECFG['c'][$kk]; 478 unset($this->TABLECFG['c'][$kk]); 481 $this->TABLECFG['c'][$kk + 3] = $this->TABLECFG['c'][$kk]; 482 unset($this->TABLECFG['c'][$kk]); 485 ksort($this->TABLECFG['c']); 487 if (substr($cmd, 0, 4) == 'col_') { 488 foreach ($this->TABLECFG['c'] as $cAK => $value) { 491 unset($this->TABLECFG['c'][$cAK][$kk]); 494 $this->TABLECFG['c'][$cAK][$kk + 1] = ''; 497 $this->TABLECFG['c'][$cAK][1] = $this->TABLECFG['c'][$cAK][$kk]; 498 unset($this->TABLECFG['c'][$cAK][$kk]); 501 $this->TABLECFG['c'][$cAK][1000000] = $this->TABLECFG['c'][$cAK][$kk]; 502 unset($this->TABLECFG['c'][$cAK][$kk]); 505 $this->TABLECFG['c'][$cAK][$kk - 3] = $this->TABLECFG['c'][$cAK][$kk]; 506 unset($this->TABLECFG['c'][$cAK][$kk]); 509 $this->TABLECFG['c'][$cAK][$kk + 3] = $this->TABLECFG['c'][$cAK][$kk]; 510 unset($this->TABLECFG['c'][$cAK][$kk]); 513 ksort($this->TABLECFG['c'][$cAK]); 517 // Convert line breaks to <br /> tags: 518 foreach ($this->TABLECFG['c'] as $a => $value) { 519 foreach ($this->TABLECFG['c'][$a] as $b => $value2) { 520 $this->TABLECFG['c'][$a][$b] = str_replace(LF, '<br />', str_replace(CR, '', $this->TABLECFG['c'][$a][$b])); 533 public function cfgArray2CfgString($cfgArr) { 536 // Traverse the elements of the table wizard and transform the settings into configuration code. 537 foreach ($this->TABLECFG['c'] as $a => $value) { 539 foreach ($this->TABLECFG['c'][$a] as $b => $value) { 540 $thisLine[] = $this->tableParsing_quote . str_replace($this->tableParsing_delimiter, '', $this->TABLECFG['c'][$a][$b]) . $this->tableParsing_quote; 542 $inLines[] = implode($this->tableParsing_delimiter, $thisLine); 544 // Finally, implode the lines into a string: 545 $bodyText = implode(LF, $inLines); 546 // Return the configuration code: 559 public function cfgString2CfgArray($cfgStr, $cols) { 560 // Explode lines in the configuration code - each line is a table row. 561 $tLines = explode(LF, $cfgStr); 562 // Setting number of columns 564 if (!$cols && trim($tLines[0])) { 565 $cols = count(explode($this->tableParsing_delimiter, $tLines[0])); 568 // Traverse the number of table elements: 570 foreach ($tLines as $k => $v) { 572 $vParts = explode($this->tableParsing_delimiter, $v); 574 for ($a = 0; $a < $cols; $a++) { 575 if ($this->tableParsing_quote && $vParts[$a][0] === $this->tableParsing_quote && substr($vParts[$a], -1, 1) === $this->tableParsing_quote) { 576 $vParts[$a] = substr(trim($vParts[$a]), 1, -1); 578 $cfgArr[$k][$a] = $vParts[$a]; 581 // Return configuration array: 593 protected function checkEditAccess($table, $uid) { 594 $calcPRec = BackendUtility::getRecord($table, $uid); 595 BackendUtility::fixVersioningPid($table, $calcPRec); 596 if (is_array($calcPRec)) { 598 if ($table == 'pages') { 599 $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms($calcPRec); 600 $hasAccess = $CALC_PERMS & 2 ? TRUE : FALSE; 602 // Fetching pid-record first. 603 $CALC_PERMS = $GLOBALS['BE_USER']->calcPerms(BackendUtility::getRecord('pages', $calcPRec['pid'])); 604 $hasAccess = $CALC_PERMS & 16 ? TRUE : FALSE; 606 // Check internals regarding access: 608 $hasAccess = $GLOBALS['BE_USER']->recordEditAccessInternals($table, $calcPRec);
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
static cshItem($table, $field, $BACK_PATH, $wrap='', $onlyIconMode=FALSE, $styleAttrib='')
static getIndpEnv($getEnvName)
static makeInstance($className)
static sanitizeLocalUrl($url='')
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]