[TASK] self:: is not used for local static member reference
[Packages/TYPO3.CMS.git] / typo3 / sysext / t3editor / classes / class.tx_t3editor.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2007-2011 Tobias Liebig <mail_typo3@etobi.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28
29 /**
30 * Provides a javascript-driven code editor with syntax highlighting for TS, HTML, CSS and more
31 *
32 * @author Tobias Liebig <mail_typo3@etobi.de>
33 */
34
35 $GLOBALS['LANG']->includeLLFile('EXT:t3editor/locallang.xml');
36
37 class tx_t3editor implements t3lib_Singleton {
38
39 const MODE_TYPOSCRIPT = 'typoscript';
40 const MODE_JAVASCRIPT = 'javascript';
41 const MODE_CSS = 'css';
42 const MODE_XML = 'xml';
43 const MODE_HTML = 'html';
44 const MODE_PHP = 'php';
45 const MODE_SPARQL = 'sparql';
46 const MODE_MIXED = 'mixed';
47
48 protected $mode = '';
49
50 protected $ajaxSaveType = '';
51
52 /**
53 * counts the editors on the current page
54 *
55 * @var int
56 */
57 protected $editorCounter = 0;
58
59 /**
60 * flag to enable the t3editor
61 *
62 * @var bool
63 */
64 protected $_isEnabled = TRUE;
65
66 /**
67 * sets the type of code to edit (::MODE_TYPOSCRIPT, ::MODE_JAVASCRIPT)
68 *
69 * @param $mode string expects one of the predefined constants
70 * @return tx_t3editor
71 */
72 public function setMode($mode) {
73 $this->mode = $mode;
74 return $this;
75 }
76
77 /**
78 *
79 * @param $ajaxSaveType
80 * @return tx_t3editor
81 */
82 public function setAjaxSaveType($ajaxSaveType) {
83 $this->ajaxSaveType = $ajaxSaveType;
84 return $this;
85 }
86
87 public function setModeByFile($file) {
88 $fileInfo = t3lib_div::split_fileref($file);
89 return $this->setModeByType($fileInfo['fileext']);
90 }
91
92 public function setModeByType($type) {
93 switch ($type) {
94 case 'html':
95 case 'htm':
96 case 'tmpl':
97 $mode = self::MODE_HTML;
98 break;
99 case 'js':
100 $mode = self::MODE_JAVASCRIPT;
101 break;
102 case 'xml':
103 case 'svg':
104 $mode = self::MODE_XML;
105 break;
106 case 'css':
107 $mode = self::MODE_CSS;
108 break;
109 case 'ts':
110 $mode = self::MODE_TYPOSCRIPT;
111 break;
112 case 'sparql':
113 $mode = self::MODE_SPARQL;
114 break;
115 case 'php':
116 case 'phpsh':
117 case 'inc':
118 $mode = self::MODE_PHP;
119 break;
120 default:
121 $mode = self::MODE_MIXED;
122 }
123 $this->setMode($mode);
124 }
125
126 public function getMode() {
127 return $this->mode;
128 }
129
130 /**
131 * @return boolean TRUE if the t3editor is enabled
132 */
133 public function isEnabled() {
134 return $this->_isEnabled;
135 }
136
137 /**
138 * Creates a new instance of the class
139 *
140 * @return void
141 */
142 public function __construct() {
143 // disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
144 $GLOBALS["BE_USER"]->uc['disablePMKTextarea'] = 1;
145 }
146
147 /**
148 * Retrieves JavaScript code (header part) for editor
149 *
150 * @param template $doc
151 * @return string JavaScript code
152 */
153 public function getJavascriptCode($doc) {
154 $content = '';
155
156 if ($this->isEnabled()) {
157
158 $path_t3e = t3lib_extmgm::extRelPath('t3editor');
159 $path_codemirror = 'contrib/codemirror/js/';
160
161 // include needed javascript-frameworks
162 $pageRenderer = $doc->getPageRenderer();
163 /** @var $pageRenderer t3lib_PageRenderer */
164 $pageRenderer->loadPrototype();
165 $pageRenderer->loadScriptaculous();
166
167 // include editor-css
168 $content .= '<link href="' .
169 t3lib_div::createVersionNumberedFilename($GLOBALS['BACK_PATH'] .
170 t3lib_extmgm::extRelPath('t3editor') .
171 'res/css/t3editor.css') .
172 '" type="text/css" rel="stylesheet" />';
173
174 // include editor-js-lib
175 $doc->loadJavascriptLib($path_codemirror . 'codemirror.js');
176 $doc->loadJavascriptLib($path_t3e . 'res/jslib/t3editor.js');
177
178 $content .= t3lib_div::wrapJS(
179 'T3editor = T3editor || {};' .
180 'T3editor.lang = ' . json_encode($this->getJavaScriptLabels()) .';' . LF .
181 'T3editor.PATH_t3e = "' . $GLOBALS['BACK_PATH'] . $path_t3e . '"; ' . LF .
182 'T3editor.PATH_codemirror = "' . $GLOBALS['BACK_PATH'] . $path_codemirror . '"; ' . LF .
183 'T3editor.URL_typo3 = "' . htmlspecialchars(t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir) . '"; ' . LF .
184 'T3editor.template = '. $this->getPreparedTemplate() .';' . LF .
185 'T3editor.ajaxSavetype = "' . $this->ajaxSaveType . '";' . LF
186 );
187 $content .= $this->getModeSpecificJavascriptCode();
188 }
189
190 return $content;
191 }
192
193 public function getModeSpecificJavascriptCode() {
194 if (empty($this->mode)) {
195 return '';
196 }
197
198 $path_t3e = $GLOBALS['BACK_PATH'] . t3lib_extmgm::extRelPath('t3editor');
199 $content = '';
200
201 if ($this->mode === self::MODE_TYPOSCRIPT) {
202 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tsref.js' . '"></script>';
203 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/completionresult.js' . '"></script>';
204 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tsparser.js' . '"></script>';
205 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tscodecompletion.js' . '"></script>';
206 }
207
208 $content .= t3lib_div::wrapJS(
209 'T3editor.parserfile = ' . $this->getParserfileByMode($this->mode) . ';' . LF .
210 'T3editor.stylesheet = ' . $this->getStylesheetByMode($this->mode) . ';'
211 );
212 return $content;
213 }
214
215 /**
216 * get the template code, prepared for javascript (no line breaks, quoted in single quotes)
217 *
218 * @return string the template code, prepared to use in javascript
219 */
220 protected function getPreparedTemplate() {
221 $T3Editor_template = t3lib_div::getUrl(
222 t3lib_div::getFileAbsFileName(
223 'EXT:t3editor/res/templates/t3editor.html'
224 )
225 );
226 $T3Editor_template = addslashes($T3Editor_template);
227 $T3Editor_template = str_replace(
228 array(CR, LF),
229 array('', "' + '"),
230 $T3Editor_template
231 );
232
233 return '\'' . $T3Editor_template . '\'';
234 }
235
236 /**
237 * determine the correct parser js file for given mode
238 *
239 * @param string $mode
240 * @return string parser file name
241 */
242 protected function getParserfileByMode($mode) {
243 switch ($mode) {
244 case self::MODE_TYPOSCRIPT:
245 $relPath = ($GLOBALS['BACK_PATH'] ? $GLOBALS['BACK_PATH'] : '../../../' ) . t3lib_extmgm::extRelPath('t3editor') . 'res/jslib/parse_typoscript/';
246 $parserfile = '["' . $relPath . 'tokenizetyposcript.js", "' . $relPath . 'parsetyposcript.js"]';
247 break;
248
249 case self::MODE_JAVASCRIPT:
250 $parserfile = '["tokenizejavascript.js", "parsejavascript.js"]';
251 break;
252
253 case self::MODE_CSS:
254 $parserfile = '"parsecss.js"';
255 break;
256
257 case self::MODE_XML:
258 $parserfile = '"parsexml.js"';
259 break;
260
261 case self::MODE_SPARQL:
262 $parserfile = '"parsesparql.js"';
263 break;
264
265 case self::MODE_HTML:
266 $parserfile = '["tokenizejavascript.js", "parsejavascript.js", "parsecss.js", "parsexml.js", "parsehtmlmixed.js"]';
267 break;
268
269 case self::MODE_PHP:
270 case self::MODE_MIXED:
271 $parserfile = '[' .
272 '"tokenizejavascript.js", ' .
273 '"parsejavascript.js", ' .
274 '"parsecss.js", ' .
275 '"parsexml.js", ' .
276 '"../contrib/php/js/tokenizephp.js", ' .
277 '"../contrib/php/js/parsephp.js", ' .
278 '"../contrib/php/js/parsephphtmlmixed.js"' .
279 ']';
280 break;
281 }
282 return $parserfile;
283 }
284
285 /**
286 * determine the correct css file for given mode
287 *
288 * @param string $mode
289 * @return string css file name
290 */
291 protected function getStylesheetByMode($mode) {
292 switch ($mode) {
293 case self::MODE_TYPOSCRIPT:
294 $stylesheet = 'T3editor.PATH_t3e + "res/css/typoscriptcolors.css"';
295 break;
296
297 case self::MODE_JAVASCRIPT:
298 $stylesheet = 'T3editor.PATH_codemirror + "../css/jscolors.css"';
299 break;
300
301 case self::MODE_CSS:
302 $stylesheet = 'T3editor.PATH_codemirror + "../css/csscolors.css"';
303 break;
304
305 case self::MODE_XML:
306 $stylesheet = 'T3editor.PATH_codemirror + "../css/xmlcolors.css"';
307 break;
308
309 case self::MODE_HTML:
310 $stylesheet = 'T3editor.PATH_codemirror + "../css/xmlcolors.css", ' .
311 'T3editor.PATH_codemirror + "../css/jscolors.css", ' .
312 'T3editor.PATH_codemirror + "../css/csscolors.css"';
313 break;
314
315 case self::MODE_SPARQL:
316 $stylesheet = 'T3editor.PATH_codemirror + "../css/sparqlcolors.css"';
317 break;
318
319 case self::MODE_PHP:
320 $stylesheet = 'T3editor.PATH_codemirror + "../contrib/php/css/phpcolors.css"';
321 break;
322
323 case self::MODE_MIXED:
324 $stylesheet = 'T3editor.PATH_codemirror + "../css/xmlcolors.css", ' .
325 'T3editor.PATH_codemirror + "../css/jscolors.css", ' .
326 'T3editor.PATH_codemirror + "../css/csscolors.css", ' .
327 'T3editor.PATH_codemirror + "../contrib/php/css/phpcolors.css"';
328 break;
329 }
330 if ($stylesheet != '') {
331 $stylesheet = '' . $stylesheet . ', ';
332 }
333 return '[' . $stylesheet . 'T3editor.PATH_t3e + "res/css/t3editor_inner.css"]';
334 }
335
336 /**
337 * Gets the labels to be used in JavaScript in the Ext JS interface.
338 * TODO this method is copied from EXT:Recycler, maybe this should be refactored into a helper class
339 *
340 * @return array The labels to be used in JavaScript
341 */
342 protected function getJavaScriptLabels() {
343 $coreLabels = array();
344 $extensionLabels = $this->getJavaScriptLabelsFromLocallang('js.', 'label_');
345 return array_merge($coreLabels, $extensionLabels);
346 }
347
348 /**
349 * Gets labels to be used in JavaScript fetched from the current locallang file.
350 * TODO this method is copied from EXT:Recycler, maybe this should be refactored into a helper class
351 *
352 * @param string $selectionPrefix: Prefix to select the correct labels (default: 'js.')
353 * @param string $stripFromSelectionName: Sub-prefix to be removed from label names in the result (default: '')
354 * @return array Lables to be used in JavaScript of the current locallang file
355 * @todo Check, whether this method can be moved in a generic way to $GLOBALS['LANG']
356 */
357 protected function getJavaScriptLabelsFromLocallang($selectionPrefix = 'js.', $stripFromSelectionName = '') {
358 $extraction = array();
359 $labels = array_merge(
360 (array)$GLOBALS['LOCAL_LANG']['default'],
361 (array)$GLOBALS['LOCAL_LANG'][$GLOBALS['LANG']->lang]
362 );
363 // Regular expression to strip the selection prefix and possibly something from the label name:
364 $labelPattern = '#^' . preg_quote($selectionPrefix, '#') . '(' . preg_quote($stripFromSelectionName, '#') . ')?#';
365 // Iterate throuh all locallang lables:
366 foreach ($labels as $label => $value) {
367 if (strpos($label, $selectionPrefix) === 0) {
368 $key = preg_replace($labelPattern, '', $label);
369 $extraction[$key] = $value;
370 }
371 }
372 return $extraction;
373 }
374
375 /**
376 * Generates HTML with code editor
377 *
378 * @param string $name Name attribute of HTML tag
379 * @param string $class Class attribute of HTML tag
380 * @param string $content Content of the editor
381 * @param string $additionalParams Any additional editor parameters
382 * @param string $alt Alt attribute
383 * @return string Generated HTML code for editor
384 */
385 public function getCodeEditor($name, $class='', $content='', $additionalParams='', $alt='', array $hiddenfields = array()) {
386 $code = '';
387
388 if ($this->isEnabled()) {
389 $this->editorCounter++;
390
391 $class .= ' t3editor';
392 $alt = htmlspecialchars($alt);
393 if (!empty($alt)) {
394 $alt = ' alt="' . $alt . '"';
395 }
396
397 $code .= '<div>' .
398 '<textarea id="t3editor_' . $this->editorCounter . '" ' .
399 'name="' . $name . '" ' .
400 'class="' . $class . '" ' .
401 $additionalParams . ' ' .
402 $alt . '>' .
403 $content .
404 '</textarea></div>';
405
406 $checked = $GLOBALS['BE_USER']->uc['disableT3Editor'] ? 'checked="checked"' : '';
407
408 $code .= '<br /><br />' .
409 '<input type="checkbox" ' .
410 'class="checkbox t3editor_disableEditor" ' .
411 'onclick="T3editor.toggleEditor(this);" ' .
412 'name="t3editor_disableEditor" ' .
413 'value="true" ' .
414 'id="t3editor_disableEditor_' . $this->editorCounter . '_checkbox" ' .
415 $checked.' />&nbsp;' .
416 '<label for="t3editor_disableEditor_' . $this->editorCounter . '_checkbox">' .
417 $GLOBALS['LANG']->getLL('deactivate') .
418 '</label>' .
419 '<br /><br />';
420
421 if (count($hiddenfields)) {
422 foreach ($hiddenfields as $name => $value) {
423 $code.= '<input type="hidden" ' .
424 'name="' . $name . '" ' .
425 'value="' . $value .
426 '" />';
427 }
428 }
429
430 } else {
431 // fallback
432 if (!empty($class)) {
433 $class = 'class="' . $class . '" ';
434 }
435
436 $code .= '<textarea name="' . $name . '" ' .
437 $class . $additionalParams.'>' .
438 $content . '</textarea>';
439 }
440
441 return $code;
442 }
443
444
445
446 /**
447 * Save the content from t3editor retrieved via Ajax
448 *
449 * new Ajax.Request('/dev/t3e/dummy/typo3/ajax.php', {
450 * parameters: {
451 * ajaxID: 'tx_t3editor::saveCode',
452 * t3editor_savetype: 'tx_tstemplateinfo'
453 * }
454 * });
455 *
456 * @param array params Parameters (not used yet)
457 * @param TYPO3AJAX ajaxObj AjaxObject to handle response
458 */
459 public function ajaxSaveCode($params, $ajaxObj) {
460 // cancel if its not an Ajax request
461 if((TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX)) {
462 $ajaxObj->setContentFormat('json');
463 $codeType = t3lib_div::_GP('t3editor_savetype');
464 $savingsuccess = FALSE;
465
466 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'])) {
467 $_params = array(
468 'pObj' => &$this,
469 'type' => $codeType,
470 'ajaxObj' => &$ajaxObj,
471 );
472 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'] as $key => $_funcRef) {
473 $savingsuccess = t3lib_div::callUserFunction($_funcRef, $_params, $this) || $savingsuccess;
474 }
475 }
476
477 $ajaxObj->setContent(array('result' => $savingsuccess));
478 }
479 }
480
481 /**
482 * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
483 * (called by typo3/ajax.php)
484 *
485 * @param array $params: additional parameters (not used here)
486 * @param TYPO3AJAX &$ajaxObj: the TYPO3AJAX object of this request
487 * @return void
488 * @author Oliver Hader <oliver@typo3.org>
489 */
490 public function getPlugins($params, TYPO3AJAX &$ajaxObj) {
491 $result = array();
492 $plugins =& $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
493
494 if (is_array($plugins)) {
495 $result = array_values($plugins);
496 }
497
498 $ajaxObj->setContent($result);
499 $ajaxObj->setContentFormat('jsonbody');
500 }
501 }
502 ?>