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