Index: t3lib/class.t3lib_pageincludes.php =================================================================== --- t3lib/class.t3lib_pageincludes.php (revision 0) +++ t3lib/class.t3lib_pageincludes.php (revision 0) @@ -0,0 +1,909 @@ + + * @package TYPO3 + * @subpackage t3lib + */ +class t3lib_pageIncludes implements t3lib_Singleton { + + + public $compressJavascript = FALSE; + public $compressCss = FALSE; + + public $concatenateFiles = FALSE; + + public $moveJsFromHeaderToFooter = FALSE; + + protected $csConvObj; + protected $lang; + + // static array containing associative array for the included files + protected static $jsFiles = array(); + protected static $jsFooterFiles = array(); + protected static $jsLibs = array(); + protected static $jsFooterLibs = array(); + protected static $cssFiles = array(); + + // static header blocks + protected static $xmlPrologAndDocType = ''; + protected static $metaTags = ''; + protected static $inlineComment = ''; + protected static $headerData = ''; + protected static $footerData = ''; + protected $metaCharsetTag = ''; + protected $titleTag = ''; + protected $htmlTag = ''; + protected $headTag = ''; + protected $baseUrlTag = ''; + protected $shortcutTag = ''; + + // static inline code blocks + protected static $jsInline = array(); + protected static $jsFooterInline = array(); + protected static $jsHandlerCode = array(); + protected static $cssInline = array(); + + protected $templateFile; + + protected $jsLibraryNames = array('prototype', 'scriptaculous', 'extjs'); + + const PART_HEADER = 0; + const PART_FOOTER = 1; + + // internal flags for JS-libraries + protected $addPrototype = FALSE; + protected $addScriptaculous = FALSE; + protected $addScriptaculousModules = array('builder'=>FALSE, 'effects'=>FALSE, 'dragdrop'=>FALSE, 'controls'=>FALSE, 'slider'=>FALSE); + protected $addExtJS = FALSE; + protected $addExtCore = FALSE; + protected $extJSadapter = 'ext/ext-base.js'; + protected $appLoader = FALSE; + protected $appLoaderLabels = ''; + protected $appLoaderIcon = ''; + + protected $enableExtJsDebug = FALSE; + protected $enableExtCoreDebug = FALSE; + + // available adapters for extJs + const EXTJS_ADAPTER_JQUERY = 'jquery'; + const EXTJS_ADAPTER_PROTOTYPE = 'prototype'; + const EXTJS_ADAPTER_YUI = 'yui'; + + // available inline-JsHandler + const JSHANDLER_EXTONREADY = 1; + + public $enableExtJSQuickTips = false; + + protected $inlineLanguageLabels = array(); + protected $inlineSettings = array(); + + // used by BE modules + public $backPath; + + + /** + * Constructor + * + * @param string $templateFile declare the used template file. Omit this parameter will use default template + * @param string $backPath relative path to typo3-folder. It varies for BE modules, in FE it will be typo3/ + * @return void + */ + public function __construct($templateFile = '', $backPath = '') { + $this->templateFile = $templateFile; + if ($this->templateFile === '') { + $this->templateFile = TYPO3_mainDir.'templates/pageincludes.html'; + } + $this->backPath = $backPath; + $this->csConvObj = TYPO3_MODE == 'BE' ? $GLOBAL['LANG']->csConvObj : $GLOBALS['TSFE']->csConvObj; + $this->lang = TYPO3_MODE == 'BE' ? $GLOBALS['BE_USER']->uc['lang'] : $GLOBALS['TSFE']->lang; + + //init vars + $this->jsFiles = $this->jsFooterFiles = $this->jsInline = $this->jsFooterInline = $this->jsLibs = array(); + $this->cssFiles = $this->cssInline = array(); + + $this->jsHandlerCode[self::JSHANDLER_EXTONREADY] = ''; + } + + + /*****************************************************/ + /* */ + /* Public Function to add Data */ + /* */ + /* */ + /*****************************************************/ + + /** + * set xml prolog and docType + * + * @param string $xmlPrologAndDocType complete tags for xml prolog and docType + */ + public function setXmlPrologAndDocType($xmlPrologAndDocType) { + $this->xmlPrologAndDocType = $xmlPrologAndDocType; + } + + /** + * set page title + * + * @param string $title title of webpage + */ + public function setTitle($title) { + $this->titleTag = '' . htmlspecialchars($title) . ''; + } + + /** + * set meta charset definition + * + * @param string $charSet used charset + * @param string $tag the tag to wrap charset, by default the meta charset tag + */ + public function setMetaCharsetTag($charSet, $tag = '') { + $this->metaCharsetTag = str_replace('|', htmlspecialchars($charSet), $tag); + } + + /** + * set html tag + * + * @param string $tag html tag + */ + public function setHtmlTag($tag = '') { + $this->htmlTag = $tag; + } + + /** + * set head tag + * + * @param string $tag head tag + */ + public function setHeadTag($tag = '') { + $this->headTag = $tag; + } + + /** + * set shortcut tags + * + * @param string $favIcon + * @param string $iconMimeType + */ + public function setShortcutTag($favIcon, $iconMimeType) { + $this->shortcutTag = ' + + '; + } + + /** + * set base url + * + * @param string $url + * @param string $tag tag that wraps the base url + */ + public function setBaseUrlTag($url, $tag = '') { + $this->baseUrlTag = str_replace('|', htmlspecialchars($url), $tag); + } + + /** + * add meta data + * + * @param string $meta meta data (complete metatag) + */ + public function addMetaData($meta) { + $this->metaTags .= $meta.chr(10); + } + + /** + * add inline HTML comment + * + * @param string $comment + */ + public function addInlineComment($comment) { + $this->inlineComment .= htmlspecialchars($comment) . chr(10); + } + + /** + * add header data + * + * @param string $data free header data for HTML header + */ + public function addHeaderData($data) { + $this->headerData .= $data . chr(10); + } + + + /* Javascript Files */ + + /** + * add JS Libraray. JS Library block is rendered on top of the JS files. + * + * @param string $name + * @param string $file + * @param string $type + * @param int $section t3lib_pageIncludes::PART_HEADER (0) or t3lib_pageIncludes::PART_FOOTER (1) + * @param boolean $compressed flag if library is compressed + * @param boolean $forceOnTop flag if added library should be inserted at begin of this block + */ + public function addJsLibrary($name, $file, $type = 'text/javascript', $section = t3lib_pageIncludes::PART_HEADER, $compressed = TRUE, $forceOnTop = FALSE) { + if (!in_array(strtolower($name), $this->jsLibraryNames)) { + $this->jsLibs[$name] = array('file'=>$file, 'type'=>'text/javascript', 'section'=>$section, 'compressed'=>$compressed, 'forceOnTop'=>$forceOnTop); + } + + } + + /** + * add JS file + * + * @param string $file + * @param string $type + * @param boolean $compressed + * @param boolean $forceOnTop + */ + public function addJsFile($file, $type = 'text/javascript', $compressed = FALSE, $forceOnTop = FALSE) { + if (!isset($this->jsFiles[$file]) && !isset($this->jsFooterFiles[$file])) { + $this->jsFiles[$file] = array('type'=>$type, 'section'=>self::PART_HEADER, 'compressed'=>$compressed, 'forceOnTop'=>$forceOnTop); + } + } + + /** + * add JS file to footer + * + * @param string $file + * @param string $type + * @param boolean $compressed + * @param boolean $forceOnTop + */ + public function addJsFooterFile($file, $type = 'text/javascript', $compressed = FALSE, $forceOnTop = FALSE) { + if (!isset($this->jsFiles[$file]) && !isset($this->jsFooterFiles[$file])) { + $this->jsFooterFiles[$file] = array('type'=>$type, 'section'=>self::PART_FOOTER, 'compressed'=>$compressed, 'forceOnTop'=>$forceOnTop); + } + } + + /*Javascript Inline Blocks */ + + /** + * add JS inline code + * + * @param string $name + * @param string $block + * @param boolean $compressed + * @param boolean $forceOnTop + */ + public function addJsInlineCode($name, $block, $compressed = FALSE, $forceOnTop = FALSE) { + if (!isset($this->jsInline[$name])) { + $this->jsInline[$name] = array('code'=>$block . chr(10), 'forceOnTop'=>$forceOnTop); + } + } + + /** + * add JS inline code to footer + * + * @param string $name + * @param string $block + * @param boolean $compressed + * @param boolean $forceOnTop + */ + public function addJsFooterInlineCode($name, $block, $compressed = FALSE, $forceOnTop = FALSE) { + if (!isset($this->jsFooterInline[$name])) { + $this->jsFooterInline[$name] = array('code'=>$block . chr(10), 'compressed'=>$compressed, 'forceOnTop'=>$forceOnTop); + } + } + + /** + * Add JS Handler code, which will be wrapped by the given GS Habdler. + * Types of handler are: + * t3lib_pageIncludes::JSHANDLER_EXTONREADY which wrap code with Ext.onReady(function() {} + * t3lib_pageIncludes::JSHANDLER_DOCUMENTONREADY which wrap code with Event.observe(document, "load", function() {} + * + * @param string $block + * @param int $handler name of the handler, t3lib_pageIncludes::JSHANDLER_EXTONREADY or t3lib_pageIncludes::JSHANDLER_DOCUMENTONREADY + */ + public function addJsHandlerCode($block, $handler = self::JSHANDLER_EXTONREADY) { + if (in_array($handler, array(self::JSHANDLER_EXTONREADY))) { + $this->jsHandlerCode[$handler] .= $this->jsHandlerCode[$handler] ? chr(10) . $block : $block; + } + } + + + /* CSS Files */ + + /** + * add CSS file + * + * @param string $file + * @param string $rel + * @param string $media + * @param string $title + * @param boolean $compressed + * @param boolean $forceOnTop + */ + public function addCssFile($file, $rel = 'stylesheet', $media = 'screen', $title = '', $compressed = FALSE, $forceOnTop = FALSE) { + if (!isset($this->cssFiles[$file])) { + $this->cssFiles[$file] = array('rel'=>$rel, 'media'=>$media, 'title'=>$title, 'compressed'=>$compressed, 'forceOnTop'=>$forceOnTop, ); + } + } + + /*CSS Inline Blocks */ + + /** + * add CSS inline code + * + * @param string $name + * @param string $block + * @param boolean $compressed + * @param boolean $forceOnTop + */ + public function addCssInlineBlock($name, $block, $compressed = FALSE, $forceOnTop = FALSE) { + if (!isset($this->cssInline[$name])) { + $this->cssInline[$name] = array('code'=>$block . chr(10), 'compressed'=>$compressed, 'forceOnTop'=>$forceOnTop, ); + } + } + + + /* JS Libraries */ + + /** + * call function if you need the prototype library + * + */ + public function loadPrototype() { + $this->addPrototype = TRUE; + } + + + /** + * call function if you need the Scriptaculous library + * + * @param string $modules add modules you need. use "all" if you need complete modules + */ + public function loadScriptaculous($modules = '') { + // Scriptaculous require prototype, so load prototype too. + $this->addPrototype = TRUE; + $this->addScriptaculous = TRUE; + if ($modules) { + if ($modules == 'all') { + foreach ($this->addScriptaculousModules as $key=>$value) { + $this->addScriptaculousModules[$key] = TRUE; + } + } else { + $mods = t3lib_div::trimExplode(',', $modules); + foreach ($mods as $mod) { + if (isset($this->addScriptaculousModules[strtolower($mod)])) { + $this->addScriptaculousModules[strtolower($mod)] = TRUE; + } + } + } + } + } + + /** + * call this function if you need the extJS library + * + * @param boolean $css flag, if set the ext-css will be loaded + * @param boolean $theme flag, if set the ext-theme "grey" will be loaded + * @param string $adapter choose alternative adapter, possible values: yui, prototype, jquery + */ + public function loadExtJS($css = TRUE, $theme = TRUE, $adapter = '') { + if ($adapter) { + // empty $adapter will always load the ext adapter + switch (t3lib_div::strtolower(trim($adapter))) { + case self::EXTJS_ADAPTER_YUI: + $this->extJSadapter = 'yui/ext-yui-adapter.js'; + break; + case self::EXTJS_ADAPTER_PROTOTYPE: + $this->extJSadapter = 'prototype/ext-prototype-adapter.js'; + break; + case self::EXTJS_ADAPTER_JQUERY: + $this->extJSadapter = 'jquery/ext-jquery-adapter.js'; + break; + } + } + if (!$this->addExtJS) { + $this->addExtJS = TRUE; + if ($theme) { + if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) { + $this->addCssFile($this->backPath.$GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'screen', '', FALSE, TRUE); + } else { + $this->addCssFile($this->backPath.'contrib/extjs/resources/css/xtheme-blue.css', 'stylesheet', 'screen', '', FALSE, TRUE); + } + } + if ($css) { + if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) { + $this->addCssFile($this->backPath.$GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'screen', '', FALSE, TRUE); + } else { + $this->addCssFile($this->backPath.'contrib/extjs/resources/css/ext-all-notheme.css', 'stylesheet', 'screen', '', FALSE, TRUE); + } + } + + } + } + + /** + * Enable Application loader. Make sure you place returned HTML after and the CSS in your stylesheet or inline code + * + * @param array $labels + * @param string $loadIcon + * @return array HTML and CSS for including in page + */ + public function enableApplicationLoader($labels = array('TYPO3 Application', 'Loading Core API...', 'Loading UI Components...', 'Initializing Application...'), $loadIcon = 'gfx/typo3ani32.gif') { + if($this->appLoader) { + // only one AppLoader possible + return array('HTML' => '', 'CSS' => '', 'JAVASCRIPT' => ''); + } + $this->appLoader = TRUE; + $this->appLoaderLabels = $labels; + $this->moveJsFromHeaderToFooter = TRUE; + return array( + 'HTML' => '
' . $labels[0] . '
' . $labels[1] . '
', + 'CSS' => '#loading-mask{position:absolute;left:0;top:0;width:100%;height:100%;z-index:20000;background-color:white;}#loading{position:absolute;left:45%;top:40%;padding:2px;z-index:20001;height:auto;}#loading a {color:#225588;}#loading .loading-indicator{background:white;color:#444;font:bold 13px tahoma,arial,helvetica;padding:10px;margin:0;height:auto;}#loading-msg {font: normal 10px arial,tahoma,sans-serif;}', + 'JAVASCRIPT' => 'var hideMask = function () {Ext.get("loading").remove();Ext.fly("loading-mask").fadeOut({remove:true});};hideMask.defer(250);' + ); + } + + + /** + * call function if you need the ExtCore library + * + */ + public function loadExtCore() { + $this->addExtCore = TRUE; + } + + /** + * call this function to load debug version of ExtJS. Use this for development only + * + */ + public function enableExtJsDebug() { + $this->enableExtJsDebug = TRUE; + } + + /** + * call this function to load debug version of ExtCore. Use this for development only + * + */ + public function enableExtCoreDebug() { + $this->enableExtCoreDebug = TRUE; + } + + /** + * set alternativ template file + * + * @param string $file + */ + public function setAlternativeTemplateFile($file) { + $this->templateFile = $file; + } + + + /** + * Add Javascript Inline Label. This will occur in TYPO3.lang - object + * The label can be used in scripts with TYPO3.lang. + * + * @param string $key + * @param string $value + */ + public function addInlineLanguageLabel($key, $value) { + $this->inlineLanguageLabels[$key] = $value; + } + + /** + * Add Javascript Inline Label Array. This will occur in TYPO3.lang - object + * The label can be used in scripts with TYPO3.lang. + * Array will be merged with existing array. + * + * @param array $array + */ + public function addInlineLanguageLabelArray(array $array) { + $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $array); + } + + /** + * Add Javascript Inline Setting. This will occur in TYPO3.settings - object + * The label can be used in scripts with TYPO3.setting. + * + * @param string $namespace + * @param string $key + * @param string $value + */ + public function addInlineSetting($namespace, $key, $value) { + if ($namespace) { + if (strpos($namespace, '.')) { + $parts = explode('.', $namespace); + $a = &$this->inlineSettings; + foreach ($parts as $part) { + $a = &$a[$part]; + } + $a[$key] = $value; + } else { + $this->inlineSettings[$namespace][$key] = $value; + } + } else { + $this->inlineSettings[$key] = $value; + } + } + + /** + * Add Javascript Inline Setting. This will occur in TYPO3.settings - object + * The label can be used in scripts with TYPO3.setting. + * Array will be merged with existing array. + * + * @param string $namespace + * @param array $array + */ + public function addInlineSettingArray($namespace, array $array) { + if ($namespace) { + if (strpos($namespace, '.')) { + $parts = explode('.', $namespace); + $a = &$this->inlineSettings; + foreach ($parts as $part) { + $a = &$a[$part]; + } + $a[$key] = array_merge((array) $a[$key], $value); + } else { + $this->inlineSettings[$namespace] = array_merge((array) $this->inlineSettings[$namespace], $array); + } + } else { + $this->inlineSettings = array_merge($this->inlineSettings, $array); + } + } + + + /*****************************************************/ + /* */ + /* Render Functions */ + /* */ + /* */ + /*****************************************************/ + + + /** + * render the section (Header or Footer) + * + * @param int $part section which should be rendered: t3lib_pageIncludes::PART_HEADER or t3lib_pageIncludes::PART_FOOTER + * @return string content of rendered section + */ + public function render($part = self::PART_HEADER) { + + $jsFiles = ''; + $noJS = FALSE; + if (($part === self::PART_HEADER && !$this->moveJsFromHeaderToFooter) || ($part === self::PART_FOOTER && $this->moveJsFromHeaderToFooter)) { + // render js libraries for header section + $jsLibs = $this->renderJsLibraries(); + } else { + $jsLibs = ''; + } + + if ($part == self::PART_FOOTER && $this->jsHandlerCode[self::JSHANDLER_EXTONREADY]) { + $this->jsFooterInline['ExtOnReady'] = array('code'=>'Ext.onReady(function() {'.chr(10).$this->jsHandlerCode[self::JSHANDLER_EXTONREADY].chr(10).'});', 'compressed'=>FALSE, ); + } + + + if ($this->moveJsFromHeaderToFooter && $part === self::PART_HEADER) { + $noJS = TRUE; + $this->jsFooterFiles = array_merge($this->jsFiles, $this->jsFooterFiles); + $this->jsFooterInline = array_merge($this->jsInline, $this->jsFooterInline); + unset($this->jsFiles, $this->jsInline); + } + + + if ($this->compressCss || $this->compressJavascript) { + // do the file compression + $this->doCompress(); + } + if ($this->concatenateFiles) { + // do the file concatenation + $this->doConcatenate(); + } + + + $cssFiles = ''; + if (count($this->cssFiles)) { + foreach ($this->cssFiles as $file=>$properties) { + if ($properties['forceOnTop']) { + $cssFiles = ''.chr(10).$cssFiles; + } else { + $cssFiles .= ''.chr(10); + } + } + } + + $cssInline = ''; + if (count($this->cssInline)) { + $cssInline .= '' . chr(10); + } + + if ($part === self::PART_HEADER) { + $refJsLibs = $this->jsLibs; + $refJsFiles = $this->jsFiles; + $refJsInline = $this->jsInline; + } else { + $refJsLibs = $this->jsLibs; + $refJsFiles = $this->jsFooterFiles; + $refJsInline = $this->jsFooterInline; + } + + + if (count($refJsLibs)) { + foreach ($refJsLibs as $name=>$properties) { + if (($properties['section'] === $part && !$this->moveJsFromHeaderToFooter) || ($this->moveJsFromHeaderToFooter && $part === self::PART_FOOTER)) { + if ($properties['forceOnTop']) { + $jsLibs = '' . chr(10) . $jsLibs; + } else { + $jsLibs .= '' . chr(10); + } + } + } + } + + if (count($refJsFiles)) { + foreach ($refJsFiles as $file=>$properties) { + if (($properties['section'] === $part && !$this->moveJsFromHeaderToFooter) || ($this->moveJsFromHeaderToFooter && $part === self::PART_FOOTER)) { + if ($properties['forceOnTop']) { + $jsFiles = '' . chr(10) . $jsFiles; + } else { + $jsFiles .= '' . chr(10); + } + } + } + } + + if ($this->appLoader && $this->addExtJS && $part === self::PART_FOOTER) { + $jsFiles = chr(10).'' . chr(10) . $jsLibs . + '' . chr(10) . $jsFiles . + ''; + } else { + $jsFiles = chr(10) . $jsLibs . chr(10) . $jsFiles; + } + + + $jsInline = ''; + if (count($refJsInline)) { + $jsInline = '' . chr(10); + } + + + // get template + $templateFile = t3lib_div::getFileAbsFileName($this->templateFile, TRUE); + $template = t3lib_div::getURL($templateFile); + + $subpart = trim(t3lib_parsehtml::getSubpart($template, '###PART_' . ($part === self::PART_HEADER ? 'HEADER' : 'FOOTER') . '###')); + + $markerArray = array( + 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType, + 'HTMLTAG' => $this->htmlTag, + 'HEADTAG' => $this->headTag, + 'METACHARSET' => $this->metaCharsetTag, + 'INLINECOMMENT' => $this->inlineComment ? chr(10) . chr(10) . '' . chr(10) . chr(10) : '', + 'BASEURL' => $this->baseUrlTag, + 'SHORTCUT' => $this->shortcutTag, + 'CSS_INCLUDE' => $cssFiles, + 'CSS_INLINE' => $cssInline, + 'JS_INCLUDE' => $jsFiles, + 'JS_INLINE' => $jsInline, + 'TITLE' => $this->titleTag, + 'META' => $this->metaTags, + 'HEADERDATA' => $this->headerData, + 'JS_INCLUDE_FOOTER' => $jsFiles, + 'JS_INLINE_FOOTER' => $jsInline, + );debug($markerArray); + + return t3lib_parsehtml::substituteMarkerArray($subpart, $markerArray, '###|###'); + } + + /** + * helper function for render the javascript libraries + * + * @return string content with javascript libraries + */ + protected function renderJsLibraries() { + $out = ''; + + if ($this->addPrototype) { + $out .= '' . chr(10); + unset($this->jsFiles[$this->backPath . 'contrib/prototype/prototype.js']); + } + + if ($this->addScriptaculous) { + $mods = array(); + foreach ($this->addScriptaculousModules as $key=>$value) { + if ($this->addScriptaculousModules[$key]) { + $mods[] = $key; + } + } + // resolve dependencies + if (in_array('dragdrop', $mods) || in_array('controls', $mods)) { + $mods = array_merge(array('effects'), $mods); + } + + if (count($mods)) { + $moduleLoadString = '?load='.implode(',', $mods); + } + + $out .= '' . chr(10); + unset($this->jsFiles[$this->backPath . 'contrib/scriptaculous/scriptaculous.js' . $moduleLoadString]); + } + + // include extCore + if ($this->addExtCore) { + $out .= '' . chr(10); + unset($this->jsFiles[$this->backPath . 'contrib/extjs/ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js']); + } + + // include extJS + if ($this->addExtJS) { + // use the base adapter all the time + $out .= '' . chr(10); + $out .= '' . chr(10); + + // add extJS localization + $localeMap = $this->csConvObj->isoArray; // load standard ISO mapping and modify for use with ExtJS + $localeMap[''] = 'en'; + $localeMap['default'] = 'en'; + $localeMap['gr'] = 'el_GR'; // Greek + $localeMap['no'] = 'no_BO'; // Norwegian Bokmaal + $localeMap['se'] = 'se_SV'; // Swedish + + $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang; + // TODO autoconvert file from UTF8 to current BE charset if necessary!!!! + $extJsLocaleFile = 'contrib/extjs/locale/ext-lang-'.$extJsLang.'-min.js'; + if (file_exists(PATH_typo3 . $extJsLocaleFile)) { + $out .= '' . chr(10); + } + // set clear.gif, move it on top + $this->jsHandlerCode[self::JSHANDLER_EXTONREADY] = 'Ext.ns("TYPO3"); + Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(t3lib_div::locationHeaderUrl($this->backPath . 'gfx/clear.gif')) . '";' . chr(10) . + 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' . + 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' . + ($this->enableExtJSQuickTips ? 'Ext.QuickTips.init();' . chr(10) : '') . + $this->jsHandlerCode[self::JSHANDLER_EXTONREADY]; + // remove extjs from JScodeLibArray + unset($this->jsFiles[$this->backPath.'contrib/extjs/ext-all.js']); + unset($this->jsFiles[$this->backPath.'contrib/extjs/ext-all-debug.js']); + } + + return $out; + } + + /*****************************************************/ + /* */ + /* Tools */ + /* */ + /* */ + /*****************************************************/ + + /** + * concatenate files into one file + * registered handler + * TODO: implement own method + * + * @return void + */ + protected function doConcatenate() { + // traverse the arrays, concatenate in one file + // then remove concatenated files from array and add the concatenated file + + // extern concatination + if ($this->concatenateFiles && $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['concatenateHandler']) { + // use extern concatenate routine + $params = array( + 'jsFiles' => $this->jsFiles, + 'jsFooterFiles' => $this->jsFooterFiles, + 'cssFiles' => $this->cssFiles, + ); + t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['concatenateHandler'], $params, $this); + } else { + // own method + + } + + } + + /** + * compress inline code + * + */ + protected function doCompress() { + + if ($this->compressJavascript && $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler']) { + // use extern compress routine + $params = array( + 'jsInline' => $this->jsInline, + 'jsFooterInline' => $this->jsFooterInline, + ); + t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this); + } else { + // traverse the arrays, compress files + $this->compressError = ''; + + if ($this->compressJavascript) { + if (count($this->jsInline)) { + foreach ($this->jsInline as $name=>$properties) { + if (!$properties['compressed']) { + $error = ''; + $this->jsInline[$name]['code'] = t3lib_div::minifyJavaScript($properties['code'], $error); + if ($error) { + $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error.chr(10); + } + } + } + } + if (count($this->jsFooterInline)) { + foreach ($this->jsFooterInline as $name=>$properties) { + if (!$properties['compressed']) { + $error = ''; + $this->jsFooterInline[$name]['code'] = t3lib_div::minifyJavaScript($properties['code'], $error); + if ($error) { + $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error.chr(10); + } + } + } + } + } + } + + + if ($this->compressJavascript && $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler']) { + // use extern compress routine + $params = array( + 'cssInline' => $this->cssInline, + ); + t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this); + } else { + if ($this->compressCss) { + // need real compressor script first + } + } + + } + + +} + + +if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pageincludes.php']) { + include_once ($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pageincludes.php']); +} +?> Index: t3lib/core_autoload.php =================================================================== --- t3lib/core_autoload.php (revision 5734) +++ t3lib/core_autoload.php (working copy) @@ -38,6 +38,7 @@ 't3lib_lock' => PATH_t3lib . 'class.t3lib_lock.php', 't3lib_matchcondition' => PATH_t3lib . 'class.t3lib_matchcondition.php', 't3lib_modsettings' => PATH_t3lib . 'class.t3lib_modsettings.php', + 't3lib_pageincludes' => PATH_t3lib . 'class.t3lib_pageincludes.php', 't3lib_pageselect' => PATH_t3lib . 'class.t3lib_page.php', 't3lib_pagetree' => PATH_t3lib . 'class.t3lib_pagetree.php', 't3lib_parsehtml' => PATH_t3lib . 'class.t3lib_parsehtml.php', Index: typo3/sysext/cms/tslib/class.tslib_fe.php =================================================================== --- typo3/sysext/cms/tslib/class.tslib_fe.php (revision 5734) +++ typo3/sysext/cms/tslib/class.tslib_fe.php (working copy) @@ -405,6 +405,8 @@ protected $pageCache; protected $pageCacheTags = array(); + // class for render the header / footer + var $pageIncludes; /** * Class constructor @@ -448,6 +450,7 @@ $this->csConvObj = t3lib_div::makeInstance('t3lib_cs'); + // Call post processing function for constructor: if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'])) { $_params = array('pObj' => &$this); @@ -2041,7 +2044,17 @@ $this->config['FEData'] = $this->tmpl->setup['FEData']; $this->config['FEData.'] = $this->tmpl->setup['FEData.']; + + // class for render Header and Footer parts + $template = ''; + if ($this->pSetup['pageHeaderFooterTemplateFile']) { + $file = $this->tmpl->getFileName($this->pSetup['pageHeaderFooterTemplateFile']); + if ($file) { + $template = $file; } + } + $this->pageIncludes = t3lib_div::makeInstance('t3lib_pageIncludes', $template, 'typo3/'); + } $GLOBALS['TT']->pull(); } else { if ($this->checkPageUnavailableHandler()) { Index: typo3/sysext/cms/tslib/class.tslib_pagegen.php =================================================================== --- typo3/sysext/cms/tslib/class.tslib_pagegen.php (revision 5734) +++ typo3/sysext/cms/tslib/class.tslib_pagegen.php (working copy) @@ -93,6 +93,8 @@ * @return void */ public static function pagegenInit() { + + if ($GLOBALS['TSFE']->page['content_from_pid']>0) { $temp_copy_TSFE = clone($GLOBALS['TSFE']); // make REAL copy of TSFE object - not reference! $temp_copy_TSFE->id = $GLOBALS['TSFE']->page['content_from_pid']; // Set ->id to the content_from_pid value - we are going to evaluate this pid as was it a given id for a page-display! @@ -342,10 +344,15 @@ * @return void */ public static function renderContentWithHeader($pageContent) { + + if ($GLOBALS['TSFE']->config['config']['moveJsFromHeaderToFooter']) { + $GLOBALS['TSFE']->pageIncludes->moveJsFromHeaderToFooter = TRUE; + } + $customContent = $GLOBALS['TSFE']->config['config']['headerComment']; if (trim($customContent)) { - $customContent = chr(10).$customContent; - } else $customContent=''; + $GLOBALS['TSFE']->pageIncludes->addInlineComment($customContent); + } // Setting charset: $theCharset = $GLOBALS['TSFE']->metaCharset; @@ -437,7 +444,9 @@ } // Adding doctype parts: - $GLOBALS['TSFE']->content.= count($docTypeParts) ? implode(chr(10),$docTypeParts).chr(10) : ''; + if (count($docTypeParts)) { + $GLOBALS['TSFE']->pageIncludes->setXmlPrologAndDocType(implode(chr(10),$docTypeParts)); + } // Begin header section: if (strcmp($GLOBALS['TSFE']->config['config']['htmlTag_setParams'],'none')) { @@ -445,30 +454,24 @@ } else { $_attr = ''; } - $GLOBALS['TSFE']->content.=''; + $GLOBALS['TSFE']->pageIncludes->setHtmlTag(''); + // Head tag: $headTag = $GLOBALS['TSFE']->pSetup['headTag'] ? $GLOBALS['TSFE']->pSetup['headTag'] : ''; - $GLOBALS['TSFE']->content.= chr(10).$headTag; + $GLOBALS['TSFE']->pageIncludes->setHeadTag($headTag); // Setting charset meta tag: - $GLOBALS['TSFE']->content.=' - '; - - $GLOBALS['TSFE']->content.=' - - -'; - - + $GLOBALS['TSFE']->pageIncludes->setMetaCharsetTag($theCharset); + + $GLOBALS['TSFE']->pageIncludes->addInlineComment('This website is powered by TYPO3 - inspiring people to share! +TYPO3 is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL. +TYPO3 is copyright 1998-2009 of Kasper Skaarhoj. Extensions are copyright of their respective owners. +Information and contribution at http://typo3.com/ and http://typo3.org/'); + + if ($GLOBALS['TSFE']->baseUrl) { - $GLOBALS['TSFE']->content.=' - '; + $GLOBALS['TSFE']->pageIncludes->setBaseUrlTag($GLOBALS['TSFE']->baseUrl); } if ($GLOBALS['TSFE']->pSetup['shortcutIcon']) { @@ -480,12 +483,11 @@ finfo_close($finfo); } } + $GLOBALS['TSFE']->pageIncludes->setShortcutTag($favIcon, $iconMimeType); + } - $GLOBALS['TSFE']->content.= ' - - '; - } - + + // Including CSS files if (is_array($GLOBALS['TSFE']->tmpl->setup['plugin.'])) { $temp_styleLines=array(); @@ -496,16 +498,9 @@ } if (count($temp_styleLines)) { if ($GLOBALS['TSFE']->config['config']['inlineStyle2TempFile']) { - $GLOBALS['TSFE']->content.=TSpagegen::inline2TempFile(implode(chr(10),$temp_styleLines),'css'); + $GLOBALS['TSFE']->pageIncludes->addCssFile(TSpagegen::inline2TempFile(implode(chr(10), $temp_styleLines), 'css')); } else { - $GLOBALS['TSFE']->content.=' - '; + $GLOBALS['TSFE']->pageIncludes->addCssInlineBlock('inlineStyle2TempFile', implode(chr(10),$temp_styleLines)); } } } @@ -513,8 +508,7 @@ if ($GLOBALS['TSFE']->pSetup['stylesheet']) { $ss = $GLOBALS['TSFE']->tmpl->getFileName($GLOBALS['TSFE']->pSetup['stylesheet']); if ($ss) { - $GLOBALS['TSFE']->content.=' - '; + $GLOBALS['TSFE']->pageIncludes->addCssFile($ss); } } if (is_array($GLOBALS['TSFE']->pSetup['includeCSS.'])) { @@ -522,23 +516,22 @@ if (!is_array($iCSSfile)) { $ss=$GLOBALS['TSFE']->tmpl->getFileName($iCSSfile); if ($ss) { - if ($GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['import']) { + if ($GLOBALS['TSFE']->pSetup['includeCSS.'][$key . '.']['import']) { if (substr($ss,0,1)!='/') { // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende) $ss = t3lib_div::dirname(t3lib_div::getIndpEnv('SCRIPT_NAME')).'/'.$ss; } - $GLOBALS['TSFE']->content.=' - - '; + $GLOBALS['TSFE']->pageIncludes->addCssInlineBlock('import_' . $key, + '@import url("' . htmlspecialchars($ss) . '") ' . htmlspecialchars($GLOBALS['TSFE']->pSetup['includeCSS.'][$key . '.']['media']) . ';', + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['compressed'] ? TRUE : FALSE, + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['forceOnTop'] ? TRUE : FALSE); } else { - $GLOBALS['TSFE']->content.=' - pSetup['includeCSS.'][$key.'.']['title'] ? ' title="'.htmlspecialchars($GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['title']).'"' : ''). - ($GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['media'] ? ' media="'.htmlspecialchars($GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['media']).'"' : ''). - ' />'; + $GLOBALS['TSFE']->pageIncludes->addCssFile(htmlspecialchars($ss), + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['alternate'] ? 'alternate stylesheet' : 'stylesheet', + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['media'] ? $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['media'] : 'screen', + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['title'] ? $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['title'] : '', + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['compressed'] ? TRUE : FALSE, + $GLOBALS['TSFE']->pSetup['includeCSS.'][$key.'.']['forceOnTop'] ? TRUE : FALSE); + } } } @@ -547,8 +540,6 @@ // Stylesheets $style=''; - $style.=trim($GLOBALS['TSFE']->pSetup['CSS_inlineStyle']).chr(10); - if ($GLOBALS['TSFE']->pSetup['insertClassesFromRTE']) { $pageTSConfig = $GLOBALS['TSFE']->getPagesTSconfig(); $RTEclasses = $pageTSConfig['RTE.']['classes.']; @@ -617,46 +608,108 @@ TABLE.typo3-editPanel TD { border: 0px; } '; } - + // CSS_inlineStyle from TS + $style .= trim($GLOBALS['TSFE']->pSetup['CSS_inlineStyle']); + $style .= $GLOBALS['TSFE']->cObj->cObjGet($GLOBALS['TSFE']->pSetup['cssInline.'], 'cssInline.'); + if (trim($style)) { if ($GLOBALS['TSFE']->config['config']['inlineStyle2TempFile']) { - $GLOBALS['TSFE']->content.=TSpagegen::inline2TempFile($style, 'css'); + $GLOBALS['TSFE']->pageIncludes->addCssFile(TSpagegen::inline2TempFile($style, 'css')); } else { - $GLOBALS['TSFE']->content.=' - '; + $GLOBALS['TSFE']->pageIncludes->addCssInlineBlock('additionalInlineStyle2TempFile', $style); } } + + + // Javascript Libraries + if (is_array($GLOBALS['TSFE']->pSetup['javascriptLibs.'])) { + if ($GLOBALS['TSFE']->pSetup['javascriptLibs.']['Prototype']) { + $GLOBALS['TSFE']->pageIncludes->loadPrototype(); + } + if ($GLOBALS['TSFE']->pSetup['javascriptLibs.']['Scriptaculous']) { + $modules = $GLOBALS['TSFE']->pSetup['javascriptLibs.']['Scriptaculous.']['modules'] ? $GLOBALS['TSFE']->pSetup['javascriptLibs.']['Scriptaculous.']['modules'] : ''; + $GLOBALS['TSFE']->pageIncludes->loadScriptaculous($modules); + } + if ($GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtCore']) { + $GLOBALS['TSFE']->pageIncludes->loadExtCore(); + if ($GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtCore.']['debug']) { + $GLOBALS['TSFE']->pageIncludes->enableExtCoreDebug(); + } + } + if ($GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs']) { + $css = $GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs.']['css'] ? TRUE : FALSE; + $theme = $GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs.']['theme'] ? TRUE : FALSE; + $adapter = $GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs.']['adapter'] ? $GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs.']['adapter'] : ''; + $GLOBALS['TSFE']->pageIncludes->loadExtJs($css, $theme, $adapter); + if ($GLOBALS['TSFE']->pSetup['javascriptLibs.']['ExtJs.']['debug']) { + $GLOBALS['TSFE']->pageIncludes->enableExtJsDebug(); + } + } + } + + // JavaScript library files + if (is_array($GLOBALS['TSFE']->pSetup['includeJSlibs.'])) { + foreach ($GLOBALS['TSFE']->pSetup['includeJSlibs.'] as $key => $JSfile) { + $ss = $GLOBALS['TSFE']->tmpl->getFileName($JSfile); + if ($ss) { + $type = $GLOBALS['TSFE']->pSetup['includeJSlibs.'][$key.'.']['type']; + if (!$type) { + $type = 'text/javascript'; + } + $section = $GLOBALS['TSFE']->pSetup['includeJSlibs.'][$key.'.']['footer'] ? t3lib_pageIncludes::PART_FOOTER : t3lib_pageIncludes::PART_HEADER; + $GLOBALS['TSFE']->pageIncludes->addJsLibrary( + htmlspecialchars($key), + htmlspecialchars($GLOBALS['TSFE']->absRefPrefix . $ss), + $type, + $section, + $GLOBALS['TSFE']->pSetup['includeJSlibs.'][$key.'.']['compressed'] ? TRUE : FALSE, + $GLOBALS['TSFE']->pSetup['includeJSlibs.'][$key.'.']['forceOnTop'] ? TRUE : FALSE + ); + } + + } + } + // JavaScript files - if (is_array($GLOBALS['TSFE']->pSetup['includeJS.'])) { - foreach ($GLOBALS['TSFE']->pSetup['includeJS.'] as $key=>$JSfile) { + if (is_array($GLOBALS['TSFE']->pSetup['includeJS.'])) { + foreach ($GLOBALS['TSFE']->pSetup['includeJS.'] as $key => $JSfile) { if (!is_array($JSfile)) { $ss = $GLOBALS['TSFE']->tmpl->getFileName($JSfile); - if ($ss) { + if ($ss) { $type = $GLOBALS['TSFE']->pSetup['includeJS.'][$key.'.']['type']; - if (!$type) $type = 'text/javascript'; - - $GLOBALS['TSFE']->content.=' - '; + if (!$type) { + $type = 'text/javascript'; + } + if (!$GLOBALS['TSFE']->pSetup['includeJS.'][$key.'.']['footer']) { + $GLOBALS['TSFE']->pageIncludes->addJsFile( + htmlspecialchars($GLOBALS['TSFE']->absRefPrefix . $ss), + htmlspecialchars($type), + $GLOBALS['TSFE']->pSetup['includeJS.'][$key.'.']['compressed'] ? TRUE : FALSE, + $GLOBALS['TSFE']->pSetup['includeJS.'][$key.'.']['forceOnTop'] ? TRUE : FALSE + ); + } else { + $GLOBALS['TSFE']->pageIncludes->addJsFooterFile( + htmlspecialchars($GLOBALS['TSFE']->absRefPrefix . $ss), + htmlspecialchars($type), + $GLOBALS['TSFE']->pSetup['includeJS.'][$key.'.']['compressed'] ? TRUE : FALSE, + $GLOBALS['TSFE']->pSetup['includeJS.'][$key.'.']['forceOnTop'] ? TRUE : FALSE + ); + } } } } } + + + - - - - // Headerdata if (is_array($GLOBALS['TSFE']->pSetup['headerData.'])) { - $GLOBALS['TSFE']->content.= chr(10).$GLOBALS['TSFE']->cObj->cObjGet($GLOBALS['TSFE']->pSetup['headerData.'],'headerData.'); + $GLOBALS['TSFE']->pageIncludes->addHeaderData($GLOBALS['TSFE']->cObj->cObjGet($GLOBALS['TSFE']->pSetup['headerData.'], 'headerData.')); } + // Title $titleTagContent = $GLOBALS['TSFE']->tmpl->printTitle( $GLOBALS['TSFE']->altPageTitle?$GLOBALS['TSFE']->altPageTitle:$GLOBALS['TSFE']->page['title'], @@ -668,11 +721,10 @@ } if (strlen($titleTagContent) && intval($GLOBALS['TSFE']->config['config']['noPageTitle'])!==2) { - $GLOBALS['TSFE']->content.=' - '.htmlspecialchars($titleTagContent).''; + $GLOBALS['TSFE']->pageIncludes->setTitle($titleTagContent); } - $GLOBALS['TSFE']->content.=' - '; + + $GLOBALS['TSFE']->pageIncludes->addMetaData(''); $conf=$GLOBALS['TSFE']->pSetup['meta.']; if (is_array($conf)) { @@ -687,8 +739,7 @@ if (trim($val)) { $a='name'; if (strtolower($key)=='refresh') {$a='http-equiv';} - $GLOBALS['TSFE']->content.= ' - '; + $GLOBALS['TSFE']->pageIncludes->addMetaData(''); } } } @@ -697,6 +748,7 @@ unset($GLOBALS['TSFE']->additionalHeaderData['JSCode']); unset($GLOBALS['TSFE']->additionalHeaderData['JSImgCode']); + if (is_array($GLOBALS['TSFE']->config['INTincScript'])) { // Storing the JSCode and JSImgCode vars... $GLOBALS['TSFE']->additionalHeaderData['JSCode'] = $GLOBALS['TSFE']->JSCode; @@ -714,7 +766,7 @@ $JSef = TSpagegen::JSeventFunctions(); // Adding default Java Script: - $_scriptCode = ' + $scriptJsCode = ' var browserName = navigator.appName; var browserVer = parseInt(navigator.appVersion); var version = ""; @@ -727,7 +779,7 @@ ' . $JSef[0]; if ($GLOBALS['TSFE']->spamProtectEmailAddresses && $GLOBALS['TSFE']->spamProtectEmailAddresses !== 'ascii') { - $_scriptCode.= ' + $scriptJsCode.= ' // decrypt helper function function decryptCharcode(n,start,end,offset) { n = n + offset; @@ -764,59 +816,101 @@ } //add inline JS - $_inlineJS = ''; - // defined in TS with page.inlineJS - if (is_array($GLOBALS['TSFE']->pSetup['inlineJS.'])) { - $GLOBALS['TSFE']->inlineJS[]= $GLOBALS['TSFE']->cObj->cObjGet($GLOBALS['TSFE']->pSetup['inlineJS.'],'inlineJS.'); - } + $inlineJS = ''; + + // defined in php if(is_array($GLOBALS['TSFE']->inlineJS)) { foreach($GLOBALS['TSFE']->inlineJS as $key=>$val) { if(!is_array($val)) { - $_inlineJS .= chr(10).$val.chr(10); + $inlineJS .= chr(10).$val.chr(10); } } } + // defined in TS with page.inlineJS + // Javascript inline code + $inline = $GLOBALS['TSFE']->cObj->cObjGet($GLOBALS['TSFE']->pSetup['jsInline.'], 'jsInline.'); + if ($inline) { + $inlineJS .= chr(10) . $inline . chr(10); + } + + // Javascript inline code for Footer + $inlineFooterJs = $GLOBALS['TSFE']->cObj->cObjGet($GLOBALS['TSFE']->pSetup['jsFooterInline.'], 'jsFooterInline.'); + + // Should minify? if ($GLOBALS['TSFE']->config['config']['minifyJS']) { + $GLOBALS['TSFE']->pageIncludes->compressJavascript = TRUE; $minifyErrorScript = $minifyErrorInline = ''; - $_scriptCode = t3lib_div::minifyJavaScript($_scriptCode,$minifyErrorScript); + $scriptJsCode = t3lib_div::minifyJavaScript($scriptJsCode, $minifyErrorScript); if ($minifyErrorScript) { $GLOBALS['TT']->setTSlogMessage($minifyErrorScript, 3); } - if ($_inlineJS) { - $_inlineJS = t3lib_div::minifyJavaScript($_inlineJS,$minifyErrorInline); + if ($inlineJS) { + $inlineJS = t3lib_div::minifyJavaScript($inlineJS, $minifyErrorInline); if ($minifyErrorInline) { $GLOBALS['TT']->setTSlogMessage($minifyErrorInline, 3); } } + if ($inlineFooterJs) { + $inlineFooterJs = t3lib_div::minifyJavaScript($inlineFooterJs, $minifyErrorInline); + if ($minifyErrorInline) { + $GLOBALS['TT']->setTSlogMessage($minifyErrorInline, 3); + } + } + } + if (!$GLOBALS['TSFE']->config['config']['removeDefaultJS']) { // inlude default and inlineJS - $GLOBALS['TSFE']->content.=' - '; + if ($scriptJsCode) { + $GLOBALS['TSFE']->pageIncludes->addJsInlineCode('_scriptCode', $scriptJsCode, $GLOBALS['TSFE']->config['config']['minifyJS']); + } + if ($inlineJS) { + $GLOBALS['TSFE']->pageIncludes->addJsInlineCode('TS_inlineJS', $inlineJS, $GLOBALS['TSFE']->config['config']['minifyJS']); + } + if ($inlineFooterJs) { + $GLOBALS['TSFE']->pageIncludes->addJsFooterInlineCode('TS_inlineFooter', $inlineJS, $GLOBALS['TSFE']->config['config']['minifyJS']); + } } elseif ($GLOBALS['TSFE']->config['config']['removeDefaultJS']==='external') { // put default and inlineJS in external file - $GLOBALS['TSFE']->content.= TSpagegen::inline2TempFile($_scriptCode.$_inlineJS, 'js'); - } elseif ($_inlineJS) { + $GLOBALS['TSFE']->pageIncludes->addJsFile(TSpagegen::inline2TempFile($scriptJsCode .$inlineJS, 'js'), 'text/javascript', $GLOBALS['TSFE']->config['config']['minifyJS']); + if ($inlineFooterJs) { + $GLOBALS['TSFE']->pageIncludes->addJsFooterFile(TSpagegen::inline2TempFile($inlineFooterJs, 'js'), 'text/javascript', $GLOBALS['TSFE']->config['config']['minifyJS']); + } + } else { // include only inlineJS - $GLOBALS['TSFE']->content.=' - '; + if ($inlineJS) { + $GLOBALS['TSFE']->pageIncludes->addJsInlineCode('TS_inlineJS', $inlineJS, $GLOBALS['TSFE']->config['config']['minifyJS']); + } + if ($inlineFooterJs) { + $GLOBALS['TSFE']->pageIncludes->addJsFooterInlineCode('TS_inlineFooter', $inlineJS, $GLOBALS['TSFE']->config['config']['minifyJS']); + } } - $GLOBALS['TSFE']->content.= chr(10).implode($GLOBALS['TSFE']->additionalHeaderData,chr(10)).' + + + if ($GLOBALS['TSFE']->config['config']['minifyCSS']) { + $GLOBALS['TSFE']->pageIncludes->compressCss = true; + } + if ($GLOBALS['TSFE']->config['config']['concatenateJSandCSS']) { + $GLOBALS['TSFE']->pageIncludes->concatenateFiles = true; + } + + // add header data block + $GLOBALS['TSFE']->pageIncludes->addHeaderData(implode(chr(10), $GLOBALS['TSFE']->additionalHeaderData)); + + + + // Header complete, render it + $GLOBALS['TSFE']->content = $GLOBALS['TSFE']->pageIncludes->render(); + + + + + $GLOBALS['TSFE']->content.= ' '; if ($GLOBALS['TSFE']->pSetup['frameSet.']) { $fs = t3lib_div::makeInstance('tslib_frameset'); @@ -859,6 +953,9 @@ // Page content $GLOBALS['TSFE']->content.= chr(10).$pageContent; + // Footer Javascript + $GLOBALS['TSFE']->content .= $GLOBALS['TSFE']->pageIncludes->render(1); + // Ending page $GLOBALS['TSFE']->content.= chr(10).''; if ($GLOBALS['TSFE']->pSetup['frameSet.']) { @@ -900,13 +997,11 @@ switch($ext) { case 'js': $script = 'typo3temp/javascript_'.substr(md5($str),0,10).'.js'; - $output = ' - '; + $output = $GLOBALS['TSFE']->absRefPrefix.$script; break; case 'css': $script = 'typo3temp/stylesheet_'.substr(md5($str),0,10).'.css'; - $output = ' - '; + $output = $GLOBALS['TSFE']->absRefPrefix.$script; break; } Index: typo3/template.php =================================================================== --- typo3/template.php (revision 5734) +++ typo3/template.php (working copy) @@ -204,23 +204,14 @@ var $sectionFlag=0; // Internal: Indicates if a
-output section is open var $divClass = ''; // (Default) Class for wrapping
-tag of page. Is set in class extensions. - // internal flags for JS-libraries - protected $addPrototype = false; - protected $addScriptaculousModules = array( - 'builder' => false, - 'effects' => false, - 'dragdrop' => false, - 'controls' => false, - 'slider' => false - ); - protected $addExtJS = false; - protected $extJSadapter = 'ext/ext-base.js'; - protected $enableExtJsDebug = false; + var $pageHeaderBlock = ''; + var $endOfPageJsBlock = ''; - // available adapters for extJs - const EXTJS_ADAPTER_JQUERY = 'jquery'; - const EXTJS_ADAPTER_PROTOTYPE = 'prototype'; - const EXTJS_ADAPTER_YUI = 'yui'; + var $hasDocheader = true; + + // class for render the header / footer + var $pageIncludes; + var $pageHeaderFooterTemplateFile = ''; // alternative template file /** @@ -269,6 +260,8 @@ // Background image if ($TBE_STYLES['background']) $this->backGroundImage = $TBE_STYLES['background']; + + $this->pageIncludes = t3lib_div::makeInstance('t3lib_pageIncludes'); } @@ -631,18 +624,23 @@ } } - // Get META tag containing the currently selected charset for backend output. The function sets $this->charSet. - $charSet = $this->initCharset(); - $generator = $this->generator(); - + // alternative template for Header and Footer + if ($this->pageHeaderFooterTemplateFile) { + $file = t3lib_div::getFileAbsFileName($this->pageHeaderFooterTemplateFile, TRUE); + if ($file) { + $this->pageIncludes->setAlternativeTemplateFile($file); + } + } // For debugging: If this outputs "QuirksMode"/"BackCompat" (IE) the browser runs in quirks-mode. Otherwise the value is "CSS1Compat" # $this->JScodeArray[]='alert(document.compatMode);'; // Send HTTP header for selected charset. Added by Robert Lemke 23.10.2003 + $this->initCharset(); header ('Content-Type:text/html;charset='.$this->charset); - + $this->pageIncludes->backPath = $this->backPath; + // Standard HTML tag - $htmlTag = ''; + $this->pageIncludes->setHtmlTag(''); switch($this->docType) { case 'html_3': @@ -697,27 +695,39 @@ $headerStart = $headerStart . chr(10) . $xmlStylesheet; } } + + $this->pageIncludes->setXmlPrologAndDocType($headerStart); + $this->pageIncludes->setHeadTag('' . chr(10). ''); + $this->pageIncludes->setMetaCharsetTag($this->charset); + $this->pageIncludes->addMetaData($this->generator()); + $this->pageIncludes->setTitle($title); + + // add docstyles + $this->docStyle(); + + + // add jsCode - has to go to headerData as it may contain the script tags already + $this->pageIncludes->addHeaderData($this->JScode); + + foreach ($this->JScodeArray as $name => $code) { + $this->pageIncludes->addJsInlineCode($name, $code); + } + + if ($this->extJScode) { + $this->pageIncludes->addJsHandlerCode($this->extJScode, t3lib_pageIncludes::JSHANDLER_EXTONREADY); + } // Construct page header. - $str = $headerStart . chr(10) . $htmlTag . ' - - - '.$charSet.' - '.$generator.' - '.htmlspecialchars($title).' - '.$this->docStyle().' - ' . $this->renderJSlibraries() . ' - '.$this->JScode.' - '.$this->wrapScriptTags(implode("\n", $this->JScodeArray)). - ($this->extJScode ? $this->wrapScriptTags('Ext.onReady(function() {' . chr(10) . $this->extJScode . chr(10) . '});') : '') . - ' - + $str = $this->pageIncludes->render(); + $str .= ' '; $this->JScodeLibArray = array(); $this->JScode = $this->extJScode = ''; $this->JScodeArray = array(); + $this->endOfPageJsBlock = $this->pageIncludes->render(1); + if ($this->docType=='xhtml_frames') { return $str; } else @@ -750,7 +760,7 @@ $str .= ($this->divClass?' -
':'').' +
':'') . $this->endOfPageJsBlock . ' '; } @@ -956,28 +966,20 @@ $this->inDocStylesArray[] = $this->inDocStyles_TBEstyle; // Implode it all: - $inDocStyles = implode(' - ',$this->inDocStylesArray); + $inDocStyles = implode(chr(10), $this->inDocStylesArray); - // The default color scheme should also in full be represented in the stylesheet. - $style=trim(' - '.($this->styleSheetFile?'':'').' - '.($this->styleSheetFile2?'':'').' - - '.($this->styleSheetFile_post?'':'').' - '.implode("\n", $this->additionalStyleSheets) - ) - ; - $this->inDocStyles=''; - $this->inDocStylesArray=array(); + if ($this->styleSheetFile) { + $this->pageIncludes->addCssFile($this->backPath . $this->styleSheetFile); + } + if ($this->styleSheetFile2) { + $this->pageIncludes->addCssFile($this->backPath . $this->styleSheetFile2); + } - return ' - '.$style; + $this->pageIncludes->addCssInlineBlock('inDocStyles', $inDocStyles . chr(10) . '/*###POSTCSSMARKER###*/'); + if ($this->styleSheetFile_post) { + $this->pageIncludes->addCssFile($this->backPath . $this->styleSheetFile_post); + } + } /** @@ -990,9 +992,7 @@ * @return void */ function addStyleSheet($key, $href, $title='', $relation='stylesheet') { - if (!isset($this->additionalStyleSheets[$key])) { - $this->additionalStyleSheets[$key] = ''; - } + $this->pageIncludes->addCssFile($this->backPath . $href, $relation, $title); } /** @@ -1319,26 +1319,10 @@ * @return void */ function loadJavascriptLib($lib) { - if (!isset($this->JScodeLibArray[$lib])) { - $this->JScodeLibArray[$lib] = ''; - } + $this->pageIncludes->addJsFile($this->backPath . $lib); } - /** - * - * @param string $lib it will remove lib from general JScodeLibArray because lib is loaded already. - */ - protected function removeJavascriptLib($lib) { - if (count($this->JScodeLibArray)) { - $scripts = array_keys($this->JScodeLibArray); - foreach ($scripts as $script) { - if (strpos($script, '/' . $lib . '/') !== false) { - unset ($this->JScodeLibArray[$script]); - } - } - } - } /** * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document @@ -1996,85 +1980,10 @@ /** - * Following functions are help function for JS library include. - * They enable loading the libraries prototype, scriptaculous and extJS from contrib-directory - */ - - - /** - * Function for render the JS-libraries in header - * Load order is prototype / scriptaculous / extJS - */ - protected function renderJSlibraries() { - $libs = array(); - - // include prototype - if ($this->addPrototype) { - $libs[] = 'contrib/prototype/prototype.js'; - // remove prototype from JScodeLibArray - $this->removeJavascriptLib('prototype'); - } - - // include scriptaculous - if ($this->addScriptaculous) { - $mods = array(); - foreach ($this->addScriptaculousModules as $key => $value) { - if ($this->addScriptaculousModules[$key]) { - $mods[] = $key; - } - } - // resolve dependencies - if (in_array('dragdrop', $mods) || in_array('controls', $mods)) { - $mods = array_merge(array('effects'), $mods); - } - - if (count($mods)) { - $moduleLoadString = '?load=' . implode(',', $mods); - } - $libs[] = 'contrib/scriptaculous/scriptaculous.js' . $moduleLoadString; - // remove scriptaculous from JScodeLibArray - $this->removeJavascriptLib('scriptaculous'); - } - - // include extJS - if ($this->addExtJS) { - // use the base adapter all the time - $libs[] = 'contrib/extjs/adapter/' . ($this->enableExtJsDebug ? str_replace('.js', '-debug.js', $this->extJSadapter) : $this->extJSadapter); - $libs[] = 'contrib/extjs/ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js'; - - // add extJS localization - $localeMap = $GLOBAL['LANG']->csConvObj->isoArray; // load standard ISO mapping and modify for use with ExtJS - $localeMap[''] = 'en'; - $localeMap['default'] = 'en'; - $localeMap['gr'] = 'el_GR'; // Greek - $localeMap['no'] = 'no_BO'; // Norwegian Bokmaal - $localeMap['se'] = 'se_SV'; // Swedish - $extJsLang = isset($localeMap[$GLOBALS['BE_USER']->uc['lang']]) ? $localeMap[$GLOBALS['BE_USER']->uc['lang']] : $GLOBALS['BE_USER']->uc['lang']; - // TODO autoconvert file from UTF8 to current BE charset if necessary!!!! - $extJsLocaleFile = 'contrib/extjs/locale/ext-lang-' . $extJsLang . '-min.js'; - if (file_exists(PATH_typo3 . $extJsLocaleFile)) { - $libs[] = $extJsLocaleFile; - } - // set clear.gif - $this->extJScode .= 'Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(t3lib_div::locationHeaderUrl('gfx/clear.gif')) . '";'; - // remove extjs from JScodeLibArray - $this->removeJavascriptLib('contrib/extjs'); - } - - foreach ($libs as &$lib) { - $lib = ''; - } - - // add other JavascriptLibs and return it - $libs = array_merge($libs, $this->JScodeLibArray); - return count($libs) ? chr(10) . chr(10) . implode(chr(10), $libs) . chr(10) . chr(10) : ''; - } - - /** * call function if you need the prototype library */ public function loadPrototype() { - $this->addPrototype = true; + $this->pageIncludes->loadPrototype(); } /** @@ -2082,23 +1991,7 @@ * @param string $modules add modules you need. use "all" if you need complete modules */ public function loadScriptaculous($modules='') { - // Scriptaculous require prototype, so load prototype too. - $this->addPrototype = true; - $this->addScriptaculous = true; - if ($modules) { - if ($modules == 'all') { - foreach ($this->addScriptaculousModules as $key => $value) { - $this->addScriptaculousModules[$key] = true; - } - } else { - $mods = t3lib_div::trimExplode(',', $modules); - foreach ($mods as $mod) { - if (isset($this->addScriptaculousModules[strtolower($mod)])) { - $this->addScriptaculousModules[strtolower($mod)] = true; - } - } - } - } + $this->pageIncludes->loadScriptaculous($modules); } /** @@ -2108,46 +2001,32 @@ * @param string $adapter choose alternative adapter, possible values: yui, prototype, jquery */ public function loadExtJS($css = true, $theme = true, $adapter = '') { - if ($adapter) { - // empty $adapter will always load the ext adapter - switch (t3lib_div::strtolower(trim($adapter))) { - case template::EXTJS_ADAPTER_YUI: - $this->extJSadapter = 'yui/ext-yui-adapter.js'; - break; - case template::EXTJS_ADAPTER_PROTOTYPE: - $this->extJSadapter = 'prototype/ext-prototype-adapter.js'; - break; - case template::EXTJS_ADAPTER_JQUERY: - $this->extJSadapter = 'jquery/ext-jquery-adapter.js'; - break; - } - } - if (!$this->addExtJS) { - $this->addExtJS = true; - if ($css) { - if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) { - $this->addStyleSheet('ext-all', $this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all']); - } else { - $this->addStyleSheet('ext-all', $this->backPath . 'contrib/extjs/resources/css/ext-all-notheme.css'); - } - } - if ($theme) { - if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) { - $this->addStyleSheet('ext-theme', $this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme']); - } else { - $this->addStyleSheet('ext-theme', $this->backPath . 'contrib/extjs/resources/css/xtheme-blue.css'); - } - } - } + $this->pageIncludes->backPath = $this->backPath; + $this->pageIncludes->loadExtJs($css, $theme, $adapter); } /** * call this function to load debug version of extJS. Use this for development only */ public function enableExtJsDebug() { - $this->enableExtJsDebug = true; + $this->pageIncludes->enableExtJsDebug(); } + /** + * call function if you need the ExtCore library + * + */ + public function loadExtCore() { + $this->pageIncludes->loadExtCore(); + } + + /** + * call this function to load debug version of ExtCore. Use this for development only + * + */ + public function enableExtCoreDebug() { + $this->pageIncludes->enableExtCoreDebug(); + } } Index: typo3/templates/pageincludes.html =================================================================== --- typo3/templates/pageincludes.html (revision 0) +++ typo3/templates/pageincludes.html (revision 0) @@ -0,0 +1,30 @@ + +###XMLPROLOG_DOCTYPE### +###HTMLTAG### +###HEADTAG### + +###METACHARSET### +###INLINECOMMENT### + +###BASEURL### +###SHORTCUT### + +###CSS_INCLUDE### +###CSS_INLINE### + +###JS_INCLUDE### +###JS_INLINE### + + +###TITLE### +###META### + +###HEADERDATA### + + + + +###JS_INCLUDE_FOOTER### +###JS_INLINE_FOOTER### + +