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