[TASK] Split action buttons into two groups
[Packages/TYPO3.CMS.git] / typo3 / sysext / tstemplate / Classes / Controller / TypoScriptTemplateInformationModuleFunctionController.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\Core\DataHandling\DataHandler;
18 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
19 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Core\Utility\HttpUtility;
22 use TYPO3\CMS\Core\Utility\MathUtility;
23 use TYPO3\CMS\Backend\Module\AbstractFunctionModule;
24 use TYPO3\CMS\Backend\Utility\IconUtility;
25 use TYPO3\CMS\Backend\Utility\BackendUtility;
26 use TYPO3\CMS\Lang\LanguageService;
27
28 /**
29 * This class displays the Info/Modify screen of the Web > Template module
30 *
31 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
32 */
33 class TypoScriptTemplateInformationModuleFunctionController extends AbstractFunctionModule {
34
35 /**
36 * Indicator for t3editor, whether data is stored
37 *
38 * @var bool
39 */
40 public $tce_processed = FALSE;
41
42 /**
43 * @var TypoScriptTemplateModuleController
44 */
45 public $pObj;
46
47 /**
48 * Creates a row for a HTML table
49 *
50 * @param string $label The label to be shown (e.g. 'Title:', 'Sitetitle:')
51 * @param string $data The data/information to be shown (e.g. 'Template for my site')
52 * @param string $field The field/variable to be sent on clicking the edit icon (e.g. 'title', 'sitetitle')
53 * @param int $id The field/variable to be sent on clicking the edit icon (e.g. 'title', 'sitetitle')
54 * @return string A row for a HTML table
55 */
56 public function tableRow($label, $data, $field, $id) {
57 $lang = $this->getLanguageService();
58 $ret = '<tr><td>';
59 if ($field === 'config' || $field === 'constants') {
60 $urlParameters = array(
61 'id' => $this->pObj->id
62 );
63 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
64 $startAnchor = '<a href="' . htmlspecialchars(($aHref . '&e[' . $field . ']=1')) . '">';
65 } else {
66 $params = '&columnsOnly=' . $field . '&createExtension=0' . '&edit[sys_template][' . $id . ']=edit';
67 $editOnClick = BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'], '');
68 $startAnchor = '<a href="#" onclick="' . $editOnClick . '">';
69 }
70 $icon = IconUtility::getSpriteIcon(
71 'actions-document-open',
72 array('title' => $lang->sL('LLL:EXT:lang/locallang_common.xlf:editField', TRUE))
73 );
74 $ret .= $startAnchor . '<strong>' . $label . '</strong></a>';
75 $ret .= '</td><td width="80%">' . $data . '</td><td>' . $startAnchor . '<span class="btn btn-default">' . $icon . '</span></a></td></tr>';
76 return $ret;
77 }
78
79 /**
80 * Create an instance of \TYPO3\CMS\Core\TypoScript\ExtendedTemplateService in
81 * $GLOBALS['tmpl'] and looks for the first (visible) template
82 * record. If $template_uid was given and greater than zero, this record will be checked.
83 *
84 * Initializes the module. Done in this function because we may need to re-initialize if data is submitted!
85 *
86 * @param int $pageId The uid of the current page
87 * @param int $template_uid: The uid of the template record to be rendered (only if more than one template on the current page)
88 * @return bool Returns TRUE if a template record was found, otherwise FALSE
89 */
90 public function initialize_editor($pageId, $template_uid = 0) {
91 /** @var ExtendedTemplateService $tmpl */
92 $tmpl = GeneralUtility::makeInstance(ExtendedTemplateService::class);
93 $GLOBALS['tmpl'] = $tmpl;
94
95 // Do not log time-performance information
96 $tmpl->tt_track = FALSE;
97 $tmpl->init();
98
99 // Get the row of the first VISIBLE template of the page. where clause like the frontend.
100 $GLOBALS['tplRow'] = $tmpl->ext_getFirstTemplate($pageId, $template_uid);
101 if (is_array($GLOBALS['tplRow'])) {
102 $GLOBALS['tplRow'] = $this->processTemplateRowAfterLoading($GLOBALS['tplRow']);
103 return TRUE;
104 }
105 return FALSE;
106 }
107
108 /**
109 * Process template row after loading
110 *
111 * @param array $tplRow Template row
112 * @return array Preprocessed template row
113 */
114 public function processTemplateRowAfterLoading(array $tplRow) {
115 if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
116 // Let the recursion detection counter start at 91, so that only 10 recursive calls will be resolved
117 // Otherwise the editor will be bloated with way to many lines making it hard the break the cyclic recursion.
118 $tplRow['config'] = TypoScriptParser::checkIncludeLines($tplRow['config'], 91);
119 $tplRow['constants'] = TypoScriptParser::checkIncludeLines($tplRow['constants'], 91);
120 }
121 return $tplRow;
122 }
123
124 /**
125 * Process template row before saving
126 *
127 * @param array $tplRow Template row
128 * @return array Preprocessed template row
129 */
130 public function processTemplateRowBeforeSaving(array $tplRow) {
131 if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
132 $tplRow = TypoScriptParser::extractIncludes_array($tplRow);
133 }
134 return $tplRow;
135 }
136
137 /**
138 * @return LanguageService
139 */
140 protected function getLanguageService() {
141 return $GLOBALS['LANG'];
142 }
143
144 /**
145 * The main processing method if this class
146 *
147 * @return string Information of the template status or the taken actions as HTML string
148 */
149 public function main() {
150 $lang = $this->getLanguageService();
151 $lang->includeLLFile('EXT:tstemplate/Resources/Private/Language/locallang_info.xlf');
152 $this->pObj->MOD_MENU['includeTypoScriptFileContent'] = TRUE;
153 $e = $this->pObj->e;
154 // Checking for more than one template an if, set a menu...
155 $manyTemplatesMenu = $this->pObj->templateMenu();
156 $template_uid = 0;
157 if ($manyTemplatesMenu) {
158 $template_uid = $this->pObj->MOD_SETTINGS['templatesOnPage'];
159 }
160 // Initialize
161 $existTemplate = $this->initialize_editor($this->pObj->id, $template_uid);
162 $tplRow = $GLOBALS['tplRow'];
163 $saveId = 0;
164 if ($existTemplate) {
165 $saveId = $tplRow['_ORIG_uid'] ? $tplRow['_ORIG_uid'] : $tplRow['uid'];
166 }
167 // Create extension template
168 $newId = $this->pObj->createTemplate($this->pObj->id, $saveId);
169 if ($newId) {
170 // Switch to new template
171 $urlParameters = array(
172 'id' => $this->pObj->id,
173 'SET[templatesOnPage]' => $newId
174 );
175 $aHref = BackendUtility::getModuleUrl('web_ts', $urlParameters);
176 HttpUtility::redirect($aHref);
177 }
178 $tce = NULL;
179 $theOutput = '';
180 if ($existTemplate) {
181 // Update template ?
182 $POST = GeneralUtility::_POST();
183 if (
184 $POST['submit']
185 || MathUtility::canBeInterpretedAsInteger($POST['submit_x']) && MathUtility::canBeInterpretedAsInteger($POST['submit_y'])
186 || $POST['saveclose']
187 || MathUtility::canBeInterpretedAsInteger($POST['saveclose_x']) && MathUtility::canBeInterpretedAsInteger($POST['saveclose_y'])
188 ) {
189 // Set the data to be saved
190 $recData = array();
191 $alternativeFileName = array();
192 if (is_array($POST['data'])) {
193 foreach ($POST['data'] as $field => $val) {
194 switch ($field) {
195 case 'constants':
196 case 'config':
197 $recData['sys_template'][$saveId][$field] = $val;
198 break;
199 }
200 }
201 }
202 if (count($recData)) {
203 $recData['sys_template'][$saveId] = $this->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]);
204 // Create new tce-object
205 $tce = GeneralUtility::makeInstance(DataHandler::class);
206 $tce->stripslashes_values = FALSE;
207 $tce->alternativeFileName = $alternativeFileName;
208 // Initialize
209 $tce->start($recData, array());
210 // Saved the stuff
211 $tce->process_datamap();
212 // Clear the cache (note: currently only admin-users can clear the cache in tce_main.php)
213 $tce->clear_cacheCmd('all');
214 // tce were processed successfully
215 $this->tce_processed = TRUE;
216 // re-read the template ...
217 $this->initialize_editor($this->pObj->id, $template_uid);
218 $tplRow = $GLOBALS['tplRow'];
219 // reload template menu
220 $manyTemplatesMenu = $this->pObj->templateMenu();
221 }
222 }
223 // Hook post updating template/TCE processing
224 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postTCEProcessingHook'])) {
225 $postTCEProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postTCEProcessingHook'];
226 if (is_array($postTCEProcessingHook)) {
227 $hookParameters = array(
228 'POST' => $POST,
229 'tce' => $tce
230 );
231 foreach ($postTCEProcessingHook as $hookFunction) {
232 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
233 }
234 }
235 }
236 $content = '<a href="#" class="t3-js-clickmenutrigger" data-table="sys_template" data-uid="' . $tplRow['uid'] . '" data-listframe="1">' . IconUtility::getSpriteIconForRecord('sys_template', $tplRow) . '</a><strong>' . htmlspecialchars($tplRow['title']) . '</strong>' . htmlspecialchars((trim($tplRow['sitetitle']) ? ' (' . $tplRow['sitetitle'] . ')' : ''));
237 $theOutput .= $this->pObj->doc->section($lang->getLL('templateInformation'), $content, 0, 1);
238 if ($manyTemplatesMenu) {
239 $theOutput .= $this->pObj->doc->section('', $manyTemplatesMenu);
240 }
241 $theOutput .= $this->pObj->doc->spacer(10);
242 $numberOfRows = 35;
243 // If abort pressed, nothing should be edited:
244 if ($POST['saveclose'] || MathUtility::canBeInterpretedAsInteger($POST['saveclose_x']) && MathUtility::canBeInterpretedAsInteger($POST['saveclose_y'])) {
245 unset($e);
246 }
247 if (isset($e['constants'])) {
248 $outCode = '<textarea name="data[constants]" rows="' . $numberOfRows . '" wrap="off" class="text-monospace enable-tab"' . $this->pObj->doc->formWidth(48, TRUE, 'width:98%;height:70%') . ' class="text-monospace">' . GeneralUtility::formatForTextarea($tplRow['constants']) . '</textarea>';
249 $outCode .= '<input type="hidden" name="e[constants]" value="1">';
250 // Display "Include TypoScript file content?" checkbox
251 $outCode .= '<div class="checkbox"><label for="checkIncludeTypoScriptFileContent">' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[includeTypoScriptFileContent]', $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], '', '&e[constants]=1', 'id="checkIncludeTypoScriptFileContent"');
252 $outCode .= $lang->getLL('includeTypoScriptFileContent') . '</label></div><br />';
253 $theOutput .= $this->pObj->doc->spacer(15);
254 $theOutput .= $this->pObj->doc->section($lang->getLL('constants'), '', TRUE);
255 $theOutput .= $this->pObj->doc->sectionEnd() . $outCode;
256 }
257 if (isset($e['config'])) {
258 $outCode = '<textarea name="data[config]" rows="' . $numberOfRows . '" wrap="off" class="text-monospace enable-tab"' . $this->pObj->doc->formWidth(48, TRUE, 'width:98%;height:70%') . ' class="text-monospace">' . GeneralUtility::formatForTextarea($tplRow['config']) . '</textarea>';
259 $outCode .= '<input type="hidden" name="e[config]" value="1">';
260 // Display "Include TypoScript file content?" checkbox
261 $outCode .= '<div class="checkbox"><label for="checkIncludeTypoScriptFileContent">' . BackendUtility::getFuncCheck($this->pObj->id, 'SET[includeTypoScriptFileContent]', $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], '', '&e[config]=1', 'id="checkIncludeTypoScriptFileContent"');
262 $outCode .= $lang->getLL('includeTypoScriptFileContent') . '</label></div><br />';
263 $theOutput .= $this->pObj->doc->spacer(15);
264 $theOutput .= $this->pObj->doc->section($lang->getLL('setup'), '', TRUE);
265 $theOutput .= $this->pObj->doc->sectionEnd() . $outCode;
266 }
267
268 // Processing:
269 $outCode = '';
270 $outCode .= $this->tableRow($lang->getLL('title'), htmlspecialchars($tplRow['title']), 'title', $tplRow['uid']);
271 $outCode .= $this->tableRow($lang->getLL('sitetitle'), htmlspecialchars($tplRow['sitetitle']), 'sitetitle', $tplRow['uid']);
272 $outCode .= $this->tableRow($lang->getLL('description'), nl2br(htmlspecialchars($tplRow['description'])), 'description', $tplRow['uid']);
273 $outCode .= $this->tableRow($lang->getLL('constants'), sprintf($lang->getLL('editToView'), trim($tplRow['constants']) ? count(explode(LF, $tplRow['constants'])) : 0), 'constants', $tplRow['uid']);
274 $outCode .= $this->tableRow($lang->getLL('setup'), sprintf($lang->getLL('editToView'), trim($tplRow['config']) ? count(explode(LF, $tplRow['config'])) : 0), 'config', $tplRow['uid']);
275 $outCode = '<div class="table-fit"><table class="table table-striped table-hover">' . $outCode . '</table></div>';
276
277 // Edit all icon:
278 $editOnClick = BackendUtility::editOnClick(rawurlencode('&createExtension=0') . '&amp;edit[sys_template][' . $tplRow['uid'] . ']=edit', $GLOBALS['BACK_PATH'], '');
279 $icon = IconUtility::getSpriteIcon('actions-document-open', array('title' => $lang->getLL('editTemplateRecord'))) . $lang->getLL('editTemplateRecord');
280 $outCode .= '<br /><a href="#" onclick="' . $editOnClick . '"><strong>' . $icon . '</strong></a>';
281 $theOutput .= $this->pObj->doc->section('', $outCode);
282
283 // hook after compiling the output
284 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'])) {
285 $postOutputProcessingHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/tstemplate_info/class.tx_tstemplateinfo.php']['postOutputProcessingHook'];
286 if (is_array($postOutputProcessingHook)) {
287 $hookParameters = array(
288 'theOutput' => &$theOutput,
289 'POST' => $POST,
290 'e' => $e,
291 'tplRow' => $tplRow,
292 'numberOfRows' => $numberOfRows
293 );
294 foreach ($postOutputProcessingHook as $hookFunction) {
295 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
296 }
297 }
298 }
299 } else {
300 $theOutput .= $this->pObj->noTemplate(1);
301 }
302 return $theOutput;
303 }
304
305 }