[TASK] Correct directory names for Resources
[Packages/TYPO3.CMS.git] / typo3 / sysext / t3editor / Classes / T3editor.php
1 <?php
2 namespace TYPO3\CMS\T3editor;
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\Page\PageRenderer;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Provides a javascript-driven code editor with syntax highlighting for TS, HTML, CSS and more
22 */
23 class T3editor implements \TYPO3\CMS\Core\SingletonInterface {
24
25 const MODE_TYPOSCRIPT = 'typoscript';
26 const MODE_JAVASCRIPT = 'javascript';
27 const MODE_CSS = 'css';
28 const MODE_XML = 'xml';
29 const MODE_HTML = 'html';
30 const MODE_PHP = 'php';
31 const MODE_SPARQL = 'sparql';
32 const MODE_MIXED = 'mixed';
33
34 /**
35 * @var string
36 */
37 protected $mode = '';
38
39 /**
40 * @var string
41 */
42 protected $ajaxSaveType = '';
43
44 /**
45 * Counts the editors on the current page
46 *
47 * @var int
48 */
49 protected $editorCounter = 0;
50
51 /**
52 * Relative path to EXT:t3editor
53 *
54 * @var string
55 */
56 protected $relExtPath = '';
57
58 /**
59 * Relative directory to codemirror
60 *
61 * @var string
62 */
63 protected $codemirrorPath = 'sysext/t3editor/Resources/Public/JavaScript/Contrib/codemirror/js/';
64
65 /**
66 * RequireJS modules loaded for code completion
67 *
68 * @var array
69 */
70 protected $codeCompletionComponents = array('TsRef', 'CompletionResult', 'TsParser', 'TsCodeCompletion');
71
72 /**
73 * sets the type of code to edit (::MODE_TYPOSCRIPT, ::MODE_JAVASCRIPT)
74 *
75 * @param $mode string Expects one of the predefined constants
76 * @return \TYPO3\CMS\T3editor\T3editor
77 */
78 public function setMode($mode) {
79 $this->mode = $mode;
80 return $this;
81 }
82
83 /**
84 * Set the AJAX save type
85 *
86 * @param string $ajaxSaveType
87 * @return \TYPO3\CMS\T3editor\T3editor
88 */
89 public function setAjaxSaveType($ajaxSaveType) {
90 $this->ajaxSaveType = $ajaxSaveType;
91 return $this;
92 }
93
94 /**
95 * Set mode by file
96 *
97 * @param string $file
98 * @return string
99 */
100 public function setModeByFile($file) {
101 $fileInfo = GeneralUtility::split_fileref($file);
102 return $this->setModeByType($fileInfo['fileext']);
103 }
104
105 /**
106 * Set mode by type
107 *
108 * @param string $type
109 * @return void
110 */
111 public function setModeByType($type) {
112 switch ($type) {
113 case 'html':
114 case 'htm':
115 case 'tmpl':
116 $mode = self::MODE_HTML;
117 break;
118 case 'js':
119 $mode = self::MODE_JAVASCRIPT;
120 break;
121 case 'xml':
122 case 'svg':
123 $mode = self::MODE_XML;
124 break;
125 case 'css':
126 $mode = self::MODE_CSS;
127 break;
128 case 'ts':
129 $mode = self::MODE_TYPOSCRIPT;
130 break;
131 case 'sparql':
132 $mode = self::MODE_SPARQL;
133 break;
134 case 'php':
135 case 'phpsh':
136 case 'inc':
137 $mode = self::MODE_PHP;
138 break;
139 default:
140 $mode = self::MODE_MIXED;
141 }
142 $this->setMode($mode);
143 }
144
145 /**
146 * Get mode
147 *
148 * @return string
149 */
150 public function getMode() {
151 return $this->mode;
152 }
153
154 /**
155 * @return bool TRUE if the t3editor is enabled
156 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
157 */
158 public function isEnabled() {
159 GeneralUtility::logDeprecatedFunction();
160 return TRUE;
161 }
162
163 /**
164 * Creates a new instance of the class
165 */
166 public function __construct() {
167 $GLOBALS['LANG']->includeLLFile('EXT:t3editor/locallang.xlf');
168 // Disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
169 $GLOBALS['BE_USER']->uc['disablePMKTextarea'] = 1;
170
171 $this->relExtPath = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('t3editor');
172 }
173
174 /**
175 * Retrieves JavaScript code (header part) for editor
176 *
177 * @param \TYPO3\CMS\Backend\Template\DocumentTemplate $doc
178 * @return string
179 */
180 public function getJavascriptCode($doc) {
181 /** @var $pageRenderer \TYPO3\CMS\Core\Page\PageRenderer */
182 $pageRenderer = $this->getPageRenderer();
183
184 // Include editor-css
185 $cssFile = GeneralUtility::createVersionNumberedFilename(
186 $this->relExtPath . 'Resources/Public/Css/t3editor.css'
187 );
188 $doc->addStyleSheet('t3editor', $cssFile);
189
190 // Include editor-js-lib
191 $doc->loadJavascriptLib($this->codemirrorPath . 'codemirror.js');
192 $this->loadTypoScriptCodeCompletion($doc);
193 $pageRenderer->loadRequireJsModule('TYPO3/CMS/T3editor/T3editor');
194 return '';
195 }
196
197 /**
198 * Load additional code completion for TypoScript
199 *
200 * @param \TYPO3\CMS\Backend\Template\DocumentTemplate $doc
201 */
202 protected function loadTypoScriptCodeCompletion($doc) {
203 if ($this->mode === self::MODE_TYPOSCRIPT) {
204 $pageRenderer = $doc->getPageRenderer();
205 foreach ($this->codeCompletionComponents as $codeCompletionComponent) {
206 $pageRenderer->loadRequireJsModule('TYPO3/CMS/T3editor/Plugins/CodeCompletion/' . $codeCompletionComponent);
207 }
208 }
209 }
210
211 /**
212 * Get the template code, prepared for javascript (no line breaks, quoted in single quotes)
213 *
214 * @return string The template code, prepared to use in javascript
215 */
216 protected function getPreparedTemplate() {
217 $T3editor_template = GeneralUtility::getUrl(
218 GeneralUtility::getFileAbsFileName('EXT:t3editor/Resources/Private/Templates/t3editor.html')
219 );
220 return str_replace(array(CR, LF), '', $T3editor_template);
221 }
222
223 /**
224 * Determine the correct parser js file for given mode
225 *
226 * @param string $mode
227 * @return string Parser file name
228 */
229 protected function getParserfileByMode($mode) {
230 switch ($mode) {
231 case self::MODE_TYPOSCRIPT:
232 $relPath = '../../../parse_typoscript/';
233 $parserfile = array($relPath . 'tokenizetyposcript.js', $relPath . 'parsetyposcript.js');
234 break;
235 case self::MODE_JAVASCRIPT:
236 $parserfile = array('tokenizetyposcript.js', 'parsejavascript.js');
237 break;
238 case self::MODE_CSS:
239 $parserfile = 'parsecss.js';
240 break;
241 case self::MODE_XML:
242 $parserfile = 'parsexml.js';
243 break;
244 case self::MODE_SPARQL:
245 $parserfile = 'parsesparql.js';
246 break;
247 case self::MODE_HTML:
248 $parserfile = array('tokenizejavascript.js', 'parsejavascript.js', 'parsecss.js', 'parsexml.js', 'parsehtmlmixed.js');
249 break;
250 case self::MODE_PHP:
251 case self::MODE_MIXED:
252 $parserfile = array('tokenizejavascript.js', 'parsejavascript.js', 'parsecss.js', 'parsexml.js', '../contrib/php/js/tokenizephp.js', '../contrib/php/js/parsephp.js', '../contrib/php/js/parsephphtmlmixed.js');
253 break;
254 }
255 return json_encode($parserfile);
256 }
257
258 /**
259 * Determine the correct css file for given mode
260 *
261 * @param string $mode
262 * @return string css file name
263 */
264 protected function getStylesheetByMode($mode) {
265 switch ($mode) {
266 case self::MODE_TYPOSCRIPT:
267 $stylesheet = array($this->relExtPath . 'Resources/Public/Css/typoscriptcolors.css');
268 break;
269 case self::MODE_JAVASCRIPT:
270 $stylesheet = array($this->codemirrorPath . '../css/jscolors.css');
271 break;
272 case self::MODE_CSS:
273 $stylesheet = array($this->codemirrorPath . '../css/csscolors.css');
274 break;
275 case self::MODE_XML:
276 $stylesheet = array($this->codemirrorPath . '../css/xmlcolors.css');
277 break;
278 case self::MODE_HTML:
279 $stylesheet = array($this->codemirrorPath . '../css/xmlcolors.css', $this->codemirrorPath . '../css/jscolors.css', $this->codemirrorPath . '../css/csscolors.css');
280 break;
281 case self::MODE_SPARQL:
282 $stylesheet = array($this->codemirrorPath . '../css/sparqlcolors.css');
283 break;
284 case self::MODE_PHP:
285 $stylesheet = array($this->codemirrorPath . '../contrib/php/css/phpcolors.css');
286 break;
287 case self::MODE_MIXED:
288 $stylesheet = array($this->codemirrorPath . '../css/xmlcolors.css', $this->codemirrorPath . '../css/jscolors.css', $this->codemirrorPath . '../css/csscolors.css', $this->codemirrorPath . '../contrib/php/css/phpcolors.css');
289 break;
290 default:
291 $stylesheet = array();
292 }
293 $stylesheet[] = $this->relExtPath . 'Resources/Public/Css/t3editor_inner.css';
294 return json_encode($stylesheet);
295 }
296
297 /**
298 * Generates HTML with code editor
299 *
300 * @param string $name Name attribute of HTML tag
301 * @param string $class Class attribute of HTML tag
302 * @param string $content Content of the editor
303 * @param string $additionalParams Any additional editor parameters
304 * @param string $alt Alt attribute
305 * @param array $hiddenfields
306 * @return string Generated HTML code for editor
307 */
308 public function getCodeEditor($name, $class = '', $content = '', $additionalParams = '', $alt = '', array $hiddenfields = array()) {
309 $code = '';
310 $class .= ' t3editor';
311 $alt = htmlspecialchars($alt);
312 if (!empty($alt)) {
313 $alt = ' alt="' . $alt . '"';
314 }
315 $code .=
316 '<div class="t3editor">'
317 . '<div class="t3e_wrap">'
318 . $this->getPreparedTemplate()
319 . '</div>'
320 . '<textarea '
321 . 'id="t3editor_' . $this->editorCounter . '" '
322 . 'name="' . $name . '" '
323 . 'class="' . $class . '" '
324 . $additionalParams . ' '
325 . $alt
326 . ' data-labels="' . htmlspecialchars(json_encode($GLOBALS['LANG']->getLabelsWithPrefix('js.', 'label_'))) . '"'
327 . ' data-instance-number="' . $this->editorCounter . '"'
328 . ' data-editor-path="' . htmlspecialchars($this->relExtPath) . '"'
329 . ' data-codemirror-path="' . htmlspecialchars($this->codemirrorPath) . '"'
330 . ' data-ajaxsavetype="' . htmlspecialchars($this->ajaxSaveType) . '"'
331 . ' data-parserfile="' . htmlspecialchars($this->getParserfileByMode($this->mode)) . '"'
332 . ' data-stylesheet="' . htmlspecialchars($this->getStylesheetByMode($this->mode)) . '"'
333 . '>' . htmlspecialchars($content)
334 . '</textarea>'
335 . '</div>';
336 if (!empty($hiddenfields)) {
337 foreach ($hiddenfields as $name => $value) {
338 $code .= '<input type="hidden" ' . 'name="' . $name . '" ' . 'value="' . $value . '" />';
339 }
340 }
341 $this->editorCounter++;
342 return $code;
343 }
344
345 /**
346 * Save the content from t3editor retrieved via Ajax
347 *
348 * new Ajax.Request('/dev/t3e/dummy/typo3/ajax.php', {
349 * parameters: {
350 * ajaxID: 'T3editor::saveCode',
351 * t3editor_savetype: 'TypoScriptTemplateInformationModuleFunctionController'
352 * }
353 * });
354 *
355 * @param array $params Parameters (not used yet)
356 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj AjaxRequestHandler to handle response
357 */
358 public function ajaxSaveCode($params, $ajaxObj) {
359 // cancel if its not an Ajax request
360 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
361 $ajaxObj->setContentFormat('json');
362 $codeType = GeneralUtility::_GP('t3editor_savetype');
363 $savingsuccess = FALSE;
364 try {
365 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'])) {
366 $_params = array(
367 'pObj' => &$this,
368 'type' => $codeType,
369 'ajaxObj' => &$ajaxObj
370 );
371 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'] as $key => $_funcRef) {
372 $savingsuccess = GeneralUtility::callUserFunction($_funcRef, $_params, $this) || $savingsuccess;
373 }
374 }
375 } catch (\Exception $e) {
376 $ajaxObj->setContent(array('result' => FALSE, 'exceptionMessage' => htmlspecialchars($e->getMessage()), 'exceptionCode' => $e->getCode()));
377 return;
378 }
379 $ajaxObj->setContent(array('result' => $savingsuccess));
380 }
381 }
382
383 /**
384 * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
385 * (called by typo3/ajax.php)
386 *
387 * @param array $params additional parameters (not used here)
388 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj The AjaxRequestHandler object of this request
389 * @return void
390 */
391 public function getPlugins($params, \TYPO3\CMS\Core\Http\AjaxRequestHandler &$ajaxObj) {
392 $result = array();
393 $plugins = &$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
394 if (is_array($plugins)) {
395 $result = array_values($plugins);
396 }
397 $ajaxObj->setContent($result);
398 $ajaxObj->setContentFormat('jsonbody');
399 }
400
401 /**
402 * @return PageRenderer
403 */
404 protected function getPageRenderer() {
405 return GeneralUtility::makeInstance(PageRenderer::class);
406 }
407
408 }