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