2 /***************************************************************
5 * (c) 2007-2011 Tobias Liebig <mail_typo3@etobi.de>
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.
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.
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.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
30 * Provides a javascript-driven code editor with syntax highlighting for TS, HTML, CSS and more
32 * @author Tobias Liebig <mail_typo3@etobi.de>
35 $GLOBALS['LANG']->includeLLFile('EXT:t3editor/locallang.xml');
37 class tx_t3editor
implements t3lib_Singleton
{
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';
50 protected $ajaxSaveType = '';
53 * counts the editors on the current page
57 protected $editorCounter = 0;
60 * flag to enable the t3editor
64 protected $_isEnabled = TRUE;
67 * sets the type of code to edit (::MODE_TYPOSCRIPT, ::MODE_JAVASCRIPT)
69 * @param $mode string expects one of the predefined constants
72 public function setMode($mode) {
79 * @param $ajaxSaveType
82 public function setAjaxSaveType($ajaxSaveType) {
83 $this->ajaxSaveType
= $ajaxSaveType;
87 public function setModeByFile($file) {
88 $fileInfo = t3lib_div
::split_fileref($file);
89 return $this->setModeByType($fileInfo['fileext']);
92 public function setModeByType($type) {
97 $mode = self
::MODE_HTML
;
100 $mode = self
::MODE_JAVASCRIPT
;
104 $mode = self
::MODE_XML
;
107 $mode = self
::MODE_CSS
;
110 $mode = self
::MODE_TYPOSCRIPT
;
113 $mode = self
::MODE_SPARQL
;
118 $mode = self
::MODE_PHP
;
121 $mode = self
::MODE_MIXED
;
123 $this->setMode($mode);
126 public function getMode() {
131 * @return boolean TRUE if the t3editor is enabled
133 public function isEnabled() {
134 return $this->_isEnabled
;
138 * Creates a new instance of the class
142 public function __construct() {
143 // disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
144 $GLOBALS["BE_USER"]->uc
['disablePMKTextarea'] = 1;
148 * Retrieves JavaScript code (header part) for editor
150 * @param template $doc
151 * @return string JavaScript code
153 public function getJavascriptCode($doc) {
156 if ($this->isEnabled()) {
158 $path_t3e = t3lib_extmgm
::extRelPath('t3editor');
159 $path_codemirror = 'contrib/codemirror/js/';
161 // include needed javascript-frameworks
162 $pageRenderer = $doc->getPageRenderer();
163 /** @var $pageRenderer t3lib_PageRenderer */
164 $pageRenderer->loadPrototype();
165 $pageRenderer->loadScriptaculous();
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" />';
174 // include editor-js-lib
175 $doc->loadJavascriptLib($path_codemirror . 'codemirror.js');
176 $doc->loadJavascriptLib($path_t3e . 'res/jslib/t3editor.js');
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
187 $content .= $this->getModeSpecificJavascriptCode();
193 public function getModeSpecificJavascriptCode() {
194 if (empty($this->mode
)) {
198 $path_t3e = $GLOBALS['BACK_PATH'] . t3lib_extmgm
::extRelPath('t3editor');
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>';
208 $content .= t3lib_div
::wrapJS(
209 'T3editor.parserfile = ' . $this->getParserfileByMode($this->mode
) . ';' . LF
.
210 'T3editor.stylesheet = ' . $this->getStylesheetByMode($this->mode
) . ';'
216 * get the template code, prepared for javascript (no line breaks, quoted in single quotes)
218 * @return string the template code, prepared to use in javascript
220 protected function getPreparedTemplate() {
221 $T3Editor_template = t3lib_div
::getUrl(
222 t3lib_div
::getFileAbsFileName(
223 'EXT:t3editor/res/templates/t3editor.html'
226 $T3Editor_template = addslashes($T3Editor_template);
227 $T3Editor_template = str_replace(
233 return '\'' . $T3Editor_template . '\'';
237 * determine the correct parser js file for given mode
239 * @param string $mode
240 * @return string parser file name
242 protected function getParserfileByMode($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"]';
249 case self
::MODE_JAVASCRIPT
:
250 $parserfile = '["tokenizejavascript.js", "parsejavascript.js"]';
254 $parserfile = '"parsecss.js"';
258 $parserfile = '"parsexml.js"';
261 case self
::MODE_SPARQL
:
262 $parserfile = '"parsesparql.js"';
265 case self
::MODE_HTML
:
266 $parserfile = '["tokenizejavascript.js", "parsejavascript.js", "parsecss.js", "parsexml.js", "parsehtmlmixed.js"]';
270 case self
::MODE_MIXED
:
272 '"tokenizejavascript.js", ' .
273 '"parsejavascript.js", ' .
276 '"../contrib/php/js/tokenizephp.js", ' .
277 '"../contrib/php/js/parsephp.js", ' .
278 '"../contrib/php/js/parsephphtmlmixed.js"' .
286 * determine the correct css file for given mode
288 * @param string $mode
289 * @return string css file name
291 protected function getStylesheetByMode($mode) {
293 case self
::MODE_TYPOSCRIPT
:
294 $stylesheet = 'T3editor.PATH_t3e + "res/css/typoscriptcolors.css"';
297 case self
::MODE_JAVASCRIPT
:
298 $stylesheet = 'T3editor.PATH_codemirror + "../css/jscolors.css"';
302 $stylesheet = 'T3editor.PATH_codemirror + "../css/csscolors.css"';
306 $stylesheet = 'T3editor.PATH_codemirror + "../css/xmlcolors.css"';
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"';
315 case self
::MODE_SPARQL
:
316 $stylesheet = 'T3editor.PATH_codemirror + "../css/sparqlcolors.css"';
320 $stylesheet = 'T3editor.PATH_codemirror + "../contrib/php/css/phpcolors.css"';
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"';
330 if ($stylesheet != '') {
331 $stylesheet = '' . $stylesheet . ', ';
333 return '[' . $stylesheet . 'T3editor.PATH_t3e + "res/css/t3editor_inner.css"]';
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
340 * @return array The labels to be used in JavaScript
342 protected function getJavaScriptLabels() {
343 $coreLabels = array();
344 $extensionLabels = $this->getJavaScriptLabelsFromLocallang('js.', 'label_');
345 return array_merge($coreLabels, $extensionLabels);
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
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']
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
]
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;
376 * Generates HTML with code editor
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
385 public function getCodeEditor($name, $class='', $content='', $additionalParams='', $alt='', array $hiddenfields = array()) {
388 if ($this->isEnabled()) {
389 $this->editorCounter++
;
391 $class .= ' t3editor';
392 $alt = htmlspecialchars($alt);
394 $alt = ' alt="' . $alt . '"';
398 '<textarea id="t3editor_' . $this->editorCounter
. '" ' .
399 'name="' . $name . '" ' .
400 'class="' . $class . '" ' .
401 $additionalParams . ' ' .
406 $checked = $GLOBALS['BE_USER']->uc
['disableT3Editor'] ?
'checked="checked"' : '';
408 $code .= '<br /><br />' .
409 '<input type="checkbox" ' .
410 'class="checkbox t3editor_disableEditor" ' .
411 'onclick="T3editor.toggleEditor(this);" ' .
412 'name="t3editor_disableEditor" ' .
414 'id="t3editor_disableEditor_' . $this->editorCounter
. '_checkbox" ' .
415 $checked.' /> ' .
416 '<label for="t3editor_disableEditor_' . $this->editorCounter
. '_checkbox">' .
417 $GLOBALS['LANG']->getLL('deactivate') .
421 if (count($hiddenfields)) {
422 foreach ($hiddenfields as $name => $value) {
423 $code.= '<input type="hidden" ' .
424 'name="' . $name . '" ' .
432 if (!empty($class)) {
433 $class = 'class="' . $class . '" ';
436 $code .= '<textarea name="' . $name . '" ' .
437 $class . $additionalParams.'>' .
438 $content . '</textarea>';
447 * Save the content from t3editor retrieved via Ajax
449 * new Ajax.Request('/dev/t3e/dummy/typo3/ajax.php', {
451 * ajaxID: 'tx_t3editor::saveCode',
452 * t3editor_savetype: 'tx_tstemplateinfo'
456 * @param array params Parameters (not used yet)
457 * @param TYPO3AJAX ajaxObj AjaxObject to handle response
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;
466 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'])) {
470 'ajaxObj' => &$ajaxObj,
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;
477 $ajaxObj->setContent(array('result' => $savingsuccess));
482 * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
483 * (called by typo3/ajax.php)
485 * @param array $params: additional parameters (not used here)
486 * @param TYPO3AJAX &$ajaxObj: the TYPO3AJAX object of this request
488 * @author Oliver Hader <oliver@typo3.org>
490 public function getPlugins($params, TYPO3AJAX
&$ajaxObj) {
492 $plugins =& $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
494 if (is_array($plugins)) {
495 $result = array_values($plugins);
498 $ajaxObj->setContent($result);
499 $ajaxObj->setContentFormat('jsonbody');