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