Cleanup: Updated copyright comments
[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
45 protected $mode = '';
46
47 protected $ajaxSaveType = '';
48
49 /**
50 * counts the editors on the current page
51 *
52 * @var int
53 */
54 protected $editorCounter = 0;
55
56 /**
57 * flag to enable the t3editor
58 *
59 * @var bool
60 */
61 protected $_isEnabled = true;
62
63 /**
64 * sets the type of code to edit (::MODE_TYPOSCRIPT, ::MODE_JAVASCRIPT)
65 *
66 * @param $mode string expects one of the predefined constants
67 * @return tx_t3editor
68 */
69 public function setMode($mode) {
70 $this->mode = $mode;
71 return $this;
72 }
73
74 /**
75 *
76 * @param $ajaxSaveType
77 * @return tx_t3editor
78 */
79 public function setAjaxSaveType($ajaxSaveType) {
80 $this->ajaxSaveType = $ajaxSaveType;
81 return $this;
82 }
83
84 public function setModeByFile($file) {
85 $fileInfo = t3lib_div::split_fileref($file);
86 switch ($fileInfo['fileext']) {
87 case 'html':
88 case 'htm':
89 case 'tmpl':
90 $mode = self::MODE_HTML;
91 break;
92 case 'js':
93 $mode = self::MODE_JAVASCRIPT;
94 break;
95 case 'xml':
96 case 'svg':
97 $mode = self::MODE_XML;
98 break;
99 case 'css':
100 $mode = self::MODE_CSS;
101 break;
102 case 'ts':
103 $mode = self::MODE_TYPOSCRIPT;
104 break;
105 default:
106 $mode = FALSE;
107 }
108 $this->setMode($mode);
109 }
110
111 public function getMode() {
112 return $this->mode;
113 }
114
115 /**
116 * @return boolean true if the t3editor is enabled
117 */
118 public function isEnabled() {
119 return $this->_isEnabled;
120 }
121
122 /**
123 * Creates a new instance of the class
124 *
125 * @return void
126 */
127 public function __construct() {
128 $this->checkEditorIsDisabled();
129
130 // disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
131 $GLOBALS["BE_USER"]->uc['disablePMKTextarea'] = 1;
132 }
133
134 /**
135 * check if the t3editor should be disabled (by a POST value)
136 */
137 protected function checkEditorIsDisabled() {
138 $editorIsDisabled = t3lib_div::_POST('t3editor_disableEditor');
139
140 if (!empty($editorIsDisabled)) {
141 $editorIsDisabled = ($editorIsDisabled == 'true');
142 } else {
143 $editorIsDisabled = $GLOBALS['BE_USER']->uc['disableT3Editor'];
144 }
145
146 if ($GLOBALS['BE_USER']->uc['disableT3Editor'] != $editorIsDisabled) {
147 $GLOBALS['BE_USER']->uc['disableT3Editor'] = $editorIsDisabled;
148 $GLOBALS['BE_USER']->writeUC();
149 }
150 }
151
152 /**
153 * Retrieves JavaScript code (header part) for editor
154 *
155 * @param template $doc
156 * @return string JavaScript code
157 */
158 public function getJavascriptCode($doc) {
159 $content = '';
160
161 if ($this->isEnabled()) {
162
163 $path_t3e = t3lib_extmgm::extRelPath('t3editor');
164 $path_codemirror = 'contrib/codemirror/js/';
165
166 // include needed javascript-frameworks
167 $pageRenderer = $doc->getPageRenderer();
168 /** @var $pageRenderer t3lib_PageRenderer */
169 $pageRenderer->loadPrototype();
170 $pageRenderer->loadScriptaculous();
171
172 // include editor-css
173 $content .= '<link href="' .
174 t3lib_div::createVersionNumberedFilename($GLOBALS['BACK_PATH'] .
175 t3lib_extmgm::extRelPath('t3editor') .
176 'res/css/t3editor.css') .
177 '" type="text/css" rel="stylesheet" />';
178
179 // include editor-js-lib
180 $doc->loadJavascriptLib($path_codemirror . 'codemirror.js');
181 $doc->loadJavascriptLib($path_t3e . 'res/jslib/t3editor.js');
182
183 $content .= t3lib_div::wrapJS(
184 'T3editor = T3editor || {};' .
185 'T3editor.lang = ' . json_encode($this->getJavaScriptLabels()) .';' . LF.
186 'T3editor.PATH_t3e = "' . $GLOBALS['BACK_PATH'] . $path_t3e . '"; ' . LF.
187 'T3editor.PATH_codemirror = "' . $GLOBALS['BACK_PATH'] . $path_codemirror . '"; ' . LF.
188 'T3editor.URL_typo3 = "' . htmlspecialchars(t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir) . '"; ' .LF.
189 'T3editor.template = '. $this->getPreparedTemplate() .';' .LF.
190 ($this->ajaxSaveType ? 'T3editor.ajaxSavetype = "' . $this->ajaxSaveType . '";' . LF : '') .
191 ($this->mode ? 'T3editor.parserfile = ' . $this->getParserfileByMode($this->mode) . ';' . LF : '') .
192 ($this->mode ? 'T3editor.stylesheet = ' . $this->getStylesheetByMode($this->mode) . ';' : '')
193 );
194 $content .= $this->getModeSpecificJavascriptCode();
195 }
196
197 return $content;
198 }
199
200 public function getModeSpecificJavascriptCode() {
201 if (empty($this->mode)) {
202 return '';
203 }
204
205 $path_t3e = $GLOBALS['BACK_PATH'] . t3lib_extmgm::extRelPath('t3editor');
206
207 if ($this->mode == self::MODE_TYPOSCRIPT) {
208 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tsref.js' . '"></script>';
209 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/completionresult.js' . '"></script>';
210 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tsparser.js' . '"></script>';
211 $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tscodecompletion.js' . '"></script>';
212 }
213
214 $content .= t3lib_div::wrapJS(
215 'T3editor.parserfile = ' . $this->getParserfileByMode($this->mode) . ';' . LF .
216 'T3editor.stylesheet = ' . $this->getStylesheetByMode($this->mode) . ';'
217 );
218 return $content;
219 }
220
221 /**
222 * get the template code, prepared for javascript (no line breaks, quoted in single quotes)
223 *
224 * @return string the template code, prepared to use in javascript
225 */
226 protected function getPreparedTemplate() {
227 $T3Editor_template = t3lib_div::getURL(
228 t3lib_div::getFileAbsFileName(
229 'EXT:t3editor/res/templates/t3editor.html'
230 )
231 );
232 $T3Editor_template = addslashes($T3Editor_template);
233 $T3Editor_template = str_replace(LF, "' + '", $T3Editor_template);
234
235 return '\'' . $T3Editor_template . '\'';
236 }
237
238 /**
239 * determine the correct parser js file for given mode
240 *
241 * @param string $mode
242 * @return string parser file name
243 */
244 protected function getParserfileByMode($mode) {
245 switch ($mode) {
246 case tx_t3editor::MODE_TYPOSCRIPT:
247 $relPath = $GLOBALS['BACK_PATH'] . t3lib_extmgm::extRelPath('t3editor') . 'res/jslib/parse_typoscript/';
248 $parserfile = '["' . $relPath . 'tokenizetyposcript.js", "' . $relPath . 'parsetyposcript.js"]';
249 break;
250
251 case tx_t3editor::MODE_JAVASCRIPT:
252 $parserfile = '["tokenizejavascript.js", "parsejavascript.js"]';
253 break;
254
255 case tx_t3editor::MODE_CSS:
256 $parserfile = '"parsecss.js"';
257 break;
258
259 case tx_t3editor::MODE_XML:
260 $parserfile = '"parsexml.js"';
261 break;
262
263 case tx_t3editor::MODE_HTML:
264 $parserfile = '["tokenizejavascript.js", "parsejavascript.js", "parsecss.js", "parsexml.js", "parsehtmlmixed.js"]';
265 break;
266 }
267 return $parserfile;
268 }
269
270 /**
271 * determine the correct css file for given mode
272 *
273 * @param string $mode
274 * @return string css file name
275 */
276 protected function getStylesheetByMode($mode) {
277 switch ($mode) {
278 case tx_t3editor::MODE_TYPOSCRIPT:
279 $stylesheet = '"res/css/typoscriptcolors.css"';
280 break;
281
282 case tx_t3editor::MODE_JAVASCRIPT:
283 $stylesheet = '"res/css/jscolors.css"';
284 break;
285
286 case tx_t3editor::MODE_CSS:
287 $stylesheet = '"res/css/csscolors.css"';
288 break;
289
290 case tx_t3editor::MODE_XML:
291 $stylesheet = '"res/css/xmlcolors.css"';
292 break;
293
294 case tx_t3editor::MODE_HTML:
295 $stylesheet = '"res/css/xmlcolors.css"';
296 // FIXME add css and js files
297 break;
298 }
299 return '[T3editor.PATH_t3e + ' . $stylesheet . ', T3editor.PATH_t3e + "res/css/t3editor_inner.css"]';
300 }
301
302 /**
303 * Gets the labels to be used in JavaScript in the Ext JS interface.
304 * TODO this method is copied from EXT:Recycler, maybe this should be refactored into a helper class
305 *
306 * @return array The labels to be used in JavaScript
307 */
308 protected function getJavaScriptLabels() {
309 $coreLabels = array();
310 $extensionLabels = $this->getJavaScriptLabelsFromLocallang('js.', 'label_');
311 return array_merge($coreLabels, $extensionLabels);
312 }
313
314 /**
315 * Gets labels to be used in JavaScript fetched from the current locallang file.
316 * TODO this method is copied from EXT:Recycler, maybe this should be refactored into a helper class
317 *
318 * @param string $selectionPrefix: Prefix to select the correct labels (default: 'js.')
319 * @param string $stripFromSelectionName: Sub-prefix to be removed from label names in the result (default: '')
320 * @return array Lables to be used in JavaScript of the current locallang file
321 * @todo Check, whether this method can be moved in a generic way to $GLOBALS['LANG']
322 */
323 protected function getJavaScriptLabelsFromLocallang($selectionPrefix = 'js.', $stripFromSelectionName = '') {
324 $extraction = array();
325 $labels = array_merge(
326 (array)$GLOBALS['LOCAL_LANG']['default'],
327 (array)$GLOBALS['LOCAL_LANG'][$GLOBALS['LANG']->lang]
328 );
329 // Regular expression to strip the selection prefix and possibly something from the label name:
330 $labelPattern = '#^' . preg_quote($selectionPrefix, '#') . '(' . preg_quote($stripFromSelectionName, '#') . ')?#';
331 // Iterate throuh all locallang lables:
332 foreach ($labels as $label => $value) {
333 if (strpos($label, $selectionPrefix) === 0) {
334 $key = preg_replace($labelPattern, '', $label);
335 $extraction[$key] = $value;
336 }
337 }
338 return $extraction;
339 }
340
341 /**
342 * Generates HTML with code editor
343 *
344 * @param string $name Name attribute of HTML tag
345 * @param string $class Class attribute of HTML tag
346 * @param string $content Content of the editor
347 * @param string $additionalParams Any additional editor parameters
348 * @param string $alt Alt attribute
349 * @return string Generated HTML code for editor
350 */
351 public function getCodeEditor($name, $class='', $content='', $additionalParams='', $alt='', array $hiddenfields = array()) {
352 $code = '';
353
354 if ($this->isEnabled()) {
355 $this->editorCounter++;
356
357 $class .= ' t3editor';
358 $alt = htmlspecialchars($alt);
359 if (!empty($alt)) {
360 $alt = ' alt="' . $alt . '"';
361 }
362
363 $code .= '<div>' .
364 '<textarea id="t3editor_' . $this->editorCounter . '" ' .
365 'name="' . $name . '" ' .
366 'class="' . $class . '" ' .
367 $additionalParams . ' ' .
368 $alt . '>' .
369 $content .
370 '</textarea></div>';
371
372 $checked = $GLOBALS['BE_USER']->uc['disableT3Editor'] ? 'checked="checked"' : '';
373
374 $code .= '<br /><br />' .
375 '<input type="checkbox" ' .
376 'class="checkbox t3editor_disableEditor" ' .
377 'onclick="T3editor.toggleEditor(this);" ' .
378 'name="t3editor_disableEditor" ' .
379 'value="true" ' .
380 'id="t3editor_disableEditor_' . $this->editorCounter . '_checkbox" ' .
381 $checked.' />&nbsp;' .
382 '<label for="t3editor_disableEditor_' . $this->editorCounter . '_checkbox">' .
383 $GLOBALS['LANG']->getLL('deactivate') .
384 '</label>' .
385 '<br /><br />';
386
387 if (count($hiddenfields)) {
388 foreach ($hiddenfields as $name => $value) {
389 $code.= '<input type="hidden" ' .
390 'name="' . $name . '" ' .
391 'value="' . $value .
392 '" />';
393 }
394 }
395
396 } else {
397 // fallback
398 if (!empty($class)) {
399 $class = 'class="' . $class . '" ';
400 }
401
402 $code .= '<textarea name="' . $name . '" ' .
403 $class . $additionalParams.'>' .
404 $content . '</textarea>';
405 }
406
407 return $code;
408 }
409
410
411
412 /**
413 * Save the content from t3editor retrieved via Ajax
414 *
415 * new Ajax.Request('/dev/t3e/dummy/typo3/ajax.php', {
416 * parameters: {
417 * ajaxID: 'tx_t3editor::saveCode',
418 * t3editor_savetype: 'tx_tstemplateinfo'
419 * }
420 * });
421 *
422 * @param array params Parameters (not used yet)
423 * @param TYPO3AJAX ajaxObj AjaxObject to handle response
424 */
425 public function ajaxSaveCode($params, $ajaxObj) {
426 // cancel if its not an Ajax request
427 if((TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX)) {
428 $ajaxObj->setContentFormat('json');
429 $codeType = t3lib_div::_GP('t3editor_savetype');
430 $savingsuccess = false;
431
432 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'])) {
433 $_params = array(
434 'pObj' => &$this,
435 'type' => $codeType,
436 'ajaxObj' => &$ajaxObj,
437 );
438 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'] as $key => $_funcRef) {
439 $savingsuccess = t3lib_div::callUserFunction($_funcRef,$_params,$this) || $savingsuccess;
440 }
441 }
442
443 $ajaxObj->setContent(array('result' => $savingsuccess));
444 }
445 }
446
447 /**
448 * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
449 * (called by typo3/ajax.php)
450 *
451 * @param array $params: additional parameters (not used here)
452 * @param TYPO3AJAX &$ajaxObj: the TYPO3AJAX object of this request
453 * @return void
454 * @author Oliver Hader <oliver@typo3.org>
455 */
456 public function getPlugins($params, TYPO3AJAX &$ajaxObj) {
457 $result = array();
458 $plugins =& $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
459
460 if (is_array($plugins)) {
461 $result = array_values($plugins);
462 }
463
464 $ajaxObj->setContent($result);
465 $ajaxObj->setContentFormat('jsonbody');
466 }
467
468 }
469
470
471
472 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/t3editor/classes/class.tx_t3editor.php'])) {
473 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/t3editor/classes/class.tx_t3editor.php']);
474 }
475
476 ?>