Fixed bug #5913: RTEhtmlarea not correctly displayed in IRRE child form-fields and...
authorOliver Hader <oliver.hader@typo3.org>
Fri, 13 Jul 2007 17:22:11 +0000 (17:22 +0000)
committerOliver Hader <oliver.hader@typo3.org>
Fri, 13 Jul 2007 17:22:11 +0000 (17:22 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/branches/TYPO3_4-1@2406 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
t3lib/class.t3lib_tceforms.php
t3lib/class.t3lib_tceforms_inline.php
t3lib/jsfunc.inline.js
typo3/sysext/rtehtmlarea/class.tx_rtehtmlarea_base.php
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-compressed.js
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js

index a1f6725..bd960ca 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2007-07-13  Oliver Hader  <oh@inpublica.de>
+
+       * Fixed bug #5913: RTEhtmlarea not correctly displayed in IRRE child form-fields and tabs (continuance of bug #5177)
+
 2007-07-11  Oliver Hader  <oh@inpublica.de>
 
        * Fixed bug #5331: Remove the caption wrap on images if no caption is set (thanks to Georg Ringer)
index 9f75dd6..88af366 100755 (executable)
@@ -493,12 +493,6 @@ class t3lib_TCEforms       {
                        if ($TCA[$table]['types'][$typeNum])    {
                                $itemList = $TCA[$table]['types'][$typeNum]['showitem'];
                                if ($itemList)  {       // If such a list existed...
-                                               // if TCEforms will render a tab menu in the next step, push the name to the tab stack
-                                       if (strstr($itemList, '--div--') !== false && $this->enableTabMenu && $TCA[$table]['ctrl']['dividers2tabs']) {
-                                               $tabIdentString = 'TCEforms:'.$table.':'.$row['uid'];
-                                               $tabIdentStringMD5 = $GLOBALS['TBE_TEMPLATE']->getDynTabMenuId('TCEforms:'.$table.':'.$row['uid']);
-                                       }
-
                                                // Explode the field list and possibly rearrange the order of the fields, if configured for
                                        $fields = t3lib_div::trimExplode(',',$itemList,1);
                                        if ($this->fieldOrder)  {
@@ -509,6 +503,16 @@ class t3lib_TCEforms       {
                                        $excludeElements = $this->excludeElements = $this->getExcludeElements($table,$row,$typeNum);
                                        $fields = $this->mergeFieldsWithAddedFields($fields,$this->getFieldsToAdd($table,$row,$typeNum));
 
+                                               // If TCEforms will render a tab menu in the next step, push the name to the tab stack:
+                                       if (strstr($itemList, '--div--') !== false && $this->enableTabMenu && $TCA[$table]['ctrl']['dividers2tabs']) {
+                                               $tabIdentString = 'TCEforms:'.$table.':'.$row['uid'];
+                                               $tabIdentStringMD5 = $GLOBALS['TBE_TEMPLATE']->getDynTabMenuId('TCEforms:'.$table.':'.$row['uid']);
+                                                       // Remember that were currently working on the general tab:
+                                               if (isset($fields[0]) && strpos($fields[0], '--div--') !== 0) {
+                                                       $this->pushToDynNestedStack('tab', $tabIdentStringMD5.'-1');
+                                               }
+                                       }
+
                                                // Traverse the fields to render:
                                        $cc=0;
                                        foreach($fields as $fieldInfo)  {
@@ -5467,35 +5471,17 @@ class t3lib_TCEforms    {
 
        /**
         * Get the dynNestedStack as associative array.
-        * It has the keys raw, tab, inline and sorted.
-        * The key "sorted" contains the levels in the sorting order they have been applied.
+        * The result is e.g. ['tab','DTM-ABCD-1'], ['inline','data[13][table][uid][field]'], ['tab','DTM-DEFG-2'], ...
         *
-        * @param       boolean         $json: Return a JSON string instead of an array
-        * @param       string          $tabSuffix: Add a suffix (e.g. "-DIV") to each tab level
-        * @param       string          $tabSuffix: Add a suffix to each inline level
-        * @return      mixed           Returns an associative array (default), if $json is true, it will be returned as JSON string.
+        * @param       boolean         $json: Return a JSON string instead of an array - default: false
+        * @param       boolean         $skipFirst: Skip the first element in the dynNestedStack - default: false
+        * @return      mixed           Returns an associative array by default. If $json is true, it will be returned as JSON string.
         */
-       function getDynNestedStack($json=false, $tabSuffix='', $inlineSuffix='') {
-               $tab = array();
-               $inline = array();
-               $sorted = array();
-               foreach ($this->dynNestedStack as $level) {
-                       if ($level[0]=='tab') {
-                               $tab[] = $level[1].$tabSuffix;
-                               $sorted[] = $level[1].$tabSuffix;
-                       } elseif ($level[0]=='inline') {
-                               $inline[] = $level[1].$inlineSuffix;
-                               $sorted[] = $level[1].$inlineSuffix;
-                       }
+       function getDynNestedStack($json=false, $skipFirst=false) {
+               $result = $this->dynNestedStack;
+               if ($skipFirst) {
+                       array_shift($result);
                }
-               $result = array(
-                       // 'raw' => $this->dynNestedStack,
-                       'tab' => $tab,
-                       'inline' => $inline,
-                       'sorted' => $sorted,
-                       // 'tabSuffix' => $tabSuffix,
-                       // 'inlineSuffix' => $inlineSuffix,
-               );
                return ($json ? $this->inline->getJSON($result) : $result);
        }
 }
index ffa2289..e336fb1 100755 (executable)
@@ -91,6 +91,7 @@ class t3lib_TCEforms_inline {
        var $fObj;                                                              // Reference to the calling TCEforms instance
        var $backPath;                                                  // Reference to $fObj->backPath
 
+       var $isAjaxCall = false;                                // Indicates if a field is rendered upon an AJAX call
        var $inlineStructure = array();                 // the structure/hierarchy where working in, e.g. cascading inline tables
        var $inlineFirstPid;                                    // the first call of an inline type appeared on this page (pid of record)
        var $inlineNames = array();                             // keys: form, object -> hold the name/id for each of them
@@ -178,7 +179,7 @@ class t3lib_TCEforms_inline {
                $config['inline']['first'] = $recordList[0]['uid'];
                $config['inline']['last'] = $recordList[count($recordList)-1]['uid'];
 
-                       // tell the browser what we have (using JSON later)
+                       // Tell the browser what we have (using JSON later):
                $top = $this->getStructureLevel(0);
                $this->inlineData['config'][$nameObject] = array('table' => $foreign_table);
                $this->inlineData['config'][$nameObject.'['.$foreign_table.']'] = array(
@@ -190,6 +191,8 @@ class t3lib_TCEforms_inline {
                                'uid'   => $top['uid'],
                        ),
                );
+                       // Set a hint for nested IRRE and tab elements:
+               $this->inlineData['nested'][$nameObject] = $this->fObj->getDynNestedStack(false, $this->isAjaxCall);
 
                        // if relations are required to be unique, get the uids that have already been used on the foreign side of the relation
                if ($config['foreign_unique']) {
@@ -308,6 +311,8 @@ class t3lib_TCEforms_inline {
                $nameObject = $this->inlineNames['object'];
                $appendFormFieldNames = '['.$foreign_table.']['.$rec['uid'].']';
                $formFieldNames = $nameObject.$appendFormFieldNames;
+                       // Put the current level also to the dynNestedStack of TCEforms:
+               $this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object'].$appendFormFieldNames);
 
                $header = $this->renderForeignRecordHeader($parentUid, $foreign_table, $rec, $config);
                $combination = $this->renderCombinationTable($rec, $appendFormFieldNames, $config);
@@ -340,6 +345,9 @@ class t3lib_TCEforms_inline {
                        // wrap the header, fields and combination part of a child record with a div container
                $out = '<div id="'.$formFieldNames.'_div"'.($isNewRecord ? ' class="inlineIsNewRecord"' : '').'>' . $out . '</div>';
 
+                       // Remove the current level also from the dynNestedStack of TCEforms:
+               $this->fObj->popFromDynNestedStack();
+
                return $out;
        }
 
@@ -781,6 +789,7 @@ class t3lib_TCEforms_inline {
         * @return      string          A JSON string
         */
        function createNewRecord($domObjectId, $foreignUid = 0) {
+               $this->isAjaxCall = true;
                        // parse the DOM identifier (string), add the levels to the structure stack (array) and load the TCA config
                $this->parseStructureString($domObjectId, true);
                        // the current table - for this table we should add/import records
@@ -789,7 +798,10 @@ class t3lib_TCEforms_inline {
                $parent = $this->getStructureLevel(-1);
                        // get TCA 'config' of the parent table
                $config = $parent['config'];
-               
+
+                       // Put the current level also to the dynNestedStack of TCEforms:
+               $this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object']);
+
                        // dynamically create a new record using t3lib_transferData
                if (!$foreignUid || !t3lib_div::testInt($foreignUid) || $config['foreign_selector']) {
                        $record = $this->getNewRecord($this->inlineFirstPid, $current['table']);
@@ -861,6 +873,9 @@ class t3lib_TCEforms_inline {
                        // fade out and fade in the new record in the browser view to catch the user's eye
                $jsonArray['scriptCall'][] = "inline.fadeOutFadeIn('".$objectId."_div');";
 
+                       // Remove the current level also from the dynNestedStack of TCEforms:
+               $this->fObj->popFromDynNestedStack();
+
                        // return the JSON string
                return $this->getJSON($jsonArray);
        }
@@ -1095,8 +1110,6 @@ class t3lib_TCEforms_inline {
                        'config' => $config,
                );
                $this->updateStructureNames();
-                       // Put the current level also to the dynNestedStack of TCEforms:
-               $this->fObj->pushToDynNestedStack('inline', $this->inlineNames['object']);
        }
 
 
@@ -1110,8 +1123,6 @@ class t3lib_TCEforms_inline {
                        $popItem = array_pop($this->inlineStructure['stable']);
                        $this->updateStructureNames();
                }
-                       // Remove the current level also from the dynNestedStack of TCEforms:
-               $this->fObj->popFromDynNestedStack();
                return $popItem;
        }
 
index 623a934..8dc37af 100755 (executable)
@@ -691,6 +691,18 @@ var inline = {
                return $(objectId+'_div') && $(objectId+'_div').hasClassName('inlineIsNewRecord')
                        ? true
                        : false;
+       },
+
+               // Find and fix nested of inline and tab levels if a new element was created dynamically (it doesn't know about its nesting):
+       findContinuedNestedLevel: function(nested, objectId) {
+               if (this.data.nested && this.data.nested[objectId]) {
+                               // Remove the first element from the new nested stack, it's just a hint:
+                       nested.shift();
+                       nested = this.data.nested[objectId].concat(nested);
+                       return nested;
+               } else {
+                       return nested;
+               }
        }
 }
 
index 0d286b7..96afea3 100644 (file)
@@ -356,7 +356,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
 
                $this->TCEform = $pObj;
                $inline =& $this->TCEform->inline;
-               
+
                $LANG->includeLLFile('EXT:' . $this->ID . '/locallang.xml');
                $this->client = $this->clientInfo();
                $this->typoVersion = t3lib_div::int_from_ver(TYPO3_version);
@@ -907,10 +907,6 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
        function registerRTEinJS($number, $table='', $uid='', $field='') {
                global $TSFE, $TYPO3_CONF_VARS;
 
-                       // if this RTE is shown inline of an IRRE record or a Tab sheet, the JS functions need to know about that
-               $tabSuffix = '-DIV';
-               $inlineSuffix = '['.$table.']['.$uid.']_fields';
-
                $registerRTEinJSString = (!is_object($TSFE) ? '' : '
                        ' . '/*<![CDATA[*/') . '
                        RTEarea['.$number.'] = new Object();
@@ -927,7 +923,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        RTEarea['.$number.']["showTagFreeClasses"] = ' . (trim($this->thisConfig['showTagFreeClasses'])?'true':'false') . ';
                        RTEarea['.$number.']["useHTTPS"] = ' . ((trim(stristr($this->siteURL, 'https')) || $this->thisConfig['forceHTTPS'])?'true':'false') . ';
                        RTEarea['.$number.']["enableMozillaExtension"] = ' . (($this->client['BROWSER'] == 'gecko' && $TYPO3_CONF_VARS['EXTCONF'][$this->ID]['enableMozillaExtension'])?'true':'false') . ';
-                       RTEarea['.$number.']["tceformsNested"] = ' . (is_object($this->TCEform) && method_exists($this->TCEform, 'getDynNestedStack') ? $this->TCEform->getDynNestedStack(true, $tabSuffix, $inlineSuffix) : '[]') . ';';
+                       RTEarea['.$number.']["tceformsNested"] = ' . (is_object($this->TCEform) && method_exists($this->TCEform, 'getDynNestedStack') ? $this->TCEform->getDynNestedStack(true) : '[]') . ';';
 
                        // The following properties apply only to the backend
                if (!is_object($TSFE)) {
index 65adf4f..a5b5698 100644 (file)
@@ -34,12 +34,14 @@ break;case"mousedown":HTMLArea._addClass(target,"buttonActive");HTMLArea._addCla
 textarea.style.display="none";var htmlarea=document.createElement("div");htmlarea.className="htmlarea";htmlarea.style.width=textarea.style.width;this._htmlArea=htmlarea;textarea.parentNode.insertBefore(htmlarea,textarea);if(textarea.form){var f=textarea.form;if(typeof(f.onreset)=="function"){var funcref=f.onreset;if(typeof(f.__msh_prevOnReset)=="undefined")f.__msh_prevOnReset=[];f.__msh_prevOnReset.push(funcref);}
 f._editorNumber=this._editorNumber;HTMLArea._addEvent(f,"reset",HTMLArea.resetHandler);}
 this._createToolbar();HTMLArea._appendToLog("[HTMLArea::generate]: Toolbar successfully created.");var iframe=document.createElement("iframe");if(HTMLArea.is_ie||HTMLArea.is_safari||HTMLArea.is_wamcom){iframe.setAttribute("src",_editor_url+"popups/blank.html");}else if(HTMLArea.is_opera){iframe.setAttribute("src",_typo3_host_url+_editor_url+"popups/blank.html");}else{iframe.setAttribute("src","javascript:void(0);");}
-iframe.className="editorIframe";if(!this.config.statusBar)iframe.className+=" noStatusBar";htmlarea.appendChild(iframe);this._iframe=iframe;this._createStatusBar();this.sizeIframe(2);HTMLArea._appendToLog("[HTMLArea::generate]: Editor iframe successfully created.");this.initIframe();return this;};HTMLArea.prototype.sizeIframe=function(diff){var height=(this.config.height=="auto"?(this._textArea.style.height):this.config.height);var textareaHeight=height;this.nested=RTEarea[this._editorNumber].tceformsNested;var parentElements=(this.nested.sorted&&this.nested.sorted.length?[].concat(this.nested.sorted):[]);var dimensions=this.accessParentElements(parentElements,'this.getDimensions()');if(height.indexOf("%")==-1){height=parseInt(height)-diff;if(this.config.sizeIncludesToolbar){this._initialToolbarOffsetHeight=dimensions.toolbar.height;height-=dimensions.toolbar.height;height-=dimensions.statusbar.height;}
+iframe.className="editorIframe";if(!this.config.statusBar)iframe.className+=" noStatusBar";htmlarea.appendChild(iframe);this._iframe=iframe;this._createStatusBar();this.sizeIframe(2);HTMLArea._appendToLog("[HTMLArea::generate]: Editor iframe successfully created.");this.initIframe();return this;};HTMLArea.prototype.sizeIframe=function(diff){var height=(this.config.height=="auto"?(this._textArea.style.height):this.config.height);var textareaHeight=height;this.nested={};this.nested.all=RTEarea[this._editorNumber].tceformsNested;this.nested.sorted=HTMLArea.simplifyNested(this.nested.all);var parentElements=(this.nested.sorted&&this.nested.sorted.length?[].concat(this.nested.sorted):[]);var dimensions=this.accessParentElements(parentElements,'this.getDimensions()');if(height.indexOf("%")==-1){height=parseInt(height)-diff;if(this.config.sizeIncludesToolbar){this._initialToolbarOffsetHeight=dimensions.toolbar.height;height-=dimensions.toolbar.height;height-=dimensions.statusbar.height;}
 if(height<0)height=0;textareaHeight=(height-4);if(textareaHeight<0)textareaHeight=0;height+="px";textareaHeight+="px";}
 this._iframe.style.height=height;this._textArea.style.height=textareaHeight;var textareaWidth=(this.config.width=="auto"?this._textArea.style.width:this.config.width);var iframeWidth=textareaWidth;if(textareaWidth.indexOf("%")==-1){iframeWidth=parseInt(textareaWidth)+"px";textareaWidth=parseInt(textareaWidth)-diff;if(textareaWidth<0)textareaWidth=0;textareaWidth+='px';}
 this._iframe.style.width="100%";if(HTMLArea.is_opera)this._iframe.style.width=iframeWidth;this._textArea.style.width=textareaWidth;};HTMLArea.prototype.getDimensions=function(){return{toolbar:{width:this._toolbar.offsetWidth,height:this._toolbar.offsetHeight},statusbar:{width:this._statusBar.offsetWidth,height:this._statusBar.offsetHeight}};};HTMLArea.prototype.accessParentElements=function(parentElements,callbackFunc){var result={};if(parentElements.length){var currentElement=parentElements.pop();var elementStyle=document.getElementById(currentElement).style;var actionRequired=(elementStyle.display=='none'?true:false);if(actionRequired){var originalVisibility=elementStyle.visibility;var originalPosition=elementStyle.position;elementStyle.visibility='hidden';elementStyle.position='absolute';elementStyle.display='';}
 result=this.accessParentElements(parentElements,callbackFunc);if(actionRequired){elementStyle.display='none';elementStyle.position=originalPosition;elementStyle.visibility=originalVisibility;}}else{result=eval(callbackFunc);}
-return result;};HTMLArea.initIframe=function(editorNumber){var editor=RTEarea[editorNumber]["editor"];editor.initIframe();};HTMLArea.prototype.initIframe=function(){if(this._initIframeTimer)window.clearTimeout(this._initIframeTimer);if(!this._iframe||(!this._iframe.contentWindow&&!this._iframe.contentDocument)){this._initIframeTimer=window.setTimeout("HTMLArea.initIframe("+this._editorNumber+");",50);return false;}else if(this._iframe.contentWindow){if(!this._iframe.contentWindow.document||!this._iframe.contentWindow.document.documentElement){this._initIframeTimer=window.setTimeout("HTMLArea.initIframe("+this._editorNumber+");",50);return false;}}else if(!this._iframe.contentDocument.documentElement){this._initIframeTimer=window.setTimeout("HTMLArea.initIframe("+this._editorNumber+");",50);return false;}
+return result;};HTMLArea.simplifyNested=function(nested){var i,type,level,max,simplifiedNested=[];if(nested&&nested.length){if(nested[0][0]=='inline'){nested=inline.findContinuedNestedLevel(nested,nested[0][1]);}
+for(i=0,max=nested.length;i<max;i++){type=nested[i][0];level=nested[i][1];if(type=='tab'){simplifiedNested.push(level+'-DIV');}else if(type=='inline'){simplifiedNested.push(level+'_fields');}}}
+return simplifiedNested;};HTMLArea.initIframe=function(editorNumber){var editor=RTEarea[editorNumber]["editor"];editor.initIframe();};HTMLArea.prototype.initIframe=function(){if(this._initIframeTimer)window.clearTimeout(this._initIframeTimer);if(!this._iframe||(!this._iframe.contentWindow&&!this._iframe.contentDocument)){this._initIframeTimer=window.setTimeout("HTMLArea.initIframe("+this._editorNumber+");",50);return false;}else if(this._iframe.contentWindow){if(!this._iframe.contentWindow.document||!this._iframe.contentWindow.document.documentElement){this._initIframeTimer=window.setTimeout("HTMLArea.initIframe("+this._editorNumber+");",50);return false;}}else if(!this._iframe.contentDocument.documentElement){this._initIframeTimer=window.setTimeout("HTMLArea.initIframe("+this._editorNumber+");",50);return false;}
 var doc=this._iframe.contentWindow?this._iframe.contentWindow.document:this._iframe.contentDocument;this._doc=doc;if(!this.config.fullPage){var head=doc.getElementsByTagName("head")[0];if(!head){head=doc.createElement("head");doc.documentElement.appendChild(head);}
 if(this.config.baseURL&&!HTMLArea.is_opera){var base=doc.getElementsByTagName("base")[0];if(!base){base=doc.createElement("base");base.href=this.config.baseURL;head.appendChild(base);}
 HTMLArea._appendToLog("[HTMLArea::initIframe]: Iframe baseURL set to: "+this.config.baseURL);}
index 0bded32..a96a0b3 100644 (file)
@@ -886,7 +886,9 @@ HTMLArea.prototype.sizeIframe = function(diff) {
        var height = (this.config.height == "auto" ? (this._textArea.style.height) : this.config.height);
        var textareaHeight = height;
                // All nested tabs and inline levels in the sorting order they were applied:
-       this.nested = RTEarea[this._editorNumber].tceformsNested;
+       this.nested = {};
+       this.nested.all = RTEarea[this._editorNumber].tceformsNested;
+       this.nested.sorted = HTMLArea.simplifyNested(this.nested.all);
                // Clone the array instead of using a reference (this.accessParentElements will change the array):
        var parentElements = (this.nested.sorted && this.nested.sorted.length ? [].concat(this.nested.sorted) : []);
                // Walk through all nested tabs and inline levels to make a correct positioning:
@@ -973,6 +975,32 @@ HTMLArea.prototype.accessParentElements = function(parentElements, callbackFunc)
        return result;
 };
 
+/**
+ * Simplify the array of nested levels. Create an indexed array with the correct names of the elements.
+ *
+ * @param      object          nested: The array with the nested levels
+ * @return     object          The simplified array
+ * @author     Oliver Hader <oh@inpublica.de>
+ */
+HTMLArea.simplifyNested = function(nested) {
+       var i, type, level, max, simplifiedNested=[];
+       if (nested && nested.length) {
+               if (nested[0][0]=='inline') {
+                       nested = inline.findContinuedNestedLevel(nested, nested[0][1]);
+               }
+               for (i=0, max=nested.length; i<max; i++) {
+                       type = nested[i][0];
+                       level = nested[i][1];
+                       if (type=='tab') {
+                               simplifiedNested.push(level+'-DIV');
+                       } else if (type=='inline') {
+                               simplifiedNested.push(level+'_fields');
+                       }
+               }
+       }
+       return simplifiedNested;
+};
+
 /*
  * Initialize the iframe
  */