TYPO3 API  SVNRelease
class.tx_t3editor.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2007-2011 Tobias Liebig <mail_typo3@etobi.de>
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *  A copy is found in the textfile GPL.txt and important notices to the license
00017 *  from the author is found in LICENSE.txt distributed with these scripts.
00018 *
00019 *
00020 *  This script is distributed in the hope that it will be useful,
00021 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 *  GNU General Public License for more details.
00024 *
00025 *  This copyright notice MUST APPEAR in all copies of the script!
00026 ***************************************************************/
00027 
00028 
00029 /**
00030  * Provides a javascript-driven code editor with syntax highlighting for TS, HTML, CSS and more
00031  *
00032  * @author  Tobias Liebig <mail_typo3@etobi.de>
00033  */
00034 
00035 $GLOBALS['LANG']->includeLLFile('EXT:t3editor/locallang.xml');
00036 
00037 class tx_t3editor implements t3lib_Singleton {
00038 
00039     const MODE_TYPOSCRIPT = 'typoscript';
00040     const MODE_JAVASCRIPT = 'javascript';
00041     const MODE_CSS = 'css';
00042     const MODE_XML = 'xml';
00043     const MODE_HTML = 'html';
00044     const MODE_PHP = 'php';
00045     const MODE_MIXED = 'mixed';
00046 
00047     protected $mode = '';
00048 
00049     protected $ajaxSaveType = '';
00050 
00051     /**
00052      * counts the editors on the current page
00053      *
00054      * @var     int
00055      */
00056     protected $editorCounter = 0;
00057 
00058     /**
00059      * flag to enable the t3editor
00060      *
00061      * @var     bool
00062      */
00063     protected $_isEnabled = true;
00064 
00065     /**
00066      * sets the type of code to edit (::MODE_TYPOSCRIPT, ::MODE_JAVASCRIPT)
00067      *
00068      * @param   $mode   string expects one of the predefined constants
00069      * @return  tx_t3editor
00070      */
00071     public function setMode($mode) {
00072         $this->mode = $mode;
00073         return $this;
00074     }
00075 
00076     /**
00077      *
00078      * @param   $ajaxSaveType
00079      * @return  tx_t3editor
00080      */
00081     public function setAjaxSaveType($ajaxSaveType) {
00082         $this->ajaxSaveType = $ajaxSaveType;
00083         return $this;
00084     }
00085 
00086     public function setModeByFile($file) {
00087         $fileInfo = t3lib_div::split_fileref($file);
00088         switch ($fileInfo['fileext']) {
00089             case 'html':
00090             case 'htm':
00091             case 'tmpl':
00092                 $mode = self::MODE_HTML;
00093                 break;
00094             case 'js':
00095                 $mode = self::MODE_JAVASCRIPT;
00096                 break;
00097             case 'xml':
00098             case 'svg':
00099                 $mode = self::MODE_XML;
00100                 break;
00101             case 'css':
00102                 $mode = self::MODE_CSS;
00103                 break;
00104             case 'ts':
00105                 $mode = self::MODE_TYPOSCRIPT;
00106                 break;
00107             case 'php':
00108             case 'phpsh':
00109             case 'inc':
00110                 $mode = self::MODE_PHP;
00111                 break;
00112             default:
00113                 $mode = self::MODE_MIXED;
00114         }
00115         $this->setMode($mode);
00116     }
00117 
00118     public function getMode() {
00119         return $this->mode;
00120     }
00121 
00122     /**
00123      * @return  boolean     true if the t3editor is enabled
00124      */
00125     public function isEnabled() {
00126         return $this->_isEnabled;
00127     }
00128 
00129     /**
00130      * Creates a new instance of the class
00131      *
00132      * @return  void
00133      */
00134     public function __construct() {
00135             // disable pmktextarea to avoid conflicts (thanks Peter Klein for this suggestion)
00136         $GLOBALS["BE_USER"]->uc['disablePMKTextarea'] = 1;
00137     }
00138 
00139     /**
00140      * Retrieves JavaScript code (header part) for editor
00141      *
00142      * @param   template    $doc
00143      * @return  string      JavaScript code
00144      */
00145     public function getJavascriptCode($doc) {
00146         $content = '';
00147 
00148         if ($this->isEnabled()) {
00149 
00150             $path_t3e = t3lib_extmgm::extRelPath('t3editor');
00151             $path_codemirror = 'contrib/codemirror/js/';
00152 
00153                 // include needed javascript-frameworks
00154             $pageRenderer = $doc->getPageRenderer();
00155             /** @var $pageRenderer t3lib_PageRenderer */
00156             $pageRenderer->loadPrototype();
00157             $pageRenderer->loadScriptaculous();
00158 
00159                 // include editor-css
00160             $content .= '<link href="' .
00161                 t3lib_div::createVersionNumberedFilename($GLOBALS['BACK_PATH'] .
00162                 t3lib_extmgm::extRelPath('t3editor') .
00163                 'res/css/t3editor.css') .
00164                 '" type="text/css" rel="stylesheet" />';
00165 
00166                 // include editor-js-lib
00167             $doc->loadJavascriptLib($path_codemirror . 'codemirror.js');
00168             $doc->loadJavascriptLib($path_t3e . 'res/jslib/t3editor.js');
00169 
00170             $content .= t3lib_div::wrapJS(
00171                 'T3editor = T3editor || {};' .
00172                 'T3editor.lang = ' . json_encode($this->getJavaScriptLabels()) .';' . LF.
00173                 'T3editor.PATH_t3e = "' . $GLOBALS['BACK_PATH'] . $path_t3e . '"; ' . LF.
00174                 'T3editor.PATH_codemirror = "' . $GLOBALS['BACK_PATH'] . $path_codemirror . '"; ' . LF.
00175                 'T3editor.URL_typo3 = "' . htmlspecialchars(t3lib_div::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir) . '"; ' .LF.
00176                 'T3editor.template = '. $this->getPreparedTemplate() .';' .LF.
00177                 ($this->ajaxSaveType ? 'T3editor.ajaxSavetype = "' . $this->ajaxSaveType . '";' . LF : '') .
00178                 ($this->mode ? 'T3editor.parserfile = ' . $this->getParserfileByMode($this->mode) . ';' . LF : '') .
00179                 ($this->mode ? 'T3editor.stylesheet = ' . $this->getStylesheetByMode($this->mode) . ';' : '')
00180             );
00181             $content .= $this->getModeSpecificJavascriptCode();
00182         }
00183 
00184         return $content;
00185     }
00186 
00187     public function getModeSpecificJavascriptCode() {
00188         if (empty($this->mode)) {
00189             return '';
00190         }
00191 
00192         $path_t3e = $GLOBALS['BACK_PATH'] . t3lib_extmgm::extRelPath('t3editor');
00193         $content = '';
00194 
00195         if ($this->mode === self::MODE_TYPOSCRIPT) {
00196             $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tsref.js' . '"></script>';
00197             $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/completionresult.js' . '"></script>';
00198             $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tsparser.js' . '"></script>';
00199             $content .= '<script type="text/javascript" src="' . $path_t3e . 'res/jslib/ts_codecompletion/tscodecompletion.js' . '"></script>';
00200         }
00201 
00202         $content .= t3lib_div::wrapJS(
00203             'T3editor.parserfile = ' . $this->getParserfileByMode($this->mode) . ';' . LF .
00204             'T3editor.stylesheet = ' . $this->getStylesheetByMode($this->mode) . ';'
00205         );
00206         return $content;
00207     }
00208 
00209     /**
00210      * get the template code, prepared for javascript (no line breaks, quoted in single quotes)
00211      *
00212      * @return  string  the template code, prepared to use in javascript
00213      */
00214     protected function getPreparedTemplate() {
00215         $T3Editor_template = t3lib_div::getURL(
00216             t3lib_div::getFileAbsFileName(
00217                 'EXT:t3editor/res/templates/t3editor.html'
00218             )
00219         );
00220         $T3Editor_template = addslashes($T3Editor_template);
00221         $T3Editor_template = str_replace(LF, "' + '", $T3Editor_template);
00222 
00223         return '\'' . $T3Editor_template . '\'';
00224     }
00225 
00226     /**
00227      * determine the correct parser js file for given mode
00228      *
00229      * @param   string  $mode
00230      * @return  string  parser file name
00231      */
00232     protected function getParserfileByMode($mode) {
00233         switch ($mode) {
00234             case tx_t3editor::MODE_TYPOSCRIPT:
00235                 $relPath = $GLOBALS['BACK_PATH'] . t3lib_extmgm::extRelPath('t3editor') . 'res/jslib/parse_typoscript/';
00236                 $parserfile = '["' . $relPath . 'tokenizetyposcript.js", "' . $relPath . 'parsetyposcript.js"]';
00237                 break;
00238 
00239             case tx_t3editor::MODE_JAVASCRIPT:
00240                 $parserfile = '["tokenizejavascript.js", "parsejavascript.js"]';
00241                 break;
00242 
00243             case tx_t3editor::MODE_CSS:
00244                 $parserfile = '"parsecss.js"';
00245                 break;
00246 
00247             case tx_t3editor::MODE_XML:
00248                 $parserfile = '"parsexml.js"';
00249                 break;
00250 
00251             case tx_t3editor::MODE_HTML:
00252                 $parserfile = '["tokenizejavascript.js", "parsejavascript.js", "parsecss.js", "parsexml.js", "parsehtmlmixed.js"]';
00253                 break;
00254 
00255             case tx_t3editor::MODE_PHP:
00256             case tx_t3editor::MODE_MIXED:
00257                 $parserfile = '[' .
00258                     '"tokenizejavascript.js", ' .
00259                     '"parsejavascript.js", ' .
00260                     '"parsecss.js", ' .
00261                     '"parsexml.js", ' .
00262                     '"../contrib/php/js/tokenizephp.js", ' .
00263                     '"../contrib/php/js/parsephp.js", ' .
00264                     '"../contrib/php/js/parsephphtmlmixed.js"' .
00265                     ']';
00266                 break;
00267         }
00268         return $parserfile;
00269     }
00270 
00271     /**
00272      * determine the correct css file for given mode
00273      *
00274      * @param   string  $mode
00275      * @return  string  css file name
00276      */
00277     protected function getStylesheetByMode($mode) {
00278         switch ($mode) {
00279             case tx_t3editor::MODE_TYPOSCRIPT:
00280                 $stylesheet = '"res/css/typoscriptcolors.css"';
00281             break;
00282 
00283             case tx_t3editor::MODE_JAVASCRIPT:
00284                 $stylesheet = '"res/css/jscolors.css"';
00285             break;
00286 
00287             case tx_t3editor::MODE_CSS:
00288                 $stylesheet = '"res/css/csscolors.css"';
00289             break;
00290 
00291             case tx_t3editor::MODE_XML:
00292                 $stylesheet = '"res/css/xmlcolors.css"';
00293             break;
00294 
00295             case tx_t3editor::MODE_HTML:
00296                 $stylesheet = '"res/css/xmlcolors.css", ' .
00297                     'T3editor.PATH_t3e + "res/css/jscolors.css", ' .
00298                     'T3editor.PATH_t3e + "res/css/csscolors.css"';
00299             break;
00300 
00301             case tx_t3editor::MODE_PHP:
00302                 $stylesheet = '"../../contrib/codemirror/contrib/php/css/phpcolors.css"';
00303             break;
00304 
00305             case tx_t3editor::MODE_MIXED:
00306                 $stylesheet = '"res/css/xmlcolors.css", ' .
00307                     'T3editor.PATH_t3e + "res/css/jscolors.css", ' .
00308                     'T3editor.PATH_t3e + "res/css/csscolors.css", ' .
00309                     'T3editor.PATH_codemirror + "../contrib/php/css/phpcolors.css"';
00310             break;
00311         }
00312         return '[T3editor.PATH_t3e + ' . $stylesheet . ', T3editor.PATH_t3e + "res/css/t3editor_inner.css"]';
00313     }
00314 
00315     /**
00316      * Gets the labels to be used in JavaScript in the Ext JS interface.
00317      * TODO this method is copied from EXT:Recycler, maybe this should be refactored into a helper class
00318      *
00319      * @return  array       The labels to be used in JavaScript
00320      */
00321     protected function getJavaScriptLabels() {
00322         $coreLabels = array();
00323         $extensionLabels = $this->getJavaScriptLabelsFromLocallang('js.', 'label_');
00324         return array_merge($coreLabels, $extensionLabels);
00325     }
00326 
00327     /**
00328      * Gets labels to be used in JavaScript fetched from the current locallang file.
00329      * TODO this method is copied from EXT:Recycler, maybe this should be refactored into a helper class
00330      *
00331      * @param   string      $selectionPrefix: Prefix to select the correct labels (default: 'js.')
00332      * @param   string      $stripFromSelectionName: Sub-prefix to be removed from label names in the result (default: '')
00333      * @return  array       Lables to be used in JavaScript of the current locallang file
00334      * @todo    Check, whether this method can be moved in a generic way to $GLOBALS['LANG']
00335      */
00336     protected function getJavaScriptLabelsFromLocallang($selectionPrefix = 'js.', $stripFromSelectionName = '') {
00337         $extraction = array();
00338         $labels = array_merge(
00339             (array)$GLOBALS['LOCAL_LANG']['default'],
00340             (array)$GLOBALS['LOCAL_LANG'][$GLOBALS['LANG']->lang]
00341         );
00342             // Regular expression to strip the selection prefix and possibly something from the label name:
00343         $labelPattern = '#^' . preg_quote($selectionPrefix, '#') . '(' . preg_quote($stripFromSelectionName, '#') . ')?#';
00344             // Iterate throuh all locallang lables:
00345         foreach ($labels as $label => $value) {
00346             if (strpos($label, $selectionPrefix) === 0) {
00347                 $key = preg_replace($labelPattern, '', $label);
00348                 $extraction[$key] = $value;
00349             }
00350         }
00351         return $extraction;
00352     }
00353 
00354     /**
00355      * Generates HTML with code editor
00356      *
00357      * @param   string      $name   Name attribute of HTML tag
00358      * @param   string      $class  Class attribute of HTML tag
00359      * @param   string      $content    Content of the editor
00360      * @param   string      $additionalParams   Any additional editor parameters
00361      * @param   string      $alt    Alt attribute
00362      * @return  string      Generated HTML code for editor
00363      */
00364     public function getCodeEditor($name, $class='', $content='', $additionalParams='', $alt='', array $hiddenfields = array()) {
00365         $code = '';
00366 
00367         if ($this->isEnabled()) {
00368             $this->editorCounter++;
00369 
00370             $class .= ' t3editor';
00371             $alt = htmlspecialchars($alt);
00372             if (!empty($alt)) {
00373                 $alt = ' alt="' . $alt . '"';
00374             }
00375 
00376             $code .= '<div>' .
00377                 '<textarea id="t3editor_' . $this->editorCounter . '" ' .
00378                 'name="' . $name . '" ' .
00379                 'class="' . $class . '" ' .
00380                 $additionalParams . ' ' .
00381                 $alt . '>' .
00382                 $content .
00383                 '</textarea></div>';
00384 
00385             $checked = $GLOBALS['BE_USER']->uc['disableT3Editor'] ? 'checked="checked"' : '';
00386 
00387             $code .= '<br /><br />' .
00388                 '<input type="checkbox" ' .
00389                 'class="checkbox t3editor_disableEditor" ' .
00390                 'onclick="T3editor.toggleEditor(this);" ' .
00391                 'name="t3editor_disableEditor" ' .
00392                 'value="true" ' .
00393                 'id="t3editor_disableEditor_' . $this->editorCounter . '_checkbox" ' .
00394                 $checked.' />&nbsp;' .
00395                 '<label for="t3editor_disableEditor_' . $this->editorCounter . '_checkbox">' .
00396                 $GLOBALS['LANG']->getLL('deactivate') .
00397                 '</label>' .
00398                 '<br /><br />';
00399 
00400             if (count($hiddenfields)) {
00401                 foreach ($hiddenfields as $name => $value) {
00402                     $code.= '<input type="hidden" ' .
00403                         'name="' . $name . '" ' .
00404                         'value="' . $value .
00405                         '" />';
00406                 }
00407             }
00408 
00409         } else {
00410             // fallback
00411             if (!empty($class)) {
00412                 $class = 'class="' . $class . '" ';
00413             }
00414 
00415             $code .= '<textarea name="' . $name . '" ' .
00416                 $class . $additionalParams.'>' .
00417                 $content . '</textarea>';
00418         }
00419 
00420         return $code;
00421     }
00422 
00423 
00424 
00425     /**
00426      * Save the content from t3editor retrieved via Ajax
00427      *
00428      * new Ajax.Request('/dev/t3e/dummy/typo3/ajax.php', {
00429      *  parameters: {
00430      *      ajaxID: 'tx_t3editor::saveCode',
00431      *      t3editor_savetype: 'tx_tstemplateinfo'
00432      *  }
00433      * });
00434      *
00435      * @param array params  Parameters (not used yet)
00436      * @param TYPO3AJAX ajaxObj AjaxObject to handle response
00437      */
00438     public function ajaxSaveCode($params, $ajaxObj) {
00439         // cancel if its not an Ajax request
00440         if((TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX)) {
00441             $ajaxObj->setContentFormat('json');
00442             $codeType = t3lib_div::_GP('t3editor_savetype');
00443             $savingsuccess = false;
00444 
00445             if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'])) {
00446                 $_params = array(
00447                     'pObj' => &$this,
00448                     'type' => $codeType,
00449                     'ajaxObj' => &$ajaxObj,
00450                 );
00451                 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/t3editor/classes/class.tx_t3editor.php']['ajaxSaveCode'] as $key => $_funcRef)   {
00452                     $savingsuccess = t3lib_div::callUserFunction($_funcRef,$_params,$this) || $savingsuccess;
00453                 }
00454             }
00455 
00456             $ajaxObj->setContent(array('result' => $savingsuccess));
00457         }
00458     }
00459 
00460     /**
00461      * Gets plugins that are defined at $TYPO3_CONF_VARS['EXTCONF']['t3editor']['plugins']
00462      * (called by typo3/ajax.php)
00463      *
00464      * @param   array       $params: additional parameters (not used here)
00465      * @param   TYPO3AJAX   &$ajaxObj: the TYPO3AJAX object of this request
00466      * @return  void
00467      * @author  Oliver Hader <oliver@typo3.org>
00468      */
00469     public function getPlugins($params, TYPO3AJAX &$ajaxObj) {
00470         $result = array();
00471         $plugins =& $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['t3editor']['plugins'];
00472 
00473         if (is_array($plugins)) {
00474             $result = array_values($plugins);
00475         }
00476 
00477         $ajaxObj->setContent($result);
00478         $ajaxObj->setContentFormat('jsonbody');
00479     }
00480 
00481 }
00482 
00483 
00484 
00485 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/t3editor/classes/class.tx_t3editor.php'])) {
00486     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/t3editor/classes/class.tx_t3editor.php']);
00487 }
00488 
00489 ?>