Fixed bug #11129: Validation issue: End tag for "br" omitted, but OMITTAG NO was...
[Packages/TYPO3.CMS.git] / typo3 / sysext / t3editor / class.tx_t3editor.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2007-2009 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 * [CLASS/FUNCTION INDEX of SCRIPT]
29 *
30 *
31 *
32 * 47: class tx_t3editor
33 * 85: public function __construct()
34 * 117: public function getJavascriptCode()
35 * 162: public function getCodeEditor($name, $class='', $content='', $additionalParams='', $alt='')
36 *
37 * TOTAL FUNCTIONS: 3
38 * (This index is automatically created/updated by the extension "extdeveval")
39 *
40 */
41
42 /**
43 * Provides a javascript-driven code editor with syntax highlighting for TS, HTML, CSS and more
44 *
45 * @author Tobias Liebig <mail_typo3@etobi.de>
46 */
47 class tx_t3editor {
48
49 /**
50 * path to the main javascript-file
51 *
52 * @var string
53 */
54 protected $filepathEditorlib;
55
56 /**
57 * path to the main stylesheet
58 *
59 * @TODO: make it configurable
60 *
61 * @var string
62 */
63 protected $filepathEditorcss;
64
65 /**
66 * counts the editors on the current page
67 *
68 * @var int
69 */
70 protected $editorCounter;
71
72 /**
73 * flag to enable the t3editor
74 *
75 * @var bool
76 */
77 public $isEnabled;
78
79 /**
80 * Creates a new instance of the class
81 *
82 * @return void
83 */
84 public function __construct() {
85
86 $this->filepathEditorlib = 'jslib/t3editor.js';
87 $this->filepathEditorcss = 'css/t3editor.css';
88 $this->editorCounter = 0;
89 $this->isEnabled = true; //TODO add a method to switch to false and turn off the editor completly
90
91 // check BE user settings
92 //TODO give $state a more descriptive name / state of/for what?
93 $state = t3lib_div::_GP('t3editor_disableEditor') == 'true' ? true : $GLOBALS['BE_USER']->uc['disableT3Editor'];
94 $this->setBEUCdisableT3Editor($state);
95
96 // disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
97 $GLOBALS["BE_USER"]->uc['disablePMKTextarea'] = 1;
98 }
99
100 /**
101 * Sets editor enabled/disabled state
102 *
103 * @param boolean $state <code>true</code> if editor is disabled
104 * @return void
105 */
106 public function setBEUCdisableT3Editor($state) { //TODO better descriptive name for $state
107 if ($GLOBALS['BE_USER']->uc['disableT3Editor'] != $state) {
108 $GLOBALS['BE_USER']->uc['disableT3Editor'] = $state;
109
110 $GLOBALS['BE_USER']->writeUC();
111 }
112 }
113
114 /**
115 * Retrieves JavaScript code for editor
116 *
117 * @param template $doc
118 * @return string JavaScript code
119 */
120 public function getJavascriptCode($doc) {
121 $code = ''; // TODO find a more descriptive name (low prio)
122
123 if ($this->isEnabled) {
124
125 $path_t3e = t3lib_extmgm::extRelPath('t3editor');
126
127 // include needed javascript-frameworks
128 $doc->loadPrototype();
129 $doc->loadScriptaculous();
130
131 // include editor-css
132 $code.= '<link href="' .
133 $GLOBALS['BACK_PATH'] .
134 t3lib_extmgm::extRelPath('t3editor') .
135 $this->filepathEditorcss .
136 '" type="text/css" rel="stylesheet" />';
137
138 // include editor-js-lib
139 $doc->loadJavascriptLib($path_t3e . 'jslib/codemirror/codemirror.js');
140 $doc->loadJavascriptLib($path_t3e . 'jslib/t3editor.js');
141
142 $doc->loadJavascriptLib($path_t3e . 'jslib/ts_codecompletion/tsref.js');
143 $doc->loadJavascriptLib($path_t3e . 'jslib/ts_codecompletion/completionresult.js');
144 $doc->loadJavascriptLib($path_t3e . 'jslib/ts_codecompletion/tsparser.js');
145 $doc->loadJavascriptLib($path_t3e . 'jslib/ts_codecompletion/tscodecompletion.js');
146
147 // set correct path to the editor
148
149 $code.= t3lib_div::wrapJS(
150 'var PATH_t3e = "' . $GLOBALS['BACK_PATH'] . t3lib_extmgm::extRelPath('t3editor') . '"; ' .
151 'var URL_typo3 = "' . htmlspecialchars(t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir) . '"; '
152 );
153 }
154
155 return $code;
156 }
157
158 /**
159 * Generates HTML with code editor
160 *
161 * @param string $name Name attribute of HTML tag
162 * @param string $class Class attribute of HTML tag
163 * @param string $content Content of the editor
164 * @param string $additionalParams Any additional editor parameters
165 * @param string $alt Alt attribute
166 * @return string Generated HTML code for editor
167 */
168 public function getCodeEditor($name, $class='', $content='', $additionalParams='', $alt='', array $hiddenfields = array()) {
169 $code = '';
170
171 if ($this->isEnabled) {
172 $this->editorCounter++;
173
174 $class .= ' t3editor';
175 if (!empty($alt)) {
176 $alt = ' alt="' . $alt . '"';
177 }
178
179 $code .= '<div>' .
180 '<textarea id="t3editor_' . $this->editorCounter . '" ' .
181 'name="' . $name . '" ' .
182 'class="' . $class . '" ' .
183 $additionalParams . ' ' .
184 $alt . '>' .
185 $content .
186 '</textarea></div>';
187
188 $checked = $GLOBALS['BE_USER']->uc['disableT3Editor'] ? 'checked="checked"' : '';
189
190 $code .= '<br/><br/>' .
191 '<input type="checkbox" ' .
192 'class="checkbox" ' .
193 'onclick="t3editor_toggleEditor(this);" ' .
194 'name="t3editor_disableEditor" ' .
195 'value="true" ' .
196 'id="t3editor_disableEditor_' . $this->editorCounter.'_checkbox" ' .
197 $checked.' />&nbsp;' .
198 '<label for="t3editor_disableEditor_' . $this->editorCounter . '_checkbox">' .
199 'deactivate t3editor' .
200 '</label>' .
201 '<br/><br/>';
202
203 if (count($hiddenfields)) {
204 foreach ($hiddenfields as $name => $value) {
205 $code.= '<input type="hidden" ' .
206 'name="' . $name . '" ' .
207 'value="' . $value .
208 '" />';
209 }
210 }
211
212 } else {
213 // fallback
214 if (!empty($class)) {
215 $class = 'class="' . $class . '" ';
216 }
217
218 $code .= '<textarea name="' . $name . '" ' .
219 $class . $additionalParams.'>' .
220 $content . '</textarea>';
221 }
222
223 return $code;
224 }
225
226
227 public function makeGlobalEditorInstance() {
228 if (!is_object($GLOBALS['T3_VAR']['t3editorObj'])) {
229 $GLOBALS['T3_VAR']['t3editorObj'] = t3lib_div::getUserObj('EXT:t3editor/class.tx_t3editor.php:&tx_t3editor');
230 }
231 }
232
233 /**
234 * Hook-function: inject t3editor JavaScript code before the page is compiled
235 * called in typo3/template.php:startPage
236 *
237 * @param array $parameters
238 * @param template $pObj
239 */
240 public function preStartPageHook($parameters, $pObj) {
241 // enable editor in Template-Modul
242 if (preg_match('/sysext\/tstemplate\/ts\/index\.php/', $_SERVER['SCRIPT_NAME'])) {
243
244 tx_t3editor::makeGlobalEditorInstance();
245
246 // insert javascript code in document header
247 $pObj->JScode .= $GLOBALS['T3_VAR']['t3editorObj']->getJavascriptCode($pObj);
248 }
249 }
250
251
252 /**
253 * Hook-function:
254 * called in typo3/sysext/tstemplate_info/class.tx_tstemplateinfo.php
255 *
256 * @param array $parameters
257 * @param tx_tstemplateinfo $pObj
258 */
259 public function postOutputProcessingHook($parameters, $pObj) {
260 tx_t3editor::makeGlobalEditorInstance();
261 if (!$GLOBALS['T3_VAR']['t3editorObj']->isEnabled) {
262 return;
263 }
264
265 // Template Constants
266 if ($parameters['e']['constants']) {
267 $attributes = 'rows="' . $parameters['numberOfRows'] . '" ' .
268 'wrap="off" ' .
269 $pObj->pObj->doc->formWidthText(48, 'width:98%;height:60%', 'off');
270
271 $title = 'Template: ' . htmlspecialchars($parameters['tplRow']['title']) . ': Constants';
272
273 $outCode = $GLOBALS['T3_VAR']['t3editorObj']->getCodeEditor(
274 'data[constants]',
275 'fixed-font enable-tab',
276 t3lib_div::formatForTextarea($parameters['tplRow']['constants']),
277 $attributes,
278 $title,
279 array(
280 'pageId' => intval($pObj->pObj->id),
281 't3editor_savetype' => 'tx_tstemplateinfo',
282 )
283 );
284 $parameters['theOutput'] = preg_replace(
285 '/\<textarea name="data\[constants\]".*\>([^\<]*)\<\/textarea\>/mi',
286 $outCode,
287 $parameters['theOutput']
288 );
289 }
290
291 // Template Setup
292 if ($parameters['e']['config']) {
293 $attributes = 'rows="' . $parameters['numberOfRows'] . '" ' .
294 'wrap="off" ' .
295 $pObj->pObj->doc->formWidthText(48, 'width:98%;height:60%', 'off');
296
297 $title = 'Template: ' . htmlspecialchars($parameters['tplRow']['title']) . ': Setup';
298
299 $outCode = $GLOBALS['T3_VAR']['t3editorObj']->getCodeEditor(
300 'data[config]',
301 'fixed-font enable-tab',
302 t3lib_div::formatForTextarea($parameters['tplRow']['config']),
303 $attributes,
304 $title,
305 array(
306 'pageId' => intval($pObj->pObj->id),
307 't3editor_savetype' => 'tx_tstemplateinfo',
308 )
309 );
310 $parameters['theOutput'] = preg_replace(
311 '/\<textarea name="data\[config\]".*\>([^\<]*)\<\/textarea\>/mi',
312 $outCode,
313 $parameters['theOutput']
314 );
315 }
316 }
317
318 /**
319 * Save the content from t3editor retrieved via Ajax
320 *
321 * new Ajax.Request('/dev/t3e/dummy/typo3/ajax.php', {
322 * parameters: {
323 * ajaxID: 'tx_t3editor::saveCode',
324 * t3editor_savetype: 'tx_tstemplateinfo'
325 * }
326 * });
327 *
328 * @param array params Parameters (not used yet)
329 * @param TYPO3AJAX ajaxObj AjaxObject to handle response
330 */
331 public function saveCode($params, $ajaxObj) {
332 // cancel if its not an Ajax request
333 if((TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX)) {
334 $ajaxObj->setContentFormat('json');
335 $codeType = t3lib_div::_GP('t3editor_savetype');
336 $savingsuccess = false;
337
338 switch ($codeType) {
339 case 'tx_tstemplateinfo':
340 $savingsuccess = $this->saveCodeTsTemplateInfo();
341 break;
342
343 // TODO: fileadmin, extmng, TCEform, ...
344
345 default:
346 $ajaxObj->setError('Unknown content type: ' . $codeType);
347 }
348 $ajaxObj->setContent(array('result' => $savingsuccess));
349 }
350 }
351
352 /**
353 * Process saving request like in class.tstemplateinfo.php (TCE processing)
354 *
355 * @return boolean true if successful
356 */
357 public function saveCodeTsTemplateInfo() {
358 $savingsuccess = false;
359
360 $pageId = t3lib_div::_GP('pageId');
361
362 if (!is_numeric($pageId) || $pageId < 1) {
363 return false;
364 }
365
366 // if given use the requested template_uid
367 // if not, use the first template-record on the page (in this case there should only be one record!)
368 $set = t3lib_div::_GP('SET');
369 $template_uid = $set['templatesOnPage'] ? $set['templatesOnPage'] : 0;
370
371 $tmpl = t3lib_div::makeInstance('t3lib_tsparser_ext'); // Defined global here!
372 $tmpl->tt_track = 0; // Do not log time-performance information
373 $tmpl->init();
374
375 // Get the row of the first VISIBLE template of the page. whereclause like the frontend.
376 $tplRow = $tmpl->ext_getFirstTemplate($pageId, $template_uid);
377 $existTemplate = (is_array($tplRow) ? true : false);
378
379 if ($existTemplate) {
380 $saveId = ($tplRow['_ORIG_uid'] ? $tplRow['_ORIG_uid'] : $tplRow['uid']);
381
382 // Update template ?
383 $POST = t3lib_div::_POST();
384
385 if ($POST['submit']) {
386 require_once(PATH_t3lib . 'class.t3lib_tcemain.php');
387
388 // Set the data to be saved
389 $recData = array();
390
391 if (is_array($POST['data'])) {
392 foreach ($POST['data'] as $field => $val) {
393 switch ($field) {
394 case 'constants':
395 case 'config':
396 case 'title':
397 case 'sitetitle':
398 case 'description':
399 $recData['sys_template'][$saveId][$field] = $val;
400 break;
401 }
402 }
403 }
404 if (count($recData)) {
405 // Create new tce-object
406 $tce = t3lib_div::makeInstance('t3lib_TCEmain');
407 $tce->stripslashes_values = 0;
408
409 // Initialize
410 $tce->start($recData, array());
411
412 // Saved the stuff
413 $tce->process_datamap();
414
415 // Clear the cache (note: currently only admin-users can clear the
416 // cache in tce_main.php)
417 $tce->clear_cacheCmd('all');
418
419 $savingsuccess = true;
420 }
421 }
422 }
423 return $savingsuccess;
424 }
425
426 /**
427 * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
428 * (called by typo3/ajax.php)
429 *
430 * @param array $params: additional parameters (not used here)
431 * @param TYPO3AJAX &$ajaxObj: the TYPO3AJAX object of this request
432 * @return void
433 * @author Oliver Hader <oliver@typo3.org>
434 */
435 public function getPlugins($params, TYPO3AJAX &$ajaxObj) {
436 $result = array();
437 $plugins =& $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
438
439 if (is_array($plugins)) {
440 $result = array_values($plugins);
441 }
442
443 $ajaxObj->setContent($result);
444 $ajaxObj->setContentFormat('jsonbody');
445 }
446 }
447
448
449
450 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/t3editor/class.tx_t3editor.php']) {
451 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/t3editor/class.tx_t3editor.php']);
452 }
453
454 ?>