[!!!][TASK] Remove deprecated miscellaneous functions
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Page / PageRenderer.php
1 <?php
2 namespace TYPO3\CMS\Core\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\Backend\Routing\Router;
18 use TYPO3\CMS\Backend\Routing\UriBuilder;
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
20 use TYPO3\CMS\Core\Localization\LocalizationFactory;
21 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
24
25 /**
26 * TYPO3 pageRender class (new in TYPO3 4.3.0)
27 * This class render the HTML of a webpage, usable for BE and FE
28 */
29 class PageRenderer implements \TYPO3\CMS\Core\SingletonInterface
30 {
31 // Constants for the part to be rendered
32 const PART_COMPLETE = 0;
33 const PART_HEADER = 1;
34 const PART_FOOTER = 2;
35 // jQuery Core version that is shipped with TYPO3
36 const JQUERY_VERSION_LATEST = '2.1.4';
37 // jQuery namespace options
38 const JQUERY_NAMESPACE_NONE = 'none';
39 const JQUERY_NAMESPACE_DEFAULT = 'jQuery';
40 const JQUERY_NAMESPACE_DEFAULT_NOCONFLICT = 'defaultNoConflict';
41
42 /**
43 * @var bool
44 */
45 protected $compressJavascript = false;
46
47 /**
48 * @var bool
49 */
50 protected $compressCss = false;
51
52 /**
53 * @var bool
54 */
55 protected $removeLineBreaksFromTemplate = false;
56
57 /**
58 * @var bool
59 */
60 protected $concatenateFiles = false;
61
62 /**
63 * @var bool
64 */
65 protected $concatenateJavascript = false;
66
67 /**
68 * @var bool
69 */
70 protected $concatenateCss = false;
71
72 /**
73 * @var bool
74 */
75 protected $moveJsFromHeaderToFooter = false;
76
77 /**
78 * @var \TYPO3\CMS\Core\Charset\CharsetConverter
79 */
80 protected $csConvObj;
81
82 /**
83 * @var \TYPO3\CMS\Core\Localization\Locales
84 */
85 protected $locales;
86
87 /**
88 * The language key
89 * Two character string or 'default'
90 *
91 * @var string
92 */
93 protected $lang;
94
95 /**
96 * List of language dependencies for actual language. This is used for local variants of a language
97 * that depend on their "main" language, like Brazilian Portuguese or Canadian French.
98 *
99 * @var array
100 */
101 protected $languageDependencies = array();
102
103 /**
104 * @var \TYPO3\CMS\Core\Resource\ResourceCompressor
105 */
106 protected $compressor;
107
108 // Arrays containing associative array for the included files
109 /**
110 * @var array
111 */
112 protected $jsFiles = array();
113
114 /**
115 * @var array
116 */
117 protected $jsFooterFiles = array();
118
119 /**
120 * @var array
121 */
122 protected $jsLibs = array();
123
124 /**
125 * @var array
126 */
127 protected $jsFooterLibs = array();
128
129 /**
130 * @var array
131 */
132 protected $cssFiles = array();
133
134 /**
135 * @var array
136 */
137 protected $cssLibs = array();
138
139 /**
140 * The title of the page
141 *
142 * @var string
143 */
144 protected $title;
145
146 /**
147 * Charset for the rendering
148 *
149 * @var string
150 */
151 protected $charSet;
152
153 /**
154 * @var string
155 */
156 protected $favIcon;
157
158 /**
159 * @var string
160 */
161 protected $baseUrl;
162
163 /**
164 * @var bool
165 */
166 protected $renderXhtml = true;
167
168 // Static header blocks
169 /**
170 * @var string
171 */
172 protected $xmlPrologAndDocType = '';
173
174 /**
175 * @var array
176 */
177 protected $metaTags = array();
178
179 /**
180 * @var array
181 */
182 protected $inlineComments = array();
183
184 /**
185 * @var array
186 */
187 protected $headerData = array();
188
189 /**
190 * @var array
191 */
192 protected $footerData = array();
193
194 /**
195 * @var string
196 */
197 protected $titleTag = '<title>|</title>';
198
199 /**
200 * @var string
201 */
202 protected $metaCharsetTag = '<meta http-equiv="Content-Type" content="text/html; charset=|" />';
203
204 /**
205 * @var string
206 */
207 protected $htmlTag = '<html>';
208
209 /**
210 * @var string
211 */
212 protected $headTag = '<head>';
213
214 /**
215 * @var string
216 */
217 protected $baseUrlTag = '<base href="|" />';
218
219 /**
220 * @var string
221 */
222 protected $iconMimeType = '';
223
224 /**
225 * @var string
226 */
227 protected $shortcutTag = '<link rel="shortcut icon" href="%1$s"%2$s />';
228
229 // Static inline code blocks
230 /**
231 * @var array
232 */
233 protected $jsInline = array();
234
235 /**
236 * @var array
237 */
238 protected $jsFooterInline = array();
239
240 /**
241 * @var array
242 */
243 protected $extOnReadyCode = array();
244
245 /**
246 * @var array
247 */
248 protected $cssInline = array();
249
250 /**
251 * @var string
252 */
253 protected $bodyContent;
254
255 /**
256 * @var string
257 */
258 protected $templateFile;
259
260 /**
261 * @var array
262 */
263 protected $jsLibraryNames = array('extjs');
264
265 // Paths to contibuted libraries
266
267 /**
268 * default path to the requireJS library, relative to the typo3/ directory
269 * @var string
270 */
271 protected $requireJsPath = 'sysext/core/Resources/Public/JavaScript/Contrib/';
272
273 /**
274 * @var string
275 */
276 protected $extJsPath = 'sysext/core/Resources/Public/JavaScript/Contrib/extjs/';
277
278 /**
279 * The local directory where one can find jQuery versions and plugins
280 *
281 * @var string
282 */
283 protected $jQueryPath = 'sysext/core/Resources/Public/JavaScript/Contrib/jquery/';
284
285 // Internal flags for JS-libraries
286 /**
287 * This array holds all jQuery versions that should be included in the
288 * current page.
289 * Each version is described by "source", "version" and "namespace"
290 *
291 * The namespace of every particular version is the key
292 * of that array, because only one version per namespace can exist.
293 *
294 * The type "source" describes where the jQuery core should be included from
295 * currently, TYPO3 supports "local" (make use of jQuery path), "google",
296 * "jquery", "msn" and "cloudflare".
297 *
298 * Currently there are downsides to "local" which supports only the latest/shipped
299 * jQuery core out of the box.
300 *
301 * @var array
302 */
303 protected $jQueryVersions = array();
304
305 /**
306 * Array of jQuery version numbers shipped with the core
307 *
308 * @var array
309 */
310 protected $availableLocalJqueryVersions = array(
311 self::JQUERY_VERSION_LATEST
312 );
313
314 /**
315 * Array of jQuery CDNs with placeholders
316 *
317 * @var array
318 */
319 protected $jQueryCdnUrls = array(
320 'google' => 'https://ajax.googleapis.com/ajax/libs/jquery/%1$s/jquery%2$s.js',
321 'msn' => 'https://ajax.aspnetcdn.com/ajax/jQuery/jquery-%1$s%2$s.js',
322 'jquery' => 'https://code.jquery.com/jquery-%1$s%2$s.js',
323 'cloudflare' => 'https://cdnjs.cloudflare.com/ajax/libs/jquery/%1$s/jquery%2$s.js'
324 );
325
326 /**
327 * if set, the requireJS library is included
328 * @var bool
329 */
330 protected $addRequireJs = false;
331
332 /**
333 * inline configuration for requireJS
334 * @var array
335 */
336 protected $requireJsConfig = array();
337
338 /**
339 * @var bool
340 */
341 protected $addExtJS = false;
342
343 /**
344 * @var bool
345 */
346 protected $extDirectCodeAdded = false;
347
348 /**
349 * @var bool
350 */
351 protected $enableExtJsDebug = false;
352
353 /**
354 * @var bool
355 */
356 protected $enableJqueryDebug = false;
357
358 /**
359 * @var bool
360 */
361 protected $extJStheme = true;
362
363 /**
364 * @var bool
365 */
366 protected $extJScss = true;
367
368 /**
369 * @var array
370 */
371 protected $inlineLanguageLabels = array();
372
373 /**
374 * @var array
375 */
376 protected $inlineLanguageLabelFiles = array();
377
378 /**
379 * @var array
380 */
381 protected $inlineSettings = array();
382
383 /**
384 * @var array
385 */
386 protected $inlineJavascriptWrap = array();
387
388 /**
389 * Saves error messages generated during compression
390 *
391 * @var string
392 */
393 protected $compressError = '';
394
395 /**
396 * Is empty string for HTML and ' /' for XHTML rendering
397 *
398 * @var string
399 */
400 protected $endingSlash = '';
401
402 /**
403 * Used by BE modules
404 *
405 * @var null|string
406 */
407 public $backPath;
408
409 /**
410 * @param string $templateFile Declare the used template file. Omit this parameter will use default template
411 * @param string $backPath Relative path to typo3-folder. It varies for BE modules, in FE it will be typo3/
412 */
413 public function __construct($templateFile = '', $backPath = null)
414 {
415 $this->reset();
416 $this->csConvObj = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Charset\CharsetConverter::class);
417 $this->locales = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Localization\Locales::class);
418 if ($templateFile !== '') {
419 $this->templateFile = $templateFile;
420 }
421 $this->backPath = isset($backPath) ? $backPath : $GLOBALS['BACK_PATH'];
422 $this->inlineJavascriptWrap = array(
423 '<script type="text/javascript">' . LF . '/*<![CDATA[*/' . LF,
424 '/*]]>*/' . LF . '</script>' . LF
425 );
426 $this->inlineCssWrap = array(
427 '<style type="text/css">' . LF . '/*<![CDATA[*/' . LF . '<!-- ' . LF,
428 '-->' . LF . '/*]]>*/' . LF . '</style>' . LF
429 );
430 }
431
432 /**
433 * Reset all vars to initial values
434 *
435 * @return void
436 */
437 protected function reset()
438 {
439 $this->templateFile = 'EXT:core/Resources/Private/Templates/PageRenderer.html';
440 $this->jsFiles = array();
441 $this->jsFooterFiles = array();
442 $this->jsInline = array();
443 $this->jsFooterInline = array();
444 $this->jsLibs = array();
445 $this->cssFiles = array();
446 $this->cssInline = array();
447 $this->metaTags = array();
448 $this->inlineComments = array();
449 $this->headerData = array();
450 $this->footerData = array();
451 $this->extOnReadyCode = array();
452 $this->jQueryVersions = array();
453 }
454
455 /*****************************************************/
456 /* */
457 /* Public Setters */
458 /* */
459 /* */
460 /*****************************************************/
461 /**
462 * Sets the title
463 *
464 * @param string $title title of webpage
465 * @return void
466 */
467 public function setTitle($title)
468 {
469 $this->title = $title;
470 }
471
472 /**
473 * Enables/disables rendering of XHTML code
474 *
475 * @param bool $enable Enable XHTML
476 * @return void
477 */
478 public function setRenderXhtml($enable)
479 {
480 $this->renderXhtml = $enable;
481 }
482
483 /**
484 * Sets xml prolog and docType
485 *
486 * @param string $xmlPrologAndDocType Complete tags for xml prolog and docType
487 * @return void
488 */
489 public function setXmlPrologAndDocType($xmlPrologAndDocType)
490 {
491 $this->xmlPrologAndDocType = $xmlPrologAndDocType;
492 }
493
494 /**
495 * Sets meta charset
496 *
497 * @param string $charSet Used charset
498 * @return void
499 */
500 public function setCharSet($charSet)
501 {
502 $this->charSet = $charSet;
503 }
504
505 /**
506 * Sets language
507 *
508 * @param string $lang Used language
509 * @return void
510 */
511 public function setLanguage($lang)
512 {
513 $this->lang = $lang;
514 $this->languageDependencies = array();
515
516 // Language is found. Configure it:
517 if (in_array($this->lang, $this->locales->getLocales())) {
518 $this->languageDependencies[] = $this->lang;
519 foreach ($this->locales->getLocaleDependencies($this->lang) as $language) {
520 $this->languageDependencies[] = $language;
521 }
522 }
523 }
524
525 /**
526 * Set the meta charset tag
527 *
528 * @param string $metaCharsetTag
529 * @return void
530 */
531 public function setMetaCharsetTag($metaCharsetTag)
532 {
533 $this->metaCharsetTag = $metaCharsetTag;
534 }
535
536 /**
537 * Sets html tag
538 *
539 * @param string $htmlTag Html tag
540 * @return void
541 */
542 public function setHtmlTag($htmlTag)
543 {
544 $this->htmlTag = $htmlTag;
545 }
546
547 /**
548 * Sets HTML head tag
549 *
550 * @param string $headTag HTML head tag
551 * @return void
552 */
553 public function setHeadTag($headTag)
554 {
555 $this->headTag = $headTag;
556 }
557
558 /**
559 * Sets favicon
560 *
561 * @param string $favIcon
562 * @return void
563 */
564 public function setFavIcon($favIcon)
565 {
566 $this->favIcon = $favIcon;
567 }
568
569 /**
570 * Sets icon mime type
571 *
572 * @param string $iconMimeType
573 * @return void
574 */
575 public function setIconMimeType($iconMimeType)
576 {
577 $this->iconMimeType = $iconMimeType;
578 }
579
580 /**
581 * Sets HTML base URL
582 *
583 * @param string $baseUrl HTML base URL
584 * @return void
585 */
586 public function setBaseUrl($baseUrl)
587 {
588 $this->baseUrl = $baseUrl;
589 }
590
591 /**
592 * Sets template file
593 *
594 * @param string $file
595 * @return void
596 */
597 public function setTemplateFile($file)
598 {
599 $this->templateFile = $file;
600 }
601
602 /**
603 * Sets back path
604 *
605 * @param string $backPath
606 * @return void
607 */
608 public function setBackPath($backPath)
609 {
610 $this->backPath = $backPath;
611 }
612
613 /**
614 * Sets Content for Body
615 *
616 * @param string $content
617 * @return void
618 */
619 public function setBodyContent($content)
620 {
621 $this->bodyContent = $content;
622 }
623
624 /**
625 * Sets path to requireJS library (relative to typo3 directory)
626 *
627 * @param string $path Path to requireJS library
628 * @return void
629 */
630 public function setRequireJsPath($path)
631 {
632 $this->requireJsPath = $path;
633 }
634
635 /**
636 * Sets Path for ExtJs library (relative to typo3 directory)
637 *
638 * @param string $path
639 * @return void
640 */
641 public function setExtJsPath($path)
642 {
643 $this->extJsPath = $path;
644 }
645
646 /*****************************************************/
647 /* */
648 /* Public Enablers / Disablers */
649 /* */
650 /* */
651 /*****************************************************/
652 /**
653 * Enables MoveJsFromHeaderToFooter
654 *
655 * @return void
656 */
657 public function enableMoveJsFromHeaderToFooter()
658 {
659 $this->moveJsFromHeaderToFooter = true;
660 }
661
662 /**
663 * Disables MoveJsFromHeaderToFooter
664 *
665 * @return void
666 */
667 public function disableMoveJsFromHeaderToFooter()
668 {
669 $this->moveJsFromHeaderToFooter = false;
670 }
671
672 /**
673 * Enables compression of javascript
674 *
675 * @return void
676 */
677 public function enableCompressJavascript()
678 {
679 $this->compressJavascript = true;
680 }
681
682 /**
683 * Disables compression of javascript
684 *
685 * @return void
686 */
687 public function disableCompressJavascript()
688 {
689 $this->compressJavascript = false;
690 }
691
692 /**
693 * Enables compression of css
694 *
695 * @return void
696 */
697 public function enableCompressCss()
698 {
699 $this->compressCss = true;
700 }
701
702 /**
703 * Disables compression of css
704 *
705 * @return void
706 */
707 public function disableCompressCss()
708 {
709 $this->compressCss = false;
710 }
711
712 /**
713 * Enables concatenation of js and css files
714 *
715 * @return void
716 */
717 public function enableConcatenateFiles()
718 {
719 $this->concatenateFiles = true;
720 }
721
722 /**
723 * Disables concatenation of js and css files
724 *
725 * @return void
726 */
727 public function disableConcatenateFiles()
728 {
729 $this->concatenateFiles = false;
730 }
731
732 /**
733 * Enables concatenation of js files
734 *
735 * @return void
736 */
737 public function enableConcatenateJavascript()
738 {
739 $this->concatenateJavascript = true;
740 }
741
742 /**
743 * Disables concatenation of js files
744 *
745 * @return void
746 */
747 public function disableConcatenateJavascript()
748 {
749 $this->concatenateJavascript = false;
750 }
751
752 /**
753 * Enables concatenation of css files
754 *
755 * @return void
756 */
757 public function enableConcatenateCss()
758 {
759 $this->concatenateCss = true;
760 }
761
762 /**
763 * Disables concatenation of css files
764 *
765 * @return void
766 */
767 public function disableConcatenateCss()
768 {
769 $this->concatenateCss = false;
770 }
771
772 /**
773 * Sets removal of all line breaks in template
774 *
775 * @return void
776 */
777 public function enableRemoveLineBreaksFromTemplate()
778 {
779 $this->removeLineBreaksFromTemplate = true;
780 }
781
782 /**
783 * Unsets removal of all line breaks in template
784 *
785 * @return void
786 */
787 public function disableRemoveLineBreaksFromTemplate()
788 {
789 $this->removeLineBreaksFromTemplate = false;
790 }
791
792 /**
793 * Enables Debug Mode
794 * This is a shortcut to switch off all compress/concatenate features to enable easier debug
795 *
796 * @return void
797 */
798 public function enableDebugMode()
799 {
800 $this->compressJavascript = false;
801 $this->compressCss = false;
802 $this->concatenateFiles = false;
803 $this->removeLineBreaksFromTemplate = false;
804 $this->enableExtJsDebug = true;
805 $this->enableJqueryDebug = true;
806 }
807
808 /*****************************************************/
809 /* */
810 /* Public Getters */
811 /* */
812 /* */
813 /*****************************************************/
814 /**
815 * Gets the title
816 *
817 * @return string $title Title of webpage
818 */
819 public function getTitle()
820 {
821 return $this->title;
822 }
823
824 /**
825 * Gets the charSet
826 *
827 * @return string $charSet
828 */
829 public function getCharSet()
830 {
831 return $this->charSet;
832 }
833
834 /**
835 * Gets the language
836 *
837 * @return string $lang
838 */
839 public function getLanguage()
840 {
841 return $this->lang;
842 }
843
844 /**
845 * Returns rendering mode XHTML or HTML
846 *
847 * @return bool TRUE if XHTML, FALSE if HTML
848 */
849 public function getRenderXhtml()
850 {
851 return $this->renderXhtml;
852 }
853
854 /**
855 * Gets html tag
856 *
857 * @return string $htmlTag Html tag
858 */
859 public function getHtmlTag()
860 {
861 return $this->htmlTag;
862 }
863
864 /**
865 * Get meta charset
866 *
867 * @return string
868 */
869 public function getMetaCharsetTag()
870 {
871 return $this->metaCharsetTag;
872 }
873
874 /**
875 * Gets head tag
876 *
877 * @return string $tag Head tag
878 */
879 public function getHeadTag()
880 {
881 return $this->headTag;
882 }
883
884 /**
885 * Gets favicon
886 *
887 * @return string $favIcon
888 */
889 public function getFavIcon()
890 {
891 return $this->favIcon;
892 }
893
894 /**
895 * Gets icon mime type
896 *
897 * @return string $iconMimeType
898 */
899 public function getIconMimeType()
900 {
901 return $this->iconMimeType;
902 }
903
904 /**
905 * Gets HTML base URL
906 *
907 * @return string $url
908 */
909 public function getBaseUrl()
910 {
911 return $this->baseUrl;
912 }
913
914 /**
915 * Gets template file
916 *
917 * @return string
918 */
919 public function getTemplateFile()
920 {
921 return $this->templateFile;
922 }
923
924 /**
925 * Gets MoveJsFromHeaderToFooter
926 *
927 * @return bool
928 */
929 public function getMoveJsFromHeaderToFooter()
930 {
931 return $this->moveJsFromHeaderToFooter;
932 }
933
934 /**
935 * Gets compress of javascript
936 *
937 * @return bool
938 */
939 public function getCompressJavascript()
940 {
941 return $this->compressJavascript;
942 }
943
944 /**
945 * Gets compress of css
946 *
947 * @return bool
948 */
949 public function getCompressCss()
950 {
951 return $this->compressCss;
952 }
953
954 /**
955 * Gets concatenate of js and css files
956 *
957 * @return bool
958 */
959 public function getConcatenateFiles()
960 {
961 return $this->concatenateFiles;
962 }
963
964 /**
965 * Gets concatenate of js files
966 *
967 * @return bool
968 */
969 public function getConcatenateJavascript()
970 {
971 return $this->concatenateJavascript;
972 }
973
974 /**
975 * Gets concatenate of css files
976 *
977 * @return bool
978 */
979 public function getConcatenateCss()
980 {
981 return $this->concatenateCss;
982 }
983
984 /**
985 * Gets remove of empty lines from template
986 *
987 * @return bool
988 */
989 public function getRemoveLineBreaksFromTemplate()
990 {
991 return $this->removeLineBreaksFromTemplate;
992 }
993
994 /**
995 * Gets content for body
996 *
997 * @return string
998 */
999 public function getBodyContent()
1000 {
1001 return $this->bodyContent;
1002 }
1003
1004 /**
1005 * Gets Path for ExtJs library (relative to typo3 directory)
1006 *
1007 * @return string
1008 */
1009 public function getExtJsPath()
1010 {
1011 return $this->extJsPath;
1012 }
1013
1014 /**
1015 * Gets the inline language labels.
1016 *
1017 * @return array The inline language labels
1018 */
1019 public function getInlineLanguageLabels()
1020 {
1021 return $this->inlineLanguageLabels;
1022 }
1023
1024 /**
1025 * Gets the inline language files
1026 *
1027 * @return array
1028 */
1029 public function getInlineLanguageLabelFiles()
1030 {
1031 return $this->inlineLanguageLabelFiles;
1032 }
1033
1034 /*****************************************************/
1035 /* */
1036 /* Public Functions to add Data */
1037 /* */
1038 /* */
1039 /*****************************************************/
1040 /**
1041 * Adds meta data
1042 *
1043 * @param string $meta Meta data (complete metatag)
1044 * @return void
1045 */
1046 public function addMetaTag($meta)
1047 {
1048 if (!in_array($meta, $this->metaTags)) {
1049 $this->metaTags[] = $meta;
1050 }
1051 }
1052
1053 /**
1054 * Adds inline HTML comment
1055 *
1056 * @param string $comment
1057 * @return void
1058 */
1059 public function addInlineComment($comment)
1060 {
1061 if (!in_array($comment, $this->inlineComments)) {
1062 $this->inlineComments[] = $comment;
1063 }
1064 }
1065
1066 /**
1067 * Adds header data
1068 *
1069 * @param string $data Free header data for HTML header
1070 * @return void
1071 */
1072 public function addHeaderData($data)
1073 {
1074 if (!in_array($data, $this->headerData)) {
1075 $this->headerData[] = $data;
1076 }
1077 }
1078
1079 /**
1080 * Adds footer data
1081 *
1082 * @param string $data Free header data for HTML header
1083 * @return void
1084 */
1085 public function addFooterData($data)
1086 {
1087 if (!in_array($data, $this->footerData)) {
1088 $this->footerData[] = $data;
1089 }
1090 }
1091
1092 /**
1093 * Adds JS Library. JS Library block is rendered on top of the JS files.
1094 *
1095 * @param string $name Arbitrary identifier
1096 * @param string $file File name
1097 * @param string $type Content Type
1098 * @param bool $compress Flag if library should be compressed
1099 * @param bool $forceOnTop Flag if added library should be inserted at begin of this block
1100 * @param string $allWrap
1101 * @param bool $excludeFromConcatenation
1102 * @param string $splitChar The char used to split the allWrap value, default is "|"
1103 * @param bool $async Flag if property 'async="async"' should be added to JavaScript tags
1104 * @param string $integrity Subresource Integrity (SRI)
1105 * @return void
1106 */
1107 public function addJsLibrary($name, $file, $type = 'text/javascript', $compress = false, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '')
1108 {
1109 if (!$type) {
1110 $type = 'text/javascript';
1111 }
1112 if (!in_array(strtolower($name), $this->jsLibs)) {
1113 $this->jsLibs[strtolower($name)] = array(
1114 'file' => $file,
1115 'type' => $type,
1116 'section' => self::PART_HEADER,
1117 'compress' => $compress,
1118 'forceOnTop' => $forceOnTop,
1119 'allWrap' => $allWrap,
1120 'excludeFromConcatenation' => $excludeFromConcatenation,
1121 'splitChar' => $splitChar,
1122 'async' => $async,
1123 'integrity' => $integrity,
1124 );
1125 }
1126 }
1127
1128 /**
1129 * Adds JS Library to Footer. JS Library block is rendered on top of the Footer JS files.
1130 *
1131 * @param string $name Arbitrary identifier
1132 * @param string $file File name
1133 * @param string $type Content Type
1134 * @param bool $compress Flag if library should be compressed
1135 * @param bool $forceOnTop Flag if added library should be inserted at begin of this block
1136 * @param string $allWrap
1137 * @param bool $excludeFromConcatenation
1138 * @param string $splitChar The char used to split the allWrap value, default is "|"
1139 * @param bool $async Flag if property 'async="async"' should be added to JavaScript tags
1140 * @param string $integrity Subresource Integrity (SRI)
1141 * @return void
1142 */
1143 public function addJsFooterLibrary($name, $file, $type = 'text/javascript', $compress = false, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '')
1144 {
1145 if (!$type) {
1146 $type = 'text/javascript';
1147 }
1148 if (!in_array(strtolower($name), $this->jsLibs)) {
1149 $this->jsLibs[strtolower($name)] = array(
1150 'file' => $file,
1151 'type' => $type,
1152 'section' => self::PART_FOOTER,
1153 'compress' => $compress,
1154 'forceOnTop' => $forceOnTop,
1155 'allWrap' => $allWrap,
1156 'excludeFromConcatenation' => $excludeFromConcatenation,
1157 'splitChar' => $splitChar,
1158 'async' => $async,
1159 'integrity' => $integrity,
1160 );
1161 }
1162 }
1163
1164 /**
1165 * Adds JS file
1166 *
1167 * @param string $file File name
1168 * @param string $type Content Type
1169 * @param bool $compress
1170 * @param bool $forceOnTop
1171 * @param string $allWrap
1172 * @param bool $excludeFromConcatenation
1173 * @param string $splitChar The char used to split the allWrap value, default is "|"
1174 * @param bool $async Flag if property 'async="async"' should be added to JavaScript tags
1175 * @param string $integrity Subresource Integrity (SRI)
1176 * @return void
1177 */
1178 public function addJsFile($file, $type = 'text/javascript', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '')
1179 {
1180 if (!$type) {
1181 $type = 'text/javascript';
1182 }
1183 if (!isset($this->jsFiles[$file])) {
1184 $this->jsFiles[$file] = array(
1185 'file' => $file,
1186 'type' => $type,
1187 'section' => self::PART_HEADER,
1188 'compress' => $compress,
1189 'forceOnTop' => $forceOnTop,
1190 'allWrap' => $allWrap,
1191 'excludeFromConcatenation' => $excludeFromConcatenation,
1192 'splitChar' => $splitChar,
1193 'async' => $async,
1194 'integrity' => $integrity,
1195 );
1196 }
1197 }
1198
1199 /**
1200 * Adds JS file to footer
1201 *
1202 * @param string $file File name
1203 * @param string $type Content Type
1204 * @param bool $compress
1205 * @param bool $forceOnTop
1206 * @param string $allWrap
1207 * @param bool $excludeFromConcatenation
1208 * @param string $splitChar The char used to split the allWrap value, default is "|"
1209 * @param bool $async Flag if property 'async="async"' should be added to JavaScript tags
1210 * @param string $integrity Subresource Integrity (SRI)
1211 * @return void
1212 */
1213 public function addJsFooterFile($file, $type = 'text/javascript', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|', $async = false, $integrity = '')
1214 {
1215 if (!$type) {
1216 $type = 'text/javascript';
1217 }
1218 if (!isset($this->jsFiles[$file])) {
1219 $this->jsFiles[$file] = array(
1220 'file' => $file,
1221 'type' => $type,
1222 'section' => self::PART_FOOTER,
1223 'compress' => $compress,
1224 'forceOnTop' => $forceOnTop,
1225 'allWrap' => $allWrap,
1226 'excludeFromConcatenation' => $excludeFromConcatenation,
1227 'splitChar' => $splitChar,
1228 'async' => $async,
1229 'integrity' => $integrity,
1230 );
1231 }
1232 }
1233
1234 /**
1235 * Adds JS inline code
1236 *
1237 * @param string $name
1238 * @param string $block
1239 * @param bool $compress
1240 * @param bool $forceOnTop
1241 * @return void
1242 */
1243 public function addJsInlineCode($name, $block, $compress = true, $forceOnTop = false)
1244 {
1245 if (!isset($this->jsInline[$name]) && !empty($block)) {
1246 $this->jsInline[$name] = array(
1247 'code' => $block . LF,
1248 'section' => self::PART_HEADER,
1249 'compress' => $compress,
1250 'forceOnTop' => $forceOnTop
1251 );
1252 }
1253 }
1254
1255 /**
1256 * Adds JS inline code to footer
1257 *
1258 * @param string $name
1259 * @param string $block
1260 * @param bool $compress
1261 * @param bool $forceOnTop
1262 * @return void
1263 */
1264 public function addJsFooterInlineCode($name, $block, $compress = true, $forceOnTop = false)
1265 {
1266 if (!isset($this->jsInline[$name]) && !empty($block)) {
1267 $this->jsInline[$name] = array(
1268 'code' => $block . LF,
1269 'section' => self::PART_FOOTER,
1270 'compress' => $compress,
1271 'forceOnTop' => $forceOnTop
1272 );
1273 }
1274 }
1275
1276 /**
1277 * Adds Ext.onready code, which will be wrapped in Ext.onReady(function() {...});
1278 *
1279 * @param string $block Javascript code
1280 * @param bool $forceOnTop Position of the javascript code (TRUE for putting it on top, default is FALSE = bottom)
1281 * @return void
1282 */
1283 public function addExtOnReadyCode($block, $forceOnTop = false)
1284 {
1285 if (!in_array($block, $this->extOnReadyCode)) {
1286 if ($forceOnTop) {
1287 array_unshift($this->extOnReadyCode, $block);
1288 } else {
1289 $this->extOnReadyCode[] = $block;
1290 }
1291 }
1292 }
1293
1294 /**
1295 * Adds the ExtDirect code
1296 *
1297 * @param array $filterNamespaces Limit the output to defined namespaces. If empty, all namespaces are generated
1298 * @return void
1299 */
1300 public function addExtDirectCode(array $filterNamespaces = array())
1301 {
1302 if ($this->extDirectCodeAdded) {
1303 return;
1304 }
1305 $this->extDirectCodeAdded = true;
1306 if (empty($filterNamespaces)) {
1307 $filterNamespaces = array('TYPO3');
1308 }
1309 // @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 9
1310 // add compatibility mapping for the old flashmessage API
1311 $this->addJsFile(GeneralUtility::resolveBackPath($this->backPath .
1312 'sysext/backend/Resources/Public/JavaScript/flashmessage_compatibility.js'));
1313
1314 // Add language labels for ExtDirect
1315 if (TYPO3_MODE === 'FE') {
1316 $this->addInlineLanguageLabelArray(array(
1317 'extDirect_timeoutHeader' => $this->getTypoScriptFrontendController()->sL('LLL:EXT:lang/locallang_misc.xlf:extDirect_timeoutHeader'),
1318 'extDirect_timeoutMessage' => $this->getTypoScriptFrontendController()->sL('LLL:EXT:lang/locallang_misc.xlf:extDirect_timeoutMessage')
1319 ));
1320 } else {
1321 $this->addInlineLanguageLabelArray(array(
1322 'extDirect_timeoutHeader' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:extDirect_timeoutHeader'),
1323 'extDirect_timeoutMessage' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:extDirect_timeoutMessage')
1324 ));
1325 }
1326
1327 $token = ($api = '');
1328 if (TYPO3_MODE === 'BE') {
1329 $formprotection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
1330 $token = $formprotection->generateToken('extDirect');
1331
1332 // Debugger Console strings
1333 $this->addInlineLanguageLabelFile('EXT:core/Resources/Private/Language/debugger.xlf');
1334 }
1335 /** @var $extDirect \TYPO3\CMS\Core\ExtDirect\ExtDirectApi */
1336 $extDirect = GeneralUtility::makeInstance(\TYPO3\CMS\Core\ExtDirect\ExtDirectApi::class);
1337 $api = $extDirect->getApiPhp($filterNamespaces);
1338 if ($api) {
1339 $this->addJsInlineCode('TYPO3ExtDirectAPI', $api, false);
1340 }
1341 // Note: we need to iterate thru the object, because the addProvider method
1342 // does this only with multiple arguments
1343 $this->addExtOnReadyCode('
1344 (function() {
1345 TYPO3.ExtDirectToken = "' . $token . '";
1346 for (var api in Ext.app.ExtDirectAPI) {
1347 var provider = Ext.Direct.addProvider(Ext.app.ExtDirectAPI[api]);
1348 provider.on("beforecall", function(provider, transaction, meta) {
1349 if (transaction.data) {
1350 transaction.data[transaction.data.length] = TYPO3.ExtDirectToken;
1351 } else {
1352 transaction.data = [TYPO3.ExtDirectToken];
1353 }
1354 });
1355
1356 provider.on("call", function(provider, transaction, meta) {
1357 if (transaction.isForm) {
1358 transaction.params.securityToken = TYPO3.ExtDirectToken;
1359 }
1360 });
1361 }
1362 })();
1363
1364 var extDirectDebug = function(message, header, group) {
1365 var DebugConsole = null;
1366
1367 if (top && top.TYPO3 && typeof top.TYPO3.DebugConsole === "object") {
1368 DebugConsole = top.TYPO3.DebugConsole;
1369 } else if (typeof TYPO3 === "object" && typeof TYPO3.DebugConsole === "object") {
1370 DebugConsole = TYPO3.DebugConsole;
1371 }
1372
1373 if (DebugConsole !== null) {
1374 DebugConsole.add(message, header, group);
1375 } else if (typeof console === "object") {
1376 console.log(message);
1377 } else {
1378 document.write(message);
1379 }
1380 };
1381
1382 Ext.Direct.on("exception", function(event) {
1383 if (event.code === Ext.Direct.exceptions.TRANSPORT && !event.where) {
1384 top.TYPO3.Notification.error(
1385 TYPO3.l10n.localize("extDirect_timeoutHeader"),
1386 TYPO3.l10n.localize("extDirect_timeoutMessage")
1387 );
1388 } else {
1389 var backtrace = "";
1390 if (event.code === "parse") {
1391 extDirectDebug(
1392 "<p>" + event.xhr.responseText + "<\\/p>",
1393 event.type,
1394 "ExtDirect - Exception"
1395 );
1396 } else if (event.code === "router") {
1397 top.TYPO3.Notification.error(
1398 event.code,
1399 event.message
1400 );
1401 } else if (event.where) {
1402 backtrace = "<p style=\\"margin-top: 20px;\\">" +
1403 "<strong>Backtrace:<\\/strong><br \\/>" +
1404 event.where.replace(/#/g, "<br \\/>#") +
1405 "<\\/p>";
1406 extDirectDebug(
1407 "<p>" + event.message + "<\\/p>" + backtrace,
1408 event.method,
1409 "ExtDirect - Exception"
1410 );
1411 }
1412
1413
1414 }
1415 });
1416
1417 Ext.Direct.on("event", function(event, provider) {
1418 if (typeof event.debug !== "undefined" && event.debug !== "") {
1419 extDirectDebug(event.debug, event.method, "ExtDirect - Debug");
1420 }
1421 });
1422 ', true);
1423 }
1424
1425 /**
1426 * Adds CSS file
1427 *
1428 * @param string $file
1429 * @param string $rel
1430 * @param string $media
1431 * @param string $title
1432 * @param bool $compress
1433 * @param bool $forceOnTop
1434 * @param string $allWrap
1435 * @param bool $excludeFromConcatenation
1436 * @param string $splitChar The char used to split the allWrap value, default is "|"
1437 * @return void
1438 */
1439 public function addCssFile($file, $rel = 'stylesheet', $media = 'all', $title = '', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|')
1440 {
1441 if (!isset($this->cssFiles[$file])) {
1442 $this->cssFiles[$file] = array(
1443 'file' => $file,
1444 'rel' => $rel,
1445 'media' => $media,
1446 'title' => $title,
1447 'compress' => $compress,
1448 'forceOnTop' => $forceOnTop,
1449 'allWrap' => $allWrap,
1450 'excludeFromConcatenation' => $excludeFromConcatenation,
1451 'splitChar' => $splitChar
1452 );
1453 }
1454 }
1455
1456 /**
1457 * Adds CSS file
1458 *
1459 * @param string $file
1460 * @param string $rel
1461 * @param string $media
1462 * @param string $title
1463 * @param bool $compress
1464 * @param bool $forceOnTop
1465 * @param string $allWrap
1466 * @param bool $excludeFromConcatenation
1467 * @param string $splitChar The char used to split the allWrap value, default is "|"
1468 * @return void
1469 */
1470 public function addCssLibrary($file, $rel = 'stylesheet', $media = 'all', $title = '', $compress = true, $forceOnTop = false, $allWrap = '', $excludeFromConcatenation = false, $splitChar = '|')
1471 {
1472 if (!isset($this->cssLibs[$file])) {
1473 $this->cssLibs[$file] = array(
1474 'file' => $file,
1475 'rel' => $rel,
1476 'media' => $media,
1477 'title' => $title,
1478 'compress' => $compress,
1479 'forceOnTop' => $forceOnTop,
1480 'allWrap' => $allWrap,
1481 'excludeFromConcatenation' => $excludeFromConcatenation,
1482 'splitChar' => $splitChar
1483 );
1484 }
1485 }
1486
1487 /**
1488 * Adds CSS inline code
1489 *
1490 * @param string $name
1491 * @param string $block
1492 * @param bool $compress
1493 * @param bool $forceOnTop
1494 * @return void
1495 */
1496 public function addCssInlineBlock($name, $block, $compress = false, $forceOnTop = false)
1497 {
1498 if (!isset($this->cssInline[$name]) && !empty($block)) {
1499 $this->cssInline[$name] = array(
1500 'code' => $block,
1501 'compress' => $compress,
1502 'forceOnTop' => $forceOnTop
1503 );
1504 }
1505 }
1506
1507 /**
1508 * Call this function if you need to include the jQuery library
1509 *
1510 * @param null|string $version The jQuery version that should be included, either "latest" or any available version
1511 * @param null|string $source The location of the jQuery source, can be "local", "google", "msn", "jquery" or just an URL to your jQuery lib
1512 * @param string $namespace The namespace in which the jQuery object of the specific version should be stored.
1513 * @return void
1514 * @throws \UnexpectedValueException
1515 */
1516 public function loadJquery($version = null, $source = null, $namespace = self::JQUERY_NAMESPACE_DEFAULT)
1517 {
1518 // Set it to the version that is shipped with the TYPO3 core
1519 if ($version === null || $version === 'latest') {
1520 $version = self::JQUERY_VERSION_LATEST;
1521 }
1522 // Check if the source is set, otherwise set it to "default"
1523 if ($source === null) {
1524 $source = 'local';
1525 }
1526 if ($source === 'local' && !in_array($version, $this->availableLocalJqueryVersions)) {
1527 throw new \UnexpectedValueException('The requested jQuery version is not available in the local filesystem.', 1341505305);
1528 }
1529 if (!preg_match('/^[a-zA-Z0-9]+$/', $namespace)) {
1530 throw new \UnexpectedValueException('The requested namespace contains non alphanumeric characters.', 1341571604);
1531 }
1532 $this->jQueryVersions[$namespace] = array(
1533 'version' => $version,
1534 'source' => $source
1535 );
1536 }
1537
1538 /**
1539 * Call function if you need the requireJS library
1540 * this automatically adds the JavaScript path of all loaded extensions in the requireJS path option
1541 * so it resolves names like TYPO3/CMS/MyExtension/MyJsFile to EXT:MyExtension/Resources/Public/JavaScript/MyJsFile.js
1542 * when using requireJS
1543 *
1544 * @return void
1545 */
1546 public function loadRequireJs()
1547 {
1548
1549 // load all paths to map to package names / namespaces
1550 if (empty($this->requireJsConfig)) {
1551 // In order to avoid browser caching of JS files, adding a GET parameter to the files loaded via requireJS
1552 if (GeneralUtility::getApplicationContext()->isDevelopment()) {
1553 $this->requireJsConfig['urlArgs'] = 'bust=' . $GLOBALS['EXEC_TIME'];
1554 } else {
1555 $this->requireJsConfig['urlArgs'] = 'bust=' . GeneralUtility::hmac(TYPO3_version . PATH_site);
1556 }
1557 // first, load all paths for the namespaces, and configure contrib libs.
1558 $this->requireJsConfig['paths'] = array(
1559 'jquery-ui' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/jquery-ui',
1560 'datatables' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/jquery.dataTables',
1561 'nprogress' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/nprogress',
1562 'moment' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/moment',
1563 'cropper' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/cropper.min',
1564 'imagesloaded' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/imagesloaded.pkgd.min',
1565 'bootstrap' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap',
1566 'twbs/bootstrap-datetimepicker' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/bootstrap-datetimepicker',
1567 'autosize' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/autosize',
1568 'taboverride' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/taboverride.min',
1569 'twbs/bootstrap-slider' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/bootstrap-slider.min',
1570 'jquery/autocomplete' => $this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/jquery.autocomplete',
1571 );
1572 // get all extensions that are loaded
1573 $loadedExtensions = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getLoadedExtensionListArray();
1574 foreach ($loadedExtensions as $packageName) {
1575 $fullJsPath = 'EXT:' . $packageName . '/Resources/Public/JavaScript/';
1576 $fullJsPath = GeneralUtility::getFileAbsFileName($fullJsPath);
1577 $fullJsPath = \TYPO3\CMS\Core\Utility\PathUtility::getRelativePath(PATH_typo3, $fullJsPath);
1578 $fullJsPath = rtrim($fullJsPath, '/');
1579 if ($fullJsPath) {
1580 $this->requireJsConfig['paths']['TYPO3/CMS/' . GeneralUtility::underscoredToUpperCamelCase($packageName)] = $this->backPath . $fullJsPath;
1581 }
1582 }
1583
1584 // check if additional AMD modules need to be loaded if a single AMD module is initialized
1585 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['RequireJS']['postInitializationModules'])) {
1586 $this->addInlineSettingArray('RequireJS.PostInitializationModules', $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['RequireJS']['postInitializationModules']);
1587 }
1588 }
1589
1590 $this->addRequireJs = true;
1591 }
1592
1593 /**
1594 * Add additional configuration to require js.
1595 *
1596 * Configuration will be merged recursive with overrule.
1597 *
1598 * To add another path mapping deliver the following configuration:
1599 * 'paths' => array(
1600 * 'EXTERN/mybootstrapjs' => 'sysext/.../twbs/bootstrap.min',
1601 * ),
1602 *
1603 * @param array $configuration The configuration that will be merged with existing one.
1604 * @return void
1605 */
1606 public function addRequireJsConfiguration(array $configuration)
1607 {
1608 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($this->requireJsConfig, $configuration);
1609 }
1610
1611 /**
1612 * includes an AMD-compatible JS file by resolving the ModuleName, and then requires the file via a requireJS request,
1613 * additionally allowing to execute JavaScript code afterwards
1614 *
1615 * this function only works for AMD-ready JS modules, used like "define('TYPO3/CMS/Backend/FormEngine..."
1616 * in the JS file
1617 *
1618 * TYPO3/CMS/Backend/FormEngine =>
1619 * "TYPO3": Vendor Name
1620 * "CMS": Product Name
1621 * "Backend": Extension Name
1622 * "FormEngine": FileName in the Resources/Public/JavaScript folder
1623 *
1624 * @param string $mainModuleName Must be in the form of "TYPO3/CMS/PackageName/ModuleName" e.g. "TYPO3/CMS/Backend/FormEngine"
1625 * @param string $callBackFunction loaded right after the requireJS loading, must be wrapped in function() {}
1626 * @return void
1627 */
1628 public function loadRequireJsModule($mainModuleName, $callBackFunction = null)
1629 {
1630 $inlineCodeKey = $mainModuleName;
1631 // make sure requireJS is initialized
1632 $this->loadRequireJs();
1633
1634 // execute the main module, and load a possible callback function
1635 $javaScriptCode = 'require(["' . $mainModuleName . '"]';
1636 if ($callBackFunction !== null) {
1637 $inlineCodeKey .= sha1($callBackFunction);
1638 $javaScriptCode .= ', ' . $callBackFunction;
1639 }
1640 $javaScriptCode .= ');';
1641 $this->addJsInlineCode('RequireJS-Module-' . $inlineCodeKey, $javaScriptCode);
1642 }
1643
1644 /**
1645 * call this function if you need the extJS library
1646 *
1647 * @param bool $css Flag, if set the ext-css will be loaded
1648 * @param bool $theme Flag, if set the ext-theme "grey" will be loaded
1649 * @return void
1650 */
1651 public function loadExtJS($css = true, $theme = true)
1652 {
1653 $this->addExtJS = true;
1654 $this->extJStheme = $theme;
1655 $this->extJScss = $css;
1656 }
1657
1658 /**
1659 * Call this function to load debug version of ExtJS. Use this for development only
1660 *
1661 * @return void
1662 */
1663 public function enableExtJsDebug()
1664 {
1665 $this->enableExtJsDebug = true;
1666 }
1667
1668 /**
1669 * Adds Javascript Inline Label. This will occur in TYPO3.lang - object
1670 * The label can be used in scripts with TYPO3.lang.<key>
1671 * Need extJs loaded
1672 *
1673 * @param string $key
1674 * @param string $value
1675 * @return void
1676 */
1677 public function addInlineLanguageLabel($key, $value)
1678 {
1679 $this->inlineLanguageLabels[$key] = $value;
1680 }
1681
1682 /**
1683 * Adds Javascript Inline Label Array. This will occur in TYPO3.lang - object
1684 * The label can be used in scripts with TYPO3.lang.<key>
1685 * Array will be merged with existing array.
1686 * Need extJs loaded
1687 *
1688 * @param array $array
1689 * @param bool $parseWithLanguageService
1690 * @return void
1691 */
1692 public function addInlineLanguageLabelArray(array $array, $parseWithLanguageService = false)
1693 {
1694 if ($parseWithLanguageService === true) {
1695 foreach ($array as $key => $value) {
1696 if (TYPO3_MODE === 'FE') {
1697 $array[$key] = $this->getTypoScriptFrontendController()->sL($value);
1698 } else {
1699 $array[$key] = $this->getLanguageService()->sL($value);
1700 }
1701 }
1702 }
1703
1704 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $array);
1705 }
1706
1707 /**
1708 * Gets labels to be used in JavaScript fetched from a locallang file.
1709 *
1710 * @param string $fileRef Input is a file-reference (see GeneralUtility::getFileAbsFileName). That file is expected to be a 'locallang.xlf' file containing a valid XML TYPO3 language structure.
1711 * @param string $selectionPrefix Prefix to select the correct labels (default: '')
1712 * @param string $stripFromSelectionName String to be removed from the label names in the output. (default: '')
1713 * @param int $errorMode Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
1714 * @return void
1715 */
1716 public function addInlineLanguageLabelFile($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0)
1717 {
1718 $index = md5($fileRef . $selectionPrefix . $stripFromSelectionName);
1719 if ($fileRef && !isset($this->inlineLanguageLabelFiles[$index])) {
1720 $this->inlineLanguageLabelFiles[$index] = array(
1721 'fileRef' => $fileRef,
1722 'selectionPrefix' => $selectionPrefix,
1723 'stripFromSelectionName' => $stripFromSelectionName,
1724 'errorMode' => $errorMode
1725 );
1726 }
1727 }
1728
1729 /**
1730 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1731 * The label can be used in scripts with TYPO3.setting.<key>
1732 * Need extJs loaded
1733 *
1734 * @param string $namespace
1735 * @param string $key
1736 * @param string $value
1737 * @return void
1738 */
1739 public function addInlineSetting($namespace, $key, $value)
1740 {
1741 if ($namespace) {
1742 if (strpos($namespace, '.')) {
1743 $parts = explode('.', $namespace);
1744 $a = &$this->inlineSettings;
1745 foreach ($parts as $part) {
1746 $a = &$a[$part];
1747 }
1748 $a[$key] = $value;
1749 } else {
1750 $this->inlineSettings[$namespace][$key] = $value;
1751 }
1752 } else {
1753 $this->inlineSettings[$key] = $value;
1754 }
1755 }
1756
1757 /**
1758 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1759 * The label can be used in scripts with TYPO3.setting.<key>
1760 * Array will be merged with existing array.
1761 * Need extJs loaded
1762 *
1763 * @param string $namespace
1764 * @param array $array
1765 * @return void
1766 */
1767 public function addInlineSettingArray($namespace, array $array)
1768 {
1769 if ($namespace) {
1770 if (strpos($namespace, '.')) {
1771 $parts = explode('.', $namespace);
1772 $a = &$this->inlineSettings;
1773 foreach ($parts as $part) {
1774 $a = &$a[$part];
1775 }
1776 $a = array_merge((array)$a, $array);
1777 } else {
1778 $this->inlineSettings[$namespace] = array_merge((array)$this->inlineSettings[$namespace], $array);
1779 }
1780 } else {
1781 $this->inlineSettings = array_merge($this->inlineSettings, $array);
1782 }
1783 }
1784
1785 /**
1786 * Adds content to body content
1787 *
1788 * @param string $content
1789 * @return void
1790 */
1791 public function addBodyContent($content)
1792 {
1793 $this->bodyContent .= $content;
1794 }
1795
1796 /*****************************************************/
1797 /* */
1798 /* Render Functions */
1799 /* */
1800 /*****************************************************/
1801 /**
1802 * Render the section (Header or Footer)
1803 *
1804 * @param int $part Section which should be rendered: self::PART_COMPLETE, self::PART_HEADER or self::PART_FOOTER
1805 * @return string Content of rendered section
1806 */
1807 public function render($part = self::PART_COMPLETE)
1808 {
1809 $this->prepareRendering();
1810 list($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs) = $this->renderJavaScriptAndCss();
1811 $metaTags = implode(LF, $this->metaTags);
1812 $markerArray = $this->getPreparedMarkerArray($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs, $metaTags);
1813 $template = $this->getTemplateForPart($part);
1814
1815 // The page renderer needs a full reset, even when only rendering one part of the page
1816 // This means that you can only register footer files *after* the header has been already rendered.
1817 // In case you render the footer part first, header files can only be added *after* the footer has been rendered
1818 $this->reset();
1819 $templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
1820 return trim($templateService->substituteMarkerArray($template, $markerArray, '###|###'));
1821 }
1822
1823 /**
1824 * Render the page but not the JavaScript and CSS Files
1825 *
1826 * @param string $substituteHash The hash that is used for the placehoder markers
1827 * @access private
1828 * @return string Content of rendered section
1829 */
1830 public function renderPageWithUncachedObjects($substituteHash)
1831 {
1832 $this->prepareRendering();
1833 $markerArray = $this->getPreparedMarkerArrayForPageWithUncachedObjects($substituteHash);
1834 $template = $this->getTemplateForPart(self::PART_COMPLETE);
1835 $templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
1836 return trim($templateService->substituteMarkerArray($template, $markerArray, '###|###'));
1837 }
1838
1839 /**
1840 * Renders the JavaScript and CSS files that have been added during processing
1841 * of uncached content objects (USER_INT, COA_INT)
1842 *
1843 * @param string $cachedPageContent
1844 * @param string $substituteHash The hash that is used for the placehoder markers
1845 * @access private
1846 * @return string
1847 */
1848 public function renderJavaScriptAndCssForProcessingOfUncachedContentObjects($cachedPageContent, $substituteHash)
1849 {
1850 $this->prepareRendering();
1851 list($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs) = $this->renderJavaScriptAndCss();
1852 $title = $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '';
1853 $markerArray = array(
1854 '<!-- ###TITLE' . $substituteHash . '### -->' => $title,
1855 '<!-- ###CSS_LIBS' . $substituteHash . '### -->' => $cssLibs,
1856 '<!-- ###CSS_INCLUDE' . $substituteHash . '### -->' => $cssFiles,
1857 '<!-- ###CSS_INLINE' . $substituteHash . '### -->' => $cssInline,
1858 '<!-- ###JS_INLINE' . $substituteHash . '### -->' => $jsInline,
1859 '<!-- ###JS_INCLUDE' . $substituteHash . '### -->' => $jsFiles,
1860 '<!-- ###JS_LIBS' . $substituteHash . '### -->' => $jsLibs,
1861 '<!-- ###HEADERDATA' . $substituteHash . '### -->' => implode(LF, $this->headerData),
1862 '<!-- ###FOOTERDATA' . $substituteHash . '### -->' => implode(LF, $this->footerData),
1863 '<!-- ###JS_LIBS_FOOTER' . $substituteHash . '### -->' => $jsFooterLibs,
1864 '<!-- ###JS_INCLUDE_FOOTER' . $substituteHash . '### -->' => $jsFooterFiles,
1865 '<!-- ###JS_INLINE_FOOTER' . $substituteHash . '### -->' => $jsFooterInline
1866 );
1867 foreach ($markerArray as $placeHolder => $content) {
1868 $cachedPageContent = str_replace($placeHolder, $content, $cachedPageContent);
1869 }
1870 $this->reset();
1871 return $cachedPageContent;
1872 }
1873
1874 /**
1875 * Remove ending slashes from static header block
1876 * if the page is beeing rendered as html (not xhtml)
1877 * and define property $this->endingSlash for further use
1878 *
1879 * @return void
1880 */
1881 protected function prepareRendering()
1882 {
1883 if ($this->getRenderXhtml()) {
1884 $this->endingSlash = ' /';
1885 } else {
1886 $this->metaCharsetTag = str_replace(' />', '>', $this->metaCharsetTag);
1887 $this->baseUrlTag = str_replace(' />', '>', $this->baseUrlTag);
1888 $this->shortcutTag = str_replace(' />', '>', $this->shortcutTag);
1889 $this->endingSlash = '';
1890 }
1891 }
1892
1893 /**
1894 * Renders all JavaScript and CSS
1895 *
1896 * @return array<string>
1897 */
1898 protected function renderJavaScriptAndCss()
1899 {
1900 $this->executePreRenderHook();
1901 $mainJsLibs = $this->renderMainJavaScriptLibraries();
1902 if ($this->concatenateFiles || $this->concatenateJavascript || $this->concatenateCss) {
1903 // Do the file concatenation
1904 $this->doConcatenate();
1905 }
1906 if ($this->compressCss || $this->compressJavascript) {
1907 // Do the file compression
1908 $this->doCompress();
1909 }
1910 $this->executeRenderPostTransformHook();
1911 $cssLibs = $this->renderCssLibraries();
1912 $cssFiles = $this->renderCssFiles();
1913 $cssInline = $this->renderCssInline();
1914 list($jsLibs, $jsFooterLibs) = $this->renderAdditionalJavaScriptLibraries();
1915 list($jsFiles, $jsFooterFiles) = $this->renderJavaScriptFiles();
1916 list($jsInline, $jsFooterInline) = $this->renderInlineJavaScript();
1917 $jsLibs = $mainJsLibs . $jsLibs;
1918 if ($this->moveJsFromHeaderToFooter) {
1919 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
1920 $jsLibs = '';
1921 $jsFooterFiles = $jsFiles . LF . $jsFooterFiles;
1922 $jsFiles = '';
1923 $jsFooterInline = $jsInline . LF . $jsFooterInline;
1924 $jsInline = '';
1925 }
1926 $this->executePostRenderHook($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs);
1927 return array($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs);
1928 }
1929
1930 /**
1931 * Fills the marker array with the given strings and trims each value
1932 *
1933 * @param $jsLibs string
1934 * @param $jsFiles string
1935 * @param $jsFooterFiles string
1936 * @param $cssLibs string
1937 * @param $cssFiles string
1938 * @param $jsInline string
1939 * @param $cssInline string
1940 * @param $jsFooterInline string
1941 * @param $jsFooterLibs string
1942 * @param $metaTags string
1943 * @return array Marker array
1944 */
1945 protected function getPreparedMarkerArray($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs, $metaTags)
1946 {
1947 $markerArray = array(
1948 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1949 'HTMLTAG' => $this->htmlTag,
1950 'HEADTAG' => $this->headTag,
1951 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1952 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1953 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1954 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1955 'CSS_LIBS' => $cssLibs,
1956 'CSS_INCLUDE' => $cssFiles,
1957 'CSS_INLINE' => $cssInline,
1958 'JS_INLINE' => $jsInline,
1959 'JS_INCLUDE' => $jsFiles,
1960 'JS_LIBS' => $jsLibs,
1961 'TITLE' => $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '',
1962 'META' => $metaTags,
1963 'HEADERDATA' => $this->headerData ? implode(LF, $this->headerData) : '',
1964 'FOOTERDATA' => $this->footerData ? implode(LF, $this->footerData) : '',
1965 'JS_LIBS_FOOTER' => $jsFooterLibs,
1966 'JS_INCLUDE_FOOTER' => $jsFooterFiles,
1967 'JS_INLINE_FOOTER' => $jsFooterInline,
1968 'BODY' => $this->bodyContent
1969 );
1970 $markerArray = array_map('trim', $markerArray);
1971 return $markerArray;
1972 }
1973
1974 /**
1975 * Fills the marker array with the given strings and trims each value
1976 *
1977 * @param string $substituteHash The hash that is used for the placehoder markers
1978 * @return array Marker array
1979 */
1980 protected function getPreparedMarkerArrayForPageWithUncachedObjects($substituteHash)
1981 {
1982 $markerArray = array(
1983 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1984 'HTMLTAG' => $this->htmlTag,
1985 'HEADTAG' => $this->headTag,
1986 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1987 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1988 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1989 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1990 'META' => implode(LF, $this->metaTags),
1991 'BODY' => $this->bodyContent,
1992 'TITLE' => '<!-- ###TITLE' . $substituteHash . '### -->',
1993 'CSS_LIBS' => '<!-- ###CSS_LIBS' . $substituteHash . '### -->',
1994 'CSS_INCLUDE' => '<!-- ###CSS_INCLUDE' . $substituteHash . '### -->',
1995 'CSS_INLINE' => '<!-- ###CSS_INLINE' . $substituteHash . '### -->',
1996 'JS_INLINE' => '<!-- ###JS_INLINE' . $substituteHash . '### -->',
1997 'JS_INCLUDE' => '<!-- ###JS_INCLUDE' . $substituteHash . '### -->',
1998 'JS_LIBS' => '<!-- ###JS_LIBS' . $substituteHash . '### -->',
1999 'HEADERDATA' => '<!-- ###HEADERDATA' . $substituteHash . '### -->',
2000 'FOOTERDATA' => '<!-- ###FOOTERDATA' . $substituteHash . '### -->',
2001 'JS_LIBS_FOOTER' => '<!-- ###JS_LIBS_FOOTER' . $substituteHash . '### -->',
2002 'JS_INCLUDE_FOOTER' => '<!-- ###JS_INCLUDE_FOOTER' . $substituteHash . '### -->',
2003 'JS_INLINE_FOOTER' => '<!-- ###JS_INLINE_FOOTER' . $substituteHash . '### -->'
2004 );
2005 $markerArray = array_map('trim', $markerArray);
2006 return $markerArray;
2007 }
2008
2009 /**
2010 * Reads the template file and returns the requested part as string
2011 *
2012 * @param int $part
2013 * @return string
2014 */
2015 protected function getTemplateForPart($part)
2016 {
2017 $templateFile = GeneralUtility::getFileAbsFileName($this->templateFile, true);
2018 $template = GeneralUtility::getUrl($templateFile);
2019 if ($this->removeLineBreaksFromTemplate) {
2020 $template = strtr($template, array(LF => '', CR => ''));
2021 }
2022 if ($part !== self::PART_COMPLETE) {
2023 $templatePart = explode('###BODY###', $template);
2024 $template = $templatePart[$part - 1];
2025 }
2026 return $template;
2027 }
2028
2029 /**
2030 * Helper function for render the main JavaScript libraries,
2031 * currently: RequireJS, jQuery, ExtJS
2032 *
2033 * @return string Content with JavaScript libraries
2034 */
2035 protected function renderMainJavaScriptLibraries()
2036 {
2037 $out = '';
2038
2039 // Include RequireJS
2040 if ($this->addRequireJs) {
2041 // load the paths of the requireJS configuration
2042 $out .= GeneralUtility::wrapJS('var require = ' . json_encode($this->requireJsConfig)) . LF;
2043 // directly after that, include the require.js file
2044 $out .= '<script src="' . $this->processJsFile(($this->backPath . $this->requireJsPath . 'require.js')) . '" type="text/javascript"></script>' . LF;
2045 }
2046
2047 // Include jQuery Core for each namespace, depending on the version and source
2048 if (!empty($this->jQueryVersions)) {
2049 foreach ($this->jQueryVersions as $namespace => $jQueryVersion) {
2050 $out .= $this->renderJqueryScriptTag($jQueryVersion['version'], $jQueryVersion['source'], $namespace);
2051 }
2052 }
2053 // Include extJS
2054 if ($this->addExtJS) {
2055 // Use the base adapter all the time
2056 $out .= '<script src="' . $this->processJsFile(($this->backPath . $this->extJsPath . 'adapter/ext-base' . ($this->enableExtJsDebug ? '-debug' : '') . '.js')) . '" type="text/javascript"></script>' . LF;
2057 $out .= '<script src="' . $this->processJsFile(($this->backPath . $this->extJsPath . 'ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js')) . '" type="text/javascript"></script>' . LF;
2058 // Add extJS localization
2059 // Load standard ISO mapping and modify for use with ExtJS
2060 $localeMap = $this->locales->getIsoMapping();
2061 $localeMap[''] = 'en';
2062 $localeMap['default'] = 'en';
2063 // Greek
2064 $localeMap['gr'] = 'el_GR';
2065 // Norwegian Bokmaal
2066 $localeMap['no'] = 'no_BO';
2067 // Swedish
2068 $localeMap['se'] = 'se_SV';
2069 $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang;
2070 // @todo autoconvert file from UTF8 to current BE charset if necessary!!!!
2071 $extJsLocaleFile = $this->extJsPath . 'locale/ext-lang-' . $extJsLang . '.js';
2072 if (file_exists(PATH_typo3 . $extJsLocaleFile)) {
2073 $out .= '<script src="' . $this->processJsFile(($this->backPath . $extJsLocaleFile)) . '" type="text/javascript" charset="utf-8"></script>' . LF;
2074 }
2075 // Remove extjs from JScodeLibArray
2076 unset($this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all.js'], $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all-debug.js']);
2077 }
2078 $this->loadJavaScriptLanguageStrings();
2079 if (TYPO3_MODE === 'BE') {
2080 $this->addAjaxUrlsToInlineSettings();
2081 }
2082 $inlineSettings = $this->inlineLanguageLabels ? 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' : '';
2083 $inlineSettings .= $this->inlineSettings ? 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' : '';
2084 if ($this->addExtJS) {
2085 // Set clear.gif, move it on top, add handler code
2086 $code = '';
2087 if (!empty($this->extOnReadyCode)) {
2088 foreach ($this->extOnReadyCode as $block) {
2089 $code .= $block;
2090 }
2091 }
2092 $out .= $this->inlineJavascriptWrap[0] . '
2093 Ext.ns("TYPO3");
2094 Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(GeneralUtility::locationHeaderUrl($this->backPath . 'sysext/t3skin/icons/gfx/clear.gif')) . '";
2095 Ext.SSL_SECURE_URL = "' . htmlspecialchars(GeneralUtility::locationHeaderUrl($this->backPath . 'sysext/t3skin/icons/gfx/clear.gif')) . '";' . LF
2096 . $inlineSettings
2097 . 'Ext.onReady(function() {'
2098 . $code
2099 . ' });'
2100 . $this->inlineJavascriptWrap[1];
2101 $this->extOnReadyCode = array();
2102 // Include TYPO3.l10n object
2103 if (TYPO3_MODE === 'BE') {
2104 $out .= '<script src="' . $this->processJsFile(($this->backPath . 'sysext/lang/Resources/Public/JavaScript/Typo3Lang.js')) . '" type="text/javascript" charset="utf-8"></script>' . LF;
2105 }
2106 if ($this->extJScss) {
2107 if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) {
2108 $this->addCssLibrary($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'all', '', true);
2109 } else {
2110 $this->addCssLibrary($this->backPath . $this->extJsPath . 'resources/css/ext-all-notheme.css', 'stylesheet', 'all', '', true);
2111 }
2112 }
2113 if ($this->extJStheme) {
2114 if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) {
2115 $this->addCssLibrary($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'all', '', true);
2116 } else {
2117 $this->addCssLibrary($this->backPath . $this->extJsPath . 'resources/css/xtheme-blue.css', 'stylesheet', 'all', '', true);
2118 }
2119 }
2120 } else {
2121 // no extJS loaded, but still inline settings
2122 if ($inlineSettings !== '') {
2123 // make sure the global TYPO3 is available
2124 $inlineSettings = 'var TYPO3 = TYPO3 || {};' . CRLF . $inlineSettings;
2125 $out .= $this->inlineJavascriptWrap[0] . $inlineSettings . $this->inlineJavascriptWrap[1];
2126 // Add language module only if also jquery is guaranteed to be there
2127 if (TYPO3_MODE === 'BE' && !empty($this->jQueryVersions)) {
2128 $this->loadRequireJsModule('TYPO3/CMS/Lang/Lang');
2129 }
2130 }
2131 }
2132 return $out;
2133 }
2134
2135 /**
2136 * Load the language strings into JavaScript
2137 */
2138 protected function loadJavaScriptLanguageStrings()
2139 {
2140 if (!empty($this->inlineLanguageLabelFiles)) {
2141 foreach ($this->inlineLanguageLabelFiles as $languageLabelFile) {
2142 $this->includeLanguageFileForInline($languageLabelFile['fileRef'], $languageLabelFile['selectionPrefix'], $languageLabelFile['stripFromSelectionName'], $languageLabelFile['errorMode']);
2143 }
2144 }
2145 $this->inlineLanguageLabelFiles = array();
2146 // Convert labels/settings back to UTF-8 since json_encode() only works with UTF-8:
2147 if (TYPO3_MODE === 'FE' && $this->getCharSet() !== 'utf-8') {
2148 if ($this->inlineLanguageLabels) {
2149 $this->csConvObj->convArray($this->inlineLanguageLabels, $this->getCharSet(), 'utf-8');
2150 }
2151 if ($this->inlineSettings) {
2152 $this->csConvObj->convArray($this->inlineSettings, $this->getCharSet(), 'utf-8');
2153 }
2154 }
2155 }
2156
2157 /**
2158 * Make URLs to all backend ajax handlers available as inline setting.
2159 */
2160 protected function addAjaxUrlsToInlineSettings()
2161 {
2162 $ajaxUrls = array();
2163 foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['AJAX'] as $ajaxHandler => $_) {
2164 $ajaxUrls[$ajaxHandler] = BackendUtility::getAjaxUrl($ajaxHandler);
2165 }
2166
2167 // also add the ajax-based routes
2168 /** @var UriBuilder $uriBuilder */
2169 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
2170 /** @var Router $router */
2171 $router = GeneralUtility::makeInstance(Router::class);
2172 $routes = $router->getRoutes();
2173 foreach ($routes as $routeIdentifier => $route) {
2174 if ($route->getOption('ajax')) {
2175 $uri = (string)$uriBuilder->buildUriFromRoute($routeIdentifier);
2176 // use the shortened value in order to use this in JavaScript
2177 $routeIdentifier = str_replace('ajax_', '', $routeIdentifier);
2178 $ajaxUrls[$routeIdentifier] = $uri;
2179 }
2180 }
2181
2182 $this->inlineSettings['ajaxUrls'] = $ajaxUrls;
2183 }
2184
2185 /**
2186 * Renders the HTML script tag for the given jQuery version.
2187 *
2188 * @param string $version The jQuery version that should be included, either "latest" or any available version
2189 * @param string $source The location of the jQuery source, can be "local", "google", "msn" or "jquery
2190 * @param string $namespace The namespace in which the jQuery object of the specific version should be stored
2191 * @return string
2192 */
2193 protected function renderJqueryScriptTag($version, $source, $namespace)
2194 {
2195 switch (true) {
2196 case isset($this->jQueryCdnUrls[$source]):
2197 if ($this->enableJqueryDebug) {
2198 $minifyPart = '';
2199 } else {
2200 $minifyPart = '.min';
2201 }
2202 $jQueryFileName = sprintf($this->jQueryCdnUrls[$source], $version, $minifyPart);
2203 break;
2204 case $source === 'local':
2205 $jQueryFileName = $this->backPath . $this->jQueryPath . 'jquery-' . rawurlencode($version);
2206 if ($this->enableJqueryDebug) {
2207 $jQueryFileName .= '.js';
2208 } else {
2209 $jQueryFileName .= '.min.js';
2210 }
2211 break;
2212 default:
2213 $jQueryFileName = $source;
2214 }
2215 // Include the jQuery Core
2216 $scriptTag = '<script src="' . htmlspecialchars($jQueryFileName) . '" type="text/javascript"></script>' . LF;
2217 // Set the noConflict mode to be available via "TYPO3.jQuery" in all installations
2218 switch ($namespace) {
2219 case self::JQUERY_NAMESPACE_DEFAULT_NOCONFLICT:
2220 $scriptTag .= GeneralUtility::wrapJS('jQuery.noConflict();') . LF;
2221 break;
2222 case self::JQUERY_NAMESPACE_NONE:
2223 break;
2224 case self::JQUERY_NAMESPACE_DEFAULT:
2225
2226 default:
2227 $scriptTag .= GeneralUtility::wrapJS('var TYPO3 = TYPO3 || {}; TYPO3.' . $namespace . ' = jQuery.noConflict(true);') . LF;
2228 }
2229 return $scriptTag;
2230 }
2231
2232 /**
2233 * Render CSS library files
2234 *
2235 * @return string
2236 */
2237 protected function renderCssLibraries()
2238 {
2239 $cssFiles = '';
2240 if (!empty($this->cssLibs)) {
2241 foreach ($this->cssLibs as $file => $properties) {
2242 $file = GeneralUtility::resolveBackPath($file);
2243 $file = GeneralUtility::createVersionNumberedFilename($file);
2244 $tag = '<link rel="' . htmlspecialchars($properties['rel'])
2245 . '" type="text/css" href="' . htmlspecialchars($file)
2246 . '" media="' . htmlspecialchars($properties['media']) . '"'
2247 . ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '')
2248 . $this->endingSlash . '>';
2249 if ($properties['allWrap']) {
2250 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2251 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2252 }
2253 $tag .= LF;
2254 if ($properties['forceOnTop']) {
2255 $cssFiles = $tag . $cssFiles;
2256 } else {
2257 $cssFiles .= $tag;
2258 }
2259 }
2260 }
2261 return $cssFiles;
2262 }
2263
2264 /**
2265 * Render CSS files
2266 *
2267 * @return string
2268 */
2269 protected function renderCssFiles()
2270 {
2271 $cssFiles = '';
2272 if (!empty($this->cssFiles)) {
2273 foreach ($this->cssFiles as $file => $properties) {
2274 $file = GeneralUtility::resolveBackPath($file);
2275 $file = GeneralUtility::createVersionNumberedFilename($file);
2276 $tag = '<link rel="' . htmlspecialchars($properties['rel'])
2277 . '" type="text/css" href="' . htmlspecialchars($file)
2278 . '" media="' . htmlspecialchars($properties['media']) . '"'
2279 . ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '')
2280 . $this->endingSlash . '>';
2281 if ($properties['allWrap']) {
2282 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2283 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2284 }
2285 $tag .= LF;
2286 if ($properties['forceOnTop']) {
2287 $cssFiles = $tag . $cssFiles;
2288 } else {
2289 $cssFiles .= $tag;
2290 }
2291 }
2292 }
2293 return $cssFiles;
2294 }
2295
2296 /**
2297 * Render inline CSS
2298 *
2299 * @return string
2300 */
2301 protected function renderCssInline()
2302 {
2303 $cssInline = '';
2304 if (!empty($this->cssInline)) {
2305 foreach ($this->cssInline as $name => $properties) {
2306 $cssCode = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
2307 if ($properties['forceOnTop']) {
2308 $cssInline = $cssCode . $cssInline;
2309 } else {
2310 $cssInline .= $cssCode;
2311 }
2312 }
2313 $cssInline = $this->inlineCssWrap[0] . $cssInline . $this->inlineCssWrap[1];
2314 }
2315 return $cssInline;
2316 }
2317
2318 /**
2319 * Render JavaScipt libraries
2320 *
2321 * @return array<string> jsLibs and jsFooterLibs strings
2322 */
2323 protected function renderAdditionalJavaScriptLibraries()
2324 {
2325 $jsLibs = '';
2326 $jsFooterLibs = '';
2327 if (!empty($this->jsLibs)) {
2328 foreach ($this->jsLibs as $properties) {
2329 $properties['file'] = GeneralUtility::resolveBackPath($properties['file']);
2330 $properties['file'] = GeneralUtility::createVersionNumberedFilename($properties['file']);
2331 $async = ($properties['async']) ? ' async="async"' : '';
2332 $integrity = ($properties['integrity']) ? ' integrity="' . htmlspecialchars($properties['integrity']) . '"' : '';
2333 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"' . $async . $integrity . '></script>';
2334 if ($properties['allWrap']) {
2335 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2336 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2337 }
2338 $tag .= LF;
2339 if ($properties['forceOnTop']) {
2340 if ($properties['section'] === self::PART_HEADER) {
2341 $jsLibs = $tag . $jsLibs;
2342 } else {
2343 $jsFooterLibs = $tag . $jsFooterLibs;
2344 }
2345 } else {
2346 if ($properties['section'] === self::PART_HEADER) {
2347 $jsLibs .= $tag;
2348 } else {
2349 $jsFooterLibs .= $tag;
2350 }
2351 }
2352 }
2353 }
2354 if ($this->moveJsFromHeaderToFooter) {
2355 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
2356 $jsLibs = '';
2357 }
2358 return array($jsLibs, $jsFooterLibs);
2359 }
2360
2361 /**
2362 * Render JavaScript files
2363 *
2364 * @return array<string> jsFiles and jsFooterFiles strings
2365 */
2366 protected function renderJavaScriptFiles()
2367 {
2368 $jsFiles = '';
2369 $jsFooterFiles = '';
2370 if (!empty($this->jsFiles)) {
2371 foreach ($this->jsFiles as $file => $properties) {
2372 $file = GeneralUtility::resolveBackPath($file);
2373 $file = GeneralUtility::createVersionNumberedFilename($file);
2374 $async = ($properties['async']) ? ' async="async"' : '';
2375 $integrity = ($properties['integrity']) ? ' integrity="' . htmlspecialchars($properties['integrity']) . '"' : '';
2376 $tag = '<script src="' . htmlspecialchars($file) . '" type="' . htmlspecialchars($properties['type']) . '"' . $async . $integrity . '></script>';
2377 if ($properties['allWrap']) {
2378 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2379 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2380 }
2381 $tag .= LF;
2382 if ($properties['forceOnTop']) {
2383 if ($properties['section'] === self::PART_HEADER) {
2384 $jsFiles = $tag . $jsFiles;
2385 } else {
2386 $jsFooterFiles = $tag . $jsFooterFiles;
2387 }
2388 } else {
2389 if ($properties['section'] === self::PART_HEADER) {
2390 $jsFiles .= $tag;
2391 } else {
2392 $jsFooterFiles .= $tag;
2393 }
2394 }
2395 }
2396 }
2397 if ($this->moveJsFromHeaderToFooter) {
2398 $jsFooterFiles = $jsFiles . $jsFooterFiles;
2399 $jsFiles = '';
2400 }
2401 return array($jsFiles, $jsFooterFiles);
2402 }
2403
2404 /**
2405 * Render inline JavaScript
2406 *
2407 * @return array<string> jsInline and jsFooterInline string
2408 */
2409 protected function renderInlineJavaScript()
2410 {
2411 $jsInline = '';
2412 $jsFooterInline = '';
2413 if (!empty($this->jsInline)) {
2414 foreach ($this->jsInline as $name => $properties) {
2415 $jsCode = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
2416 if ($properties['forceOnTop']) {
2417 if ($properties['section'] === self::PART_HEADER) {
2418 $jsInline = $jsCode . $jsInline;
2419 } else {
2420 $jsFooterInline = $jsCode . $jsFooterInline;
2421 }
2422 } else {
2423 if ($properties['section'] === self::PART_HEADER) {
2424 $jsInline .= $jsCode;
2425 } else {
2426 $jsFooterInline .= $jsCode;
2427 }
2428 }
2429 }
2430 }
2431 if ($jsInline) {
2432 $jsInline = $this->inlineJavascriptWrap[0] . $jsInline . $this->inlineJavascriptWrap[1];
2433 }
2434 if ($jsFooterInline) {
2435 $jsFooterInline = $this->inlineJavascriptWrap[0] . $jsFooterInline . $this->inlineJavascriptWrap[1];
2436 }
2437 if ($this->moveJsFromHeaderToFooter) {
2438 $jsFooterInline = $jsInline . $jsFooterInline;
2439 $jsInline = '';
2440 }
2441 return array($jsInline, $jsFooterInline);
2442 }
2443
2444 /**
2445 * Include language file for inline usage
2446 *
2447 * @param string $fileRef
2448 * @param string $selectionPrefix
2449 * @param string $stripFromSelectionName
2450 * @param int $errorMode
2451 * @return void
2452 * @throws \RuntimeException
2453 */
2454 protected function includeLanguageFileForInline($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0)
2455 {
2456 if (!isset($this->lang) || !isset($this->charSet)) {
2457 throw new \RuntimeException('Language and character encoding are not set.', 1284906026);
2458 }
2459 $labelsFromFile = array();
2460 $allLabels = $this->readLLfile($fileRef, $errorMode);
2461 if ($allLabels !== false) {
2462 // Merge language specific translations:
2463 if ($this->lang !== 'default' && isset($allLabels[$this->lang])) {
2464 $labels = array_merge($allLabels['default'], $allLabels[$this->lang]);
2465 } else {
2466 $labels = $allLabels['default'];
2467 }
2468 // Iterate through all locallang labels:
2469 foreach ($labels as $label => $value) {
2470 // If $selectionPrefix is set, only respect labels that start with $selectionPrefix
2471 if ($selectionPrefix === '' || strpos($label, $selectionPrefix) === 0) {
2472 // Remove substring $stripFromSelectionName from label
2473 $label = str_replace($stripFromSelectionName, '', $label);
2474 $labelsFromFile[$label] = $value;
2475 }
2476 }
2477 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $labelsFromFile);
2478 }
2479 }
2480
2481 /**
2482 * Reads a locallang file.
2483 *
2484 * @param string $fileRef Reference to a relative filename to include.
2485 * @param int $errorMode Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
2486 * @return array Returns the $LOCAL_LANG array found in the file. If no array found, returns empty array.
2487 */
2488 protected function readLLfile($fileRef, $errorMode = 0)
2489 {
2490 /** @var $languageFactory LocalizationFactory */
2491 $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
2492
2493 if ($this->lang !== 'default') {
2494 $languages = array_reverse($this->languageDependencies);
2495 // At least we need to have English
2496 if (empty($languages)) {
2497 $languages[] = 'default';
2498 }
2499 } else {
2500 $languages = array('default');
2501 }
2502
2503 $localLanguage = array();
2504 foreach ($languages as $language) {
2505 $tempLL = $languageFactory->getParsedData($fileRef, $language, $this->charSet, $errorMode);
2506
2507 $localLanguage['default'] = $tempLL['default'];
2508 if (!isset($localLanguage[$this->lang])) {
2509 $localLanguage[$this->lang] = $localLanguage['default'];
2510 }
2511 if ($this->lang !== 'default' && isset($tempLL[$language])) {
2512 // Merge current language labels onto labels from previous language
2513 // This way we have a labels with fall back applied
2514 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($localLanguage[$this->lang], $tempLL[$language], true, false);
2515 }
2516 }
2517
2518 return $localLanguage;
2519 }
2520
2521 /*****************************************************/
2522 /* */
2523 /* Tools */
2524 /* */
2525 /*****************************************************/
2526 /**
2527 * Concatenate files into one file
2528 * registered handler
2529 *
2530 * @return void
2531 */
2532 protected function doConcatenate()
2533 {
2534 $this->doConcatenateCss();
2535 $this->doConcatenateJavaScript();
2536 }
2537
2538 /**
2539 * Concatenate JavaScript files according to the configuration.
2540 *
2541 * @return void
2542 */
2543 protected function doConcatenateJavaScript()
2544 {
2545 if ($this->concatenateFiles || $this->concatenateJavascript) {
2546 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'])) {
2547 // use external concatenation routine
2548 $params = array(
2549 'jsLibs' => &$this->jsLibs,
2550 'jsFiles' => &$this->jsFiles,
2551 'jsFooterFiles' => &$this->jsFooterFiles,
2552 'headerData' => &$this->headerData,
2553 'footerData' => &$this->footerData
2554 );
2555 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'], $params, $this);
2556 } else {
2557 $this->jsLibs = $this->getCompressor()->concatenateJsFiles($this->jsLibs);
2558 $this->jsFiles = $this->getCompressor()->concatenateJsFiles($this->jsFiles);
2559 $this->jsFooterFiles = $this->getCompressor()->concatenateJsFiles($this->jsFooterFiles);
2560 }
2561 }
2562 }
2563
2564 /**
2565 * Concatenate CSS files according to configuration.
2566 *
2567 * @return void
2568 */
2569 protected function doConcatenateCss()
2570 {
2571 if ($this->concatenateFiles || $this->concatenateCss) {
2572 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'])) {
2573 // use external concatenation routine
2574 $params = array(
2575 'cssFiles' => &$this->cssFiles,
2576 'cssLibs' => &$this->cssLibs,
2577 'headerData' => &$this->headerData,
2578 'footerData' => &$this->footerData
2579 );
2580 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'], $params, $this);
2581 } else {
2582 $cssOptions = array();
2583 if (TYPO3_MODE === 'BE') {
2584 $cssOptions = array('baseDirectories' => $GLOBALS['TBE_TEMPLATE']->getSkinStylesheetDirectories());
2585 }
2586 $this->cssLibs = $this->getCompressor()->concatenateCssFiles($this->cssLibs, $cssOptions);
2587 $this->cssFiles = $this->getCompressor()->concatenateCssFiles($this->cssFiles, $cssOptions);
2588 }
2589 }
2590 }
2591
2592 /**
2593 * Compresses inline code
2594 *
2595 * @return void
2596 */
2597 protected function doCompress()
2598 {
2599 $this->doCompressJavaScript();
2600 $this->doCompressCss();
2601 }
2602
2603 /**
2604 * Compresses CSS according to configuration.
2605 *
2606 * @return void
2607 */
2608 protected function doCompressCss()
2609 {
2610 if ($this->compressCss) {
2611 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'])) {
2612 // Use external compression routine
2613 $params = array(
2614 'cssInline' => &$this->cssInline,
2615 'cssFiles' => &$this->cssFiles,
2616 'cssLibs' => &$this->cssLibs,
2617 'headerData' => &$this->headerData,
2618 'footerData' => &$this->footerData
2619 );
2620 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this);
2621 } else {
2622 $this->cssLibs = $this->getCompressor()->compressCssFiles($this->cssLibs);
2623 $this->cssFiles = $this->getCompressor()->compressCssFiles($this->cssFiles);
2624 }
2625 }
2626 }
2627
2628 /**
2629 * Compresses JavaScript according to configuration.
2630 *
2631 * @return void
2632 */
2633 protected function doCompressJavaScript()
2634 {
2635 if ($this->compressJavascript) {
2636 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'])) {
2637 // Use external compression routine
2638 $params = array(
2639 'jsInline' => &$this->jsInline,
2640 'jsFooterInline' => &$this->jsFooterInline,
2641 'jsLibs' => &$this->jsLibs,
2642 'jsFiles' => &$this->jsFiles,
2643 'jsFooterFiles' => &$this->jsFooterFiles,
2644 'headerData' => &$this->headerData,
2645 'footerData' => &$this->footerData
2646 );
2647 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this);
2648 } else {
2649 // Traverse the arrays, compress files
2650 if (!empty($this->jsInline)) {
2651 foreach ($this->jsInline as $name => $properties) {
2652 if ($properties['compress']) {
2653 $error = '';
2654 $this->jsInline[$name]['code'] = GeneralUtility::minifyJavaScript($properties['code'], $error);
2655 if ($error) {
2656 $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error . LF;
2657 }
2658 }
2659 }
2660 }
2661 $this->jsLibs = $this->getCompressor()->compressJsFiles($this->jsLibs);
2662 $this->jsFiles = $this->getCompressor()->compressJsFiles($this->jsFiles);
2663 $this->jsFooterFiles = $this->getCompressor()->compressJsFiles($this->jsFooterFiles);
2664 }
2665 }
2666 }
2667
2668 /**
2669 * Returns instance of \TYPO3\CMS\Core\Resource\ResourceCompressor
2670 *
2671 * @return \TYPO3\CMS\Core\Resource\ResourceCompressor
2672 */
2673 protected function getCompressor()
2674 {
2675 if ($this->compressor === null) {
2676 $this->compressor = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceCompressor::class);
2677 }
2678 return $this->compressor;
2679 }
2680
2681 /**
2682 * Processes a Javascript file dependent on the current context
2683 *
2684 * Adds the version number for Frontend, compresses the file for Backend
2685 *
2686 * @param string $filename Filename
2687 * @return string New filename
2688 */
2689 protected function processJsFile($filename)
2690 {
2691 switch (TYPO3_MODE) {
2692 case 'FE':
2693 if ($this->compressJavascript) {
2694 $filename = $this->getCompressor()->compressJsFile($filename);
2695 } else {
2696 $filename = GeneralUtility::createVersionNumberedFilename($filename);
2697 }
2698 break;
2699 case 'BE':
2700 if ($this->compressJavascript) {
2701 $filename = $this->getCompressor()->compressJsFile($filename);
2702 }
2703 break;
2704 }
2705 return $filename;
2706 }
2707
2708 /**
2709 * Returns global frontend controller
2710 *
2711 * @return TypoScriptFrontendController
2712 */
2713 protected function getTypoScriptFrontendController()
2714 {
2715 return $GLOBALS['TSFE'];
2716 }
2717
2718 /**
2719 * Returns global language service instance
2720 *
2721 * @return \TYPO3\CMS\Lang\LanguageService
2722 */
2723 protected function getLanguageService()
2724 {
2725 return $GLOBALS['LANG'];
2726 }
2727
2728 /*****************************************************/
2729 /* */
2730 /* Hooks */
2731 /* */
2732 /*****************************************************/
2733 /**
2734 * Execute PreRenderHook for possible manipulation
2735 *
2736 * @return void
2737 */
2738 protected function executePreRenderHook()
2739 {
2740 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'])) {
2741 $params = array(
2742 'jsLibs' => &$this->jsLibs,
2743 'jsFooterLibs' => &$this->jsFooterLibs,
2744 'jsFiles' => &$this->jsFiles,
2745 'jsFooterFiles' => &$this->jsFooterFiles,
2746 'cssFiles' => &$this->cssFiles,
2747 'headerData' => &$this->headerData,
2748 'footerData' => &$this->footerData,
2749 'jsInline' => &$this->jsInline,
2750 'jsFooterInline' => &$this->jsFooterInline,
2751 'cssInline' => &$this->cssInline
2752 );
2753 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'] as $hook) {
2754 GeneralUtility::callUserFunction($hook, $params, $this);
2755 }
2756 }
2757 }
2758
2759 /**
2760 * PostTransform for possible manipulation of concatenated and compressed files
2761 *
2762 * @return void
2763 */
2764 protected function executeRenderPostTransformHook()
2765 {
2766 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postTransform'])) {
2767 $params = array(
2768 'jsLibs' => &$this->jsLibs,
2769 'jsFooterLibs' => &$this->jsFooterLibs,
2770 'jsFiles' => &$this->jsFiles,
2771 'jsFooterFiles' => &$this->jsFooterFiles,
2772 'cssFiles' => &$this->cssFiles,
2773 'headerData' => &$this->headerData,
2774 'footerData' => &$this->footerData,
2775 'jsInline' => &$this->jsInline,
2776 'jsFooterInline' => &$this->jsFooterInline,
2777 'cssInline' => &$this->cssInline
2778 );
2779 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postTransform'] as $hook) {
2780 GeneralUtility::callUserFunction($hook, $params, $this);
2781 }
2782 }
2783 }
2784
2785 /**
2786 * Execute postRenderHook for possible manipulation
2787 *
2788 * @param $jsLibs string
2789 * @param $jsFiles string
2790 * @param $jsFooterFiles string
2791 * @param $cssLibs string
2792 * @param $cssFiles string
2793 * @param $jsInline string
2794 * @param $cssInline string
2795 * @param $jsFooterInline string
2796 * @param $jsFooterLibs string
2797 * @return void
2798 */
2799 protected function executePostRenderHook(&$jsLibs, &$jsFiles, &$jsFooterFiles, &$cssLibs, &$cssFiles, &$jsInline, &$cssInline, &$jsFooterInline, &$jsFooterLibs)
2800 {
2801 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'])) {
2802 $params = array(
2803 'jsLibs' => &$jsLibs,
2804 'jsFiles' => &$jsFiles,
2805 'jsFooterFiles' => &$jsFooterFiles,
2806 'cssLibs' => &$cssLibs,
2807 'cssFiles' => &$cssFiles,
2808 'headerData' => &$this->headerData,
2809 'footerData' => &$this->footerData,
2810 'jsInline' => &$jsInline,
2811 'cssInline' => &$cssInline,
2812 'xmlPrologAndDocType' => &$this->xmlPrologAndDocType,
2813 'htmlTag' => &$this->htmlTag,
2814 'headTag' => &$this->headTag,
2815 'charSet' => &$this->charSet,
2816 'metaCharsetTag' => &$this->metaCharsetTag,
2817 'shortcutTag' => &$this->shortcutTag,
2818 'inlineComments' => &$this->inlineComments,
2819 'baseUrl' => &$this->baseUrl,
2820 'baseUrlTag' => &$this->baseUrlTag,
2821 'favIcon' => &$this->favIcon,
2822 'iconMimeType' => &$this->iconMimeType,
2823 'titleTag' => &$this->titleTag,
2824 'title' => &$this->title,
2825 'metaTags' => &$this->metaTags,
2826 'jsFooterInline' => &$jsFooterInline,
2827 'jsFooterLibs' => &$jsFooterLibs,
2828 'bodyContent' => &$this->bodyContent
2829 );
2830 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'] as $hook) {
2831 GeneralUtility::callUserFunction($hook, $params, $this);
2832 }
2833 }
2834 }
2835 }