Index: t3lib/config_default.php =================================================================== --- t3lib/config_default.php (Revision 7539) +++ t3lib/config_default.php (Arbeitskopie) @@ -285,6 +285,7 @@ 'WorkspaceMenu::setWorkspace' => 'typo3/classes/class.workspaceselector.php:WorkspaceSelector->setWorkspace', 'ExtDirect::getAPI' => 't3lib/extjs/class.t3lib_extjs_extdirectapi.php:t3lib_extjs_ExtDirectApi->getAPI', 'ExtDirect::route' => 't3lib/extjs/class.t3lib_extjs_extdirectrouter.php:t3lib_extjs_ExtDirectRouter->route', + 'ExtJS_TabMenu::setExtTabMenuActiveTab' => 'typo3/template.php:template->setActiveTab', ), 'XCLASS' => array(), // See 'Inside TYPO3' document for more information. 'spriteIconRecordOverlayPriorities' => array('hidden', 'starttime', 'endtime', 'futureendtime', 'fe_group', 'protectedSection'), Index: t3lib/class.t3lib_tceforms.php =================================================================== --- t3lib/class.t3lib_tceforms.php (Revision 7539) +++ t3lib/class.t3lib_tceforms.php (Arbeitskopie) @@ -477,6 +477,7 @@ global $TCA, $TYPO3_CONF_VARS; $this->renderDepth=$depth; + $tabType = 'exttab'; // Init vars: $out_array = array(array()); @@ -530,10 +531,10 @@ $tabIdentStringMD5 = ''; if (strstr($itemList, '--div--') !== false && $this->enableTabMenu && $dividers2tabs) { $tabIdentString = 'TCEforms:'.$table.':'.$row['uid']; - $tabIdentStringMD5 = $GLOBALS['TBE_TEMPLATE']->getDynTabMenuId($tabIdentString); + $tabIdentStringMD5 = $GLOBALS['TBE_TEMPLATE']->getExtTabMenuId($tabIdentString); // Remember that were currently working on the general tab: if (isset($fields[0]) && strpos($fields[0], '--div--') !== 0) { - $this->pushToDynNestedStack('tab', $tabIdentStringMD5.'-1'); + $this->pushToDynNestedStack($tabType, $tabIdentStringMD5 . '-1'); } } @@ -581,9 +582,9 @@ // Remove last tab entry from the dynNestedStack: $out_sheet++; // Remove the previous sheet from stack (if any): - $this->popFromDynNestedStack('tab', $tabIdentStringMD5.'-'.($out_sheet)); + $this->popFromDynNestedStack($tabType, $tabIdentStringMD5 . '-' . $out_sheet); // Remember on which sheet we're currently working: - $this->pushToDynNestedStack('tab', $tabIdentStringMD5.'-'.($out_sheet+1)); + $this->pushToDynNestedStack($tabType, $tabIdentStringMD5 . '-' . ($out_sheet+1)); $out_array[$out_sheet] = array(); $out_array_meta[$out_sheet]['title'] = $this->sL($parts[1]); // Register newline for Tab @@ -593,7 +594,7 @@ $out_array_meta[$out_sheet]['title'] = $this->sL($parts[1]); // Only add the first tab to the dynNestedStack if there are more tabs: if ($tabIdentString && strpos($itemList, '--div--', strlen($fieldInfo))) { - $this->pushToDynNestedStack('tab', $tabIdentStringMD5.'-1'); + $this->pushToDynNestedStack($tabType, $tabIdentStringMD5 . '-1'); } } } elseif($theField=='--palette--') { @@ -669,7 +670,7 @@ if (count($parts) > 1) { // Unset the current level of tab menus: - $this->popFromDynNestedStack('tab', $tabIdentStringMD5.'-'.($out_sheet+1)); + $this->popFromDynNestedStack($tabType, $tabIdentStringMD5 . '-' . ($out_sheet+1)); $dividersToTabsBehaviour = (isset($TCA[$table]['ctrl']['dividers2tabs']) ? $TCA[$table]['ctrl']['dividers2tabs'] : 1); $output = $this->getDynTabMenu($parts, $tabIdentString, $dividersToTabsBehaviour); @@ -4323,7 +4324,7 @@ function getDynTabMenu($parts, $idString, $dividersToTabsBehaviour = 1) { if (is_object($GLOBALS['TBE_TEMPLATE'])) { $GLOBALS['TBE_TEMPLATE']->backPath = $this->backPath; - return $GLOBALS['TBE_TEMPLATE']->getDynTabMenu($parts, $idString, 0, false, 50, 1, false, 1, $dividersToTabsBehaviour); + return $GLOBALS['TBE_TEMPLATE']->getExtTabMenu($parts, $idString, 1, $dividersToTabsBehaviour); } else { $output = ''; foreach($parts as $singlePad) { @@ -5424,6 +5425,9 @@ '; } + $out .= 'Ext.onReady(function(){ + '; + // add JS required for inline fields if (count($this->inline->inlineData)) { $out .= ' @@ -5457,6 +5461,14 @@ $out .= ' TBE_EDITOR.loginRefreshed(); '; + + // Focus first element + $out .= ' + Ext.select(".typo3-TCEforms input:first").focus(); + '; + + $out .= ' + });'; // Regular direct output: if (!$update) { Index: typo3/jsfunc.tbe_editor.js =================================================================== --- typo3/jsfunc.tbe_editor.js (Revision 7539) +++ typo3/jsfunc.tbe_editor.js (Arbeitskopie) @@ -249,18 +249,27 @@ nestedLevelType = fieldLevels[i][0]; nestedLevelName = fieldLevels[i][1]; fieldLevelIdent = TBE_EDITOR.getNestedLevelIdent(fieldLevels[i]); + var backgroundImage = false; + // Construct the CSS id strings of the image/icon tags showing the notification: if (nestedLevelType == 'tab') { element = nestedLevelName+'-REQ'; } else if (nestedLevelType == 'inline') { element = nestedLevelName+'_req'; + } else if (nestedLevelType == 'exttab') { + element = 'ext-comp-1001__' + nestedLevelName + '-DIV'; + backgroundImage = true; } else { continue; } // Set the icons: if (resolved) { if (TBE_EDITOR.checkNested(fieldLevelIdent)) { - TBE_EDITOR.setImage(element, TBE_EDITOR.images.clear); + if (backgroundImage) { + TBE_EDITOR.unsetExtBackgroundImage(element); + } else { + TBE_EDITOR.unsetImage(element); + } } else { break; } @@ -268,7 +277,12 @@ if (TBE_EDITOR.nested.level && TBE_EDITOR.nested.level[fieldLevelIdent]) { TBE_EDITOR.nested.level[fieldLevelIdent].clean = false; } - TBE_EDITOR.setImage(element, TBE_EDITOR.images.req); + + if (backgroundImage) { + TBE_EDITOR.setExtBackgroundImage(element, TBE_EDITOR.images.req); + } else { + TBE_EDITOR.setImage(element, TBE_EDITOR.images.req); + } } } } @@ -480,6 +494,39 @@ } } }, + unsetImage: function(name) { + TBE_EDITOR.setImage(name, TBE_EDITOR.images.clear); + }, + setExtBackgroundImage: function(name,image) { + // Get Image Path + if (typeof image == 'object') { + var imagePath = image.src; + } else { + var imagePath = eval(image+'.src'); + } + + // Set the class in the top element + Ext.select('#'+name).addClass("x-tab-with-icon"); + + // set Background Image in the inner text + var outerBox = Ext.DomQuery.selectNode("#"+name+" .x-tab-strip-text"); + Ext.fly(outerBox).setStyle("background-image", "url("+imagePath+")"); + }, + unsetExtBackgroundImage: function(name) { + // get the image + var image = TBE_EDITOR.images.clear; + if (typeof image == 'object') { + var imagePath = image.src; + } else { + var imagePath = eval(image+'.src'); + } + + Ext.select('#'+name).removeClass("x-tab-with-icon"); + + // Set blank icon + var outerBox = Ext.DomQuery.selectNode("#"+name+" .x-tab-strip-text"); + Ext.fly(outerBox).setStyle("background-image", "url("+imagePath+")"); + }, submitForm: function() { if (TBE_EDITOR.doSaveFieldName) { document[TBE_EDITOR.formname][TBE_EDITOR.doSaveFieldName].value=1; Index: typo3/template.php =================================================================== --- typo3/template.php (Revision 7539) +++ typo3/template.php (Arbeitskopie) @@ -1772,7 +1772,144 @@ return ''; } + /** + * Creates a DYNAMIC tab-menu eith extJS TabPanel + * + * @param array Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text. + * @param string Identification string. This should be unique for every instance of a dynamic menu! + * @param integer Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open. + * @param integer If set to '1' empty tabs will be remove, If set to '2' empty tabs will be disabled + * @return string rendered HTML + */ + function getExtTabMenu($menuItems, $identString, $defaultTabIndex = 1, $dividers2tabs = 2, $tabPanelConfig = array()) { + $tabId = $this->getExtTabMenuId($identString); + $content = '
'; + if (isset($GLOBALS['BE_USER']->uc['extTabs'][$identString])) { + $activeTab = '"' . $GLOBALS['BE_USER']->uc['extTabs'][$identString] . '"'; + } else { + $activeTab = max($defaultTabIndex, 0); + } + + + // load extJS + $this->getDynTabMenuJScode(); + $this->pageRenderer->loadExtJs(); + + $c = 0; + foreach($menuItems as $key => $value) { + // the id should be kept like this (+1 and the -DIV) to let the RTE work in Tabs (TCEforms) + $id = $tabId . '-' . ($key+1) . '-DIV'; + $items[] = array( + 'id' => $id, + 'label' => $value['label'], + 'hasContent' => ($value['content'] != ''), + 'autoLoad' => ($value['autoLoad'] != '')?$value['autoLoad']:false, + 'iconPath' => ($value['iconPath'] != '')?$value['iconPath']:false, + ); + + //$hide = ($c == $activeTab)?'':' class="x-hide-display"'; + + $content .= '
' . $value['content'] . '
'; + $c++; + } + $content .= '
'; + + + $defaultOptions = array( + 'renderTo' => $tabId, + 'autoHeight' => true, + 'autoScroll' => false, + 'layoutOnTabChange' => true, + 'monitorResize' => true, + 'plain' => true, + 'enableTabScroll' => true + ); + + $tabPanel = ' + var rendered'.t3lib_div::shortMD5($identString).' = false; + var extTabsConfig = ' . json_encode($defaultOptions) . '; +'; + // add custom configuration to the element + if (!isset($tabPanelConfig['width'])) { + $tabPanelConfig['width'] = 'Ext.get(\'typo3-docbody\').getWidth() - 40'; + } + foreach ($tabPanelConfig as $configKey => $configValue) { + $tabPanel .= ' + extTabsConfig.' . htmlspecialchars($configKey) . ' = ' . htmlspecialchars($configValue) . ';'; + } + + $tabPanel .= ' + var extTabs = new Ext.TabPanel(extTabsConfig)'; + foreach ($items as $item) { + if ($dividers2tabs !=1 || ($dividers2tabs == 1 && $item['hasContent'])) { + $tabPanel .= ' + extTabs.add({ + title: "' . htmlspecialchars($item['label']) . '", + id: "' . $item['id'] . '", + listeners: { activate: handleActivate'.t3lib_div::shortMD5($identString).' }, + contentEl : "tabcontent-' . $item['id'] . '", + '.($item['autoLoad']?'autoLoad:\''.$item['autoLoad'].'\',':'').' + '.($item['iconPath']?'iconCls:\'icon-'.$item['id'].'\',':'').' + disabled: ' . ($item['hasContent'] || $item['autoLoad'] ? 'false' : 'true') . ' + }).show();'; + + if($item['iconPath']) { + $content .= ''; + } + } + } + + $tabPanel .= ' + rendered'.t3lib_div::shortMD5($identString).' = true; + extTabs.activate(' . $activeTab . '); + function handleActivate'.t3lib_div::shortMD5($identString).'(tab) { + if (rendered'.t3lib_div::shortMD5($identString).') { + // send request to save selected tab + Ext.Ajax.request({ + url: "' . $this->backPath . 'ajax.php", + params: { + ajaxID: "ExtJS_TabMenu::setActiveTab", + identifier: "' . $identString . '", + activeTab: tab.id + } + }); + } + var innerBox = Ext.DomQuery.selectNode("#"+tab.id+" .x-panel-body"); + Ext.fly(innerBox).setStyle("height", "auto"); + }'; + + + $this->extJScode .= $tabPanel; + return $content; + } + + + /** + * Creates the id for dynTabMenus. + * + * @param string $identString: Identification string. This should be unique for every instance of a dynamic menu! + * @return string The id with a short MD5 of $identString and prefixed "DTM-", like "DTM-2e8791854a" + */ + function getExtTabMenuId($identString) { + $badChars = array('[',']',':'); + return 'extmenu-' . str_replace($badChars, '-', $identString); + } + + + /** + * Save active tab status with ajax + */ + public function setExtTabMenuActiveTab($params = array(), TYPO3AJAX &$ajaxObj = null) { + $id = t3lib_div::_GP('identifier'); + $activeTab = t3lib_div::_GP('activeTab'); + $GLOBALS['BE_USER']->uc['extTabs'][$id] = $activeTab; + $GLOBALS['BE_USER']->writeUC(); + } + + + + /** * Creates the version selector for the page id inputted. * Requires the core version management extension, "version" to be loaded. * Index: typo3/mod/user/ws/index.php =================================================================== --- typo3/mod/user/ws/index.php (Revision 7539) +++ typo3/mod/user/ws/index.php (Arbeitskopie) @@ -279,9 +279,6 @@ // Setting up the context sensitive menu: $this->doc->getContextMenuCode(); - // Add JS for dynamic tabs: - $this->doc->JScode.= $this->doc->getDynTabMenuJScode(); - // Setting publish access permission for workspace: $this->publishAccess = $BE_USER->workspacePublishAccess($BE_USER->workspace); @@ -328,7 +325,7 @@ ); // Add hidden fields and create tabs: - $content = $this->doc->getDynTabMenu($menuItems,'user_ws'); + $content = $this->doc->getExtTabMenu($menuItems, 'user-ws', 0, 0); $this->content.=$this->doc->section('',$content,0,1); // Setting up the buttons and markers for docheader