[FEATURE] Exclude Page CSS from Concatenation
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Page / PageGenerator.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Page;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Page\PageRenderer;
18 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
19 use TYPO3\CMS\Core\Type\File\ImageInfo;
20 use TYPO3\CMS\Core\Utility\ArrayUtility;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Core\Utility\MathUtility;
23 use TYPO3\CMS\Extbase\Service\TypoScriptService;
24 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
25 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
26
27 /**
28 * Class for starting TypoScript page generation
29 *
30 * The class is not instantiated as an objects but called directly with the "::" operator.
31 * eg: \TYPO3\CMS\Frontend\Page\PageGenerator::pagegenInit()
32 */
33 class PageGenerator {
34
35 /**
36 * Do not render title tag
37 * Typoscript setting: [config][noPageTitle]
38 */
39 const NO_PAGE_TITLE = 2;
40
41 /**
42 * Setting some vars in TSFE, primarily based on TypoScript config settings.
43 *
44 * @return void
45 */
46 static public function pagegenInit() {
47 /** @var TypoScriptFrontendController $tsfe */
48 $tsfe = $GLOBALS['TSFE'];
49 if ($tsfe->page['content_from_pid'] > 0) {
50 // make REAL copy of TSFE object - not reference!
51 $temp_copy_TSFE = clone $tsfe;
52 // 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!
53 $temp_copy_TSFE->id = $tsfe->page['content_from_pid'];
54 $temp_copy_TSFE->MP = '';
55 $temp_copy_TSFE->getPageAndRootlineWithDomain($tsfe->config['config']['content_from_pid_allowOutsideDomain'] ? 0 : $tsfe->domainStartPage);
56 $tsfe->contentPid = (int)$temp_copy_TSFE->id;
57 unset($temp_copy_TSFE);
58 }
59 if ($tsfe->config['config']['MP_defaults']) {
60 $temp_parts = GeneralUtility::trimExplode('|', $tsfe->config['config']['MP_defaults'], TRUE);
61 foreach ($temp_parts as $temp_p) {
62 list($temp_idP, $temp_MPp) = explode(':', $temp_p, 2);
63 $temp_ids = GeneralUtility::intExplode(',', $temp_idP);
64 foreach ($temp_ids as $temp_id) {
65 $tsfe->MP_defaults[$temp_id] = $temp_MPp;
66 }
67 }
68 }
69 // Global vars...
70 $tsfe->indexedDocTitle = $tsfe->page['title'];
71 $tsfe->debug = '' . $tsfe->config['config']['debug'];
72 // Base url:
73 if (isset($tsfe->config['config']['baseURL'])) {
74 $tsfe->baseUrl = $tsfe->config['config']['baseURL'];
75 // Deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
76 $tsfe->anchorPrefix = substr(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), strlen(GeneralUtility::getIndpEnv('TYPO3_SITE_URL')));
77 }
78 // Internal and External target defaults
79 $tsfe->intTarget = '' . $tsfe->config['config']['intTarget'];
80 $tsfe->extTarget = '' . $tsfe->config['config']['extTarget'];
81 $tsfe->fileTarget = '' . $tsfe->config['config']['fileTarget'];
82 if ($tsfe->config['config']['spamProtectEmailAddresses'] === 'ascii') {
83 $tsfe->spamProtectEmailAddresses = 'ascii';
84 } else {
85 $tsfe->spamProtectEmailAddresses = MathUtility::forceIntegerInRange($tsfe->config['config']['spamProtectEmailAddresses'], -10, 10, 0);
86 }
87 // calculate the absolute path prefix
88 if (!empty($tsfe->config['config']['absRefPrefix'])) {
89 $absRefPrefix = trim($tsfe->config['config']['absRefPrefix']);
90 if ($absRefPrefix === 'auto') {
91 $tsfe->absRefPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
92 } else {
93 $tsfe->absRefPrefix = $absRefPrefix;
94 }
95 } else {
96 $tsfe->absRefPrefix = '';
97 }
98 if ($tsfe->type && $tsfe->config['config']['frameReloadIfNotInFrameset']) {
99 $tdlLD = $tsfe->tmpl->linkData($tsfe->page, '_top', $tsfe->no_cache, '');
100 $tsfe->additionalJavaScript['JSCode'] .= 'if(!parent.' . trim($tsfe->sPre) . ' && !parent.view_frame) top.location.href="' . $tsfe->baseUrlWrap($tdlLD['totalURL']) . '"';
101 }
102 $tsfe->compensateFieldWidth = '' . $tsfe->config['config']['compensateFieldWidth'];
103 $tsfe->lockFilePath = '' . $tsfe->config['config']['lockFilePath'];
104 $tsfe->lockFilePath = $tsfe->lockFilePath ?: $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'];
105 $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_noScaleUp'] = isset($tsfe->config['config']['noScaleUp']) ? '' . $tsfe->config['config']['noScaleUp'] : $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_noScaleUp'];
106 $tsfe->TYPO3_CONF_VARS['GFX']['im_noScaleUp'] = $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_noScaleUp'];
107 $tsfe->ATagParams = trim($tsfe->config['config']['ATagParams']) ? ' ' . trim($tsfe->config['config']['ATagParams']) : '';
108 if ($tsfe->config['config']['setJS_mouseOver']) {
109 $tsfe->setJS('mouseOver');
110 }
111 if ($tsfe->config['config']['setJS_openPic']) {
112 $tsfe->setJS('openPic');
113 }
114 static::initializeSearchWordDataInTsfe();
115 // linkVars
116 $tsfe->calculateLinkVars();
117 // dtdAllowsFrames indicates whether to use the target attribute in links
118 $tsfe->dtdAllowsFrames = FALSE;
119 if ($tsfe->config['config']['doctype']) {
120 if (in_array(
121 (string)$tsfe->config['config']['doctype'],
122 array('xhtml_trans', 'xhtml_frames', 'xhtml_basic', 'xhtml_2', 'html5'),
123 TRUE)
124 ) {
125 $tsfe->dtdAllowsFrames = TRUE;
126 }
127 } else {
128 $tsfe->dtdAllowsFrames = TRUE;
129 }
130 // Setting XHTML-doctype from doctype
131 if (!$tsfe->config['config']['xhtmlDoctype']) {
132 $tsfe->config['config']['xhtmlDoctype'] = $tsfe->config['config']['doctype'];
133 }
134 if ($tsfe->config['config']['xhtmlDoctype']) {
135 $tsfe->xhtmlDoctype = $tsfe->config['config']['xhtmlDoctype'];
136 // Checking XHTML-docytpe
137 switch ((string)$tsfe->config['config']['xhtmlDoctype']) {
138 case 'xhtml_trans':
139
140 case 'xhtml_strict':
141
142 case 'xhtml_frames':
143 $tsfe->xhtmlVersion = 100;
144 break;
145 case 'xhtml_basic':
146 $tsfe->xhtmlVersion = 105;
147 break;
148 case 'xhtml_11':
149
150 case 'xhtml+rdfa_10':
151 $tsfe->xhtmlVersion = 110;
152 break;
153 case 'xhtml_2':
154 GeneralUtility::deprecationLog('The option "config.xhtmlDoctype=xhtml_2" is deprecated since TYPO3 CMS 7, and will be removed with CMS 8');
155 $tsfe->xhtmlVersion = 200;
156 break;
157 default:
158 static::getPageRenderer()->setRenderXhtml(FALSE);
159 $tsfe->xhtmlDoctype = '';
160 $tsfe->xhtmlVersion = 0;
161 }
162 } else {
163 static::getPageRenderer()->setRenderXhtml(FALSE);
164 }
165 }
166
167 /**
168 * Processing JavaScript handlers
169 *
170 * @return array Array with a) a JavaScript section with event handlers and variables set and b) an array with attributes for the body tag.
171 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use JS directly
172 */
173 static public function JSeventFunctions() {
174 $functions = array();
175 $setEvents = array();
176 $setBody = array();
177 foreach ($GLOBALS['TSFE']->JSeventFuncCalls as $event => $handlers) {
178 if (!empty($handlers)) {
179 GeneralUtility::deprecationLog('The usage of $GLOBALS[\'TSFE\']->JSeventFuncCalls is deprecated as of TYPO3 CMS 7. Use Javascript directly.');
180 $functions[] = ' function T3_' . $event . 'Wrapper(e) { ' . implode(' ', $handlers) . ' }';
181 $setEvents[] = ' document.' . $event . '=T3_' . $event . 'Wrapper;';
182 if ($event == 'onload') {
183 // Dubiuos double setting breaks on some browser - do we need it?
184 $setBody[] = 'onload="T3_onloadWrapper();"';
185 }
186 }
187 }
188 return array(!empty($functions) ? implode(LF, $functions) . LF . implode(LF, $setEvents) : '', $setBody);
189 }
190
191 /**
192 * Rendering the page content
193 *
194 * @return void
195 */
196 static public function renderContent() {
197 /** @var TypoScriptFrontendController $tsfe */
198 $tsfe = $GLOBALS['TSFE'];
199
200 /** @var TimeTracker $timeTracker */
201 $timeTracker = $GLOBALS['TT'];
202
203 // PAGE CONTENT
204 $timeTracker->incStackPointer();
205 $timeTracker->push($tsfe->sPre, 'PAGE');
206 $pageContent = $tsfe->cObj->cObjGet($tsfe->pSetup);
207 if ($tsfe->pSetup['wrap']) {
208 $pageContent = $tsfe->cObj->wrap($pageContent, $tsfe->pSetup['wrap']);
209 }
210 if ($tsfe->pSetup['stdWrap.']) {
211 $pageContent = $tsfe->cObj->stdWrap($pageContent, $tsfe->pSetup['stdWrap.']);
212 }
213 // PAGE HEADER (after content - maybe JS is inserted!
214 // if 'disableAllHeaderCode' is set, all the header-code is discarded!
215 if ($tsfe->config['config']['disableAllHeaderCode']) {
216 $tsfe->content = $pageContent;
217 } else {
218 self::renderContentWithHeader($pageContent);
219 }
220 $timeTracker->pull($timeTracker->LR ? $tsfe->content : '');
221 $timeTracker->decStackPointer();
222 }
223
224 /**
225 * Rendering normal HTML-page with header by wrapping the generated content ($pageContent) in body-tags and setting the header accordingly.
226 *
227 * @param string $pageContent The page content which TypoScript objects has generated
228 * @return void
229 */
230 static public function renderContentWithHeader($pageContent) {
231 /** @var TypoScriptFrontendController $tsfe */
232 $tsfe = $GLOBALS['TSFE'];
233
234 /** @var TimeTracker $timeTracker */
235 $timeTracker = $GLOBALS['TT'];
236
237 $pageRenderer = static::getPageRenderer();
238 if ($tsfe->config['config']['moveJsFromHeaderToFooter']) {
239 $pageRenderer->enableMoveJsFromHeaderToFooter();
240 }
241 if ($tsfe->config['config']['pageRendererTemplateFile']) {
242 $file = $tsfe->tmpl->getFileName($tsfe->config['config']['pageRendererTemplateFile']);
243 if ($file) {
244 $pageRenderer->setTemplateFile($file);
245 }
246 }
247 $headerComment = $tsfe->config['config']['headerComment'];
248 if (trim($headerComment)) {
249 $pageRenderer->addInlineComment(TAB . str_replace(LF, (LF . TAB), trim($headerComment)) . LF);
250 }
251 // Setting charset:
252 $theCharset = $tsfe->metaCharset;
253 // Reset the content variables:
254 $tsfe->content = '';
255 $htmlTagAttributes = array();
256 $htmlLang = $tsfe->config['config']['htmlTag_langKey'] ?: ($tsfe->sys_language_isocode ?: 'en');
257 // Set content direction: (More info: http://www.tau.ac.il/~danon/Hebrew/HTML_and_Hebrew.html)
258 if ($tsfe->config['config']['htmlTag_dir']) {
259 $htmlTagAttributes['dir'] = htmlspecialchars($tsfe->config['config']['htmlTag_dir']);
260 }
261 // Setting document type:
262 $docTypeParts = array();
263 $xmlDocument = TRUE;
264 // Part 1: XML prologue
265 switch ((string)$tsfe->config['config']['xmlprologue']) {
266 case 'none':
267 $xmlDocument = FALSE;
268 break;
269 case 'xml_10':
270 $docTypeParts[] = '<?xml version="1.0" encoding="' . $theCharset . '"?>';
271 break;
272 case 'xml_11':
273 $docTypeParts[] = '<?xml version="1.1" encoding="' . $theCharset . '"?>';
274 break;
275 case '':
276 if ($tsfe->xhtmlVersion) {
277 $docTypeParts[] = '<?xml version="1.0" encoding="' . $theCharset . '"?>';
278 }
279 break;
280 default:
281 $docTypeParts[] = $tsfe->config['config']['xmlprologue'];
282 }
283 // Part 2: DTD
284 $doctype = $tsfe->config['config']['doctype'];
285 if ($doctype) {
286 switch ($doctype) {
287 case 'xhtml_trans':
288 $docTypeParts[] = '<!DOCTYPE html
289 PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
290 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
291 break;
292 case 'xhtml_strict':
293 $docTypeParts[] = '<!DOCTYPE html
294 PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
295 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
296 break;
297 case 'xhtml_frames':
298 $docTypeParts[] = '<!DOCTYPE html
299 PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
300 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';
301 break;
302 case 'xhtml_basic':
303 $docTypeParts[] = '<!DOCTYPE html
304 PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
305 "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">';
306 break;
307 case 'xhtml_11':
308 $docTypeParts[] = '<!DOCTYPE html
309 PUBLIC "-//W3C//DTD XHTML 1.1//EN"
310 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
311 break;
312 case 'xhtml_2':
313 $docTypeParts[] = '<!DOCTYPE html
314 PUBLIC "-//W3C//DTD XHTML 2.0//EN"
315 "http://www.w3.org/TR/xhtml2/DTD/xhtml2.dtd">';
316 break;
317 case 'xhtml+rdfa_10':
318 $docTypeParts[] = '<!DOCTYPE html
319 PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
320 "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">';
321 break;
322 case 'html5':
323 $docTypeParts[] = '<!DOCTYPE html>';
324 if ($xmlDocument) {
325 $pageRenderer->setMetaCharsetTag('<meta charset="|" />');
326 } else {
327 $pageRenderer->setMetaCharsetTag('<meta charset="|">');
328 }
329 break;
330 case 'none':
331 break;
332 default:
333 $docTypeParts[] = $doctype;
334 }
335 } else {
336 $docTypeParts[] = '<!DOCTYPE html>';
337 if ($xmlDocument){
338 $pageRenderer->setMetaCharsetTag('<meta charset="|" />');
339 } else {
340 $pageRenderer->setMetaCharsetTag('<meta charset="|">');
341 }
342 }
343 if ($tsfe->xhtmlVersion) {
344 $htmlTagAttributes['xml:lang'] = $htmlLang;
345 }
346 if ($tsfe->xhtmlVersion < 110 || $doctype === 'html5') {
347 $htmlTagAttributes['lang'] = $htmlLang;
348 }
349 if ($tsfe->xhtmlVersion || $doctype === 'html5' && $xmlDocument) {
350 // We add this to HTML5 to achieve a slightly better backwards compatibility
351 $htmlTagAttributes['xmlns'] = 'http://www.w3.org/1999/xhtml';
352 if (is_array($tsfe->config['config']['namespaces.'])) {
353 foreach ($tsfe->config['config']['namespaces.'] as $prefix => $uri) {
354 // $uri gets htmlspecialchared later
355 $htmlTagAttributes['xmlns:' . htmlspecialchars($prefix)] = $uri;
356 }
357 }
358 }
359 // Swap XML and doctype order around (for MSIE / Opera standards compliance)
360 if ($tsfe->config['config']['doctypeSwitch']) {
361 $docTypeParts = array_reverse($docTypeParts);
362 }
363 // Adding doctype parts:
364 if (!empty($docTypeParts)) {
365 $pageRenderer->setXmlPrologAndDocType(implode(LF, $docTypeParts));
366 }
367 // Begin header section:
368 if ($tsfe->config['config']['htmlTag_setParams'] !== 'none') {
369 $_attr = $tsfe->config['config']['htmlTag_setParams'] ? $tsfe->config['config']['htmlTag_setParams'] : GeneralUtility::implodeAttributes($htmlTagAttributes);
370 } else {
371 $_attr = '';
372 }
373 $htmlTag = '<html' . ($_attr ? ' ' . $_attr : '') . '>';
374 if (isset($tsfe->config['config']['htmlTag_stdWrap.'])) {
375 $htmlTag = $tsfe->cObj->stdWrap($htmlTag, $tsfe->config['config']['htmlTag_stdWrap.']);
376 }
377 $pageRenderer->setHtmlTag($htmlTag);
378 // Head tag:
379 $headTag = $tsfe->pSetup['headTag'] ?: '<head>';
380 if (isset($tsfe->pSetup['headTag.'])) {
381 $headTag = $tsfe->cObj->stdWrap($headTag, $tsfe->pSetup['headTag.']);
382 }
383 $pageRenderer->setHeadTag($headTag);
384 // Setting charset meta tag:
385 $pageRenderer->setCharSet($theCharset);
386 $pageRenderer->addInlineComment(' This website is powered by TYPO3 - inspiring people to share!
387 TYPO3 is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.
388 TYPO3 is copyright ' . TYPO3_copyright_year . ' of Kasper Skaarhoj. Extensions are copyright of their respective owners.
389 Information and contribution at ' . TYPO3_URL_GENERAL . '
390 ');
391 if ($tsfe->baseUrl) {
392 $pageRenderer->setBaseUrl($tsfe->baseUrl);
393 }
394 if ($tsfe->pSetup['shortcutIcon']) {
395 $favIcon = $tsfe->tmpl->getFileName($tsfe->pSetup['shortcutIcon']);
396 $iconFileInfo = GeneralUtility::makeInstance(ImageInfo::class, PATH_site . $favIcon);
397 if ($iconFileInfo->isFile()) {
398 $iconMimeType = $iconFileInfo->getMimeType();
399 if ($iconMimeType) {
400 $iconMimeType = ' type="' . $iconMimeType . '"';
401 $pageRenderer->setIconMimeType($iconMimeType);
402 }
403 $pageRenderer->setFavIcon(GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . $favIcon);
404 }
405 }
406 // Including CSS files
407 if (is_array($tsfe->tmpl->setup['plugin.'])) {
408 $stylesFromPlugins = '';
409 foreach ($tsfe->tmpl->setup['plugin.'] as $key => $iCSScode) {
410 if (is_array($iCSScode)) {
411 if ($iCSScode['_CSS_DEFAULT_STYLE'] && empty($tsfe->config['config']['removeDefaultCss'])) {
412 if (isset($iCSScode['_CSS_DEFAULT_STYLE.'])) {
413 $cssDefaultStyle = $tsfe->cObj->stdWrap($iCSScode['_CSS_DEFAULT_STYLE'], $iCSScode['_CSS_DEFAULT_STYLE.']);
414 } else {
415 $cssDefaultStyle = $iCSScode['_CSS_DEFAULT_STYLE'];
416 }
417 $stylesFromPlugins .= '/* default styles for extension "' . substr($key, 0, -1) . '" */' . LF . $cssDefaultStyle . LF;
418 }
419 if ($iCSScode['_CSS_PAGE_STYLE'] && empty($tsfe->config['config']['removePageCss'])) {
420 $cssPageStyle = implode(LF, $iCSScode['_CSS_PAGE_STYLE']);
421 if (isset($iCSScode['_CSS_PAGE_STYLE.'])) {
422 $cssPageStyle = $tsfe->cObj->stdWrap($cssPageStyle, $iCSScode['_CSS_PAGE_STYLE.']);
423 }
424 $cssPageStyle = '/* specific page styles for extension "' . substr($key, 0, -1) . '" */' . LF . $cssPageStyle;
425 self::addCssToPageRenderer($cssPageStyle, TRUE);
426 }
427 }
428 }
429 if (!empty($stylesFromPlugins)) {
430 self::addCssToPageRenderer($stylesFromPlugins);
431 }
432 }
433 if ($tsfe->pSetup['stylesheet']) {
434 $ss = $tsfe->tmpl->getFileName($tsfe->pSetup['stylesheet']);
435 if ($ss) {
436 $pageRenderer->addCssFile($ss);
437 }
438 }
439 /**********************************************************************/
440 /* config.includeCSS / config.includeCSSLibs
441 /**********************************************************************/
442 if (is_array($tsfe->pSetup['includeCSS.'])) {
443 foreach ($tsfe->pSetup['includeCSS.'] as $key => $CSSfile) {
444 if (!is_array($CSSfile)) {
445 $cssFileConfig = &$tsfe->pSetup['includeCSS.'][$key . '.'];
446 if (isset($cssFileConfig['if.']) && !$tsfe->cObj->checkIf($cssFileConfig['if.'])) {
447 continue;
448 }
449 $ss = $cssFileConfig['external'] ? $CSSfile : $tsfe->tmpl->getFileName($CSSfile);
450 if ($ss) {
451 if ($cssFileConfig['import']) {
452 if (!$cssFileConfig['external'] && $ss[0] !== '/') {
453 // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende)
454 $ss = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/' . $ss;
455 }
456 $pageRenderer->addCssInlineBlock('import_' . $key, '@import url("' . htmlspecialchars($ss) . '") ' . htmlspecialchars($cssFileConfig['media']) . ';', empty($cssFileConfig['disableCompression']), (bool)$cssFileConfig['forceOnTop'], '');
457 } else {
458 $pageRenderer->addCssFile(
459 $ss,
460 $cssFileConfig['alternate'] ? 'alternate stylesheet' : 'stylesheet',
461 $cssFileConfig['media'] ?: 'all',
462 $cssFileConfig['title'] ?: '',
463 empty($cssFileConfig['disableCompression']),
464 (bool)$cssFileConfig['forceOnTop'],
465 $cssFileConfig['allWrap'],
466 (bool)$cssFileConfig['excludeFromConcatenation'],
467 $cssFileConfig['allWrap.']['splitChar']
468 );
469 unset($cssFileConfig);
470 }
471 }
472 }
473 }
474 }
475 if (is_array($tsfe->pSetup['includeCSSLibs.'])) {
476 foreach ($tsfe->pSetup['includeCSSLibs.'] as $key => $CSSfile) {
477 if (!is_array($CSSfile)) {
478 $cssFileConfig = &$tsfe->pSetup['includeCSSLibs.'][$key . '.'];
479 if (isset($cssFileConfig['if.']) && !$tsfe->cObj->checkIf($cssFileConfig['if.'])) {
480 continue;
481 }
482 $ss = $cssFileConfig['external'] ? $CSSfile : $tsfe->tmpl->getFileName($CSSfile);
483 if ($ss) {
484 if ($cssFileConfig['import']) {
485 if (!$cssFileConfig['external'] && $ss[0] !== '/') {
486 // To fix MSIE 6 that cannot handle these as relative paths (according to Ben v Ende)
487 $ss = GeneralUtility::dirname(GeneralUtility::getIndpEnv('SCRIPT_NAME')) . '/' . $ss;
488 }
489 $pageRenderer->addCssInlineBlock('import_' . $key, '@import url("' . htmlspecialchars($ss) . '") ' . htmlspecialchars($cssFileConfig['media']) . ';', empty($cssFileConfig['disableCompression']), (bool)$cssFileConfig['forceOnTop'], '');
490 } else {
491 $pageRenderer->addCssLibrary(
492 $ss,
493 $cssFileConfig['alternate'] ? 'alternate stylesheet' : 'stylesheet',
494 $cssFileConfig['media'] ?: 'all',
495 $cssFileConfig['title'] ?: '',
496 empty($cssFileConfig['disableCompression']),
497 (bool)$cssFileConfig['forceOnTop'],
498 $cssFileConfig['allWrap'],
499 (bool)$cssFileConfig['excludeFromConcatenation'],
500 $cssFileConfig['allWrap.']['splitChar']
501 );
502 unset($cssFileConfig);
503 }
504 }
505 }
506 }
507 }
508
509 // Stylesheets
510 $style = '';
511 if ($tsfe->pSetup['insertClassesFromRTE']) {
512 $pageTSConfig = $tsfe->getPagesTSconfig();
513 $RTEclasses = $pageTSConfig['RTE.']['classes.'];
514 if (is_array($RTEclasses)) {
515 foreach ($RTEclasses as $RTEclassName => $RTEvalueArray) {
516 if ($RTEvalueArray['value']) {
517 $style .= '
518 .' . substr($RTEclassName, 0, -1) . ' {' . $RTEvalueArray['value'] . '}';
519 }
520 }
521 }
522 if ($tsfe->pSetup['insertClassesFromRTE.']['add_mainStyleOverrideDefs'] && is_array($pageTSConfig['RTE.']['default.']['mainStyleOverride_add.'])) {
523 $mSOa_tList = GeneralUtility::trimExplode(',', strtoupper($tsfe->pSetup['insertClassesFromRTE.']['add_mainStyleOverrideDefs']), TRUE);
524 foreach ($pageTSConfig['RTE.']['default.']['mainStyleOverride_add.'] as $mSOa_key => $mSOa_value) {
525 if (!is_array($mSOa_value) && (in_array('*', $mSOa_tList) || in_array($mSOa_key, $mSOa_tList))) {
526 $style .= '
527 ' . $mSOa_key . ' {' . $mSOa_value . '}';
528 }
529 }
530 }
531 }
532 // Setting body tag margins in CSS:
533 if (isset($tsfe->pSetup['bodyTagMargins']) && $tsfe->pSetup['bodyTagMargins.']['useCSS']) {
534 $margins = (int)$tsfe->pSetup['bodyTagMargins'];
535 $style .= '
536 BODY {margin: ' . $margins . 'px ' . $margins . 'px ' . $margins . 'px ' . $margins . 'px;}';
537 }
538 // CSS_inlineStyle from TS
539 $style .= trim($tsfe->pSetup['CSS_inlineStyle']);
540 $style .= $tsfe->cObj->cObjGet($tsfe->pSetup['cssInline.'], 'cssInline.');
541 if (trim($style)) {
542 self::addCssToPageRenderer($style, TRUE, 'additionalTSFEInlineStyle');
543 }
544 // Javascript Libraries
545 if (is_array($tsfe->pSetup['javascriptLibs.'])) {
546 // Include jQuery into the page renderer
547 if (!empty($tsfe->pSetup['javascriptLibs.']['jQuery'])) {
548 $jQueryTS = $tsfe->pSetup['javascriptLibs.']['jQuery.'];
549 // Check if version / source is set, if not set variable to "NULL" to use the default of the page renderer
550 $version = isset($jQueryTS['version']) ? $jQueryTS['version'] : NULL;
551 $source = isset($jQueryTS['source']) ? $jQueryTS['source'] : NULL;
552 // When "noConflict" is not set or "1" enable the default jQuery noConflict mode, otherwise disable the namespace
553 if (!isset($jQueryTS['noConflict']) || !empty($jQueryTS['noConflict'])) {
554 // Set namespace to the "noConflict.namespace" value if "noConflict.namespace" has a value
555 if (!empty($jQueryTS['noConflict.']['namespace'])) {
556 $namespace = $jQueryTS['noConflict.']['namespace'];
557 } else {
558 $namespace = PageRenderer::JQUERY_NAMESPACE_DEFAULT_NOCONFLICT;
559 }
560 } else {
561 $namespace = PageRenderer::JQUERY_NAMESPACE_NONE;
562 }
563 $pageRenderer->loadJQuery($version, $source, $namespace);
564 }
565 if ($tsfe->pSetup['javascriptLibs.']['ExtJs']) {
566 $css = (bool)$tsfe->pSetup['javascriptLibs.']['ExtJs.']['css'];
567 $theme = (bool)$tsfe->pSetup['javascriptLibs.']['ExtJs.']['theme'];
568 $pageRenderer->loadExtJs($css, $theme);
569 if ($tsfe->pSetup['javascriptLibs.']['ExtJs.']['debug']) {
570 $pageRenderer->enableExtJsDebug();
571 }
572 }
573 }
574 // JavaScript library files
575 if (is_array($tsfe->pSetup['includeJSlibs.']) || is_array($tsfe->pSetup['includeJSLibs.'])) {
576 if (!is_array($tsfe->pSetup['includeJSlibs.'])) {
577 $tsfe->pSetup['includeJSlibs.'] = array();
578 } else {
579 GeneralUtility::deprecationLog('The property page.includeJSlibs is marked for deprecation and will be removed in TYPO3 CMS 8. Please use page.includeJSLibs (with an uppercase L) instead.');
580 }
581 if (!is_array($tsfe->pSetup['includeJSLibs.'])) {
582 $tsfe->pSetup['includeJSLibs.'] = array();
583 }
584 ArrayUtility::mergeRecursiveWithOverrule(
585 $tsfe->pSetup['includeJSLibs.'],
586 $tsfe->pSetup['includeJSlibs.']
587 );
588 unset($tsfe->pSetup['includeJSlibs.']);
589 foreach ($tsfe->pSetup['includeJSLibs.'] as $key => $JSfile) {
590 if (!is_array($JSfile)) {
591 if (isset($tsfe->pSetup['includeJSLibs.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJSLibs.'][($key . '.')]['if.'])) {
592 continue;
593 }
594 $ss = $tsfe->pSetup['includeJSLibs.'][$key . '.']['external'] ? $JSfile : $tsfe->tmpl->getFileName($JSfile);
595 if ($ss) {
596 $jsFileConfig = &$tsfe->pSetup['includeJSLibs.'][$key . '.'];
597 $type = $jsFileConfig['type'];
598 if (!$type) {
599 $type = 'text/javascript';
600 }
601
602 $pageRenderer->addJsLibrary(
603 $key,
604 $ss,
605 $type,
606 empty($jsFileConfig['disableCompression']),
607 (bool)$jsFileConfig['forceOnTop'],
608 $jsFileConfig['allWrap'],
609 (bool)$jsFileConfig['excludeFromConcatenation'],
610 $jsFileConfig['allWrap.']['splitChar'],
611 (bool)$jsFileConfig['async'],
612 $jsFileConfig['integrity']
613 );
614 unset($jsFileConfig);
615 }
616 }
617 }
618 }
619 if (is_array($tsfe->pSetup['includeJSFooterlibs.'])) {
620 foreach ($tsfe->pSetup['includeJSFooterlibs.'] as $key => $JSfile) {
621 if (!is_array($JSfile)) {
622 if (isset($tsfe->pSetup['includeJSFooterlibs.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJSFooterlibs.'][($key . '.')]['if.'])) {
623 continue;
624 }
625 $ss = $tsfe->pSetup['includeJSFooterlibs.'][$key . '.']['external'] ? $JSfile : $tsfe->tmpl->getFileName($JSfile);
626 if ($ss) {
627 $jsFileConfig = &$tsfe->pSetup['includeJSFooterlibs.'][$key . '.'];
628 $type = $jsFileConfig['type'];
629 if (!$type) {
630 $type = 'text/javascript';
631 }
632 $pageRenderer->addJsFooterLibrary(
633 $key,
634 $ss,
635 $type,
636 empty($jsFileConfig['disableCompression']),
637 (bool)$jsFileConfig['forceOnTop'],
638 $jsFileConfig['allWrap'],
639 (bool)$jsFileConfig['excludeFromConcatenation'],
640 $jsFileConfig['allWrap.']['splitChar'],
641 (bool)$jsFileConfig['async'],
642 $jsFileConfig['integrity']
643 );
644 unset($jsFileConfig);
645 }
646 }
647 }
648 }
649 // JavaScript files
650 if (is_array($tsfe->pSetup['includeJS.'])) {
651 foreach ($tsfe->pSetup['includeJS.'] as $key => $JSfile) {
652 if (!is_array($JSfile)) {
653 if (isset($tsfe->pSetup['includeJS.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJS.'][($key . '.')]['if.'])) {
654 continue;
655 }
656 $ss = $tsfe->pSetup['includeJS.'][$key . '.']['external'] ? $JSfile : $tsfe->tmpl->getFileName($JSfile);
657 if ($ss) {
658 $jsConfig = &$tsfe->pSetup['includeJS.'][$key . '.'];
659 $type = $jsConfig['type'];
660 if (!$type) {
661 $type = 'text/javascript';
662 }
663 $pageRenderer->addJsFile(
664 $ss,
665 $type,
666 empty($jsConfig['disableCompression']),
667 (bool)$jsConfig['forceOnTop'],
668 $jsConfig['allWrap'],
669 (bool)$jsConfig['excludeFromConcatenation'],
670 $jsConfig['allWrap.']['splitChar'],
671 (bool)$jsConfig['async'],
672 $jsConfig['integrity']
673 );
674 unset($jsConfig);
675 }
676 }
677 }
678 }
679 if (is_array($tsfe->pSetup['includeJSFooter.'])) {
680 foreach ($tsfe->pSetup['includeJSFooter.'] as $key => $JSfile) {
681 if (!is_array($JSfile)) {
682 if (isset($tsfe->pSetup['includeJSFooter.'][$key . '.']['if.']) && !$tsfe->cObj->checkIf($tsfe->pSetup['includeJSFooter.'][($key . '.')]['if.'])) {
683 continue;
684 }
685 $ss = $tsfe->pSetup['includeJSFooter.'][$key . '.']['external'] ? $JSfile : $tsfe->tmpl->getFileName($JSfile);
686 if ($ss) {
687 $jsConfig = &$tsfe->pSetup['includeJSFooter.'][$key . '.'];
688 $type = $jsConfig['type'];
689 if (!$type) {
690 $type = 'text/javascript';
691 }
692 $pageRenderer->addJsFooterFile(
693 $ss,
694 $type,
695 empty($jsConfig['disableCompression']),
696 (bool)$jsConfig['forceOnTop'],
697 $jsConfig['allWrap'],
698 (bool)$jsConfig['excludeFromConcatenation'],
699 $jsConfig['allWrap.']['splitChar'],
700 (bool)$jsConfig['async'],
701 $jsConfig['integrity']
702 );
703 unset($jsConfig);
704 }
705 }
706 }
707 }
708 // Headerdata
709 if (is_array($tsfe->pSetup['headerData.'])) {
710 $pageRenderer->addHeaderData($tsfe->cObj->cObjGet($tsfe->pSetup['headerData.'], 'headerData.'));
711 }
712 // Footerdata
713 if (is_array($tsfe->pSetup['footerData.'])) {
714 $pageRenderer->addFooterData($tsfe->cObj->cObjGet($tsfe->pSetup['footerData.'], 'footerData.'));
715 }
716 static::generatePageTitle();
717
718 $metaTagsHtml = static::generateMetaTagHtml(
719 isset($tsfe->pSetup['meta.']) ? $tsfe->pSetup['meta.'] : array(),
720 $tsfe->xhtmlVersion,
721 $tsfe->cObj
722 );
723 foreach ($metaTagsHtml as $metaTag) {
724 $pageRenderer->addMetaTag($metaTag);
725 }
726
727 unset($tsfe->additionalHeaderData['JSCode']);
728 if (is_array($tsfe->config['INTincScript'])) {
729 $tsfe->additionalHeaderData['JSCode'] = $tsfe->JSCode;
730 // Storing the JSCode vars...
731 $tsfe->config['INTincScript_ext']['divKey'] = $tsfe->uniqueHash();
732 $tsfe->config['INTincScript_ext']['additionalHeaderData'] = $tsfe->additionalHeaderData;
733 // Storing the header-data array
734 $tsfe->config['INTincScript_ext']['additionalFooterData'] = $tsfe->additionalFooterData;
735 // Storing the footer-data array
736 $tsfe->config['INTincScript_ext']['additionalJavaScript'] = $tsfe->additionalJavaScript;
737 // Storing the JS-data array
738 $tsfe->config['INTincScript_ext']['additionalCSS'] = $tsfe->additionalCSS;
739 // Storing the Style-data array
740 $tsfe->additionalHeaderData = array('<!--HD_' . $tsfe->config['INTincScript_ext']['divKey'] . '-->');
741 // Clearing the array
742 $tsfe->additionalFooterData = array('<!--FD_' . $tsfe->config['INTincScript_ext']['divKey'] . '-->');
743 // Clearing the array
744 $tsfe->divSection .= '<!--TDS_' . $tsfe->config['INTincScript_ext']['divKey'] . '-->';
745 } else {
746 $tsfe->INTincScript_loadJSCode();
747 }
748 $JSef = self::JSeventFunctions();
749 $scriptJsCode = $JSef[0];
750
751 if ($tsfe->spamProtectEmailAddresses && $tsfe->spamProtectEmailAddresses !== 'ascii') {
752 $scriptJsCode = '
753 // decrypt helper function
754 function decryptCharcode(n,start,end,offset) {
755 n = n + offset;
756 if (offset > 0 && n > end) {
757 n = start + (n - end - 1);
758 } else if (offset < 0 && n < start) {
759 n = end - (start - n - 1);
760 }
761 return String.fromCharCode(n);
762 }
763 // decrypt string
764 function decryptString(enc,offset) {
765 var dec = "";
766 var len = enc.length;
767 for(var i=0; i < len; i++) {
768 var n = enc.charCodeAt(i);
769 if (n >= 0x2B && n <= 0x3A) {
770 dec += decryptCharcode(n,0x2B,0x3A,offset); // 0-9 . , - + / :
771 } else if (n >= 0x40 && n <= 0x5A) {
772 dec += decryptCharcode(n,0x40,0x5A,offset); // A-Z @
773 } else if (n >= 0x61 && n <= 0x7A) {
774 dec += decryptCharcode(n,0x61,0x7A,offset); // a-z
775 } else {
776 dec += enc.charAt(i);
777 }
778 }
779 return dec;
780 }
781 // decrypt spam-protected emails
782 function linkTo_UnCryptMailto(s) {
783 location.href = decryptString(s,' . $tsfe->spamProtectEmailAddresses * -1 . ');
784 }
785 ';
786 }
787 // Add inline JS
788 $inlineJS = '';
789 // defined in php
790 if (is_array($tsfe->inlineJS)) {
791 foreach ($tsfe->inlineJS as $key => $val) {
792 if (!is_array($val)) {
793 $inlineJS .= LF . $val . LF;
794 }
795 }
796 }
797 // defined in TS with page.inlineJS
798 // Javascript inline code
799 $inline = $tsfe->cObj->cObjGet($tsfe->pSetup['jsInline.'], 'jsInline.');
800 if ($inline) {
801 $inlineJS .= LF . $inline . LF;
802 }
803 // Javascript inline code for Footer
804 $inlineFooterJs = $tsfe->cObj->cObjGet($tsfe->pSetup['jsFooterInline.'], 'jsFooterInline.');
805 // Should minify?
806 if ($tsfe->config['config']['compressJs']) {
807 $pageRenderer->enableCompressJavascript();
808 $minifyErrorScript = ($minifyErrorInline = '');
809 $scriptJsCode = GeneralUtility::minifyJavaScript($scriptJsCode, $minifyErrorScript);
810 if ($minifyErrorScript) {
811 $timeTracker->setTSlogMessage($minifyErrorScript, 3);
812 }
813 if ($inlineJS) {
814 $inlineJS = GeneralUtility::minifyJavaScript($inlineJS, $minifyErrorInline);
815 if ($minifyErrorInline) {
816 $timeTracker->setTSlogMessage($minifyErrorInline, 3);
817 }
818 }
819 if ($inlineFooterJs) {
820 $inlineFooterJs = GeneralUtility::minifyJavaScript($inlineFooterJs, $minifyErrorInline);
821 if ($minifyErrorInline) {
822 $timeTracker->setTSlogMessage($minifyErrorInline, 3);
823 }
824 }
825 }
826 if (!$tsfe->config['config']['removeDefaultJS']) {
827 // inlude default and inlineJS
828 if ($scriptJsCode) {
829 $pageRenderer->addJsInlineCode('_scriptCode', $scriptJsCode, $tsfe->config['config']['compressJs']);
830 }
831 if ($inlineJS) {
832 $pageRenderer->addJsInlineCode('TS_inlineJS', $inlineJS, $tsfe->config['config']['compressJs']);
833 }
834 if ($inlineFooterJs) {
835 $pageRenderer->addJsFooterInlineCode('TS_inlineFooter', $inlineFooterJs, $tsfe->config['config']['compressJs']);
836 }
837 } elseif ($tsfe->config['config']['removeDefaultJS'] === 'external') {
838 /*
839 * This keeps inlineJS from *_INT Objects from being moved to external files.
840 * At this point in frontend rendering *_INT Objects only have placeholders instead
841 * of actual content so moving these placeholders to external files would
842 * a) break the JS file (syntax errors due to the placeholders)
843 * b) the needed JS would never get included to the page
844 * Therefore inlineJS from *_INT Objects must not be moved to external files but
845 * kept internal.
846 */
847 $inlineJSint = '';
848 self::stripIntObjectPlaceholder($inlineJS, $inlineJSint);
849 if ($inlineJSint) {
850 $pageRenderer->addJsInlineCode('TS_inlineJSint', $inlineJSint, $tsfe->config['config']['compressJs']);
851 }
852 if (trim($scriptJsCode . $inlineJS)) {
853 $pageRenderer->addJsFile(self::inline2TempFile($scriptJsCode . $inlineJS, 'js'), 'text/javascript', $tsfe->config['config']['compressJs']);
854 }
855 if ($inlineFooterJs) {
856 $inlineFooterJSint = '';
857 self::stripIntObjectPlaceholder($inlineFooterJs, $inlineFooterJSint);
858 if ($inlineFooterJSint) {
859 $pageRenderer->addJsFooterInlineCode('TS_inlineFooterJSint', $inlineFooterJSint, $tsfe->config['config']['compressJs']);
860 }
861 $pageRenderer->addJsFooterFile(self::inline2TempFile($inlineFooterJs, 'js'), 'text/javascript', $tsfe->config['config']['compressJs']);
862 }
863 } else {
864 // Include only inlineJS
865 if ($inlineJS) {
866 $pageRenderer->addJsInlineCode('TS_inlineJS', $inlineJS, $tsfe->config['config']['compressJs']);
867 }
868 if ($inlineFooterJs) {
869 $pageRenderer->addJsFooterInlineCode('TS_inlineFooter', $inlineFooterJs, $tsfe->config['config']['compressJs']);
870 }
871 }
872 if (is_array($tsfe->pSetup['inlineLanguageLabelFiles.'])) {
873 foreach ($tsfe->pSetup['inlineLanguageLabelFiles.'] as $key => $languageFile) {
874 if (is_array($languageFile)) {
875 continue;
876 }
877 $languageFileConfig = &$tsfe->pSetup['inlineLanguageLabelFiles.'][$key . '.'];
878 if (isset($languageFileConfig['if.']) && !$tsfe->cObj->checkIf($languageFileConfig['if.'])) {
879 continue;
880 }
881 $pageRenderer->addInlineLanguageLabelFile(
882 $languageFile,
883 $languageFileConfig['selectionPrefix'] ?: '',
884 $languageFileConfig['stripFromSelectionName'] ?: '',
885 $languageFileConfig['errorMode'] ? (int)$languageFileConfig['errorMode'] : 0
886 );
887 }
888 }
889 // ExtJS specific code
890 if (is_array($tsfe->pSetup['inlineLanguageLabel.'])) {
891 $pageRenderer->addInlineLanguageLabelArray($tsfe->pSetup['inlineLanguageLabel.'], TRUE);
892 }
893 if (is_array($tsfe->pSetup['inlineSettings.'])) {
894 $pageRenderer->addInlineSettingArray('TS', $tsfe->pSetup['inlineSettings.']);
895 }
896 if (is_array($tsfe->pSetup['extOnReady.'])) {
897 $pageRenderer->addExtOnReadyCode($tsfe->cObj->cObjGet($tsfe->pSetup['extOnReady.'], 'extOnReady.'));
898 }
899 // Compression and concatenate settings
900 if ($tsfe->config['config']['compressCss']) {
901 $pageRenderer->enableCompressCss();
902 }
903 if ($tsfe->config['config']['compressJs']) {
904 $pageRenderer->enableCompressJavascript();
905 }
906 if ($tsfe->config['config']['concatenateCss']) {
907 $pageRenderer->enableConcatenateCss();
908 }
909 if ($tsfe->config['config']['concatenateJs']) {
910 $pageRenderer->enableConcatenateJavascript();
911 }
912 // Backward compatibility for old configuration
913 if ($tsfe->config['config']['concatenateJsAndCss']) {
914 $pageRenderer->enableConcatenateFiles();
915 }
916 // Add header data block
917 if ($tsfe->additionalHeaderData) {
918 $pageRenderer->addHeaderData(implode(LF, $tsfe->additionalHeaderData));
919 }
920 // Add footer data block
921 if ($tsfe->additionalFooterData) {
922 $pageRenderer->addFooterData(implode(LF, $tsfe->additionalFooterData));
923 }
924 // Header complete, now add content
925 if ($tsfe->pSetup['frameSet.']) {
926 $fs = GeneralUtility::makeInstance(FramesetRenderer::class);
927 $pageRenderer->addBodyContent($fs->make($tsfe->pSetup['frameSet.']));
928 $pageRenderer->addBodyContent(LF . '<noframes>' . LF);
929 }
930 // Bodytag:
931 if ($tsfe->config['config']['disableBodyTag']) {
932 $bodyTag = '';
933 } else {
934 $defBT = $tsfe->pSetup['bodyTagCObject'] ? $tsfe->cObj->cObjGetSingle($tsfe->pSetup['bodyTagCObject'], $tsfe->pSetup['bodyTagCObject.'], 'bodyTagCObject') : '';
935 if (!$defBT) {
936 $defBT = $tsfe->defaultBodyTag;
937 }
938 $bodyTag = $tsfe->pSetup['bodyTag'] ? $tsfe->pSetup['bodyTag'] : $defBT;
939 if ($bgImg = $tsfe->cObj->getImgResource($tsfe->pSetup['bgImg'], $tsfe->pSetup['bgImg.'])) {
940 GeneralUtility::deprecationLog('The option "page.bgImg" is deprecated since TYPO3 CMS 7, and will be removed with CMS 8');
941 $bodyTag = preg_replace('/>$/', '', trim($bodyTag)) . ' background="' . $tsfe->absRefPrefix . $bgImg[3] . '">';
942 }
943 if (isset($tsfe->pSetup['bodyTagMargins'])) {
944 $margins = (int)$tsfe->pSetup['bodyTagMargins'];
945 if ($tsfe->pSetup['bodyTagMargins.']['useCSS']) {
946
947 } else {
948 $bodyTag = preg_replace('/>$/', '', trim($bodyTag)) . ' leftmargin="' . $margins . '" topmargin="' . $margins . '" marginwidth="' . $margins . '" marginheight="' . $margins . '">';
949 }
950 }
951 if (trim($tsfe->pSetup['bodyTagAdd'])) {
952 $bodyTag = preg_replace('/>$/', '', trim($bodyTag)) . ' ' . trim($tsfe->pSetup['bodyTagAdd']) . '>';
953 }
954 // Event functions
955 if (!empty($JSef[1])) {
956 $bodyTag = preg_replace('/>$/', '', trim($bodyTag)) . ' ' . trim(implode(' ', $JSef[1])) . '>';
957 }
958 }
959 $pageRenderer->addBodyContent(LF . $bodyTag);
960 // Div-sections
961 if ($tsfe->divSection) {
962 $pageRenderer->addBodyContent(LF . $tsfe->divSection);
963 }
964 // Page content
965 $pageRenderer->addBodyContent(LF . $pageContent);
966 if (!empty($tsfe->config['INTincScript']) && is_array($tsfe->config['INTincScript'])) {
967 // Store the serialized pageRenderer in configuration
968 $tsfe->config['INTincScript_ext']['pageRenderer'] = serialize($pageRenderer);
969 // Render complete page, keep placeholders for JavaScript and CSS
970 $tsfe->content = $pageRenderer->renderPageWithUncachedObjects($tsfe->config['INTincScript_ext']['divKey']);
971 } else {
972 // Render complete page
973 $tsfe->content = $pageRenderer->render();
974 }
975 // Ending page
976 if ($tsfe->pSetup['frameSet.']) {
977 $tsfe->content .= LF . '</noframes>';
978 }
979 }
980
981 /*************************
982 *
983 * Helper functions
984 * Remember: Calls internally must still be done on the non-instantiated class: PageGenerator::inline2TempFile()
985 *
986 *************************/
987 /**
988 * Searches for placeholder created from *_INT cObjects, removes them from
989 * $searchString and merges them to $intObjects
990 *
991 * @param string $searchString The String which should be cleaned from int-object markers
992 * @param string $intObjects The String the found int-placeholders are moved to (for further processing)
993 */
994 static protected function stripIntObjectPlaceholder(&$searchString, &$intObjects) {
995 $tempArray = array();
996 preg_match_all('/\\<\\!--INT_SCRIPT.[a-z0-9]*--\\>/', $searchString, $tempArray);
997 $searchString = preg_replace('/\\<\\!--INT_SCRIPT.[a-z0-9]*--\\>/', '', $searchString);
998 $intObjects = implode('', $tempArray[0]);
999 }
1000
1001 /**
1002 * Writes string to a temporary file named after the md5-hash of the string
1003 *
1004 * @param string $str CSS styles / JavaScript to write to file.
1005 * @param string $ext Extension: "css" or "js
1006 * @return string <script> or <link> tag for the file.
1007 */
1008 static public function inline2TempFile($str, $ext) {
1009 // Create filename / tags:
1010 $script = '';
1011 switch ($ext) {
1012 case 'js':
1013 $script = 'typo3temp/javascript_' . substr(md5($str), 0, 10) . '.js';
1014 break;
1015 case 'css':
1016 $script = 'typo3temp/stylesheet_' . substr(md5($str), 0, 10) . '.css';
1017 break;
1018 }
1019 // Write file:
1020 if ($script) {
1021 if (!@is_file((PATH_site . $script))) {
1022 GeneralUtility::writeFile(PATH_site . $script, $str);
1023 }
1024 }
1025 return $script;
1026 }
1027
1028 /**
1029 * Checks if the value defined in "config.linkVars" contains an allowed value. Otherwise, return FALSE which means the value will not be added to any links.
1030 *
1031 * @param string $haystack The string in which to find $needle
1032 * @param string $needle The string to find in $haystack
1033 * @return bool Returns TRUE if $needle matches or is found in $haystack
1034 */
1035 static public function isAllowedLinkVarValue($haystack, $needle) {
1036 $OK = FALSE;
1037 // Integer
1038 if ($needle == 'int' || $needle == 'integer') {
1039 if (MathUtility::canBeInterpretedAsInteger($haystack)) {
1040 $OK = TRUE;
1041 }
1042 } elseif (preg_match('/^\\/.+\\/[imsxeADSUXu]*$/', $needle)) {
1043 // Regular expression, only "//" is allowed as delimiter
1044 if (@preg_match($needle, $haystack)) {
1045 $OK = TRUE;
1046 }
1047 } elseif (strstr($needle, '-')) {
1048 // Range
1049 if (MathUtility::canBeInterpretedAsInteger($haystack)) {
1050 $range = explode('-', $needle);
1051 if ($range[0] <= $haystack && $range[1] >= $haystack) {
1052 $OK = TRUE;
1053 }
1054 }
1055 } elseif (strstr($needle, '|')) {
1056 // List
1057 // Trim the input
1058 $haystack = str_replace(' ', '', $haystack);
1059 if (strstr('|' . $needle . '|', '|' . $haystack . '|')) {
1060 $OK = TRUE;
1061 }
1062 } elseif ((string)$needle === (string)$haystack) {
1063 // String comparison
1064 $OK = TRUE;
1065 }
1066 return $OK;
1067 }
1068
1069 /**
1070 * Generate title for page.
1071 * Takes the settings [config][noPageTitle], [config][pageTitleFirst], [config][titleTagFunction]
1072 * [config][pageTitleSeparator] and [config][noPageTitle] into account.
1073 * Furthermore $GLOBALS[TSFE]->altPageTitle is observed.
1074 *
1075 * @return void
1076 */
1077 static public function generatePageTitle() {
1078 /** @var TypoScriptFrontendController $tsfe */
1079 $tsfe = $GLOBALS['TSFE'];
1080
1081 $pageTitleSeparator = '';
1082
1083 // check for a custom pageTitleSeparator, and perform stdWrap on it
1084 if (isset($tsfe->config['config']['pageTitleSeparator']) && $tsfe->config['config']['pageTitleSeparator'] !== '') {
1085 $pageTitleSeparator = $tsfe->config['config']['pageTitleSeparator'];
1086
1087 if (isset($tsfe->config['config']['pageTitleSeparator.']) && is_array($tsfe->config['config']['pageTitleSeparator.'])) {
1088 $pageTitleSeparator = $tsfe->cObj->stdWrap($pageTitleSeparator, $tsfe->config['config']['pageTitleSeparator.']);
1089 } else {
1090 $pageTitleSeparator .= ' ';
1091 }
1092 }
1093
1094 $titleTagContent = $tsfe->tmpl->printTitle(
1095 $tsfe->altPageTitle ?: $tsfe->page['title'],
1096 $tsfe->config['config']['noPageTitle'],
1097 $tsfe->config['config']['pageTitleFirst'],
1098 $pageTitleSeparator
1099 );
1100 if ($tsfe->config['config']['titleTagFunction']) {
1101 $titleTagContent = $tsfe->cObj->callUserFunction(
1102 $tsfe->config['config']['titleTagFunction'],
1103 array(),
1104 $titleTagContent
1105 );
1106 }
1107 // stdWrap around the title tag
1108 if (isset($tsfe->config['config']['pageTitle.']) && is_array($tsfe->config['config']['pageTitle.'])) {
1109 $titleTagContent = $tsfe->cObj->stdWrap($titleTagContent, $tsfe->config['config']['pageTitle.']);
1110 }
1111 if ($titleTagContent !== '' && (int)$tsfe->config['config']['noPageTitle'] !== self::NO_PAGE_TITLE) {
1112 static::getPageRenderer()->setTitle($titleTagContent);
1113 }
1114 }
1115
1116 /**
1117 * Generate meta tags from meta tag TypoScript
1118 *
1119 * @param array $metaTagTypoScript TypoScript configuration for meta tags (e.g. $GLOBALS['TSFE']->pSetup['meta.'])
1120 * @param bool $xhtml Whether xhtml tag-style should be used. (e.g. pass $GLOBALS['TSFE']->xhtmlVersion here)
1121 * @param ContentObjectRenderer $cObj
1122 * @return array Array of HTML meta tags
1123 */
1124 static protected function generateMetaTagHtml(array $metaTagTypoScript, $xhtml, ContentObjectRenderer $cObj) {
1125 // Add ending slash only to documents rendered as xhtml
1126 $endingSlash = $xhtml ? ' /' : '';
1127
1128 $metaTags = array(
1129 '<meta name="generator" content="TYPO3 CMS"' . $endingSlash . '>'
1130 );
1131
1132 /** @var TypoScriptService $typoScriptService */
1133 $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
1134 $conf = $typoScriptService->convertTypoScriptArrayToPlainArray($metaTagTypoScript);
1135 foreach ($conf as $key => $properties) {
1136 if (is_array($properties)) {
1137 $nodeValue = isset($properties['_typoScriptNodeValue']) ? $properties['_typoScriptNodeValue'] : '';
1138 $value = trim($cObj->stdWrap($nodeValue, $metaTagTypoScript[$key . '.']));
1139 if ($value === '' && !empty($properties['value'])) {
1140 $value = $properties['value'];
1141 }
1142 } else {
1143 $value = $properties;
1144 }
1145
1146 $attribute = 'name';
1147 if ((is_array($properties) && !empty($properties['httpEquivalent'])) || strtolower($key) === 'refresh') {
1148 $attribute = 'http-equiv';
1149 }
1150 if (is_array($properties) && !empty($properties['attribute'])) {
1151 $attribute = $properties['attribute'];
1152 }
1153
1154 if (!is_array($value)) {
1155 $value = (array)$value;
1156 }
1157 foreach ($value as $subValue) {
1158 if (trim($subValue) !== '') {
1159 $metaTags[] = '<meta ' . $attribute . '="' . $key . '" content="' . htmlspecialchars($subValue) . '"' . $endingSlash . '>';
1160 }
1161 }
1162 }
1163 return $metaTags;
1164 }
1165
1166 /**
1167 * Fills the sWordList property and builds the regular expression in TSFE that can be used to split
1168 * strings by the submitted search words.
1169 *
1170 * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::sWordList
1171 * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::sWordRegEx
1172 */
1173 static protected function initializeSearchWordDataInTsfe() {
1174 /** @var TypoScriptFrontendController $tsfe */
1175 $tsfe = $GLOBALS['TSFE'];
1176
1177 $tsfe->sWordRegEx = '';
1178 $tsfe->sWordList = GeneralUtility::_GP('sword_list');
1179 if (is_array($tsfe->sWordList)) {
1180 $space = !empty($tsfe->config['config']['sword_standAlone']) ? '[[:space:]]' : '';
1181 foreach ($tsfe->sWordList as $val) {
1182 if (trim($val) !== '') {
1183 $tsfe->sWordRegEx .= $space . preg_quote($val, '/') . $space . '|';
1184 }
1185 }
1186 $tsfe->sWordRegEx = rtrim($tsfe->sWordRegEx, '|');
1187 }
1188 }
1189
1190 /**
1191 * @return PageRenderer
1192 */
1193 static protected function getPageRenderer() {
1194 return GeneralUtility::makeInstance(PageRenderer::class);
1195 }
1196
1197 /**
1198 * Adds inline CSS code, by respecting the inlineStyle2TempFile option
1199 *
1200 * @param string $cssStyles the inline CSS styling
1201 * @param bool $excludeFromConcatenation option to see if it should be conctatenated
1202 * @param string $inlineBlockName the block name to add it
1203 */
1204 static protected function addCssToPageRenderer($cssStyles, $excludeFromConcatenation = FALSE, $inlineBlockName = 'TSFEinlineStyle') {
1205 if (empty($GLOBALS['TSFE']->config['config']['inlineStyle2TempFile'])) {
1206 self::getPageRenderer()->addCssInlineBlock($inlineBlockName, $cssStyles, !empty($GLOBALS['TSFE']->config['config']['compressCss']));
1207 } else {
1208 self::getPageRenderer()->addCssFile(
1209 self::inline2TempFile($cssStyles, 'css'),
1210 'stylesheet',
1211 'all',
1212 '',
1213 (bool)$GLOBALS['TSFE']->config['config']['compressCss'],
1214 FALSE,
1215 '',
1216 $excludeFromConcatenation
1217 );
1218 }
1219 }
1220 }