added feature #16183: Edit TypoScript file content in t3editor (Thanks to Fabrizio...
authorTobias Liebig <mail@etobi.de>
Thu, 4 Nov 2010 10:19:12 +0000 (10:19 +0000)
committerTobias Liebig <mail@etobi.de>
Thu, 4 Nov 2010 10:19:12 +0000 (10:19 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@9273 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
t3lib/class.t3lib_tsparser.php
typo3/sysext/t3editor/classes/class.tx_t3editor_hooks_tstemplateinfo.php
typo3/sysext/tstemplate_info/class.tx_tstemplateinfo.php
typo3/sysext/tstemplate_info/locallang.xml

index b1289c2..a1bc3eb 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-11-04  Tobias Liebig  <mail_typo3@etobi.de>
+
+       * added feature #16183: Edit TypoScript file content in t3editor (Thanks to Fabrizio Branca)
+
 2010-11-04  Steffen Kamper  <steffen@typo3.org>
 
        * Follow-up to #16228: [Feature] TCA tree
index 3d86838..b0b9711 100644 (file)
@@ -514,7 +514,7 @@ class t3lib_TSparser {
                                        'files' => $includedFiles,
                                );
                        }
-                       return '';
+                       return "\n###\n### ERROR: Recursion!\n###\n";
                }
                $splitStr='<INCLUDE_TYPOSCRIPT:';
                if (strstr($string,$splitStr))  {
@@ -581,7 +581,137 @@ class t3lib_TSparser {
                }
                return $array;
        }
