*/ if (!defined('TYPO3_MODE')) die("Can't include this file directly."); /** * TYPO3 Backend Template Class * * This class contains functions for starting and ending the HTML of backend modules * It also contains methods for outputting sections of content. * Further there are functions for making icons, links, setting form-field widths etc. * Color scheme and stylesheet definitions are also available here. * Finally this file includes the language class for TYPO3's backend. * * After this file $LANG and $TBE_TEMPLATE are global variables / instances of their respective classes. * This file is typically included right after the init.php file, * if language and layout is needed. * * Please refer to Inside TYPO3 for a discussion of how to use this API. * * @author Kasper Skårhøj * @package TYPO3 * @subpackage core */ class template { // Vars you typically might want to/should set from outside after making instance of this class: var $backPath = ''; // 'backPath' pointing back to the PATH_typo3 var $form=''; // This can be set to the HTML-code for a formtag. Useful when you need a form to span the whole page; Inserted exactly after the body-tag. var $JScodeLibArray = array(); // Similar to $JScode (see below) but used as an associative array to prevent double inclusion of JS code. This is used to include certain external Javascript libraries before the inline JS code. ':''); } /** * Creates the bodyTag. * You can add to the bodyTag by $this->bodyTagAdditions * * @return string HTML body tag */ function docBodyTagBegin() { $bodyContent = 'body onclick="if (top.menuReset) top.menuReset();" '.trim($this->bodyTagAdditions.($this->bodyTagId ? ' id="'.$this->bodyTagId.'"' : '')); return '<'.trim($bodyContent).'>'; } /** * Outputting document style * * @return string HTML style section/link tags */ function docStyle() { // Request background image: if ($this->backGroundImage) { $this->inDocStylesArray[]=' BODY { background-image: url('.$this->backPath.$this->backGroundImage.'); }'; } // Add inDoc styles variables as well: $this->inDocStylesArray[] = $this->inDocStyles; $this->inDocStylesArray[] = $this->inDocStyles_TBEstyle; // Implode it all: $inDocStyles = implode(LF, $this->inDocStylesArray); if ($this->styleSheetFile) { $this->pageRenderer->addCssFile($this->backPath . $this->styleSheetFile); } if ($this->styleSheetFile2) { $this->pageRenderer->addCssFile($this->backPath . $this->styleSheetFile2); } $this->pageRenderer->addCssInlineBlock('inDocStyles', $inDocStyles . LF . '/*###POSTCSSMARKER###*/'); if ($this->styleSheetFile_post) { $this->pageRenderer->addCssFile($this->backPath . $this->styleSheetFile_post); } } /** * Insert additional style sheet link * * @param string $key some key identifying the style sheet * @param string $href uri to the style sheet file * @param string $title value for the title attribute of the link element * @param string $relation value for the rel attribute of the link element * @return void */ function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') { if (strpos($href, '://') !== FALSE || substr($href, 0, 1) === '/') { $file = $href; } else { $file = $this->backPath . $href; } $this->pageRenderer->addCssFile($file, $relation, 'screen', $title); } /** * Add all *.css files of the directory $path to the stylesheets * * @param string $path directory to add * @return void */ function addStyleSheetDirectory($path) { // calculation needed, when TYPO3 source is used via a symlink // absolute path to the stylesheets $filePath = dirname(t3lib_div::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $path; // clean the path $resolvedPath = t3lib_div::resolveBackPath($filePath); // read all files in directory and sort them alphabetically $files = t3lib_div::getFilesInDir($resolvedPath, 'css', FALSE, 1); foreach ($files as $file) { $this->pageRenderer->addCssFile($GLOBALS['BACK_PATH'] . $path . $file, 'stylesheet', 'all'); } } /** * Insert post rendering document style into already rendered content * This is needed for extobjbase * * @param string $content style-content to insert. * @return string content with inserted styles */ function insertStylesAndJS($content) { // insert accumulated CSS $this->inDocStylesArray[] = $this->inDocStyles; $styles = LF.implode(LF, $this->inDocStylesArray); $content = str_replace('/*###POSTCSSMARKER###*/',$styles,$content); // insert accumulated JS $jscode = $this->JScode.LF.$this->wrapScriptTags(implode(LF, $this->JScodeArray)); $content = str_replace('',$jscode,$content); return $content; } /** * Returns an array of all stylesheet directories belonging to core and skins * * @return array Stylesheet directories */ public function getSkinStylesheetDirectories() { $stylesheetDirectories = array(); // add default core stylesheets foreach ($this->stylesheetsCore as $stylesheetDir) { $stylesheetDirectories[] = $stylesheetDir; } // Stylesheets from skins // merge default css directories ($this->stylesheetsSkin) with additional ones and include them if (is_array($GLOBALS['TBE_STYLES']['skins'])) { // loop over all registered skins foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) { $skinStylesheetDirs = $this->stylesheetsSkins; // skins can add custom stylesheetDirectories using // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories'] if (is_array($skin['stylesheetDirectories'])) { $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']); } // add all registered directories foreach ($skinStylesheetDirs as $stylesheetDir) { // for EXT:myskin/stylesheets/ syntax if (substr($stylesheetDir, 0, 4) === 'EXT:') { list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2); if (strcmp($extKey, '') && t3lib_extMgm::isLoaded($extKey) && strcmp($path, '')) { $stylesheetDirectories[] = t3lib_extMgm::extRelPath($extKey) . $path; } } else { // for relative paths $stylesheetDirectories[] = t3lib_extMgm::extRelPath($skinExtKey) . $stylesheetDir; } } } } return $stylesheetDirectories; } /** * Initialize the charset. * Sets the internal $this->charset variable to the charset defined in $GLOBALS["LANG"] (or the default as set in this class) * Returns the meta-tag for the document header * * @return string tag with charset from $this->charset or $GLOBALS['LANG']->charSet */ function initCharset() { // Set charset to the charset provided by the current backend users language selection: $this->charset = $GLOBALS['LANG']->charSet ? $GLOBALS['LANG']->charSet : $this->charset; // Return meta tag: return ''; } /** * Returns generator meta tag * * @return string tag with name "generator" */ function generator() { $str = 'TYPO3 '.TYPO3_branch.', ' . TYPO3_URL_GENERAL . ', © Kasper Skårhøj ' . TYPO3_copyright_year . ', extensions are copyright of their respective owners.'; return ''; } /** * Returns X-UA-Compatible meta tag * * @param string $content Content of the compatible tag (default: IE-8) * @return string */ public function xUaCompatible($content = 'IE=8') { return ''; } /***************************************** * * OTHER ELEMENTS * Tables, buttons, formatting dimmed/red strings * ******************************************/ /** * Returns an image-tag with an 18x16 icon of the following types: * * $type: * -1: OK icon (Check-mark) * 1: Notice (Speach-bubble) * 2: Warning (Yellow triangle) * 3: Fatal error (Red stop sign) * * @param integer $type See description * @param string $styleAttribValue Value for style attribute * @return string HTML image tag (if applicable) */ function icons($type, $styleAttribValue = '') { switch($type) { case self::STATUS_ICON_ERROR: $icon = 'status-dialog-error'; break; case self::STATUS_ICON_WARNING: $icon = 'status-dialog-warning'; break; case self::STATUS_ICON_NOTIFICATION: $icon = 'status-dialog-notification'; break; case self::STATUS_ICON_OK: $icon = 'status-dialog-ok'; break; default: break; } if ($icon) { return t3lib_iconWorks::getSpriteIcon($icon); } } /** * Returns an button with the $onClick action and $label * * @param string $onClick The value of the onclick attribute of the input tag (submit type) * @param string $label The label for the button (which will be htmlspecialchar'ed) * @return string A tag of the type "submit" */ function t3Button($onClick, $label) { $button = ''; return $button; } /** * dimmed-fontwrap. Returns the string wrapped in a -tag defining the color to be gray/dimmed * * @param string $string Input string * @return string Output string */ function dfw($string) { return ''.$string.''; } /** * red-fontwrap. Returns the string wrapped in a -tag defining the color to be red * * @param string $string Input string * @return string Output string */ function rfw($string) { return ''.$string.''; } /** * Returns string wrapped in CDATA "tags" for XML / XHTML (wrap content of '.$cr; } return trim($string); } // These vars defines the layout for the table produced by the table() function. // You can override these values from outside if you like. var $tableLayout = array( 'defRow' => array( 'defCol' => array('','') ) ); var $table_TR = ''; var $table_TABLE = ''; /** * Returns a table based on the input $data * * @param array $data Multidim array with first levels = rows, second levels = cells * @param array $layout If set, then this provides an alternative layout array instead of $this->tableLayout * @return string The HTML table. * @internal */ function table($data, $layout = NULL) { $result = ''; if (is_array($data)) { $tableLayout = (is_array($layout) ? $layout : $this->tableLayout); $rowCount = 0; foreach ($data as $tableRow) { if ($rowCount % 2) { $layout = is_array($tableLayout['defRowOdd']) ? $tableLayout['defRowOdd'] : $tableLayout['defRow']; } else { $layout = is_array($tableLayout['defRowEven']) ? $tableLayout['defRowEven'] : $tableLayout['defRow']; } $rowLayout = is_array($tableLayout[$rowCount]) ? $tableLayout[$rowCount] : $layout; $rowResult = ''; if (is_array($tableRow)) { $cellCount = 0; foreach ($tableRow as $tableCell) { $cellWrap = (is_array($layout[$cellCount]) ? $layout[$cellCount] : $layout['defCol']); $cellWrap = (is_array($rowLayout['defCol']) ? $rowLayout['defCol'] : $cellWrap); $cellWrap = (is_array($rowLayout[$cellCount]) ? $rowLayout[$cellCount] : $cellWrap); $rowResult .= $cellWrap[0] . $tableCell . $cellWrap[1]; $cellCount++; } } $rowWrap = (is_array($layout['tr']) ? $layout['tr'] : array($this->table_TR, '')); $rowWrap = (is_array($rowLayout['tr']) ? $rowLayout['tr'] : $rowWrap); $result .= $rowWrap[0] . $rowResult . $rowWrap[1]; $rowCount++; } $tableWrap = is_array($tableLayout['table']) ? $tableLayout['table'] : array($this->table_TABLE, '
'); $result = $tableWrap[0] . $result . $tableWrap[1]; } return $result; } /** * Constructs a table with content from the $arr1, $arr2 and $arr3. * Used in eg. ext/belog/mod/index.php - refer to that for examples * * @param array $arr1 Menu elements on first level * @param array $arr2 Secondary items * @param array $arr3 Third-level items * @return string HTML content, ...
*/ function menuTable($arr1,$arr2 = array(), $arr3 = array()) { $rows = max(array(count($arr1),count($arr2),count($arr3))); $menu=' '; for($a=0;$a<$rows;$a++) { $menu.=''; $cls=array(); $valign='middle'; $cls[]=''; if (count($arr2)) { $cls[]=''; if (count($arr3)) { $cls[]=''; } } $menu.=implode($cls,''); $menu.=''; } $menu.='
'.$arr1[$a][0].''.$arr1[$a][1].''.$arr2[$a][0].''.$arr2[$a][1].''.$arr3[$a][0].''.$arr3[$a][1].'  
'; return $menu; } /** * Returns a one-row/two-celled table with $content and $menu side by side. * The table is a 100% width table and each cell is aligned left / right * * @param string $content Content cell content (left) * @param string $menu Menu cell content (right) * @return string HTML output */ function funcMenu($content, $menu) { return '
'.$content.' '.$menu.'
'; } /** * Includes a javascript library that exists in the core /typo3/ directory. The * backpath is automatically applied * * @param string $lib: Library name. Call it with the full path like "contrib/prototype/prototype.js" to load it * @return void */ function loadJavascriptLib($lib) { $this->pageRenderer->addJsFile($this->backPath . $lib); } /** * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document * @return void */ function getContextMenuCode() { $this->pageRenderer->loadPrototype(); $this->loadJavascriptLib('js/clickmenu.js'); $this->JScodeArray['clickmenu'] = ' Clickmenu.clickURL = "'.$this->backPath.'alt_clickmenu.php"; Clickmenu.ajax = '.($this->isCMLayers() ? 'true' : 'false' ).';'; } /** * Includes the necessary javascript file (tree.js) for use on pages which have the * drag and drop functionality (usually pages and folder display trees) * * @param string $table indicator of which table the drag and drop function should work on (pages or folders) * @return void */ function getDragDropCode($table) { $this->pageRenderer->loadPrototype(); $this->loadJavascriptLib('js/common.js'); $this->loadJavascriptLib('js/tree.js'); // setting prefs for drag & drop $this->JScodeArray['dragdrop'] = ' DragDrop.changeURL = "'.$this->backPath.'alt_clickmenu.php"; DragDrop.backPath = "'.t3lib_div::shortMD5(''.'|'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']).'"; DragDrop.table = "'.$table.'"; '; } /** * This loads everything needed for the Context Sensitive Help (CSH) * * @return void */ protected function loadCshJavascript() { $this->pageRenderer->loadExtJS(); $this->pageRenderer->addJsFile($this->backPath .'../t3lib/js/extjs/contexthelp.js'); $this->pageRenderer->addExtDirectCode(); } /** * Creates a tab menu from an array definition * * Returns a tab menu for a module * Requires the JS function jumpToUrl() to be available * * @param mixed $mainParams is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=... * @param string $elementName it the form elements name, probably something like "SET[...]" * @param string $currentValue is the value to be selected currently. * @param array $menuItems is an array with the menu items for the selector box * @param string $script is the script to send the &id to, if empty it's automatically found * @param string $addparams is additional parameters to pass to the script. * @return string HTML code for tab menu */ function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '') { $content=''; if (is_array($menuItems)) { if (!is_array($mainParams)) { $mainParams = array('id' => $mainParams); } $mainParams = t3lib_div::implodeArrayForUrl('',$mainParams); if (!$script) {$script=basename(PATH_thisScript);} $menuDef = array(); foreach($menuItems as $value => $label) { $menuDef[$value]['isActive'] = !strcmp($currentValue,$value); $menuDef[$value]['label'] = t3lib_div::deHSCentities(htmlspecialchars($label)); $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value; } $content = $this->getTabMenuRaw($menuDef); } return $content; } /** * Creates the HTML content for the tab menu * * @param array $menuItems Menu items for tabs * @return string Table HTML * @access private */ function getTabMenuRaw($menuItems) { $content=''; if (is_array($menuItems)) { $options=''; $count = count($menuItems); $widthLeft = 1; $addToAct = 5; $widthRight = max (1,floor(30-pow($count,1.72))); $widthTabs = 100 - $widthRight - $widthLeft; $widthNo = floor(($widthTabs - $addToAct)/$count); $addToAct = max ($addToAct,$widthTabs-($widthNo*$count)); $widthAct = $widthNo + $addToAct; $widthRight = 100 - ($widthLeft + ($count*$widthNo) + $addToAct); foreach($menuItems as $id => $def) { $isActive = $def['isActive']; $class = $isActive ? 'tabact' : 'tab'; $width = $isActive ? $widthAct : $widthNo; // @rene: Here you should probably wrap $label and $url in htmlspecialchars() in order to make sure its XHTML compatible! I did it for $url already since that is VERY likely to break. $label = $def['label']; $url = htmlspecialchars($def['url']); $params = $def['addParams']; $options .= '' . $label . ''; } if ($options) { $content .= ' '.$options.'
  
'; } } return $content; } /** * Creates a DYNAMIC tab-menu where the tabs are switched between with DHTML. * Should work in MSIE, Mozilla, Opera and Konqueror. On Konqueror I did find a serious problem: