vendor/contao/core-bundle/src/Resources/contao/pages/PageRegular.php line 63

Open in your IDE?
  1. <?php
  2. /*
  3. * This file is part of Contao.
  4. *
  5. * (c) Leo Feyer
  6. *
  7. * @license LGPL-3.0-or-later
  8. */
  9. namespace Contao;
  10. use Contao\CoreBundle\EventListener\SubrequestCacheSubscriber;
  11. use Contao\CoreBundle\Exception\NoLayoutSpecifiedException;
  12. use Contao\CoreBundle\Framework\ContaoFramework;
  13. use Contao\CoreBundle\Routing\ResponseContext\HtmlHeadBag\HtmlHeadBag;
  14. use Contao\CoreBundle\Routing\ResponseContext\JsonLd\JsonLdManager;
  15. use Contao\CoreBundle\Routing\ResponseContext\ResponseContext;
  16. use Contao\CoreBundle\Util\LocaleUtil;
  17. use Symfony\Component\HttpFoundation\Response;
  18. /**
  19. * Provide methods to handle a regular front end page.
  20. */
  21. #[\AllowDynamicProperties]
  22. class PageRegular extends Frontend
  23. {
  24. /**
  25. * @var ResponseContext
  26. */
  27. protected $responseContext;
  28. /**
  29. * Generate a regular page
  30. *
  31. * @param PageModel $objPage
  32. * @param boolean $blnCheckRequest
  33. *
  34. * @deprecated Deprecated since Contao 4.9, to be removed in Contao 5; use
  35. * the PageRegular::getResponse() method instead
  36. */
  37. public function generate($objPage, $blnCheckRequest=false)
  38. {
  39. trigger_deprecation('contao/core-bundle', '4.9', 'Using PageRegular::generate() has been deprecated in Contao 4.9 and will be removed in Contao 5.0. Use the PageRegular::getResponse() method instead.');
  40. $this->prepare($objPage);
  41. $this->Template->output($blnCheckRequest);
  42. }
  43. /**
  44. * Return a response object
  45. *
  46. * @param PageModel $objPage
  47. * @param boolean $blnCheckRequest
  48. *
  49. * @return Response
  50. */
  51. public function getResponse($objPage, $blnCheckRequest=false)
  52. {
  53. $this->prepare($objPage);
  54. $response = $this->Template->getResponse($blnCheckRequest);
  55. // Allow subrequests on this controller (fragments) to dynamically influence the Cache-Control header
  56. $response->headers->set(SubrequestCacheSubscriber::MERGE_CACHE_HEADER, true);
  57. // Finalize the response context so it cannot be used anymore
  58. System::getContainer()->get('contao.routing.response_context_accessor')->finalizeCurrentContext($response);
  59. return $response;
  60. }
  61. /**
  62. * Generate a regular page
  63. *
  64. * @param PageModel $objPage
  65. *
  66. * @internal Do not call this method in your code. It will be made private in Contao 5.0.
  67. */
  68. protected function prepare($objPage)
  69. {
  70. $GLOBALS['TL_KEYWORDS'] = '';
  71. $GLOBALS['TL_LANGUAGE'] = LocaleUtil::formatAsLanguageTag($objPage->language);
  72. $locale = LocaleUtil::formatAsLocale($objPage->language);
  73. $container = System::getContainer();
  74. $container->get('translator')->setLocale($locale);
  75. $request = $container->get('request_stack')->getCurrentRequest();
  76. $request->setLocale($locale);
  77. $responseContextAccessor = System::getContainer()->get('contao.routing.response_context_accessor');
  78. if (!$this->responseContext = $responseContextAccessor->getResponseContext())
  79. {
  80. $this->responseContext = $container->get('contao.routing.response_context_factory')->createContaoWebpageResponseContext($objPage);
  81. }
  82. $blnShowUnpublished = $container->get('contao.security.token_checker')->isPreviewMode();
  83. System::loadLanguageFile('default');
  84. // Static URLs
  85. $this->setStaticUrls();
  86. // Get the page layout
  87. $objLayout = $this->getPageLayout($objPage);
  88. /** @var ThemeModel $objTheme */
  89. $objTheme = $objLayout->getRelated('pid');
  90. // Set the default image densities
  91. $container->get('contao.image.picture_factory')->setDefaultDensities($objLayout->defaultImageDensities);
  92. $container->get('contao.image.preview_factory')->setDefaultDensities($objLayout->defaultImageDensities);
  93. // Store the layout ID
  94. $objPage->layoutId = $objLayout->id;
  95. // Set the layout template and template group
  96. $objPage->template = $objLayout->template ?: 'fe_page';
  97. $objPage->templateGroup = $objTheme->templates ?? null;
  98. // Minify the markup
  99. $objPage->minifyMarkup = $objLayout->minifyMarkup;
  100. // Initialize the template
  101. $this->createTemplate($objPage, $objLayout);
  102. // Initialize modules and sections
  103. $arrCustomSections = array();
  104. $arrSections = array('header', 'left', 'right', 'main', 'footer');
  105. $arrModules = StringUtil::deserialize($objLayout->modules);
  106. $arrModuleIds = array();
  107. // Filter the disabled modules
  108. foreach ($arrModules as $module)
  109. {
  110. if ($module['enable'] ?? null)
  111. {
  112. $arrModuleIds[] = (int) $module['mod'];
  113. }
  114. }
  115. // Get all modules in a single DB query
  116. $objModules = ModuleModel::findMultipleByIds($arrModuleIds);
  117. if ($objModules !== null || \in_array(0, $arrModuleIds, true))
  118. {
  119. $arrMapper = array();
  120. // Create a mapper array in case a module is included more than once (see #4849)
  121. if ($objModules !== null)
  122. {
  123. while ($objModules->next())
  124. {
  125. $arrMapper[$objModules->id] = $objModules->current();
  126. }
  127. }
  128. foreach ($arrModules as $arrModule)
  129. {
  130. // Disabled module
  131. if (!$blnShowUnpublished && !($arrModule['enable'] ?? null))
  132. {
  133. continue;
  134. }
  135. // Replace the module ID with the module model
  136. if ($arrModule['mod'] > 0 && isset($arrMapper[$arrModule['mod']]))
  137. {
  138. $arrModule['mod'] = $arrMapper[$arrModule['mod']];
  139. }
  140. // Generate the modules
  141. if (\in_array($arrModule['col'], $arrSections))
  142. {
  143. // Filter active sections (see #3273)
  144. if ($objLayout->rows != '2rwh' && $objLayout->rows != '3rw' && $arrModule['col'] == 'header')
  145. {
  146. continue;
  147. }
  148. if ($objLayout->cols != '2cll' && $objLayout->cols != '3cl' && $arrModule['col'] == 'left')
  149. {
  150. continue;
  151. }
  152. if ($objLayout->cols != '2clr' && $objLayout->cols != '3cl' && $arrModule['col'] == 'right')
  153. {
  154. continue;
  155. }
  156. if ($objLayout->rows != '2rwf' && $objLayout->rows != '3rw' && $arrModule['col'] == 'footer')
  157. {
  158. continue;
  159. }
  160. $this->Template->{$arrModule['col']} .= $this->getFrontendModule($arrModule['mod'], $arrModule['col']);
  161. }
  162. else
  163. {
  164. if (!isset($arrCustomSections[$arrModule['col']]))
  165. {
  166. $arrCustomSections[$arrModule['col']] = '';
  167. }
  168. $arrCustomSections[$arrModule['col']] .= $this->getFrontendModule($arrModule['mod'], $arrModule['col']);
  169. }
  170. }
  171. }
  172. $this->Template->sections = $arrCustomSections;
  173. // Mark RTL languages (see #7171, #3360)
  174. if ((\ResourceBundle::create($locale, 'ICUDATA', true)['layout']['characters'] ?? null) == 'right-to-left')
  175. {
  176. $this->Template->isRTL = true;
  177. }
  178. // HOOK: modify the page or layout object
  179. if (isset($GLOBALS['TL_HOOKS']['generatePage']) && \is_array($GLOBALS['TL_HOOKS']['generatePage']))
  180. {
  181. foreach ($GLOBALS['TL_HOOKS']['generatePage'] as $callback)
  182. {
  183. $this->import($callback[0]);
  184. $this->{$callback[0]}->{$callback[1]}($objPage, $objLayout, $this);
  185. }
  186. }
  187. $headBag = $this->responseContext->get(HtmlHeadBag::class);
  188. // Set the page title and description AFTER the modules have been generated
  189. $this->Template->mainTitle = $objPage->rootPageTitle;
  190. $this->Template->pageTitle = htmlspecialchars($headBag->getTitle(), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5);
  191. // Remove shy-entities (see #2709)
  192. $this->Template->mainTitle = str_replace('[-]', '', $this->Template->mainTitle);
  193. $this->Template->pageTitle = str_replace('[-]', '', $this->Template->pageTitle);
  194. // Meta robots tag
  195. $this->Template->robots = htmlspecialchars($headBag->getMetaRobots(), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5);
  196. // Canonical
  197. if ($objPage->enableCanonical)
  198. {
  199. $this->Template->canonical = htmlspecialchars(
  200. str_replace(array('{', '}'), array('%7B', '%7D'), $headBag->getCanonicalUriForRequest($request)),
  201. ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5
  202. );
  203. }
  204. // Fall back to the default title tag
  205. if (!$objLayout->titleTag)
  206. {
  207. $objLayout->titleTag = '{{page::pageTitle}} - {{page::rootPageTitle}}';
  208. }
  209. // Assign the title and description
  210. $this->Template->title = strip_tags(System::getContainer()->get('contao.insert_tag.parser')->replaceInline($objLayout->titleTag));
  211. $this->Template->description = htmlspecialchars($headBag->getMetaDescription(), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5);
  212. // Body onload and body classes
  213. $this->Template->onload = trim($objLayout->onload);
  214. $this->Template->class = trim($objLayout->cssClass . ' ' . $objPage->cssClass);
  215. // Execute AFTER the modules have been generated and create footer scripts first
  216. $this->createFooterScripts($objLayout, $objPage);
  217. $this->createHeaderScripts($objPage, $objLayout);
  218. }
  219. /**
  220. * Get a page layout and return it as database result object
  221. *
  222. * @param PageModel $objPage
  223. *
  224. * @return LayoutModel
  225. */
  226. protected function getPageLayout($objPage)
  227. {
  228. $objLayout = LayoutModel::findByPk($objPage->layout);
  229. // Die if there is no layout
  230. if (null === $objLayout)
  231. {
  232. System::getContainer()->get('monolog.logger.contao.error')->error('Could not find layout ID "' . $objPage->layout . '"');
  233. throw new NoLayoutSpecifiedException('No layout specified');
  234. }
  235. $objPage->hasJQuery = $objLayout->addJQuery;
  236. $objPage->hasMooTools = $objLayout->addMooTools;
  237. // HOOK: modify the page or layout object (see #4736)
  238. if (isset($GLOBALS['TL_HOOKS']['getPageLayout']) && \is_array($GLOBALS['TL_HOOKS']['getPageLayout']))
  239. {
  240. foreach ($GLOBALS['TL_HOOKS']['getPageLayout'] as $callback)
  241. {
  242. $this->import($callback[0]);
  243. $this->{$callback[0]}->{$callback[1]}($objPage, $objLayout, $this);
  244. }
  245. }
  246. return $objLayout;
  247. }
  248. /**
  249. * Create a new template
  250. *
  251. * @param PageModel $objPage
  252. * @param LayoutModel $objLayout
  253. */
  254. protected function createTemplate($objPage, $objLayout)
  255. {
  256. $this->Template = new FrontendTemplate($objPage->template);
  257. $this->Template->viewport = '';
  258. $this->Template->framework = '';
  259. $arrFramework = StringUtil::deserialize($objLayout->framework);
  260. // Generate the CSS framework
  261. if (\is_array($arrFramework) && \in_array('layout.css', $arrFramework))
  262. {
  263. $strFramework = '';
  264. if (\in_array('responsive.css', $arrFramework))
  265. {
  266. $this->Template->viewport = '<meta name="viewport" content="width=device-width,initial-scale=1.0">' . "\n";
  267. }
  268. // Wrapper
  269. if ($objLayout->static)
  270. {
  271. $arrSize = StringUtil::deserialize($objLayout->width);
  272. if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  273. {
  274. $arrMargin = array('left'=>'0 auto 0 0', 'center'=>'0 auto', 'right'=>'0 0 0 auto');
  275. $strFramework .= sprintf('#wrapper{width:%s;margin:%s}', $arrSize['value'] . $arrSize['unit'], $arrMargin[$objLayout->align]);
  276. }
  277. }
  278. // Header
  279. if ($objLayout->rows == '2rwh' || $objLayout->rows == '3rw')
  280. {
  281. $arrSize = StringUtil::deserialize($objLayout->headerHeight);
  282. if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  283. {
  284. $strFramework .= sprintf('#header{height:%s}', $arrSize['value'] . $arrSize['unit']);
  285. }
  286. }
  287. $strContainer = '';
  288. // Left column
  289. if ($objLayout->cols == '2cll' || $objLayout->cols == '3cl')
  290. {
  291. $arrSize = StringUtil::deserialize($objLayout->widthLeft);
  292. if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  293. {
  294. $strFramework .= sprintf('#left{width:%s;right:%s}', $arrSize['value'] . $arrSize['unit'], $arrSize['value'] . $arrSize['unit']);
  295. $strContainer .= sprintf('padding-left:%s;', $arrSize['value'] . $arrSize['unit']);
  296. }
  297. }
  298. // Right column
  299. if ($objLayout->cols == '2clr' || $objLayout->cols == '3cl')
  300. {
  301. $arrSize = StringUtil::deserialize($objLayout->widthRight);
  302. if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  303. {
  304. $strFramework .= sprintf('#right{width:%s}', $arrSize['value'] . $arrSize['unit']);
  305. $strContainer .= sprintf('padding-right:%s;', $arrSize['value'] . $arrSize['unit']);
  306. }
  307. }
  308. // Main column
  309. if ($strContainer)
  310. {
  311. $strFramework .= sprintf('#container{%s}', substr($strContainer, 0, -1));
  312. }
  313. // Footer
  314. if ($objLayout->rows == '2rwf' || $objLayout->rows == '3rw')
  315. {
  316. $arrSize = StringUtil::deserialize($objLayout->footerHeight);
  317. if (isset($arrSize['value']) && $arrSize['value'] && $arrSize['value'] >= 0)
  318. {
  319. $strFramework .= sprintf('#footer{height:%s}', $arrSize['value'] . $arrSize['unit']);
  320. }
  321. }
  322. // Add the layout specific CSS
  323. if ($strFramework)
  324. {
  325. $this->Template->framework = Template::generateInlineStyle($strFramework) . "\n";
  326. }
  327. }
  328. // Overwrite the viewport tag (see #6251)
  329. if ($objLayout->viewport)
  330. {
  331. $this->Template->viewport = '<meta name="viewport" content="' . $objLayout->viewport . '">' . "\n";
  332. }
  333. $this->Template->mooScripts = '';
  334. // Make sure TL_JAVASCRIPT exists (see #4890)
  335. if (isset($GLOBALS['TL_JAVASCRIPT']) && \is_array($GLOBALS['TL_JAVASCRIPT']))
  336. {
  337. $arrAppendJs = $GLOBALS['TL_JAVASCRIPT'];
  338. $GLOBALS['TL_JAVASCRIPT'] = array();
  339. }
  340. else
  341. {
  342. $arrAppendJs = array();
  343. $GLOBALS['TL_JAVASCRIPT'] = array();
  344. }
  345. // jQuery scripts
  346. if ($objLayout->addJQuery)
  347. {
  348. $GLOBALS['TL_JAVASCRIPT'][] = 'assets/jquery/js/jquery.min.js|static';
  349. }
  350. // MooTools scripts
  351. if ($objLayout->addMooTools)
  352. {
  353. $GLOBALS['TL_JAVASCRIPT'][] = 'assets/mootools/js/mootools.min.js|static';
  354. }
  355. // Check whether TL_APPEND_JS exists (see #4890)
  356. if (!empty($arrAppendJs))
  357. {
  358. $GLOBALS['TL_JAVASCRIPT'] = array_merge($GLOBALS['TL_JAVASCRIPT'], $arrAppendJs);
  359. }
  360. // Initialize the sections
  361. $this->Template->header = '';
  362. $this->Template->left = '';
  363. $this->Template->main = '';
  364. $this->Template->right = '';
  365. $this->Template->footer = '';
  366. // Initialize the custom layout sections
  367. $this->Template->sections = array();
  368. $this->Template->positions = array();
  369. if ($objLayout->sections)
  370. {
  371. $arrPositions = array();
  372. $arrSections = StringUtil::deserialize($objLayout->sections);
  373. if (!empty($arrSections) && \is_array($arrSections))
  374. {
  375. foreach ($arrSections as $v)
  376. {
  377. $arrPositions[$v['position']][$v['id']] = $v;
  378. }
  379. }
  380. $this->Template->positions = $arrPositions;
  381. }
  382. // Add the check_cookies image and the request token script if needed
  383. if ($objPage->alwaysLoadFromCache)
  384. {
  385. $GLOBALS['TL_BODY'][] = sprintf('<img src="%s" width="1" height="1" class="invisible" alt aria-hidden="true" onload="this.parentNode.removeChild(this)">', System::getContainer()->get('router')->generate('contao_frontend_check_cookies'));
  386. $GLOBALS['TL_BODY'][] = sprintf('<script src="%s" async></script>', System::getContainer()->get('router')->generate('contao_frontend_request_token_script'));
  387. }
  388. // Default settings
  389. $this->Template->layout = $objLayout;
  390. $this->Template->language = $GLOBALS['TL_LANGUAGE'];
  391. $this->Template->charset = System::getContainer()->getParameter('kernel.charset');
  392. $this->Template->base = Environment::get('base');
  393. $this->Template->isRTL = false;
  394. }
  395. /**
  396. * Create all header scripts
  397. *
  398. * @param PageModel $objPage
  399. * @param LayoutModel $objLayout
  400. */
  401. protected function createHeaderScripts($objPage, $objLayout)
  402. {
  403. $strStyleSheets = '';
  404. $strCcStyleSheets = '';
  405. $arrStyleSheets = StringUtil::deserialize($objLayout->stylesheet);
  406. $arrFramework = StringUtil::deserialize($objLayout->framework);
  407. // Add the Contao CSS framework style sheets
  408. if (\is_array($arrFramework))
  409. {
  410. foreach ($arrFramework as $strFile)
  411. {
  412. if ($strFile != 'tinymce.css')
  413. {
  414. $GLOBALS['TL_FRAMEWORK_CSS'][] = 'assets/contao/css/' . basename($strFile, '.css') . '.min.css';
  415. }
  416. }
  417. }
  418. // Make sure TL_USER_CSS is set
  419. if (!isset($GLOBALS['TL_USER_CSS']) || !\is_array($GLOBALS['TL_USER_CSS']))
  420. {
  421. $GLOBALS['TL_USER_CSS'] = array();
  422. }
  423. // User style sheets
  424. if (\is_array($arrStyleSheets) && isset($arrStyleSheets[0]))
  425. {
  426. $objStylesheets = StyleSheetModel::findByIds($arrStyleSheets);
  427. if ($objStylesheets !== null)
  428. {
  429. while ($objStylesheets->next())
  430. {
  431. $media = implode(',', StringUtil::deserialize($objStylesheets->media));
  432. // Overwrite the media type with a custom media query
  433. if ($objStylesheets->mediaQuery)
  434. {
  435. $media = $objStylesheets->mediaQuery;
  436. }
  437. // Style sheets with a CC or a combination of font-face and media-type != all cannot be aggregated (see #5216)
  438. if ($objStylesheets->cc || ($objStylesheets->hasFontFace && $media != 'all'))
  439. {
  440. $strStyleSheet = '';
  441. // External style sheet
  442. if ($objStylesheets->type == 'external')
  443. {
  444. $objFile = FilesModel::findByPk($objStylesheets->singleSRC);
  445. if ($objFile !== null)
  446. {
  447. $strStyleSheet = Template::generateStyleTag(Controller::addFilesUrlTo($objFile->path), $media, null);
  448. }
  449. }
  450. else
  451. {
  452. $strStyleSheet = Template::generateStyleTag(Controller::addAssetsUrlTo('assets/css/' . $objStylesheets->name . '.css'), $media, max($objStylesheets->tstamp, $objStylesheets->tstamp2, $objStylesheets->tstamp3));
  453. }
  454. if ($objStylesheets->cc)
  455. {
  456. $strStyleSheet = '<!--[' . $objStylesheets->cc . ']>' . $strStyleSheet . '<![endif]-->';
  457. }
  458. $strCcStyleSheets .= $strStyleSheet . "\n";
  459. }
  460. elseif ($objStylesheets->type == 'external')
  461. {
  462. $objFile = FilesModel::findByPk($objStylesheets->singleSRC);
  463. if ($objFile !== null)
  464. {
  465. $GLOBALS['TL_USER_CSS'][] = $objFile->path . '|' . $media . '|static';
  466. }
  467. }
  468. else
  469. {
  470. $GLOBALS['TL_USER_CSS'][] = 'assets/css/' . $objStylesheets->name . '.css|' . $media . '|static|' . max($objStylesheets->tstamp, $objStylesheets->tstamp2, $objStylesheets->tstamp3);
  471. }
  472. }
  473. }
  474. }
  475. $arrExternal = StringUtil::deserialize($objLayout->external);
  476. // External style sheets
  477. if (!empty($arrExternal) && \is_array($arrExternal))
  478. {
  479. // Get the file entries from the database
  480. $objFiles = FilesModel::findMultipleByUuids($arrExternal);
  481. $projectDir = System::getContainer()->getParameter('kernel.project_dir');
  482. if ($objFiles !== null)
  483. {
  484. $arrFiles = array();
  485. while ($objFiles->next())
  486. {
  487. if (file_exists($projectDir . '/' . $objFiles->path))
  488. {
  489. $arrFiles[] = $objFiles->path . '|static';
  490. }
  491. }
  492. // Inject the external style sheets before or after the internal ones (see #6937)
  493. if ($objLayout->loadingOrder == 'external_first')
  494. {
  495. array_splice($GLOBALS['TL_USER_CSS'], 0, 0, $arrFiles);
  496. }
  497. else
  498. {
  499. array_splice($GLOBALS['TL_USER_CSS'], \count($GLOBALS['TL_USER_CSS']), 0, $arrFiles);
  500. }
  501. }
  502. }
  503. $nonce = ContaoFramework::getNonce();
  504. // Add a placeholder for dynamic style sheets (see #4203)
  505. $strStyleSheets .= "[[TL_CSS_$nonce]]";
  506. // Always add conditional style sheets at the end
  507. $strStyleSheets .= $strCcStyleSheets;
  508. // Add a placeholder for dynamic <head> tags (see #4203)
  509. $strHeadTags = "[[TL_HEAD_$nonce]]";
  510. // Add the analytics scripts
  511. if ($objLayout->analytics)
  512. {
  513. $arrAnalytics = StringUtil::deserialize($objLayout->analytics, true);
  514. foreach ($arrAnalytics as $strTemplate)
  515. {
  516. if ($strTemplate)
  517. {
  518. $objTemplate = new FrontendTemplate($strTemplate);
  519. $strHeadTags .= $objTemplate->parse();
  520. }
  521. }
  522. }
  523. // Add the user <head> tags
  524. if ($strHead = trim($objLayout->head ?? ''))
  525. {
  526. $strHeadTags .= $strHead . "\n";
  527. }
  528. $this->Template->stylesheets = $strStyleSheets;
  529. $this->Template->head = $strHeadTags;
  530. }
  531. /**
  532. * Create all footer scripts
  533. *
  534. * @param LayoutModel $objLayout
  535. * @param PageModel $objPage
  536. *
  537. * @todo Change the method signature to ($objPage, $objLayout) in Contao 5.0
  538. */
  539. protected function createFooterScripts($objLayout, $objPage = null)
  540. {
  541. $strScripts = '';
  542. $nonce = ContaoFramework::getNonce();
  543. // jQuery
  544. if ($objLayout->addJQuery)
  545. {
  546. $arrJquery = StringUtil::deserialize($objLayout->jquery, true);
  547. foreach ($arrJquery as $strTemplate)
  548. {
  549. if ($strTemplate)
  550. {
  551. $objTemplate = new FrontendTemplate($strTemplate);
  552. $strScripts .= $objTemplate->parse();
  553. }
  554. }
  555. // Add a placeholder for dynamic scripts (see #4203)
  556. $strScripts .= "[[TL_JQUERY_$nonce]]";
  557. }
  558. // MooTools
  559. if ($objLayout->addMooTools)
  560. {
  561. $arrMootools = StringUtil::deserialize($objLayout->mootools, true);
  562. foreach ($arrMootools as $strTemplate)
  563. {
  564. if ($strTemplate)
  565. {
  566. $objTemplate = new FrontendTemplate($strTemplate);
  567. $strScripts .= $objTemplate->parse();
  568. }
  569. }
  570. // Add a placeholder for dynamic scripts (see #4203)
  571. $strScripts .= "[[TL_MOOTOOLS_$nonce]]";
  572. }
  573. // Add the framework-agnostic JavaScripts
  574. if ($objLayout->scripts)
  575. {
  576. $arrScripts = StringUtil::deserialize($objLayout->scripts, true);
  577. foreach ($arrScripts as $strTemplate)
  578. {
  579. if ($strTemplate)
  580. {
  581. $objTemplate = new FrontendTemplate($strTemplate);
  582. $strScripts .= $objTemplate->parse();
  583. }
  584. }
  585. }
  586. // Add a placeholder for dynamic scripts (see #4203, #5583)
  587. $strScripts .= "[[TL_BODY_$nonce]]";
  588. // Add the external JavaScripts
  589. $arrExternalJs = StringUtil::deserialize($objLayout->externalJs);
  590. // Get the file entries from the database
  591. $objFiles = FilesModel::findMultipleByUuids($arrExternalJs);
  592. $projectDir = System::getContainer()->getParameter('kernel.project_dir');
  593. if ($objFiles !== null)
  594. {
  595. while ($objFiles->next())
  596. {
  597. if (file_exists($projectDir . '/' . $objFiles->path))
  598. {
  599. $strScripts .= Template::generateScriptTag($objFiles->path, false, null);
  600. }
  601. }
  602. }
  603. // Add the custom JavaScript
  604. if ($objLayout->script)
  605. {
  606. $strScripts .= "\n" . trim($objLayout->script) . "\n";
  607. }
  608. $this->Template->mootools = $strScripts;
  609. $this->Template->jsonLdScripts = function ()
  610. {
  611. if (!$this->responseContext->isInitialized(JsonLdManager::class))
  612. {
  613. return '';
  614. }
  615. /** @var JsonLdManager $jsonLdManager */
  616. $jsonLdManager = $this->responseContext->get(JsonLdManager::class);
  617. return $jsonLdManager->collectFinalScriptFromGraphs();
  618. };
  619. }
  620. }
  621. class_alias(PageRegular::class, 'PageRegular');