+       
+       /**
+        * Search for commented INCLUDE_TYPOSCRIPT statements 
+        * and save the content between the BEGIN and the END line to the specified file
+        * 
+        * @param       string  template content
+        * @param       int             Counter for detecting endless loops
+        * @return      string  template content with uncommented include statements
+        * @author      Fabrizio Branca <typo3@fabrizio-branca.de>
+        */
+       function extractIncludes($string, $cycle_counter=1, $extractedFileNames=array()) {
+               
+               if ($cycle_counter>10) {
+                       t3lib_div::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "&lt;INCLUDE_TYPOSCRIPT: ..." tags','Core',2);
+                       return "\n###\n### ERROR: Recursion!\n###\n";
+               }
+               
+               $fileContent = array();
+               $restContent = array();
+               $fileName = NULL;
+               $inIncludePart = false;
+               $lines = explode("\n", $string);
+               $skipNextLineIfEmpty = false;
+               $openingCommentedIncludeStatement = NULL;
+               foreach ($lines as $line) {
+                       
+                               // t3lib_TSparser::checkIncludeLines inserts an additional empty line, remove this again
+                       if ($skipNextLineIfEmpty) {
+                               if (trim($line) == '') {
+                                       continue;
+                               }
+                               $skipNextLineIfEmpty = false;
+                       }
+                       
+                       if (!$inIncludePart) { // outside commented include statements
+                               
+                                       // search for beginning commented include statements
+                               $matches = array();
+                               if (preg_match('/###\s*<INCLUDE_TYPOSCRIPT:\s*source\s*=\s*"\s*FILE\s*:\s*(.*)\s*">\s*BEGIN/i', $line, $matches)) {
+                                       
+                                               // save this line in case there is no ending tag
+                                       $openingCommentedIncludeStatement = trim($line);
+                                       $openingCommentedIncludeStatement = trim(preg_replace('/### Warning: .*###/', '', $openingCommentedIncludeStatement));
+                                       
+                                               // found a commented include statement
+                                       $fileName = trim($matches[1]);  
+                                       $inIncludePart = true;
+                                       
+                                       $expectedEndTag = '### <INCLUDE_TYPOSCRIPT: source="FILE:'.$fileName.'"> END';
+                                               // strip all whitespace characters to make comparision safer
+                                       $expectedEndTag = strtolower(preg_replace('/\s/', '', $expectedEndTag)); 
+                               } else {
+                                               // if this is not a beginning commented include statement this line goes into the rest content
+                                       $restContent[] = $line;
+                               }       
+                               
+                       } else { // inside commented include statements
+                               
+                                       // search for the matching ending commented include statement
+                               $strippedLine = strtolower(preg_replace('/\s/', '', $line));
+                               if (strpos($strippedLine, $expectedEndTag) !== false) {
+                                               
+                                               // found the matching ending include statement
+                                       $fileContentString = implode("\n", $fileContent);
+                                       
+                                               // write the content to the file
+                                       $realFileName = t3lib_div::getFileAbsFileName($fileName);
+                                       
+                                               // some file checks
+                                       if (empty($realFileName)) {
+                                               throw new Exception(sprintf('"%s" is not a valid file location.', $fileName));
+                                       }
+                                       
+                                       if (!is_writable($realFileName)) {
+                                               throw new Exception(sprintf('"%s" is not writable.', $fileName));
+                                       }
+                                       
+                                       if (in_array($realFileName, $extractedFileNames)) {
+                                               throw new Exception(sprintf('Recursive/multiple inclusion of file "%s"', $realFileName));
+                                       }
+                                       $extractedFileNames[] = $realFileName;
+                                       
+                                               // recursive call to detected nested commented include statements
+                                       $fileContentString = self::extractIncludes($fileContentString, ++$cycle_counter, $extractedFileNames);
+                                       
+                                       if (!t3lib_div::writeFile($realFileName, $fileContentString)) {
+                                               throw new Exception(sprintf('Could not write file "%s"', $realFileName));
+                                       }
+                                       
+                                               // insert reference to the file in the rest content
+                                       $restContent[] = "<INCLUDE_TYPOSCRIPT: source=\"FILE:$fileName\">";
+                                       
+                                               // reset variables (preparing for the next commented include statement)
+                                       $fileContent = array();
+                                       $fileName = NULL;
+                                       $inIncludePart = false;
+                                       $openingCommentedIncludeStatement = NULL;
+                                               // t3lib_TSparser::checkIncludeLines inserts an additional empty line, remove this again
+                                       $skipNextLineIfEmpty = true;
+                               } else {
+                                               // if this is not a ending commented include statement this line goes into the file content
+                                       $fileContent[] = $line;
+                               }
+                               
+                       }
+                       
+               }
+               
+                       // if we're still inside commented include statements copy the lines back to the rest content
+               if ($inIncludePart) {
+                       $restContent[] = $openingCommentedIncludeStatement . ' ### Warning: Corresponding end line missing! ###';
+                       $restContent = array_merge($restContent, $fileContent);
+               }
+               
+               $restContentString = implode("\n", $restContent);
+               return $restContentString;
+       }
 
+       /**
+        * Processes the string in each value of the input array with extractIncludes
+        *
+        * @param       array           Array with TypoScript in each value
+        * @return      array           Same array but where the values has been processed with extractIncludes
+        * @author      Fabrizio Branca <typo3@fabrizio-branca.de>
+        */
+       function extractIncludes_array($array)  {
+               foreach ($array as $k => $v) {
+                       $array[$k]=t3lib_TSparser::extractIncludes($array[$k]);
+               }
+               return $array;
+       }
 
 
 
index c3deb2b..eef2386 100644 (file)
@@ -168,6 +168,18 @@ class tx_t3editor_hooks_tstemplateinfo {
                                                }
                                        }
                                        if (count($recData)) {
+                                               
+                                               // process template row before saving
+                                               require_once t3lib_extMgm::extPath('tstemplate_info').'class.tx_tstemplateinfo.php';
+                                               $tstemplateinfo = t3lib_div::makeInstance('tx_tstemplateinfo'); /* @var $tstemplateinfo tx_tstemplateinfo */
+                                                       // load the MOD_SETTINGS in order to check if the includeTypoScriptFileContent is set                                           
+                                               $tstemplateinfo->pObj->MOD_SETTINGS = t3lib_BEfunc::getModuleData(
+                                                       array('includeTypoScriptFileContent' => true), 
+                                                       array(), 
+                                                       'web_ts'
+                                               );
+                                               $recData['sys_template'][$saveId] = $tstemplateinfo->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]);
+                                               
                                                // Create new tce-object
                                                $tce = t3lib_div::makeInstance('t3lib_TCEmain');
                                                $tce->stripslashes_values = 0;
