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