[TASK] Streamline usage of DebugConsole
[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 8
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 /**
1646 * call this function if you need the extJS library
1647 *
1648 * @param bool $css Flag, if set the ext-css will be loaded
1649 * @param bool $theme Flag, if set the ext-theme "grey" will be loaded
1650 * @return void
1651 */
1652 public function loadExtJS($css = true, $theme = true)
1653 {
1654 $this->addExtJS = true;
1655 $this->extJStheme = $theme;
1656 $this->extJScss = $css;
1657 }
1658
1659 /**
1660 * Call this function to load debug version of ExtJS. Use this for development only
1661 *
1662 * @return void
1663 */
1664 public function enableExtJsDebug()
1665 {
1666 $this->enableExtJsDebug = true;
1667 }
1668
1669 /**
1670 * Adds Javascript Inline Label. This will occur in TYPO3.lang - object
1671 * The label can be used in scripts with TYPO3.lang.<key>
1672 * Need extJs loaded
1673 *
1674 * @param string $key
1675 * @param string $value
1676 * @return void
1677 */
1678 public function addInlineLanguageLabel($key, $value)
1679 {
1680 $this->inlineLanguageLabels[$key] = $value;
1681 }
1682
1683 /**
1684 * Adds Javascript Inline Label Array. This will occur in TYPO3.lang - object
1685 * The label can be used in scripts with TYPO3.lang.<key>
1686 * Array will be merged with existing array.
1687 * Need extJs loaded
1688 *
1689 * @param array $array
1690 * @param bool $parseWithLanguageService
1691 * @return void
1692 */
1693 public function addInlineLanguageLabelArray(array $array, $parseWithLanguageService = false)
1694 {
1695 if ($parseWithLanguageService === true) {
1696 foreach ($array as $key => $value) {
1697 if (TYPO3_MODE === 'FE') {
1698 $array[$key] = $this->getTypoScriptFrontendController()->sL($value);
1699 } else {
1700 $array[$key] = $this->getLanguageService()->sL($value);
1701 }
1702 }
1703 }
1704
1705 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $array);
1706 }
1707
1708 /**
1709 * Gets labels to be used in JavaScript fetched from a locallang file.
1710 *
1711 * @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.
1712 * @param string $selectionPrefix Prefix to select the correct labels (default: '')
1713 * @param string $stripFromSelectionName String to be removed from the label names in the output. (default: '')
1714 * @param int $errorMode Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
1715 * @return void
1716 */
1717 public function addInlineLanguageLabelFile($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0)
1718 {
1719 $index = md5($fileRef . $selectionPrefix . $stripFromSelectionName);
1720 if ($fileRef && !isset($this->inlineLanguageLabelFiles[$index])) {
1721 $this->inlineLanguageLabelFiles[$index] = array(
1722 'fileRef' => $fileRef,
1723 'selectionPrefix' => $selectionPrefix,
1724 'stripFromSelectionName' => $stripFromSelectionName,
1725 'errorMode' => $errorMode
1726 );
1727 }
1728 }
1729
1730 /**
1731 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1732 * The label can be used in scripts with TYPO3.setting.<key>
1733 * Need extJs loaded
1734 *
1735 * @param string $namespace
1736 * @param string $key
1737 * @param string $value
1738 * @return void
1739 */
1740 public function addInlineSetting($namespace, $key, $value)
1741 {
1742 if ($namespace) {
1743 if (strpos($namespace, '.')) {
1744 $parts = explode('.', $namespace);
1745 $a = &$this->inlineSettings;
1746 foreach ($parts as $part) {
1747 $a = &$a[$part];
1748 }
1749 $a[$key] = $value;
1750 } else {
1751 $this->inlineSettings[$namespace][$key] = $value;
1752 }
1753 } else {
1754 $this->inlineSettings[$key] = $value;
1755 }
1756 }
1757
1758 /**
1759 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1760 * The label can be used in scripts with TYPO3.setting.<key>
1761 * Array will be merged with existing array.
1762 * Need extJs loaded
1763 *
1764 * @param string $namespace
1765 * @param array $array
1766 * @return void
1767 */
1768 public function addInlineSettingArray($namespace, array $array)
1769 {
1770 if ($namespace) {
1771 if (strpos($namespace, '.')) {
1772 $parts = explode('.', $namespace);
1773 $a = &$this->inlineSettings;
1774 foreach ($parts as $part) {
1775 $a = &$a[$part];
1776 }
1777 $a = array_merge((array)$a, $array);
1778 } else {
1779 $this->inlineSettings[$namespace] = array_merge((array)$this->inlineSettings[$namespace], $array);
1780 }
1781 } else {
1782 $this->inlineSettings = array_merge($this->inlineSettings, $array);
1783 }
1784 }
1785
1786 /**
1787 * Adds content to body content
1788 *
1789 * @param string $content
1790 * @return void
1791 */
1792 public function addBodyContent($content)
1793 {
1794 $this->bodyContent .= $content;
1795 }
1796
1797 /*****************************************************/
1798 /* */
1799 /* Render Functions */
1800 /* */
1801 /*****************************************************/
1802 /**
1803 * Render the section (Header or Footer)
1804 *
1805 * @param int $part Section which should be rendered: self::PART_COMPLETE, self::PART_HEADER or self::PART_FOOTER
1806 * @return string Content of rendered section
1807 */
1808 public function render($part = self::PART_COMPLETE)
1809 {
1810 $this->prepareRendering();
1811 list($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs) = $this->renderJavaScriptAndCss();
1812 $metaTags = implode(LF, $this->metaTags);
1813 $markerArray = $this->getPreparedMarkerArray($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs, $metaTags);
1814 $template = $this->getTemplateForPart($part);
1815
1816 // The page renderer needs a full reset, even when only rendering one part of the page
1817 // This means that you can only register footer files *after* the header has been already rendered.
1818 // In case you render the footer part first, header files can only be added *after* the footer has been rendered
1819 $this->reset();
1820 $templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
1821 return trim($templateService->substituteMarkerArray($template, $markerArray, '###|###'));
1822 }
1823
1824 /**
1825 * Render the page but not the JavaScript and CSS Files
1826 *
1827 * @param string $substituteHash The hash that is used for the placehoder markers
1828 * @access private
1829 * @return string Content of rendered section
1830 */
1831 public function renderPageWithUncachedObjects($substituteHash)
1832 {
1833 $this->prepareRendering();
1834 $markerArray = $this->getPreparedMarkerArrayForPageWithUncachedObjects($substituteHash);
1835 $template = $this->getTemplateForPart(self::PART_COMPLETE);
1836 $templateService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
1837 return trim($templateService->substituteMarkerArray($template, $markerArray, '###|###'));
1838 }
1839
1840 /**
1841 * Renders the JavaScript and CSS files that have been added during processing
1842 * of uncached content objects (USER_INT, COA_INT)
1843 *
1844 * @param string $cachedPageContent
1845 * @param string $substituteHash The hash that is used for the placehoder markers
1846 * @access private
1847 * @return string
1848 */
1849 public function renderJavaScriptAndCssForProcessingOfUncachedContentObjects($cachedPageContent, $substituteHash)
1850 {
1851 $this->prepareRendering();
1852 list($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs) = $this->renderJavaScriptAndCss();
1853 $title = $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '';
1854 $markerArray = array(
1855 '<!-- ###TITLE' . $substituteHash . '### -->' => $title,
1856 '<!-- ###CSS_LIBS' . $substituteHash . '### -->' => $cssLibs,
1857 '<!-- ###CSS_INCLUDE' . $substituteHash . '### -->' => $cssFiles,
1858 '<!-- ###CSS_INLINE' . $substituteHash . '### -->' => $cssInline,
1859 '<!-- ###JS_INLINE' . $substituteHash . '### -->' => $jsInline,
1860 '<!-- ###JS_INCLUDE' . $substituteHash . '### -->' => $jsFiles,
1861 '<!-- ###JS_LIBS' . $substituteHash . '### -->' => $jsLibs,
1862 '<!-- ###HEADERDATA' . $substituteHash . '### -->' => implode(LF, $this->headerData),
1863 '<!-- ###FOOTERDATA' . $substituteHash . '### -->' => implode(LF, $this->footerData),
1864 '<!-- ###JS_LIBS_FOOTER' . $substituteHash . '### -->' => $jsFooterLibs,
1865 '<!-- ###JS_INCLUDE_FOOTER' . $substituteHash . '### -->' => $jsFooterFiles,
1866 '<!-- ###JS_INLINE_FOOTER' . $substituteHash . '### -->' => $jsFooterInline
1867 );
1868 foreach ($markerArray as $placeHolder => $content) {
1869 $cachedPageContent = str_replace($placeHolder, $content, $cachedPageContent);
1870 }
1871 $this->reset();
1872 return $cachedPageContent;
1873 }
1874
1875 /**
1876 * Remove ending slashes from static header block
1877 * if the page is beeing rendered as html (not xhtml)
1878 * and define property $this->endingSlash for further use
1879 *
1880 * @return void
1881 */
1882 protected function prepareRendering()
1883 {
1884 if ($this->getRenderXhtml()) {
1885 $this->endingSlash = ' /';
1886 } else {
1887 $this->metaCharsetTag = str_replace(' />', '>', $this->metaCharsetTag);
1888 $this->baseUrlTag = str_replace(' />', '>', $this->baseUrlTag);
1889 $this->shortcutTag = str_replace(' />', '>', $this->shortcutTag);
1890 $this->endingSlash = '';
1891 }
1892 }
1893
1894 /**
1895 * Renders all JavaScript and CSS
1896 *
1897 * @return array<string>
1898 */
1899 protected function renderJavaScriptAndCss()
1900 {
1901 $this->executePreRenderHook();
1902 $mainJsLibs = $this->renderMainJavaScriptLibraries();
1903 if ($this->concatenateFiles || $this->concatenateJavascript || $this->concatenateCss) {
1904 // Do the file concatenation
1905 $this->doConcatenate();
1906 }
1907 if ($this->compressCss || $this->compressJavascript) {
1908 // Do the file compression
1909 $this->doCompress();
1910 }
1911 $this->executeRenderPostTransformHook();
1912 $cssLibs = $this->renderCssLibraries();
1913 $cssFiles = $this->renderCssFiles();
1914 $cssInline = $this->renderCssInline();
1915 list($jsLibs, $jsFooterLibs) = $this->renderAdditionalJavaScriptLibraries();
1916 list($jsFiles, $jsFooterFiles) = $this->renderJavaScriptFiles();
1917 list($jsInline, $jsFooterInline) = $this->renderInlineJavaScript();
1918 $jsLibs = $mainJsLibs . $jsLibs;
1919 if ($this->moveJsFromHeaderToFooter) {
1920 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
1921 $jsLibs = '';
1922 $jsFooterFiles = $jsFiles . LF . $jsFooterFiles;
1923 $jsFiles = '';
1924 $jsFooterInline = $jsInline . LF . $jsFooterInline;
1925 $jsInline = '';
1926 }
1927 $this->executePostRenderHook($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs);
1928 return array($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs);
1929 }
1930
1931 /**
1932 * Fills the marker array with the given strings and trims each value
1933 *
1934 * @param $jsLibs string
1935 * @param $jsFiles string
1936 * @param $jsFooterFiles string
1937 * @param $cssLibs string
1938 * @param $cssFiles string
1939 * @param $jsInline string
1940 * @param $cssInline string
1941 * @param $jsFooterInline string
1942 * @param $jsFooterLibs string
1943 * @param $metaTags string
1944 * @return array Marker array
1945 */
1946 protected function getPreparedMarkerArray($jsLibs, $jsFiles, $jsFooterFiles, $cssLibs, $cssFiles, $jsInline, $cssInline, $jsFooterInline, $jsFooterLibs, $metaTags)
1947 {
1948 $markerArray = array(
1949 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1950 'HTMLTAG' => $this->htmlTag,
1951 'HEADTAG' => $this->headTag,
1952 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1953 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1954 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1955 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1956 'CSS_LIBS' => $cssLibs,
1957 'CSS_INCLUDE' => $cssFiles,
1958 'CSS_INLINE' => $cssInline,
1959 'JS_INLINE' => $jsInline,
1960 'JS_INCLUDE' => $jsFiles,
1961 'JS_LIBS' => $jsLibs,
1962 'TITLE' => $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '',
1963 'META' => $metaTags,
1964 'HEADERDATA' => $this->headerData ? implode(LF, $this->headerData) : '',
1965 'FOOTERDATA' => $this->footerData ? implode(LF, $this->footerData) : '',
1966 'JS_LIBS_FOOTER' => $jsFooterLibs,
1967 'JS_INCLUDE_FOOTER' => $jsFooterFiles,
1968 'JS_INLINE_FOOTER' => $jsFooterInline,
1969 'BODY' => $this->bodyContent
1970 );
1971 $markerArray = array_map('trim', $markerArray);
1972 return $markerArray;
1973 }
1974
1975 /**
1976 * Fills the marker array with the given strings and trims each value
1977 *
1978 * @param string $substituteHash The hash that is used for the placehoder markers
1979 * @return array Marker array
1980 */
1981 protected function getPreparedMarkerArrayForPageWithUncachedObjects($substituteHash)
1982 {
1983 $markerArray = array(
1984 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1985 'HTMLTAG' => $this->htmlTag,
1986 'HEADTAG' => $this->headTag,
1987 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1988 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1989 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1990 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1991 'META' => implode(LF, $this->metaTags),
1992 'BODY' => $this->bodyContent,
1993 'TITLE' => '<!-- ###TITLE' . $substituteHash . '### -->',
1994 'CSS_LIBS' => '<!-- ###CSS_LIBS' . $substituteHash . '### -->',
1995 'CSS_INCLUDE' => '<!-- ###CSS_INCLUDE' . $substituteHash . '### -->',
1996 'CSS_INLINE' => '<!-- ###CSS_INLINE' . $substituteHash . '### -->',
1997 'JS_INLINE' => '<!-- ###JS_INLINE' . $substituteHash . '### -->',
1998 'JS_INCLUDE' => '<!-- ###JS_INCLUDE' . $substituteHash . '### -->',
1999 'JS_LIBS' => '<!-- ###JS_LIBS' . $substituteHash . '### -->',
2000 'HEADERDATA' => '<!-- ###HEADERDATA' . $substituteHash . '### -->',
2001 'FOOTERDATA' => '<!-- ###FOOTERDATA' . $substituteHash . '### -->',
2002 'JS_LIBS_FOOTER' => '<!-- ###JS_LIBS_FOOTER' . $substituteHash . '### -->',
2003 'JS_INCLUDE_FOOTER' => '<!-- ###JS_INCLUDE_FOOTER' . $substituteHash . '### -->',
2004 'JS_INLINE_FOOTER' => '<!-- ###JS_INLINE_FOOTER' . $substituteHash . '### -->'
2005 );
2006 $markerArray = array_map('trim', $markerArray);
2007 return $markerArray;
2008 }
2009
2010 /**
2011 * Reads the template file and returns the requested part as string
2012 *
2013 * @param int $part
2014 * @return string
2015 */
2016 protected function getTemplateForPart($part)
2017 {
2018 $templateFile = GeneralUtility::getFileAbsFileName($this->templateFile, true);
2019 $template = GeneralUtility::getUrl($templateFile);
2020 if ($this->removeLineBreaksFromTemplate) {
2021 $template = strtr($template, array(LF => '', CR => ''));
2022 }
2023 if ($part !== self::PART_COMPLETE) {
2024 $templatePart = explode('###BODY###', $template);
2025 $template = $templatePart[$part - 1];
2026 }
2027 return $template;
2028 }
2029
2030 /**
2031 * Helper function for render the main JavaScript libraries,
2032 * currently: RequireJS, jQuery, ExtJS
2033 *
2034 * @return string Content with JavaScript libraries
2035 */
2036 protected function renderMainJavaScriptLibraries()
2037 {
2038 $out = '';
2039
2040 // Include RequireJS
2041 if ($this->addRequireJs) {
2042 // load the paths of the requireJS configuration
2043 $out .= GeneralUtility::wrapJS('var require = ' . json_encode($this->requireJsConfig)) . LF;
2044 // directly after that, include the require.js file
2045 $out .= '<script src="' . $this->processJsFile(($this->backPath . $this->requireJsPath . 'require.js')) . '" type="text/javascript"></script>' . LF;
2046 }
2047
2048 // Include jQuery Core for each namespace, depending on the version and source
2049 if (!empty($this->jQueryVersions)) {
2050 foreach ($this->jQueryVersions as $namespace => $jQueryVersion) {
2051 $out .= $this->renderJqueryScriptTag($jQueryVersion['version'], $jQueryVersion['source'], $namespace);
2052 }
2053 }
2054 // Include extJS
2055 if ($this->addExtJS) {
2056 // Use the base adapter all the time
2057 $out .= '<script src="' . $this->processJsFile(($this->backPath . $this->extJsPath . 'adapter/ext-base' . ($this->enableExtJsDebug ? '-debug' : '') . '.js')) . '" type="text/javascript"></script>' . LF;
2058 $out .= '<script src="' . $this->processJsFile(($this->backPath . $this->extJsPath . 'ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js')) . '" type="text/javascript"></script>' . LF;
2059 // Add extJS localization
2060 // Load standard ISO mapping and modify for use with ExtJS
2061 $localeMap = $this->locales->getIsoMapping();
2062 $localeMap[''] = 'en';
2063 $localeMap['default'] = 'en';
2064 // Greek
2065 $localeMap['gr'] = 'el_GR';
2066 // Norwegian Bokmaal
2067 $localeMap['no'] = 'no_BO';
2068 // Swedish
2069 $localeMap['se'] = 'se_SV';
2070 $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang;
2071 // @todo autoconvert file from UTF8 to current BE charset if necessary!!!!
2072 $extJsLocaleFile = $this->extJsPath . 'locale/ext-lang-' . $extJsLang . '.js';
2073 if (file_exists(PATH_typo3 . $extJsLocaleFile)) {
2074 $out .= '<script src="' . $this->processJsFile(($this->backPath . $extJsLocaleFile)) . '" type="text/javascript" charset="utf-8"></script>' . LF;
2075 }
2076 // Remove extjs from JScodeLibArray
2077 unset($this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all.js'], $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all-debug.js']);
2078 }
2079 $this->loadJavaScriptLanguageStrings();
2080 if (TYPO3_MODE === 'BE') {
2081 $this->addAjaxUrlsToInlineSettings();
2082 }
2083 $inlineSettings = $this->inlineLanguageLabels ? 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' : '';
2084 $inlineSettings .= $this->inlineSettings ? 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' : '';
2085 if ($this->addExtJS) {
2086 // Set clear.gif, move it on top, add handler code
2087 $code = '';
2088 if (!empty($this->extOnReadyCode)) {
2089 foreach ($this->extOnReadyCode as $block) {
2090 $code .= $block;
2091 }
2092 }
2093 $out .= $this->inlineJavascriptWrap[0] . '
2094 Ext.ns("TYPO3");
2095 Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(GeneralUtility::locationHeaderUrl($this->backPath . 'sysext/t3skin/icons/gfx/clear.gif')) . '";
2096 Ext.SSL_SECURE_URL = "' . htmlspecialchars(GeneralUtility::locationHeaderUrl($this->backPath . 'sysext/t3skin/icons/gfx/clear.gif')) . '";' . LF
2097 . $inlineSettings
2098 . 'Ext.onReady(function() {'
2099 . $code
2100 . ' });'
2101 . $this->inlineJavascriptWrap[1];
2102 $this->extOnReadyCode = array();
2103 // Include TYPO3.l10n object
2104 if (TYPO3_MODE === 'BE') {
2105 $out .= '<script src="' . $this->processJsFile(($this->backPath . 'sysext/lang/Resources/Public/JavaScript/Typo3Lang.js')) . '" type="text/javascript" charset="utf-8"></script>' . LF;
2106 }
2107 if ($this->extJScss) {
2108 if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) {
2109 $this->addCssLibrary($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'all', '', true);
2110 } else {
2111 $this->addCssLibrary($this->backPath . $this->extJsPath . 'resources/css/ext-all-notheme.css', 'stylesheet', 'all', '', true);
2112 }
2113 }
2114 if ($this->extJStheme) {
2115 if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) {
2116 $this->addCssLibrary($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'all', '', true);
2117 } else {
2118 $this->addCssLibrary($this->backPath . $this->extJsPath . 'resources/css/xtheme-blue.css', 'stylesheet', 'all', '', true);
2119 }
2120 }
2121 } else {
2122 // no extJS loaded, but still inline settings
2123 if ($inlineSettings !== '') {
2124 // make sure the global TYPO3 is available
2125 $inlineSettings = 'var TYPO3 = TYPO3 || {};' . CRLF . $inlineSettings;
2126 $out .= $this->inlineJavascriptWrap[0] . $inlineSettings . $this->inlineJavascriptWrap[1];
2127 // Add language module only if also jquery is guaranteed to be there
2128 if (TYPO3_MODE === 'BE' && !empty($this->jQueryVersions)) {
2129 $this->loadRequireJsModule('TYPO3/CMS/Lang/Lang');
2130 }
2131 }
2132 }
2133 return $out;
2134 }
2135
2136 /**
2137 * Load the language strings into JavaScript
2138 */
2139 protected function loadJavaScriptLanguageStrings()
2140 {
2141 if (!empty($this->inlineLanguageLabelFiles)) {
2142 foreach ($this->inlineLanguageLabelFiles as $languageLabelFile) {
2143 $this->includeLanguageFileForInline($languageLabelFile['fileRef'], $languageLabelFile['selectionPrefix'], $languageLabelFile['stripFromSelectionName'], $languageLabelFile['errorMode']);
2144 }
2145 }
2146 $this->inlineLanguageLabelFiles = array();
2147 // Convert labels/settings back to UTF-8 since json_encode() only works with UTF-8:
2148 if (TYPO3_MODE === 'FE' && $this->getCharSet() !== 'utf-8') {
2149 if ($this->inlineLanguageLabels) {
2150 $this->csConvObj->convArray($this->inlineLanguageLabels, $this->getCharSet(), 'utf-8');
2151 }
2152 if ($this->inlineSettings) {
2153 $this->csConvObj->convArray($this->inlineSettings, $this->getCharSet(), 'utf-8');
2154 }
2155 }
2156 }
2157
2158 /**
2159 * Make URLs to all backend ajax handlers available as inline setting.
2160 */
2161 protected function addAjaxUrlsToInlineSettings()
2162 {
2163 $ajaxUrls = array();
2164 foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['AJAX'] as $ajaxHandler => $_) {
2165 $ajaxUrls[$ajaxHandler] = BackendUtility::getAjaxUrl($ajaxHandler);
2166 }
2167
2168 // also add the ajax-based routes
2169 /** @var UriBuilder $uriBuilder */
2170 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
2171 /** @var Router $router */
2172 $router = GeneralUtility::makeInstance(Router::class);
2173 $routes = $router->getRoutes();
2174 foreach ($routes as $routeIdentifier => $route) {
2175 if ($route->getOption('ajax')) {
2176 $uri = (string)$uriBuilder->buildUriFromRoute($routeIdentifier);
2177 // use the shortened value in order to use this in JavaScript
2178 $routeIdentifier = str_replace('ajax_', '', $routeIdentifier);
2179 $ajaxUrls[$routeIdentifier] = $uri;
2180 }
2181 }
2182
2183 $this->inlineSettings['ajaxUrls'] = $ajaxUrls;
2184 }
2185
2186 /**
2187 * Renders the HTML script tag for the given jQuery version.
2188 *
2189 * @param string $version The jQuery version that should be included, either "latest" or any available version
2190 * @param string $source The location of the jQuery source, can be "local", "google", "msn" or "jquery
2191 * @param string $namespace The namespace in which the jQuery object of the specific version should be stored
2192 * @return string
2193 */
2194 protected function renderJqueryScriptTag($version, $source, $namespace)
2195 {
2196 switch (true) {
2197 case isset($this->jQueryCdnUrls[$source]):
2198 if ($this->enableJqueryDebug) {
2199 $minifyPart = '';
2200 } else {
2201 $minifyPart = '.min';
2202 }
2203 $jQueryFileName = sprintf($this->jQueryCdnUrls[$source], $version, $minifyPart);
2204 break;
2205 case $source === 'local':
2206 $jQueryFileName = $this->backPath . $this->jQueryPath . 'jquery-' . rawurlencode($version);
2207 if ($this->enableJqueryDebug) {
2208 $jQueryFileName .= '.js';
2209 } else {
2210 $jQueryFileName .= '.min.js';
2211 }
2212 break;
2213 default:
2214 $jQueryFileName = $source;
2215 }
2216 // Include the jQuery Core
2217 $scriptTag = '<script src="' . htmlspecialchars($jQueryFileName) . '" type="text/javascript"></script>' . LF;
2218 // Set the noConflict mode to be available via "TYPO3.jQuery" in all installations
2219 switch ($namespace) {
2220 case self::JQUERY_NAMESPACE_DEFAULT_NOCONFLICT:
2221 $scriptTag .= GeneralUtility::wrapJS('jQuery.noConflict();') . LF;
2222 break;
2223 case self::JQUERY_NAMESPACE_NONE:
2224 break;
2225 case self::JQUERY_NAMESPACE_DEFAULT:
2226
2227 default:
2228 $scriptTag .= GeneralUtility::wrapJS('var TYPO3 = TYPO3 || {}; TYPO3.' . $namespace . ' = jQuery.noConflict(true);') . LF;
2229 }
2230 return $scriptTag;
2231 }
2232
2233 /**
2234 * Render CSS library files
2235 *
2236 * @return string
2237 */
2238 protected function renderCssLibraries()
2239 {
2240 $cssFiles = '';
2241 if (!empty($this->cssLibs)) {
2242 foreach ($this->cssLibs as $file => $properties) {
2243 $file = GeneralUtility::resolveBackPath($file);
2244 $file = GeneralUtility::createVersionNumberedFilename($file);
2245 $tag = '<link rel="' . htmlspecialchars($properties['rel'])
2246 . '" type="text/css" href="' . htmlspecialchars($file)
2247 . '" media="' . htmlspecialchars($properties['media']) . '"'
2248 . ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '')
2249 . $this->endingSlash . '>';
2250 if ($properties['allWrap']) {
2251 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2252 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2253 }
2254 $tag .= LF;
2255 if ($properties['forceOnTop']) {
2256 $cssFiles = $tag . $cssFiles;
2257 } else {
2258 $cssFiles .= $tag;
2259 }
2260 }
2261 }
2262 return $cssFiles;
2263 }
2264
2265 /**
2266 * Render CSS files
2267 *
2268 * @return string
2269 */
2270 protected function renderCssFiles()
2271 {
2272 $cssFiles = '';
2273 if (!empty($this->cssFiles)) {
2274 foreach ($this->cssFiles as $file => $properties) {
2275 $file = GeneralUtility::resolveBackPath($file);
2276 $file = GeneralUtility::createVersionNumberedFilename($file);
2277 $tag = '<link rel="' . htmlspecialchars($properties['rel'])
2278 . '" type="text/css" href="' . htmlspecialchars($file)
2279 . '" media="' . htmlspecialchars($properties['media']) . '"'
2280 . ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '')
2281 . $this->endingSlash . '>';
2282 if ($properties['allWrap']) {
2283 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2284 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2285 }
2286 $tag .= LF;
2287 if ($properties['forceOnTop']) {
2288 $cssFiles = $tag . $cssFiles;
2289 } else {
2290 $cssFiles .= $tag;
2291 }
2292 }
2293 }
2294 return $cssFiles;
2295 }
2296
2297 /**
2298 * Render inline CSS
2299 *
2300 * @return string
2301 */
2302 protected function renderCssInline()
2303 {
2304 $cssInline = '';
2305 if (!empty($this->cssInline)) {
2306 foreach ($this->cssInline as $name => $properties) {
2307 $cssCode = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
2308 if ($properties['forceOnTop']) {
2309 $cssInline = $cssCode . $cssInline;
2310 } else {
2311 $cssInline .= $cssCode;
2312 }
2313 }
2314 $cssInline = $this->inlineCssWrap[0] . $cssInline . $this->inlineCssWrap[1];
2315 }
2316 return $cssInline;
2317 }
2318
2319 /**
2320 * Render JavaScipt libraries
2321 *
2322 * @return array<string> jsLibs and jsFooterLibs strings
2323 */
2324 protected function renderAdditionalJavaScriptLibraries()
2325 {
2326 $jsLibs = '';
2327 $jsFooterLibs = '';
2328 if (!empty($this->jsLibs)) {
2329 foreach ($this->jsLibs as $properties) {
2330 $properties['file'] = GeneralUtility::resolveBackPath($properties['file']);
2331 $properties['file'] = GeneralUtility::createVersionNumberedFilename($properties['file']);
2332 $async = ($properties['async']) ? ' async="async"' : '';
2333 $integrity = ($properties['integrity']) ? ' integrity="' . htmlspecialchars($properties['integrity']) . '"' : '';
2334 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"' . $async . $integrity . '></script>';
2335 if ($properties['allWrap']) {
2336 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2337 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2338 }
2339 $tag .= LF;
2340 if ($properties['forceOnTop']) {
2341 if ($properties['section'] === self::PART_HEADER) {
2342 $jsLibs = $tag . $jsLibs;
2343 } else {
2344 $jsFooterLibs = $tag . $jsFooterLibs;
2345 }
2346 } else {
2347 if ($properties['section'] === self::PART_HEADER) {
2348 $jsLibs .= $tag;
2349 } else {
2350 $jsFooterLibs .= $tag;
2351 }
2352 }
2353 }
2354 }
2355 if ($this->moveJsFromHeaderToFooter) {
2356 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
2357 $jsLibs = '';
2358 }
2359 return array($jsLibs, $jsFooterLibs);
2360 }
2361
2362 /**
2363 * Render JavaScript files
2364 *
2365 * @return array<string> jsFiles and jsFooterFiles strings
2366 */
2367 protected function renderJavaScriptFiles()
2368 {
2369 $jsFiles = '';
2370 $jsFooterFiles = '';
2371 if (!empty($this->jsFiles)) {
2372 foreach ($this->jsFiles as $file => $properties) {
2373 $file = GeneralUtility::resolveBackPath($file);
2374 $file = GeneralUtility::createVersionNumberedFilename($file);
2375 $async = ($properties['async']) ? ' async="async"' : '';
2376 $integrity = ($properties['integrity']) ? ' integrity="' . htmlspecialchars($properties['integrity']) . '"' : '';
2377 $tag = '<script src="' . htmlspecialchars($file) . '" type="' . htmlspecialchars($properties['type']) . '"' . $async . $integrity . '></script>';
2378 if ($properties['allWrap']) {
2379 $wrapArr = explode($properties['splitChar'] ?: '|', $properties['allWrap'], 2);
2380 $tag = $wrapArr[0] . $tag . $wrapArr[1];
2381 }
2382 $tag .= LF;
2383 if ($properties['forceOnTop']) {
2384 if ($properties['section'] === self::PART_HEADER) {
2385 $jsFiles = $tag . $jsFiles;
2386 } else {
2387 $jsFooterFiles = $tag . $jsFooterFiles;
2388 }
2389 } else {
2390 if ($properties['section'] === self::PART_HEADER) {
2391 $jsFiles .= $tag;
2392 } else {
2393 $jsFooterFiles .= $tag;
2394 }
2395 }
2396 }
2397 }
2398 if ($this->moveJsFromHeaderToFooter) {
2399 $jsFooterFiles = $jsFiles . $jsFooterFiles;
2400 $jsFiles = '';
2401 }
2402 return array($jsFiles, $jsFooterFiles);
2403 }
2404
2405 /**
2406 * Render inline JavaScript
2407 *
2408 * @return array<string> jsInline and jsFooterInline string
2409 */
2410 protected function renderInlineJavaScript()
2411 {
2412 $jsInline = '';
2413 $jsFooterInline = '';
2414 if (!empty($this->jsInline)) {
2415 foreach ($this->jsInline as $name => $properties) {
2416 $jsCode = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
2417 if ($properties['forceOnTop']) {
2418 if ($properties['section'] === self::PART_HEADER) {
2419 $jsInline = $jsCode . $jsInline;
2420 } else {
2421 $jsFooterInline = $jsCode . $jsFooterInline;
2422 }
2423 } else {
2424 if ($properties['section'] === self::PART_HEADER) {
2425 $jsInline .= $jsCode;
2426 } else {
2427 $jsFooterInline .= $jsCode;
2428 }
2429 }
2430 }
2431 }
2432 if ($jsInline) {
2433 $jsInline = $this->inlineJavascriptWrap[0] . $jsInline . $this->inlineJavascriptWrap[1];
2434 }
2435 if ($jsFooterInline) {
2436 $jsFooterInline = $this->inlineJavascriptWrap[0] . $jsFooterInline . $this->inlineJavascriptWrap[1];
2437 }
2438 if ($this->moveJsFromHeaderToFooter) {
2439 $jsFooterInline = $jsInline . $jsFooterInline;
2440 $jsInline = '';
2441 }
2442 return array($jsInline, $jsFooterInline);
2443 }
2444
2445 /**
2446 * Include language file for inline usage
2447 *
2448 * @param string $fileRef
2449 * @param string $selectionPrefix
2450 * @param string $stripFromSelectionName
2451 * @param int $errorMode
2452 * @return void
2453 * @throws \RuntimeException
2454 */
2455 protected function includeLanguageFileForInline($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0)
2456 {
2457 if (!isset($this->lang) || !isset($this->charSet)) {
2458 throw new \RuntimeException('Language and character encoding are not set.', 1284906026);
2459 }
2460 $labelsFromFile = array();
2461 $allLabels = $this->readLLfile($fileRef, $errorMode);
2462 if ($allLabels !== false) {
2463 // Merge language specific translations:
2464 if ($this->lang !== 'default' && isset($allLabels[$this->lang])) {
2465 $labels = array_merge($allLabels['default'], $allLabels[$this->lang]);
2466 } else {
2467 $labels = $allLabels['default'];
2468 }
2469 // Iterate through all locallang labels:
2470 foreach ($labels as $label => $value) {
2471 // If $selectionPrefix is set, only respect labels that start with $selectionPrefix
2472 if ($selectionPrefix === '' || strpos($label, $selectionPrefix) === 0) {
2473 // Remove substring $stripFromSelectionName from label
2474 $label = str_replace($stripFromSelectionName, '', $label);
2475 $labelsFromFile[$label] = $value;
2476 }
2477 }
2478 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $labelsFromFile);
2479 }
2480 }
2481
2482 /**
2483 * Reads a locallang file.
2484 *
2485 * @param string $fileRef Reference to a relative filename to include.
2486 * @param int $errorMode Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
2487 * @return array Returns the $LOCAL_LANG array found in the file. If no array found, returns empty array.
2488 */
2489 protected function readLLfile($fileRef, $errorMode = 0)
2490 {
2491 /** @var $languageFactory LocalizationFactory */
2492 $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
2493
2494 if ($this->lang !== 'default') {
2495 $languages = array_reverse($this->languageDependencies);
2496 // At least we need to have English
2497 if (empty($languages)) {
2498 $languages[] = 'default';
2499 }
2500 } else {
2501 $languages = array('default');
2502 }
2503
2504 $localLanguage = array();
2505 foreach ($languages as $language) {
2506 $tempLL = $languageFactory->getParsedData($fileRef, $language, $this->charSet, $errorMode);
2507
2508 $localLanguage['default'] = $tempLL['default'];
2509 if (!isset($localLanguage[$this->lang])) {
2510 $localLanguage[$this->lang] = $localLanguage['default'];
2511 }
2512 if ($this->lang !== 'default' && isset($tempLL[$language])) {
2513 // Merge current language labels onto labels from previous language
2514 // This way we have a labels with fall back applied
2515 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($localLanguage[$this->lang], $tempLL[$language], true, false);
2516 }
2517 }
2518
2519 return $localLanguage;
2520 }
2521
2522
2523 /*****************************************************/
2524 /* */
2525 /* Tools */
2526 /* */
2527 /*****************************************************/
2528 /**
2529 * Concatenate files into one file
2530 * registered handler
2531 *
2532 * @return void
2533 */
2534 protected function doConcatenate()
2535 {
2536 $this->doConcatenateCss();
2537 $this->doConcatenateJavaScript();
2538 }
2539
2540 /**
2541 * Concatenate JavaScript files according to the configuration.
2542 *
2543 * @return void
2544 */
2545 protected function doConcatenateJavaScript()
2546 {
2547 if ($this->concatenateFiles || $this->concatenateJavascript) {
2548 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'])) {
2549 // use external concatenation routine
2550 $params = array(
2551 'jsLibs' => &$this->jsLibs,
2552 'jsFiles' => &$this->jsFiles,
2553 'jsFooterFiles' => &$this->jsFooterFiles,
2554 'headerData' => &$this->headerData,
2555 'footerData' => &$this->footerData
2556 );
2557 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'], $params, $this);
2558 } else {
2559 $this->jsLibs = $this->getCompressor()->concatenateJsFiles($this->jsLibs);
2560 $this->jsFiles = $this->getCompressor()->concatenateJsFiles($this->jsFiles);
2561 $this->jsFooterFiles = $this->getCompressor()->concatenateJsFiles($this->jsFooterFiles);
2562 }
2563 }
2564 }
2565
2566 /**
2567 * Concatenate CSS files according to configuration.
2568 *
2569 * @return void
2570 */
2571 protected function doConcatenateCss()
2572 {
2573 if ($this->concatenateFiles || $this->concatenateCss) {
2574 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'])) {
2575 // use external concatenation routine
2576 $params = array(
2577 'cssFiles' => &$this->cssFiles,
2578 'cssLibs' => &$this->cssLibs,
2579 'headerData' => &$this->headerData,
2580 'footerData' => &$this->footerData
2581 );
2582 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'], $params, $this);
2583 } else {
2584 $cssOptions = array();
2585 if (TYPO3_MODE === 'BE') {
2586 $cssOptions = array('baseDirectories' => $GLOBALS['TBE_TEMPLATE']->getSkinStylesheetDirectories());
2587 }
2588 $this->cssLibs = $this->getCompressor()->concatenateCssFiles($this->cssLibs, $cssOptions);
2589 $this->cssFiles = $this->getCompressor()->concatenateCssFiles($this->cssFiles, $cssOptions);
2590 }
2591 }
2592 }
2593
2594 /**
2595 * Compresses inline code
2596 *
2597 * @return void
2598 */
2599 protected function doCompress()
2600 {
2601 $this->doCompressJavaScript();
2602 $this->doCompressCss();
2603 }
2604
2605 /**
2606 * Compresses CSS according to configuration.
2607 *
2608 * @return void
2609 */
2610 protected function doCompressCss()
2611 {
2612 if ($this->compressCss) {
2613 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'])) {
2614 // Use external compression routine
2615 $params = array(
2616 'cssInline' => &$this->cssInline,
2617 'cssFiles' => &$this->cssFiles,
2618 'cssLibs' => &$this->cssLibs,
2619 'headerData' => &$this->headerData,
2620 'footerData' => &$this->footerData
2621 );
2622 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this);
2623 } else {
2624 $this->cssLibs = $this->getCompressor()->compressCssFiles($this->cssLibs);
2625 $this->cssFiles = $this->getCompressor()->compressCssFiles($this->cssFiles);
2626 }
2627 }
2628 }
2629
2630 /**
2631 * Compresses JavaScript according to configuration.
2632 *
2633 * @return void
2634 */
2635 protected function doCompressJavaScript()
2636 {
2637 if ($this->compressJavascript) {
2638 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'])) {
2639 // Use external compression routine
2640 $params = array(
2641 'jsInline' => &$this->jsInline,
2642 'jsFooterInline' => &$this->jsFooterInline,
2643 'jsLibs' => &$this->jsLibs,
2644 'jsFiles' => &$this->jsFiles,
2645 'jsFooterFiles' => &$this->jsFooterFiles,
2646 'headerData' => &$this->headerData,
2647 'footerData' => &$this->footerData
2648 );
2649 GeneralUtility::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this);
2650 } else {
2651 // Traverse the arrays, compress files
2652 if (!empty($this->jsInline)) {
2653 foreach ($this->jsInline as $name => $properties) {
2654 if ($properties['compress']) {
2655 $error = '';
2656 $this->jsInline[$name]['code'] = GeneralUtility::minifyJavaScript($properties['code'], $error);
2657 if ($error) {
2658 $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error . LF;
2659 }
2660 }
2661 }
2662 }
2663 $this->jsLibs = $this->getCompressor()->compressJsFiles($this->jsLibs);
2664 $this->jsFiles = $this->getCompressor()->compressJsFiles($this->jsFiles);
2665 $this->jsFooterFiles = $this->getCompressor()->compressJsFiles($this->jsFooterFiles);
2666 }
2667 }
2668 }
2669
2670 /**
2671 * Returns instance of \TYPO3\CMS\Core\Resource\ResourceCompressor
2672 *
2673 * @return \TYPO3\CMS\Core\Resource\ResourceCompressor
2674 */
2675 protected function getCompressor()
2676 {
2677 if ($this->compressor === null) {
2678 $this->compressor = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceCompressor::class);
2679 }
2680 return $this->compressor;
2681 }
2682
2683 /**
2684 * Processes a Javascript file dependent on the current context
2685 *
2686 * Adds the version number for Frontend, compresses the file for Backend
2687 *
2688 * @param string $filename Filename
2689 * @return string New filename
2690 */
2691 protected function processJsFile($filename)
2692 {
2693 switch (TYPO3_MODE) {
2694 case 'FE':
2695 if ($this->compressJavascript) {
2696 $filename = $this->getCompressor()->compressJsFile($filename);
2697 } else {
2698 $filename = GeneralUtility::createVersionNumberedFilename($filename);
2699 }
2700 break;
2701 case 'BE':
2702 if ($this->compressJavascript) {
2703 $filename = $this->getCompressor()->compressJsFile($filename);
2704 }
2705 break;
2706 }
2707 return $filename;
2708 }
2709
2710 /**
2711 * Returns global frontend controller
2712 *
2713 * @return TypoScriptFrontendController
2714 */
2715 protected function getTypoScriptFrontendController()
2716 {
2717 return $GLOBALS['TSFE'];
2718 }
2719
2720 /**
2721 * Returns global language service instance
2722 *
2723 * @return \TYPO3\CMS\Lang\LanguageService
2724 */
2725 protected function getLanguageService()
2726 {
2727 return $GLOBALS['LANG'];
2728 }
2729
2730 /*****************************************************/
2731 /* */
2732 /* Hooks */
2733 /* */
2734 /*****************************************************/
2735 /**
2736 * Execute PreRenderHook for possible manipulation
2737 *
2738 * @return void
2739 */
2740 protected function executePreRenderHook()
2741 {
2742 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'])) {
2743 $params = array(
2744 'jsLibs' => &$this->jsLibs,
2745 'jsFooterLibs' => &$this->jsFooterLibs,
2746 'jsFiles' => &$this->jsFiles,
2747 'jsFooterFiles' => &$this->jsFooterFiles,
2748 'cssFiles' => &$this->cssFiles,
2749 'headerData' => &$this->headerData,
2750 'footerData' => &$this->footerData,
2751 'jsInline' => &$this->jsInline,
2752 'jsFooterInline' => &$this->jsFooterInline,
2753 'cssInline' => &$this->cssInline
2754 );
2755 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'] as $hook) {
2756 GeneralUtility::callUserFunction($hook, $params, $this);
2757 }
2758 }
2759 }
2760
2761 /**
2762 * PostTransform for possible manipulation of concatenated and compressed files
2763 *
2764 * @return void
2765 */
2766 protected function executeRenderPostTransformHook()
2767 {
2768 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postTransform'])) {
2769 $params = array(
2770 'jsLibs' => &$this->jsLibs,
2771 'jsFooterLibs' => &$this->jsFooterLibs,
2772 'jsFiles' => &$this->jsFiles,
2773 'jsFooterFiles' => &$this->jsFooterFiles,
2774 'cssFiles' => &$this->cssFiles,
2775 'headerData' => &$this->headerData,
2776 'footerData' => &$this->footerData,
2777 'jsInline' => &$this->jsInline,
2778 'jsFooterInline' => &$this->jsFooterInline,
2779 'cssInline' => &$this->cssInline
2780 );
2781 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postTransform'] as $hook) {
2782 GeneralUtility::callUserFunction($hook, $params, $this);
2783 }
2784 }
2785 }
2786
2787 /**
2788 * Execute postRenderHook for possible manipulation
2789 *
2790 * @param $jsLibs string
2791 * @param $jsFiles string
2792 * @param $jsFooterFiles string
2793 * @param $cssLibs string
2794 * @param $cssFiles string
2795 * @param $jsInline string
2796 * @param $cssInline string
2797 * @param $jsFooterInline string
2798 * @param $jsFooterLibs string
2799 * @return void
2800 */
2801 protected function executePostRenderHook(&$jsLibs, &$jsFiles, &$jsFooterFiles, &$cssLibs, &$cssFiles, &$jsInline, &$cssInline, &$jsFooterInline, &$jsFooterLibs)
2802 {
2803 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'])) {
2804 $params = array(
2805 'jsLibs' => &$jsLibs,
2806 'jsFiles' => &$jsFiles,
2807 'jsFooterFiles' => &$jsFooterFiles,
2808 'cssLibs' => &$cssLibs,
2809 'cssFiles' => &$cssFiles,
2810 'headerData' => &$this->headerData,
2811 'footerData' => &$this->footerData,
2812 'jsInline' => &$jsInline,
2813 'cssInline' => &$cssInline,
2814 'xmlPrologAndDocType' => &$this->xmlPrologAndDocType,
2815 'htmlTag' => &$this->htmlTag,
2816 'headTag' => &$this->headTag,
2817 'charSet' => &$this->charSet,
2818 'metaCharsetTag' => &$this->metaCharsetTag,
2819 'shortcutTag' => &$this->shortcutTag,
2820 'inlineComments' => &$this->inlineComments,
2821 'baseUrl' => &$this->baseUrl,
2822 'baseUrlTag' => &$this->baseUrlTag,
2823 'favIcon' => &$this->favIcon,
2824 'iconMimeType' => &$this->iconMimeType,
2825 'titleTag' => &$this->titleTag,
2826 'title' => &$this->title,
2827 'metaTags' => &$this->metaTags,
2828 'jsFooterInline' => &$jsFooterInline,
2829 'jsFooterLibs' => &$jsFooterLibs,
2830 'bodyContent' => &$this->bodyContent
2831 );
2832 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'] as $hook) {
2833 GeneralUtility::callUserFunction($hook, $params, $this);
2834 }
2835 }
2836 }
2837 }