/** * Parse the template file, add the TinyMCE configuration and print it to the screen * * @throws \Exception */ public function output() { // User agent class (see #3074 and #6277) $this->ua = \Environment::get('agent')->class; // Style sheets if (!empty($GLOBALS['TL_CSS']) && is_array($GLOBALS['TL_CSS'])) { $strStyleSheets = ''; foreach (array_unique($GLOBALS['TL_CSS']) as $stylesheet) { $options = \StringUtil::resolveFlaggedUrl($stylesheet); $strStyleSheets .= \Template::generateStyleTag($this->addStaticUrlTo($stylesheet), $options->media); } $this->stylesheets = $strStyleSheets; } // Add the debug style sheet if (\Config::get('debugMode')) { $this->stylesheets .= '<link rel="stylesheet" href="' . $this->addStaticUrlTo('assets/contao/css/debug.css') . '">' . "\n"; } // JavaScripts if (!empty($GLOBALS['TL_JAVASCRIPT']) && is_array($GLOBALS['TL_JAVASCRIPT'])) { $strJavaScripts = ''; foreach (array_unique($GLOBALS['TL_JAVASCRIPT']) as $javascript) { $options = \StringUtil::resolveFlaggedUrl($javascript); $strJavaScripts .= \Template::generateScriptTag($this->addStaticUrlTo($javascript), false, $options->async) . "\n"; } $this->javascripts = $strJavaScripts; } // MooTools scripts (added at the page bottom) if (!empty($GLOBALS['TL_MOOTOOLS']) && is_array($GLOBALS['TL_MOOTOOLS'])) { $strMootools = ''; foreach (array_unique($GLOBALS['TL_MOOTOOLS']) as $script) { $strMootools .= "\n" . trim($script) . "\n"; } $this->mootools = $strMootools; } $strBuffer = $this->parse(); // HOOK: add custom output filter if (isset($GLOBALS['TL_HOOKS']['outputBackendTemplate']) && is_array($GLOBALS['TL_HOOKS']['outputBackendTemplate'])) { foreach ($GLOBALS['TL_HOOKS']['outputBackendTemplate'] as $callback) { $this->import($callback[0]); $strBuffer = $this->{$callback[0]}->{$callback[1]}($strBuffer, $this->strTemplate); } } $this->strBuffer = $strBuffer; parent::output(); }
/** * Compile the template * * @internal */ protected function compile() { // User agent class (see #3074 and #6277) $this->ua = \Environment::get('agent')->class; // Style sheets if (!empty($GLOBALS['TL_CSS']) && is_array($GLOBALS['TL_CSS'])) { $strStyleSheets = ''; foreach (array_unique($GLOBALS['TL_CSS']) as $stylesheet) { $options = \StringUtil::resolveFlaggedUrl($stylesheet); $strStyleSheets .= \Template::generateStyleTag($this->addStaticUrlTo($stylesheet), $options->media); } $this->stylesheets = $strStyleSheets; } // JavaScripts if (!empty($GLOBALS['TL_JAVASCRIPT']) && is_array($GLOBALS['TL_JAVASCRIPT'])) { $strJavaScripts = ''; foreach (array_unique($GLOBALS['TL_JAVASCRIPT']) as $javascript) { $options = \StringUtil::resolveFlaggedUrl($javascript); $strJavaScripts .= \Template::generateScriptTag($this->addStaticUrlTo($javascript), $options->async) . "\n"; } $this->javascripts = $strJavaScripts; } // MooTools scripts (added at the page bottom) if (!empty($GLOBALS['TL_MOOTOOLS']) && is_array($GLOBALS['TL_MOOTOOLS'])) { $strMootools = ''; foreach (array_unique($GLOBALS['TL_MOOTOOLS']) as $script) { $strMootools .= "\n" . trim($script) . "\n"; } $this->mootools = $strMootools; } $strBuffer = $this->parse(); $strBuffer = static::replaceOldBePaths($strBuffer); // HOOK: add custom output filter if (isset($GLOBALS['TL_HOOKS']['outputBackendTemplate']) && is_array($GLOBALS['TL_HOOKS']['outputBackendTemplate'])) { foreach ($GLOBALS['TL_HOOKS']['outputBackendTemplate'] as $callback) { $this->import($callback[0]); $strBuffer = $this->{$callback}[0]->{$callback}[1]($strBuffer, $this->strTemplate); } } $this->strBuffer = $strBuffer; parent::compile(); }
/** * Create all header scripts * * @param \PageModel $objPage * @param \LayoutModel $objLayout */ protected function createHeaderScripts($objPage, $objLayout) { $strStyleSheets = ''; $strCcStyleSheets = ''; $arrStyleSheets = deserialize($objLayout->stylesheet); $blnXhtml = $objPage->outputFormat == 'xhtml'; $arrFramework = deserialize($objLayout->framework); // Google web fonts if ($objLayout->webfonts != '') { $strStyleSheets .= \Template::generateStyleTag('//fonts.googleapis.com/css?family=' . str_replace('|', '%7C', $objLayout->webfonts), 'all', $blnXhtml) . "\n"; } // Add the Contao CSS framework style sheets if (is_array($arrFramework)) { foreach ($arrFramework as $strFile) { if ($strFile != 'tinymce.css') { $GLOBALS['TL_FRAMEWORK_CSS'][] = 'assets/contao/css/' . $strFile; } } } // Add the TinyMCE style sheet if (is_array($arrFramework) && in_array('tinymce.css', $arrFramework) && file_exists(TL_ROOT . '/' . \Config::get('uploadPath') . '/tinymce.css')) { $GLOBALS['TL_FRAMEWORK_CSS'][] = \Config::get('uploadPath') . '/tinymce.css'; } // Make sure TL_USER_CSS is set if (!is_array($GLOBALS['TL_USER_CSS'])) { $GLOBALS['TL_USER_CSS'] = array(); } // User style sheets if (is_array($arrStyleSheets) && strlen($arrStyleSheets[0])) { $objStylesheets = \StyleSheetModel::findByIds($arrStyleSheets); if ($objStylesheets !== null) { while ($objStylesheets->next()) { $media = implode(',', deserialize($objStylesheets->media)); // Overwrite the media type with a custom media query if ($objStylesheets->mediaQuery != '') { $media = $objStylesheets->mediaQuery; } // Style sheets with a CC or a combination of font-face and media-type != all cannot be aggregated (see #5216) if ($objStylesheets->cc || $objStylesheets->hasFontFace && $media != 'all') { $strStyleSheet = ''; // External style sheet if ($objStylesheets->type == 'external') { $objFile = \FilesModel::findByPk($objStylesheets->singleSRC); if ($objFile !== null) { $strStyleSheet = \Template::generateStyleTag(TL_ASSETS_URL . $objFile->path, $media, $blnXhtml); } } else { $strStyleSheet = \Template::generateStyleTag(TL_ASSETS_URL . 'assets/css/' . $objStylesheets->name . '.css', $media, $blnXhtml); } if ($objStylesheets->cc) { $strStyleSheet = '<!--[' . $objStylesheets->cc . ']>' . $strStyleSheet . '<![endif]-->'; } $strCcStyleSheets .= $strStyleSheet . "\n"; } else { // External style sheet if ($objStylesheets->type == 'external') { $objFile = \FilesModel::findByPk($objStylesheets->singleSRC); if ($objFile !== null) { $GLOBALS['TL_USER_CSS'][] = $objFile->path . '|' . $media . '|static|' . filemtime(TL_ROOT . '/' . $objFile->path); } } else { $GLOBALS['TL_USER_CSS'][] = 'assets/css/' . $objStylesheets->name . '.css|' . $media . '|static|' . max($objStylesheets->tstamp, $objStylesheets->tstamp2, $objStylesheets->tstamp3); } } } } } $arrExternal = deserialize($objLayout->external); // External style sheets if (!empty($arrExternal) && is_array($arrExternal)) { // Consider the sorting order (see #5038) if ($objLayout->orderExt != '') { $tmp = deserialize($objLayout->orderExt); if (!empty($tmp) && is_array($tmp)) { // Remove all values $arrOrder = array_map(function () { }, array_flip($tmp)); // Move the matching elements to their position in $arrOrder foreach ($arrExternal as $k => $v) { if (array_key_exists($v, $arrOrder)) { $arrOrder[$v] = $v; unset($arrExternal[$k]); } } // Append the left-over style sheets at the end if (!empty($arrExternal)) { $arrOrder = array_merge($arrOrder, array_values($arrExternal)); } // Remove empty (unreplaced) entries $arrExternal = array_values(array_filter($arrOrder)); unset($arrOrder); } } // Get the file entries from the database $objFiles = \FilesModel::findMultipleByUuids($arrExternal); if ($objFiles !== null) { $arrFiles = array(); while ($objFiles->next()) { if (file_exists(TL_ROOT . '/' . $objFiles->path)) { $arrFiles[] = $objFiles->path . '|static'; } } // Inject the external style sheets before or after the internal ones (see #6937) if ($objLayout->loadingOrder == 'external_first') { array_splice($GLOBALS['TL_USER_CSS'], 0, 0, $arrFiles); } else { array_splice($GLOBALS['TL_USER_CSS'], count($GLOBALS['TL_USER_CSS']), 0, $arrFiles); } } } // Add a placeholder for dynamic style sheets (see #4203) $strStyleSheets .= '[[TL_CSS]]'; // Add the debug style sheet if (\Config::get('debugMode')) { $strStyleSheets .= \Template::generateStyleTag($this->addStaticUrlTo('assets/contao/css/debug.css'), 'all', $blnXhtml) . "\n"; } // Always add conditional style sheets at the end $strStyleSheets .= $strCcStyleSheets; $newsfeeds = deserialize($objLayout->newsfeeds); $calendarfeeds = deserialize($objLayout->calendarfeeds); // Add newsfeeds if (!empty($newsfeeds) && is_array($newsfeeds)) { $objFeeds = \NewsFeedModel::findByIds($newsfeeds); if ($objFeeds !== null) { while ($objFeeds->next()) { $strStyleSheets .= \Template::generateFeedTag(($objFeeds->feedBase ?: \Environment::get('base')) . 'share/' . $objFeeds->alias . '.xml', $objFeeds->format, $objFeeds->title, $blnXhtml) . "\n"; } } } // Add calendarfeeds if (!empty($calendarfeeds) && is_array($calendarfeeds)) { $objFeeds = \CalendarFeedModel::findByIds($calendarfeeds); if ($objFeeds !== null) { while ($objFeeds->next()) { $strStyleSheets .= \Template::generateFeedTag(($objFeeds->feedBase ?: \Environment::get('base')) . 'share/' . $objFeeds->alias . '.xml', $objFeeds->format, $objFeeds->title, $blnXhtml) . "\n"; } } } // Add a placeholder for dynamic <head> tags (see #4203) $strHeadTags = '[[TL_HEAD]]'; // Add the user <head> tags if (($strHead = trim($objLayout->head)) != false) { $strHeadTags .= $strHead . "\n"; } $this->Template->stylesheets = $strStyleSheets; $this->Template->head = $strHeadTags; }
/** * Replace the dynamic script tags (see #4203) * * @param string $strBuffer The string with the tags to be replaced * * @return string The string with the replaced tags */ public static function replaceDynamicScriptTags($strBuffer) { // HOOK: add custom logic if (isset($GLOBALS['TL_HOOKS']['replaceDynamicScriptTags']) && is_array($GLOBALS['TL_HOOKS']['replaceDynamicScriptTags'])) { foreach ($GLOBALS['TL_HOOKS']['replaceDynamicScriptTags'] as $callback) { $strBuffer = static::importStatic($callback[0])->{$callback[1]}($strBuffer); } } /** @var \PageModel $objPage */ global $objPage; $arrReplace = array(); $blnXhtml = $objPage->outputFormat == 'xhtml'; $strScripts = ''; // Add the internal jQuery scripts if (!empty($GLOBALS['TL_JQUERY']) && is_array($GLOBALS['TL_JQUERY'])) { foreach (array_unique($GLOBALS['TL_JQUERY']) as $script) { $strScripts .= "\n" . trim($script) . "\n"; } } $arrReplace['[[TL_JQUERY]]'] = $strScripts; $strScripts = ''; // Add the internal MooTools scripts if (!empty($GLOBALS['TL_MOOTOOLS']) && is_array($GLOBALS['TL_MOOTOOLS'])) { foreach (array_unique($GLOBALS['TL_MOOTOOLS']) as $script) { $strScripts .= "\n" . trim($script) . "\n"; } } $arrReplace['[[TL_MOOTOOLS]]'] = $strScripts; $strScripts = ''; // Add the internal <body> tags if (!empty($GLOBALS['TL_BODY']) && is_array($GLOBALS['TL_BODY'])) { foreach (array_unique($GLOBALS['TL_BODY']) as $script) { $strScripts .= trim($script) . "\n"; } } // Add the syntax highlighter scripts if (!empty($GLOBALS['TL_HIGHLIGHTER']) && is_array($GLOBALS['TL_HIGHLIGHTER'])) { $objCombiner = new \Combiner(); foreach (array_unique($GLOBALS['TL_HIGHLIGHTER']) as $script) { $objCombiner->add($script); } $strScripts .= "\n" . \Template::generateScriptTag($objCombiner->getCombinedFile(), $blnXhtml); $strScripts .= "\n" . \Template::generateInlineScript('SyntaxHighlighter.defaults.toolbar=false;SyntaxHighlighter.all()', $blnXhtml) . "\n"; } // Command scheduler if (!\Config::get('disableCron')) { $strScripts .= "\n" . \Template::generateInlineScript('setTimeout(function(){var e=function(e,t){try{var n=new XMLHttpRequest}catch(r){return}n.open("GET",e,!0),n.onreadystatechange=function(){this.readyState==4&&this.status==200&&typeof t=="function"&&t(this.responseText)},n.send()},t="system/cron/cron.";e(t+"txt",function(n){parseInt(n||0)<Math.round(+(new Date)/1e3)-' . \Frontend::getCronTimeout() . '&&e(t+"php")})},5e3);', $blnXhtml) . "\n"; } $arrReplace['[[TL_BODY]]'] = $strScripts; $strScripts = ''; $objCombiner = new \Combiner(); // Add the CSS framework style sheets if (!empty($GLOBALS['TL_FRAMEWORK_CSS']) && is_array($GLOBALS['TL_FRAMEWORK_CSS'])) { foreach (array_unique($GLOBALS['TL_FRAMEWORK_CSS']) as $stylesheet) { $objCombiner->add($stylesheet); } } // Add the internal style sheets if (!empty($GLOBALS['TL_CSS']) && is_array($GLOBALS['TL_CSS'])) { foreach (array_unique($GLOBALS['TL_CSS']) as $stylesheet) { $options = \StringUtil::resolveFlaggedUrl($stylesheet); if ($options->static) { if ($options->mtime === null) { $options->mtime = filemtime(TL_ROOT . '/' . $stylesheet); } $objCombiner->add($stylesheet, $options->mtime, $options->media); } else { $strScripts .= \Template::generateStyleTag(static::addStaticUrlTo($stylesheet), $options->media, $blnXhtml) . "\n"; } } } // Add the user style sheets if (!empty($GLOBALS['TL_USER_CSS']) && is_array($GLOBALS['TL_USER_CSS'])) { foreach (array_unique($GLOBALS['TL_USER_CSS']) as $stylesheet) { $options = \StringUtil::resolveFlaggedUrl($stylesheet); if ($options->static) { if ($options->mtime === null) { $options->mtime = filemtime(TL_ROOT . '/' . $stylesheet); } $objCombiner->add($stylesheet, $options->mtime, $options->media); } else { $strScripts .= \Template::generateStyleTag(static::addStaticUrlTo($stylesheet), $options->media, $blnXhtml) . "\n"; } } } // Create the aggregated style sheet if ($objCombiner->hasEntries()) { $strScripts .= \Template::generateStyleTag($objCombiner->getCombinedFile(), 'all', $blnXhtml) . "\n"; } $arrReplace['[[TL_CSS]]'] = $strScripts; $strScripts = ''; // Add the internal scripts if (!empty($GLOBALS['TL_JAVASCRIPT']) && is_array($GLOBALS['TL_JAVASCRIPT'])) { $objCombiner = new \Combiner(); $objCombinerAsync = new \Combiner(); foreach (array_unique($GLOBALS['TL_JAVASCRIPT']) as $javascript) { $options = \StringUtil::resolveFlaggedUrl($javascript); if ($options->static) { if ($options->mtime === null) { $options->mtime = filemtime(TL_ROOT . '/' . $javascript); } $options->async ? $objCombinerAsync->add($javascript, $options->mtime) : $objCombiner->add($javascript, $options->mtime); } else { $strScripts .= \Template::generateScriptTag(static::addStaticUrlTo($javascript), $blnXhtml, $options->async) . "\n"; } } // Create the aggregated script and add it before the non-static scripts (see #4890) if ($objCombiner->hasEntries()) { $strScripts = \Template::generateScriptTag($objCombiner->getCombinedFile(), $blnXhtml) . "\n" . $strScripts; } if ($objCombinerAsync->hasEntries()) { $strScripts = \Template::generateScriptTag($objCombinerAsync->getCombinedFile(), $blnXhtml, true) . "\n" . $strScripts; } } // Add the internal <head> tags if (!empty($GLOBALS['TL_HEAD']) && is_array($GLOBALS['TL_HEAD'])) { foreach (array_unique($GLOBALS['TL_HEAD']) as $head) { $strScripts .= trim($head) . "\n"; } } $arrReplace['[[TL_HEAD]]'] = $strScripts; return str_replace(array_keys($arrReplace), array_values($arrReplace), $strBuffer); }
public function generateCSS(\PageModel $objPage, \LayoutModel $objLayout, \PageRegular $objPageRegular) { $db = \Database::getInstance(); $lessFolder = 'assets/css'; $options = array('compress' => true, 'cache_dir' => TL_ROOT . '/' . $lessFolder); $objFiles = unserialize($objLayout->external_css); if (!$objFiles || !is_array($objFiles)) { return; } $objFiles = $db->query("SELECT * FROM tl_external_css WHERE id IN(" . implode(',', $objFiles) . ") ORDER BY sorting")->fetchAllAssoc(); $arrFiles = array(); if ($objFiles) { foreach ($objFiles as $file) { if ($file['type'] == 'url' && $file['url']) { $GLOBALS['TL_HEAD'][] = \Template::generateStyleTag($file['url'], '', false); } if ($file['type'] == 'file') { $obj = \FilesModel::findByUuid($file['file']); if ($obj) { $arrFiles[] = $obj->path; } else { if (is_file($file['file'])) { $arrFiles[] = $file['file']; } } } } } if (isset($GLOBALS['TL_HOOKS']['addExternalCssFiles']) && is_array($GLOBALS['TL_HOOKS']['addExternalCssFiles'])) { foreach ($GLOBALS['TL_HOOKS']['addExternalCssFiles'] as $callback) { $this->import($callback[0]); $arrFiles = $this->{$callback}[0]->{$callback}[1]($arrFiles); } } if ($arrFiles) { $tmpFiles = array(); foreach ($arrFiles as $file) { if (is_readable($file)) { $tmpFiles[TL_ROOT . '/' . $file] = '/' . dirname($file); } } } else { return; } $variables = array(); $arrVars = array(); $objTheme = \ThemeModel::findByPk($objLayout->pid); if ($objTheme->vars) { $arrVars = deserialize($objTheme->vars); foreach ($arrVars as $var) { $k = preg_replace('/\\$/', '@', $var['key'], 1); if ($k[0] != '@') { $k = '@' . $k; } $variables[$k] = $var['value']; } } if (isset($GLOBALS['TL_HOOKS']['addExternalCssVariables']) && is_array($GLOBALS['TL_HOOKS']['addExternalCssVariables'])) { foreach ($GLOBALS['TL_HOOKS']['addExternalCssVariables'] as $callback) { $this->import($callback[0]); $variables = $this->{$callback}[0]->{$callback}[1]($variables); } } $arrFiles = $tmpFiles; if ($_COOKIE['BE_USER_AUTH']) { $DB = \Database::getInstance(); $Session = $DB->prepare('SELECT pid FROM tl_session WHERE name="BE_USER_AUTH" AND hash=?')->limit(1)->execute($_COOKIE['BE_USER_AUTH']); $User = \Database::getInstance()->prepare('SELECT external_css_livereload FROM tl_user WHERE id=?')->execute($Session->pid)->fetchAssoc(); if ($User['external_css_livereload']) { $arrParsed = array(); $strFiles = ''; $strAjaxFiles = array(); foreach ($arrFiles as $file => $path) { $reloadFile = false; $parser = new \Less_Parser(); $parser->parseFile($file, $path); $css = $parser->getCss(); $filename = str_replace('.less', '.css', basename($file)); $path = $lessFolder . '/' . $filename; $oldCss = ''; if (is_file($path)) { $oldCss = file_get_contents($path); if ($oldCss != $css) { file_put_contents($path, $css); $reloadFile = true; } } else { file_put_contents($path, $css); } $filetime = filemtime($path); $fileClass = 'external_css_' . standardize($filename); $fileSRC = '<link class="' . $fileClass . '" rel="stylesheet" href="' . $path . '?v=' . $filetime . '" />'; $strFiles .= $fileSRC; if ($reloadFile) { $strAjaxFiles[] = array('class' => $fileClass, 'src' => $fileSRC, 'path' => $path . '?v=' . $filetime); } } if (\Input::get('action') == 'getLiveCSS') { echo json_encode(array('files' => $strAjaxFiles)); die; } $GLOBALS['TL_HEAD'][] = $strFiles; $GLOBALS['TL_JQUERY'][] = '<script src="system/modules/external_css/assets/j/livereload.js"></script>'; return; } } $file = \Less_Cache::Get($arrFiles, $options, $variables); if (!$file) { return; } $filePath = $lessFolder . '/' . $file; $imgs = array(); $strCss = file_get_contents($filePath); $re = '/url\\(\\s*[\'"]?(\\S*\\.(?:jpe?g|gif|png))[\'"]?\\s*\\)[^;}]*?/i'; if (preg_match_all($re, $strCss, $matches)) { $imgs = $matches[1]; } $embedFile = str_replace('.css', '_embed.css', $filePath); if (!is_file($embedFile)) { $arrParsed = array(); $strCss = file_get_contents($filePath); foreach ($imgs as $img) { $imgPath = TL_ROOT . $img; if (in_array($img, $arrParsed)) { continue; } if (is_file($imgPath)) { $size = filesize($imgPath); $mb = $size / 1048576; if ($mb < 0.2) { $ext = pathinfo($imgPath, PATHINFO_EXTENSION); $b64 = file_get_contents($imgPath); $b64 = base64_encode($b64); $base64 = 'data:image/' . $ext . ';base64,' . $b64; $strCss = str_replace($img, $base64, $strCss); $arrParsed[] = $img; } } } file_put_contents($embedFile, $strCss); } $filePath = $embedFile; $GLOBALS['TL_HEAD'][] = \Template::generateStyleTag(\Controller::addStaticUrlTo($filePath), '', false); }