index 6f0f77f..a506c1e 100644 (file)
@@ -53,7 +53,7 @@ $GLOBALS['LANG']->includeLLFile('EXT:tstemplate_info/locallang.xml');
 class tx_tstemplateinfo extends t3lib_extobjbase {
 
        public $tce_processed = false;  // indicator for t3editor, whether data is stored
-
+       
        /**
         * Creates a row for a HTML table
         *
@@ -152,8 +152,40 @@ class tx_tstemplateinfo extends t3lib_extobjbase {
                $tmpl->init();
 
                $tplRow = $tmpl->ext_getFirstTemplate($pageId, $template_uid);  // Get the row of the first VISIBLE template of the page. whereclause like the frontend.
+               $tplRow = $this->processTemplateRowAfterLoading($tplRow);
                return (is_array($tplRow) ? true : false);
        }
+       
+       /**
+        * Process template row after loading
+        * 
+        * @param       array   $tplRow: template row
+        * @return      array   preprocessed template row
+        * @author      Fabrizio Branca <typo3@fabrizio-branca.de>
+        */
+       function processTemplateRowAfterLoading(array $tplRow) {
+               if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
+                               // Let the recursion detection counter start at 91, so that only 10 recursive calls will be resolved
+                               // Otherwise the editor will be bloated with way to many lines making it hard the break the cyclic recursion.
+                       $tplRow['config'] = t3lib_TSparser::checkIncludeLines($tplRow['config'], 91);
+                       $tplRow['constants'] = t3lib_TSparser::checkIncludeLines($tplRow['constants'], 91);
+               }
+               return $tplRow;
+       }
+       
+       /**
+        * Process template row before saving
+        * 
+        * @param       array   $tplRow: template row
+        * @return      array   preprocessed template row
+        * @author      Fabrizio Branca <typo3@fabrizio-branca.de>
+        */
+       function processTemplateRowBeforeSaving(array $tplRow) {
+               if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) {
+                       $tplRow = t3lib_TSparser::extractIncludes_array($tplRow);
+               }
+               return $tplRow;
+       }
 
        /**
         * The main processing method if this class
@@ -163,6 +195,8 @@ class tx_tstemplateinfo extends t3lib_extobjbase {
        function main() {
                global $SOBE,$BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS;
                global $tmpl,$tplRow,$theConstants;
+               
+               $this->pObj->MOD_MENU['includeTypoScriptFileContent'] = true;
 
                $edit = $this->pObj->edit;
                $e = $this->pObj->e;
@@ -274,6 +308,9 @@ class tx_tstemplateinfo extends t3lib_extobjbase {
                                        $recData['sys_template'][$saveId]['resources'] = $resList;
                                }
                                if (count($recData))    {
+                                       
+                                       $recData['sys_template'][$saveId] = $this->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]);
+                                       
                                                // Create new  tce-object
                                        $tce = t3lib_div::makeInstance('t3lib_TCEmain');
                                        $tce->stripslashes_values=0;
@@ -413,6 +450,19 @@ class tx_tstemplateinfo extends t3lib_extobjbase {
                        if ($e['constants'])    {
                                $outCode = '<textarea name="data[constants]" rows="'.$numberOfRows.'" wrap="off" class="fixed-font enable-tab"'.$this->pObj->doc->formWidthText(48, 'width:98%;height:70%', 'off').' class="fixed-font">'.t3lib_div::formatForTextarea($tplRow['constants']).'</textarea>';
                                $outCode.= '<input type="Hidden" name="e[constants]" value="1">';
+                               
+                                       // Display "Include TypoScript file content?" checkbox
+                               $outCode .= t3lib_BEfunc::getFuncCheck(
+                                       $this->pObj->id, 
+                                       'SET[includeTypoScriptFileContent]', 
+                                       $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], 
+                                       'index.php', 
+                                       '&e[constants]=1', 
+                                       'id="checkIncludeTypoScriptFileContent"'
+                               );
+                               $outCode .= '<label for="checkIncludeTypoScriptFileContent">' . $GLOBALS['LANG']->getLL('includeTypoScriptFileContent') . '</label><br />';
+                               
+                               
                                $theOutput.= $this->pObj->doc->spacer(15);
                                $theOutput.= $this->pObj->doc->section($GLOBALS['LANG']->getLL('constants'), '');
                                $theOutput.= $this->pObj->doc->sectionEnd().$outCode;
@@ -445,6 +495,18 @@ class tx_tstemplateinfo extends t3lib_extobjbase {
                        }
                        if ($e['config'])       {
                                $outCode='<textarea name="data[config]" rows="'.$numberOfRows.'" wrap="off" class="fixed-font enable-tab"'.$this->pObj->doc->formWidthText(48,"width:98%;height:70%","off").' class="fixed-font">'.t3lib_div::formatForTextarea($tplRow["config"]).'</textarea>';
+                               $outCode.= '<input type="Hidden" name="e[config]" value="1">';
+                               
+                                       // Display "Include TypoScript file content?" checkbox
+                               $outCode .= t3lib_BEfunc::getFuncCheck(
+                                       $this->pObj->id, 
+                                       'SET[includeTypoScriptFileContent]', 
+                                       $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], 
+                                       'index.php', 
+                                       '&e[config]=1', 
+                                       'id="checkIncludeTypoScriptFileContent"'
+                               );
+                               $outCode .= '<label for="checkIncludeTypoScriptFileContent">' . $GLOBALS['LANG']->getLL('includeTypoScriptFileContent') . '</label><br />';
 
                                if (t3lib_extMgm::isLoaded('tsconfig_help'))    {
                                        $url = $BACK_PATH.'wizard_tsconfig.php?mode=tsref';
@@ -455,12 +517,11 @@ class tx_tstemplateinfo extends t3lib_extobjbase {
                                        $outCode.= '<a href="#" onClick="vHWin=window.open(\''.$url.t3lib_div::implodeArrayForUrl('', array('P' => $params)).'\',\'popUp'.$md5ID.'\',\'height=500,width=780,status=0,menubar=0,scrollbars=1\');vHWin.focus();return false;">'.t3lib_iconWorks::getSpriteIcon('actions-system-typoscript-documentation-open', array('title'=> $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:tsRef', true))) . '</a>';
                                }
 
-                               $outCode.= '<input type="Hidden" name="e[config]" value="1">';
                                $theOutput.= $this->pObj->doc->spacer(15);
                                $theOutput.= $this->pObj->doc->section($GLOBALS['LANG']->getLL('setup'), '');
                                $theOutput.= $this->pObj->doc->sectionEnd().$outCode;
                        }
-
+                       
                                // Processing:
                        $outCode = '';
                        $outCode.= $this->tableRow(
index d32a2ef..4e9f4a0 100644 (file)
@@ -29,6 +29,7 @@
                        <label index="resources">Resources:</label>
                        <label index="editToView">(edit to view, %s lines)</label>
                        <label index="editTemplateRecord">Edit the whole template record</label>
+                       <label index="includeTypoScriptFileContent">Include TypoScript file content</label>
                </languageKey>
        </data>
 </T3locallang>
\ No newline at end of file