[FEATURE] Speedup backend and allow compression in frontend
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_pagerenderer.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009-2011 Steffen Kamper <info@sk-typo3.de>
6 * (c) 2011 Kai Vogel <kai.vogel@speedprogs.de>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 * A copy is found in the textfile GPL.txt and important notices to the license
18 * from the author is found in LICENSE.txt distributed with these scripts.
19 *
20 *
21 * This script is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * This copyright notice MUST APPEAR in all copies of the script!
27 ***************************************************************/
28
29 /**
30 * TYPO3 pageRender class (new in TYPO3 4.3.0)
31 * This class render the HTML of a webpage, usable for BE and FE
32 *
33 * @author Steffen Kamper <info@sk-typo3.de>
34 * @author Kai Vogel <kai.vogel@speedprogs.de>
35 * @package TYPO3
36 * @subpackage t3lib
37 */
38 class t3lib_PageRenderer implements t3lib_Singleton {
39
40 protected $compressJavascript = FALSE;
41 protected $compressCss = FALSE;
42 protected $removeLineBreaksFromTemplate = FALSE;
43
44 protected $concatenateFiles = FALSE;
45 protected $concatenateJavascript = FALSE;
46 protected $concatenateCss = FALSE;
47
48 protected $moveJsFromHeaderToFooter = FALSE;
49
50 /* @var t3lib_cs Instance of t3lib_cs */
51 protected $csConvObj;
52 protected $lang;
53
54 /* @var t3lib_Compressor Instance of t3lib_Compressor */
55 protected $compressor;
56
57 // arrays containing associative array for the included files
58 protected $jsFiles = array();
59 protected $jsFooterFiles = array();
60 protected $jsLibs = array();
61 protected $jsFooterLibs = array();
62 protected $cssFiles = array();
63
64 protected $title;
65 protected $charSet;
66 protected $favIcon;
67 protected $baseUrl;
68
69 protected $renderXhtml = TRUE;
70
71 // static header blocks
72 protected $xmlPrologAndDocType = '';
73 protected $metaTags = array();
74 protected $inlineComments = array();
75 protected $headerData = array();
76 protected $footerData = array();
77 protected $titleTag = '<title>|</title>';
78 protected $metaCharsetTag = '<meta http-equiv="Content-Type" content="text/html; charset=|" />';
79 protected $htmlTag = '<html>';
80 protected $headTag = '<head>';
81 protected $baseUrlTag = '<base href="|" />';
82 protected $iconMimeType = '';
83 protected $shortcutTag = '<link rel="shortcut icon" href="%1$s"%2$s />
84 <link rel="icon" href="%1$s"%2$s />';
85
86 // static inline code blocks
87 protected $jsInline = array();
88 protected $jsFooterInline = array();
89 protected $extOnReadyCode = array();
90 protected $cssInline = array();
91
92 protected $bodyContent;
93
94 protected $templateFile;
95
96 protected $jsLibraryNames = array('prototype', 'scriptaculous', 'extjs');
97
98 const PART_COMPLETE = 0;
99 const PART_HEADER = 1;
100 const PART_FOOTER = 2;
101
102 // paths to contibuted libraries
103 protected $prototypePath = 'contrib/prototype/';
104 protected $scriptaculousPath = 'contrib/scriptaculous/';
105 protected $extCorePath = 'contrib/extjs/';
106 protected $extJsPath = 'contrib/extjs/';
107 protected $svgPath = 'contrib/websvg/';
108
109
110 // internal flags for JS-libraries
111 protected $addPrototype = FALSE;
112 protected $addScriptaculous = FALSE;
113 protected $addScriptaculousModules = array('builder' => FALSE, 'effects' => FALSE, 'dragdrop' => FALSE, 'controls' => FALSE, 'slider' => FALSE);
114 protected $addExtJS = FALSE;
115 protected $addExtCore = FALSE;
116 protected $extJSadapter = 'ext/ext-base.js';
117 protected $extDirectCodeAdded = FALSE;
118
119 protected $enableExtJsDebug = FALSE;
120 protected $enableExtCoreDebug = FALSE;
121
122 // available adapters for extJs
123 const EXTJS_ADAPTER_JQUERY = 'jquery';
124 const EXTJS_ADAPTER_PROTOTYPE = 'prototype';
125 const EXTJS_ADAPTER_YUI = 'yui';
126
127 protected $extJStheme = TRUE;
128 protected $extJScss = TRUE;
129
130 protected $enableExtJSQuickTips = FALSE;
131
132 protected $inlineLanguageLabels = array();
133 protected $inlineLanguageLabelFiles = array();
134 protected $inlineSettings = array();
135
136 protected $inlineJavascriptWrap = array();
137
138 // saves error messages generated during compression
139 protected $compressError = '';
140
141 // SVG library
142 protected $addSvg = FALSE;
143 protected $enableSvgDebug = FALSE;
144
145 // used by BE modules
146 public $backPath;
147
148 /**
149 * Constructor
150 *
151 * @param string $templateFile declare the used template file. Omit this parameter will use default template
152 * @param string $backPath relative path to typo3-folder. It varies for BE modules, in FE it will be typo3/
153 * @return void
154 */
155 public function __construct($templateFile = '', $backPath = NULL) {
156
157 $this->reset();
158 $this->csConvObj = t3lib_div::makeInstance('t3lib_cs');
159
160 if (strlen($templateFile)) {
161 $this->templateFile = $templateFile;
162 }
163 $this->backPath = isset($backPath) ? $backPath : $GLOBALS['BACK_PATH'];
164
165 $this->inlineJavascriptWrap = array(
166 '<script type="text/javascript">' . LF . '/*<![CDATA[*/' . LF . '<!-- ' . LF,
167 '// -->' . LF . '/*]]>*/' . LF . '</script>' . LF
168 );
169 $this->inlineCssWrap = array(
170 '<style type="text/css">' . LF . '/*<![CDATA[*/' . LF . '<!-- ' . LF,
171 '-->' . LF . '/*]]>*/' . LF . '</style>' . LF
172 );
173
174 }
175
176 /**
177 * reset all vars to initial values
178 *
179 * @return void
180 */
181 protected function reset() {
182 $this->templateFile = TYPO3_mainDir . 'templates/template_page_backend.html';
183 $this->jsFiles = array();
184 $this->jsFooterFiles = array();
185 $this->jsInline = array();
186 $this->jsFooterInline = array();
187 $this->jsLibs = array();
188 $this->cssFiles = array();
189 $this->cssInline = array();
190 $this->metaTags = array();
191 $this->inlineComments = array();
192 $this->headerData = array();
193 $this->footerData = array();
194 $this->extOnReadyCode = array();
195 }
196
197 /*****************************************************/
198 /* */
199 /* Public Setters */
200 /* */
201 /* */
202 /*****************************************************/
203
204 /**
205 * Sets the title
206 *
207 * @param string $title title of webpage
208 * @return void
209 */
210 public function setTitle($title) {
211 $this->title = $title;
212 }
213
214
215 /**
216 * Enables/disables rendering of XHTML code
217 *
218 * @param boolean $enable Enable XHTML
219 * @return void
220 */
221 public function setRenderXhtml($enable) {
222 $this->renderXhtml = $enable;
223 }
224
225 /**
226 * Sets xml prolog and docType
227 *
228 * @param string $xmlPrologAndDocType complete tags for xml prolog and docType
229 * @return void
230 */
231 public function setXmlPrologAndDocType($xmlPrologAndDocType) {
232 $this->xmlPrologAndDocType = $xmlPrologAndDocType;
233 }
234
235 /**
236 * Sets meta charset
237 *
238 * @param string $charSet used charset
239 * @return void
240 */
241 public function setCharSet($charSet) {
242 $this->charSet = $charSet;
243 }
244
245 /**
246 * Sets language
247 *
248 * @param string $lang used language
249 * @return void
250 */
251 public function setLanguage($lang) {
252 $this->lang = $lang;
253 }
254
255 /**
256 * Set the meta charset tag
257 *
258 * @param string $metaCharsetTag
259 * @return void
260 */
261 public function setMetaCharsetTag($metaCharsetTag) {
262 $this->metaCharsetTag = $metaCharsetTag;
263 }
264
265 /**
266 * Sets html tag
267 *
268 * @param string $htmlTag html tag
269 * @return void
270 */
271 public function setHtmlTag($htmlTag) {
272 $this->htmlTag = $htmlTag;
273 }
274
275 /**
276 * Sets head tag
277 *
278 * @param string $tag head tag
279 * @return void
280 */
281 public function setHeadTag($headTag) {
282 $this->headTag = $headTag;
283 }
284
285 /**
286 * Sets favicon
287 *
288 * @param string $favIcon
289 * @return void
290 */
291 public function setFavIcon($favIcon) {
292 $this->favIcon = $favIcon;
293 }
294
295 /**
296 * Sets icon mime type
297 *
298 * @param string $iconMimeType
299 * @return void
300 */
301 public function setIconMimeType($iconMimeType) {
302 $this->iconMimeType = $iconMimeType;
303 }
304
305 /**
306 * Sets base url
307 *
308 * @param string $url
309 * @return void
310 */
311 public function setBaseUrl($baseUrl) {
312 $this->baseUrl = $baseUrl;
313 }
314
315 /**
316 * Sets template file
317 *
318 * @param string $file
319 * @return void
320 */
321 public function setTemplateFile($file) {
322 $this->templateFile = $file;
323 }
324
325 /**
326 * Sets back path
327 *
328 * @param string $backPath
329 * @return void
330 */
331 public function setBackPath($backPath) {
332 $this->backPath = $backPath;
333 }
334
335 /**
336 * Sets Content for Body
337 *
338 * @param string $content
339 * @return void
340 */
341 public function setBodyContent($content) {
342 $this->bodyContent = $content;
343 }
344
345 /**
346 * Sets Path for prototype library (relative to typo3 directory)
347 *
348 * @param string path
349 * @return void
350 */
351 public function setPrototypePath($path) {
352 $this->prototypePath = $path;
353 }
354
355 /**
356 * Sets Path for scriptaculous library (relative to typo3 directory)
357 *
358 * @param string $path
359 * @return void
360 */
361 public function setScriptaculousPath($path) {
362 $this->scriptaculousPath = $path;
363 }
364
365 /**
366 * Sets Path for Ext Core library (relative to typo3 directory)
367 *
368 * @param string $path
369 * @return void
370 */
371 public function setExtCorePath($path) {
372 $this->extCorePath = $path;
373 }
374
375 /**
376 * Sets Path for ExtJs library (relative to typo3 directory)
377 *
378 * @param string $path
379 * @return void
380 */
381 public function setExtJsPath($path) {
382 $this->extJsPath = $path;
383 }
384
385 /**
386 * Sets Path for SVG library (websvg)
387 *
388 * @param string $path
389 * @return void
390 */
391 public function setSvgPath($path) {
392 $this->svgPath = $path;
393 }
394
395 /*****************************************************/
396 /* */
397 /* Public Enablers / Disablers */
398 /* */
399 /* */
400 /*****************************************************/
401
402 /**
403 * Enables MoveJsFromHeaderToFooter
404 *
405 * @param void
406 * @return void
407 */
408 public function enableMoveJsFromHeaderToFooter() {
409 $this->moveJsFromHeaderToFooter = TRUE;
410 }
411
412 /**
413 * Disables MoveJsFromHeaderToFooter
414 *
415 * @param void
416 * @return void
417 */
418 public function disableMoveJsFromHeaderToFooter() {
419 $this->moveJsFromHeaderToFooter = FALSE;
420 }
421
422 /**
423 * Enables compression of javascript
424 *
425 * @param void
426 * @return void
427 */
428 public function enableCompressJavascript() {
429 $this->compressJavascript = TRUE;
430 }
431
432 /**
433 * Disables compression of javascript
434 *
435 * @param void
436 * @return void
437 */
438 public function disableCompressJavascript() {
439 $this->compressJavascript = FALSE;
440 }
441
442 /**
443 * Enables compression of css
444 *
445 * @param void
446 * @return void
447 */
448 public function enableCompressCss() {
449 $this->compressCss = TRUE;
450 }
451
452 /**
453 * Disables compression of css
454 *
455 * @param void
456 * @return void
457 */
458 public function disableCompressCss() {
459 $this->compressCss = FALSE;
460 }
461
462 /**
463 * Enables concatenation of js and css files
464 *
465 * @param void
466 * @return void
467 */
468 public function enableConcatenateFiles() {
469 $this->concatenateFiles = TRUE;
470 }
471
472 /**
473 * Disables concatenation of js and css files
474 *
475 * @param void
476 * @return void
477 */
478 public function disableConcatenateFiles() {
479 $this->concatenateFiles = FALSE;
480 }
481
482 /**
483 * Enables concatenation of js files
484 *
485 * @param void
486 * @return void
487 */
488 public function enableConcatenateJavascript() {
489 $this->concatenateJavascript = TRUE;
490 }
491
492 /**
493 * Disables concatenation of js files
494 *
495 * @param void
496 * @return void
497 */
498 public function disableConcatenateJavascript() {
499 $this->concatenateJavascript = FALSE;
500 }
501
502 /**
503 * Enables concatenation of css files
504 *
505 * @param void
506 * @return void
507 */
508 public function enableConcatenateCss() {
509 $this->concatenateCss = TRUE;
510 }
511
512 /**
513 * Disables concatenation of css files
514 *
515 * @param void
516 * @return void
517 */
518 public function disableConcatenateCss() {
519 $this->concatenateCss = FALSE;
520 }
521
522 /**
523 * Sets removal of all line breaks in template
524 *
525 * @param void
526 * @return void
527 */
528 public function enableRemoveLineBreaksFromTemplate() {
529 $this->removeLineBreaksFromTemplate = TRUE;
530 }
531
532 /**
533 * Unsets removal of all line breaks in template
534 *
535 * @param void
536 * @return void
537 */
538 public function disableRemoveLineBreaksFromTemplate() {
539 $this->removeLineBreaksFromTemplate = FALSE;
540 }
541
542 /**
543 * Enables Debug Mode
544 * This is a shortcut to switch off all compress/concatenate features to enable easier debug
545 *
546 * @param void
547 * @return void
548 */
549 public function enableDebugMode() {
550 $this->compressJavascript = FALSE;
551 $this->compressCss = FALSE;
552 $this->concatenateFiles = FALSE;
553 $this->removeLineBreaksFromTemplate = FALSE;
554 $this->enableExtCoreDebug = TRUE;
555 $this->enableExtJsDebug = TRUE;
556 $this->enableSvgDebug = TRUE;
557 }
558
559 /*****************************************************/
560 /* */
561 /* Public Getters */
562 /* */
563 /* */
564 /*****************************************************/
565
566 /**
567 * Gets the title
568 *
569 * @return string $title title of webpage
570 */
571 public function getTitle() {
572 return $this->title;
573 }
574
575 /**
576 * Gets the charSet
577 *
578 * @return string $charSet
579 */
580 public function getCharSet() {
581 return $this->charSet;
582 }
583
584 /**
585 * Gets the language
586 *
587 * @return string $lang
588 */
589 public function getLanguage() {
590 return $this->lang;
591 }
592
593 /**
594 * Returns rendering mode XHTML or HTML
595 *
596 * @return boolean TRUE if XHTML, FALSE if HTML
597 */
598 public function getRenderXhtml() {
599 return $this->renderXhtml;
600 }
601
602 /**
603 * Gets html tag
604 *
605 * @return string $htmlTag html tag
606 */
607 public function getHtmlTag() {
608 return $this->htmlTag;
609 }
610
611 /**
612 * Get meta charset
613 *
614 * @return string
615 */
616 public function getMetaCharsetTag() {
617 return $this->metaCharsetTag;
618 }
619
620 /**
621 * Gets head tag
622 *
623 * @return string $tag head tag
624 */
625 public function getHeadTag() {
626 return $this->headTag;
627 }
628
629 /**
630 * Gets favicon
631 *
632 * @return string $favIcon
633 */
634 public function getFavIcon() {
635 return $this->favIcon;
636 }
637
638 /**
639 * Gets icon mime type
640 *
641 * @return string $iconMimeType
642 */
643 public function getIconMimeType() {
644 return $this->iconMimeType;
645 }
646
647 /**
648 * Gets base url
649 *
650 * @return string $url
651 */
652 public function getBaseUrl() {
653 return $this->baseUrl;
654 }
655
656 /**
657 * Gets template file
658 *
659 * @return string $file
660 */
661 public function getTemplateFile($file) {
662 return $this->templateFile;
663 }
664
665 /**
666 * Gets MoveJsFromHeaderToFooter
667 *
668 * @return boolean
669 */
670 public function getMoveJsFromHeaderToFooter() {
671 return $this->moveJsFromHeaderToFooter;
672 }
673
674 /**
675 * Gets compress of javascript
676 *
677 * @return boolean
678 */
679 public function getCompressJavascript() {
680 return $this->compressJavascript;
681 }
682
683 /**
684 * Gets compress of css
685 *
686 * @return boolean
687 */
688 public function getCompressCss() {
689 return $this->compressCss;
690 }
691
692 /**
693 * Gets concatenate of js and css files
694 *
695 * @return boolean
696 */
697 public function getConcatenateFiles() {
698 return $this->concatenateFiles;
699 }
700
701 /**
702 * Gets concatenate of js files
703 *
704 * @return boolean
705 */
706 public function getConcatenateJavascript() {
707 return $this->concatenateJavascript;
708 }
709
710 /**
711 * Gets concatenate of css files
712 *
713 * @return boolean
714 */
715 public function getConcatenateCss() {
716 return $this->concatenateCss;
717 }
718
719 /**
720 * Gets remove of empty lines from template
721 *
722 * @return boolean
723 */
724 public function getRemoveLineBreaksFromTemplate() {
725 return $this->removeLineBreaksFromTemplate;
726 }
727
728 /**
729 * Gets content for body
730 *
731 * @return string
732 */
733 public function getBodyContent() {
734 return $this->bodyContent;
735 }
736
737 /**
738 * Gets Path for prototype library (relative to typo3 directory)
739 *
740 * @return string
741 */
742 public function getPrototypePath() {
743 return $this->prototypePath;
744 }
745
746 /**
747 * Gets Path for scriptaculous library (relative to typo3 directory)
748 *
749 * @return string
750 */
751 public function getScriptaculousPath() {
752 return $this->scriptaculousPath;
753 }
754
755 /**
756 * Gets Path for Ext Core library (relative to typo3 directory)
757 *
758 * @return string
759 */
760 public function getExtCorePath() {
761 return $this->extCorePath;
762 }
763
764 /**
765 * Gets Path for ExtJs library (relative to typo3 directory)
766 *
767 * @return string
768 */
769 public function getExtJsPath() {
770 return $this->extJsPath;
771 }
772
773 /**
774 * Gets Path for SVG library (relative to typo3 directory)
775 *
776 * @return string
777 */
778 public function getSvgPath() {
779 return $this->svgPath;
780 }
781
782 /**
783 * Gets the inline language labels.
784 *
785 * @return array The inline language labels
786 */
787 public function getInlineLanguageLabels() {
788 return $this->inlineLanguageLabels;
789 }
790
791 /**
792 * Gets the inline language files
793 *
794 * @return array
795 */
796 public function getInlineLanguageLabelFiles() {
797 return $this->inlineLanguageLabelFiles;
798 }
799
800 /*****************************************************/
801 /* */
802 /* Public Function to add Data */
803 /* */
804 /* */
805 /*****************************************************/
806
807 /**
808 * Adds meta data
809 *
810 * @param string $meta meta data (complete metatag)
811 * @return void
812 */
813 public function addMetaTag($meta) {
814 if (!in_array($meta, $this->metaTags)) {
815 $this->metaTags[] = $meta;
816 }
817 }
818
819 /**
820 * Adds inline HTML comment
821 *
822 * @param string $comment
823 * @return void
824 */
825 public function addInlineComment($comment) {
826 if (!in_array($comment, $this->inlineComments)) {
827 $this->inlineComments[] = $comment;
828 }
829 }
830
831 /**
832 * Adds header data
833 *
834 * @param string $data free header data for HTML header
835 * @return void
836 */
837 public function addHeaderData($data) {
838 if (!in_array($data, $this->headerData)) {
839 $this->headerData[] = $data;
840 }
841 }
842
843 /**
844 * Adds footer data
845 *
846 * @param string $data free header data for HTML header
847 * @return void
848 */
849 public function addFooterData($data) {
850 if (!in_array($data, $this->footerData)) {
851 $this->footerData[] = $data;
852 }
853 }
854
855 /* Javascript Files */
856
857 /**
858 * Adds JS Library. JS Library block is rendered on top of the JS files.
859 *
860 * @param string $name Arbitrary identifier
861 * @param string $file File name
862 * @param string $type Content Type
863 * @param boolean $compress flag if library should be compressed
864 * @param boolean $forceOnTop flag if added library should be inserted at begin of this block
865 * @param string $allWrap
866 * @param boolean $excludeFromConcatenation
867 * @return void
868 */
869 public function addJsLibrary($name, $file, $type = 'text/javascript', $compress = FALSE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
870 if (!$type) {
871 $type = 'text/javascript';
872 }
873 if (!in_array(strtolower($name), $this->jsLibs)) {
874 $this->jsLibs[strtolower($name)] = array(
875 'file' => $file,
876 'type' => $type,
877 'section' => self::PART_HEADER,
878 'compress' => $compress,
879 'forceOnTop' => $forceOnTop,
880 'allWrap' => $allWrap,
881 'excludeFromConcatenation' => $excludeFromConcatenation,
882 );
883 }
884
885 }
886
887 /**
888 * Adds JS Library to Footer. JS Library block is rendered on top of the Footer JS files.
889 *
890 * @param string $name Arbitrary identifier
891 * @param string $file File name
892 * @param string $type Content Type
893 * @param boolean $compress flag if library should be compressed
894 * @param boolean $forceOnTop flag if added library should be inserted at begin of this block
895 * @param string $allWrap
896 * @param boolean $excludeFromConcatenation
897 * @return void
898 */
899 public function addJsFooterLibrary($name, $file, $type = 'text/javascript', $compress = FALSE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
900 if (!$type) {
901 $type = 'text/javascript';
902 }
903 if (!in_array(strtolower($name), $this->jsLibs)) {
904 $this->jsLibs[strtolower($name)] = array(
905 'file' => $file,
906 'type' => $type,
907 'section' => self::PART_FOOTER,
908 'compress' => $compress,
909 'forceOnTop' => $forceOnTop,
910 'allWrap' => $allWrap,
911 'excludeFromConcatenation' => $excludeFromConcatenation,
912 );
913 }
914
915 }
916
917 /**
918 * Adds JS file
919 *
920 * @param string $file File name
921 * @param string $type Content Type
922 * @param boolean $compress
923 * @param boolean $forceOnTop
924 * @param string $allWrap
925 * @param boolean $excludeFromConcatenation
926 * @return void
927 */
928 public function addJsFile($file, $type = 'text/javascript', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
929 if (!$type) {
930 $type = 'text/javascript';
931 }
932 if (!isset($this->jsFiles[$file])) {
933 $this->jsFiles[$file] = array(
934 'file' => $file,
935 'type' => $type,
936 'section' => self::PART_HEADER,
937 'compress' => $compress,
938 'forceOnTop' => $forceOnTop,
939 'allWrap' => $allWrap,
940 'excludeFromConcatenation' => $excludeFromConcatenation,
941 );
942 }
943 }
944
945 /**
946 * Adds JS file to footer
947 *
948 * @param string $file File name
949 * @param string $type Content Type
950 * @param boolean $compress
951 * @param boolean $forceOnTop
952 * @param string $allWrap
953 * @param boolean $excludeFromConcatenation
954 * @return void
955 */
956 public function addJsFooterFile($file, $type = 'text/javascript', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
957 if (!$type) {
958 $type = 'text/javascript';
959 }
960 if (!isset($this->jsFiles[$file])) {
961 $this->jsFiles[$file] = array(
962 'file' => $file,
963 'type' => $type,
964 'section' => self::PART_FOOTER,
965 'compress' => $compress,
966 'forceOnTop' => $forceOnTop,
967 'allWrap' => $allWrap,
968 'excludeFromConcatenation' => $excludeFromConcatenation,
969 );
970 }
971 }
972
973 /*Javascript Inline Blocks */
974
975 /**
976 * Adds JS inline code
977 *
978 * @param string $name
979 * @param string $block
980 * @param boolean $compress
981 * @param boolean $forceOnTop
982 * @return void
983 */
984 public function addJsInlineCode($name, $block, $compress = TRUE, $forceOnTop = FALSE) {
985 if (!isset($this->jsInline[$name]) && !empty($block)) {
986 $this->jsInline[$name] = array(
987 'code' => $block . LF,
988 'section' => self::PART_HEADER,
989 'compress' => $compress,
990 'forceOnTop' => $forceOnTop
991 );
992 }
993 }
994
995 /**
996 * Adds JS inline code to footer
997 *
998 * @param string $name
999 * @param string $block
1000 * @param boolean $compress
1001 * @param boolean $forceOnTop
1002 * @return void
1003 */
1004 public function addJsFooterInlineCode($name, $block, $compress = TRUE, $forceOnTop = FALSE) {
1005 if (!isset($this->jsInline[$name]) && !empty($block)) {
1006 $this->jsInline[$name] = array(
1007 'code' => $block . LF,
1008 'section' => self::PART_FOOTER,
1009 'compress' => $compress,
1010 'forceOnTop' => $forceOnTop
1011 );
1012 }
1013 }
1014
1015 /**
1016 * Adds Ext.onready code, which will be wrapped in Ext.onReady(function() {...});
1017 *
1018 * @param string $block javascript code
1019 * @param boolean $forceOnTop position of the javascript code (TRUE for putting it on top, default is FALSE = bottom)
1020 * @return void
1021 */
1022 public function addExtOnReadyCode($block, $forceOnTop = FALSE) {
1023 if (!in_array($block, $this->extOnReadyCode)) {
1024 if ($forceOnTop) {
1025 array_unshift($this->extOnReadyCode, $block);
1026 } else {
1027 $this->extOnReadyCode[] = $block;
1028 }
1029 }
1030 }
1031
1032 /**
1033 * Adds the ExtDirect code
1034 *
1035 * @param array $filterNamespaces limit the output to defined namespaces. If empty, all namespaces are generated
1036 * @return void
1037 */
1038 public function addExtDirectCode(array $filterNamespaces = array()) {
1039 if ($this->extDirectCodeAdded) {
1040 return;
1041 }
1042 $this->extDirectCodeAdded = TRUE;
1043
1044 if (count($filterNamespaces) === 0) {
1045 $filterNamespaces = array('TYPO3');
1046 }
1047
1048 // for ExtDirect we need flash message support
1049 $this->addJsFile(t3lib_div::resolveBackPath($this->backPath . '../t3lib/js/extjs/ux/flashmessages.js'));
1050
1051 // add language labels for ExtDirect
1052 if (TYPO3_MODE === 'FE') {
1053 $this->addInlineLanguageLabelArray(array(
1054 'extDirect_timeoutHeader' => $GLOBALS['TSFE']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutHeader'),
1055 'extDirect_timeoutMessage' => $GLOBALS['TSFE']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutMessage'),
1056 ));
1057 } else {
1058 $this->addInlineLanguageLabelArray(array(
1059 'extDirect_timeoutHeader' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutHeader'),
1060 'extDirect_timeoutMessage' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutMessage'),
1061 ));
1062 }
1063
1064 $token = $api = '';
1065 if (TYPO3_MODE === 'BE') {
1066 $formprotection = t3lib_formprotection_Factory::get();
1067 $token = $formprotection->generateToken('extDirect');
1068 }
1069
1070 /** @var $extDirect t3lib_extjs_ExtDirectApi */
1071 $extDirect = t3lib_div::makeInstance('t3lib_extjs_ExtDirectApi');
1072 $api = $extDirect->getApiPhp($filterNamespaces);
1073 if ($api) {
1074 $this->addJsInlineCode('TYPO3ExtDirectAPI', $api);
1075 }
1076 // Note: we need to iterate thru the object, because the addProvider method
1077 // does this only with multiple arguments
1078 $this->addExtOnReadyCode('
1079 (function() {
1080 TYPO3.ExtDirectToken = "' . $token . '";
1081 for (var api in Ext.app.ExtDirectAPI) {
1082 var provider = Ext.Direct.addProvider(Ext.app.ExtDirectAPI[api]);
1083 provider.on("beforecall", function(provider, transaction, meta) {
1084 if (transaction.data) {
1085 transaction.data[transaction.data.length] = TYPO3.ExtDirectToken;
1086 } else {
1087 transaction.data = [TYPO3.ExtDirectToken];
1088 }
1089 });
1090
1091 provider.on("call", function(provider, transaction, meta) {
1092 if (transaction.isForm) {
1093 transaction.params.securityToken = TYPO3.ExtDirectToken;
1094 }
1095 });
1096 }
1097 })();
1098
1099 var extDirectDebug = function(message, header, group) {
1100 var TYPO3ViewportInstance = null;
1101
1102 if (top && top.TYPO3 && typeof top.TYPO3.Backend === "object") {
1103 TYPO3ViewportInstance = top.TYPO3.Backend;
1104 } else if (typeof TYPO3 === "object" && typeof TYPO3.Backend === "object") {
1105 TYPO3ViewportInstance = TYPO3.Backend;
1106 }
1107
1108 if (TYPO3ViewportInstance !== null) {
1109 TYPO3ViewportInstance.DebugConsole.addTab(message, header, group);
1110 } else if (typeof console === "object") {
1111 console.log(message);
1112 } else {
1113 document.write(message);
1114 }
1115 };
1116
1117 Ext.Direct.on("exception", function(event) {
1118 if (event.code === Ext.Direct.exceptions.TRANSPORT && !event.where) {
1119 TYPO3.Flashmessage.display(
1120 TYPO3.Severity.error,
1121 TYPO3.lang.extDirect_timeoutHeader,
1122 TYPO3.lang.extDirect_timeoutMessage,
1123 30
1124 );
1125 } else {
1126 var backtrace = "";
1127 if (event.code === "parse") {
1128 extDirectDebug(
1129 "<p>" + event.xhr.responseText + "<\/p>",
1130 event.type,
1131 "ExtDirect - Exception"
1132 );
1133 } else if (event.code === "router") {
1134 TYPO3.Flashmessage.display(
1135 TYPO3.Severity.error,
1136 event.code,
1137 event.message,
1138 30
1139 );
1140 } else if (event.where) {
1141 backtrace = "<p style=\"margin-top: 20px;\">" +
1142 "<strong>Backtrace:<\/strong><br \/>" +
1143 event.where.replace(/#/g, "<br \/>#") +
1144 "<\/p>";
1145 extDirectDebug(
1146 "<p>" + event.message + "<\/p>" + backtrace,
1147 event.method,
1148 "ExtDirect - Exception"
1149 );
1150 }
1151
1152
1153 }
1154 });
1155
1156 Ext.Direct.on("event", function(event, provider) {
1157 if (typeof event.debug !== "undefined" && event.debug !== "") {
1158 extDirectDebug(event.debug, event.method, "ExtDirect - Debug");
1159 }
1160 });
1161 ',
1162 TRUE
1163 );
1164 }
1165
1166 /* CSS Files */
1167
1168 /**
1169 * Adds CSS file
1170 *
1171 * @param string $file
1172 * @param string $rel
1173 * @param string $media
1174 * @param string $title
1175 * @param boolean $compress
1176 * @param boolean $forceOnTop
1177 * @param string $allWrap
1178 * @param boolean $excludeFromConcatenation
1179 * @return void
1180 */
1181 public function addCssFile($file, $rel = 'stylesheet', $media = 'all', $title = '', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
1182 if (!isset($this->cssFiles[$file])) {
1183 $this->cssFiles[$file] = array(
1184 'file' => $file,
1185 'rel' => $rel,
1186 'media' => $media,
1187 'title' => $title,
1188 'compress' => $compress,
1189 'forceOnTop' => $forceOnTop,
1190 'allWrap' => $allWrap,
1191 'excludeFromConcatenation' => $excludeFromConcatenation,
1192 );
1193 }
1194 }
1195
1196 /*CSS Inline Blocks */
1197
1198 /**
1199 * Adds CSS inline code
1200 *
1201 * @param string $name
1202 * @param string $block
1203 * @param boolean $compress
1204 * @param boolean $forceOnTop
1205 * @return void
1206 */
1207 public function addCssInlineBlock($name, $block, $compress = FALSE, $forceOnTop = FALSE) {
1208 if (!isset($this->cssInline[$name]) && !empty($block)) {
1209 $this->cssInline[$name] = array(
1210 'code' => $block,
1211 'compress' => $compress,
1212 'forceOnTop' => $forceOnTop
1213 );
1214 }
1215 }
1216
1217 /* JS Libraries */
1218
1219 /**
1220 * call function if you need the prototype library
1221 *
1222 * @return void
1223 */
1224 public function loadPrototype() {
1225 $this->addPrototype = TRUE;
1226 }
1227
1228 /**
1229 * call function if you need the Scriptaculous library
1230 *
1231 * @param string $modules add modules you need. use "all" if you need complete modules
1232 * @return void
1233 */
1234 public function loadScriptaculous($modules = 'all') {
1235 // Scriptaculous require prototype, so load prototype too.
1236 $this->addPrototype = TRUE;
1237 $this->addScriptaculous = TRUE;
1238 if ($modules) {
1239 if ($modules == 'all') {
1240 foreach ($this->addScriptaculousModules as $key => $value) {
1241 $this->addScriptaculousModules[$key] = TRUE;
1242 }
1243 } else {
1244 $mods = t3lib_div::trimExplode(',', $modules);
1245 foreach ($mods as $mod) {
1246 if (isset($this->addScriptaculousModules[strtolower($mod)])) {
1247 $this->addScriptaculousModules[strtolower($mod)] = TRUE;
1248 }
1249 }
1250 }
1251 }
1252 }
1253
1254 /**
1255 * call this function if you need the extJS library
1256 *
1257 * @param boolean $css flag, if set the ext-css will be loaded
1258 * @param boolean $theme flag, if set the ext-theme "grey" will be loaded
1259 * @param string $adapter choose alternative adapter, possible values: yui, prototype, jquery
1260 * @return void
1261 */
1262 public function loadExtJS($css = TRUE, $theme = TRUE, $adapter = '') {
1263 if ($adapter) {
1264 // empty $adapter will always load the ext adapter
1265 switch (t3lib_div::strtolower(trim($adapter))) {
1266 case self::EXTJS_ADAPTER_YUI :
1267 $this->extJSadapter = 'yui/ext-yui-adapter.js';
1268 break;
1269 case self::EXTJS_ADAPTER_PROTOTYPE :
1270 $this->extJSadapter = 'prototype/ext-prototype-adapter.js';
1271 break;
1272 case self::EXTJS_ADAPTER_JQUERY :
1273 $this->extJSadapter = 'jquery/ext-jquery-adapter.js';
1274 break;
1275 }
1276 }
1277 $this->addExtJS = TRUE;
1278 $this->extJStheme = $theme;
1279 $this->extJScss = $css;
1280
1281 }
1282
1283 /**
1284 * Enables ExtJs QuickTips
1285 * Need extJs loaded
1286 *
1287 * @return void
1288 *
1289 */
1290 public function enableExtJSQuickTips() {
1291 $this->enableExtJSQuickTips = TRUE;
1292 }
1293
1294
1295 /**
1296 * call function if you need the ExtCore library
1297 *
1298 * @return void
1299 */
1300 public function loadExtCore() {
1301 $this->addExtCore = TRUE;
1302 }
1303
1304 /**
1305 * call function if you need the SVG library
1306 *
1307 * @return void
1308 */
1309 public function loadSvg() {
1310 $this->addSvg = TRUE;
1311 }
1312
1313 /**
1314 * call this function to load debug version of ExtJS. Use this for development only
1315 *
1316 */
1317 public function enableSvgDebug() {
1318 $this->enableSvgDebug = TRUE;
1319 }
1320
1321 /**
1322 * call this function to force flash usage with SVG library
1323 *
1324 */
1325 public function svgForceFlash() {
1326 $this->addMetaTag('<meta name="svg.render.forceflash" content="true" />');
1327 }
1328
1329 /**
1330 * call this function to load debug version of ExtJS. Use this for development only
1331 *
1332 */
1333 public function enableExtJsDebug() {
1334 $this->enableExtJsDebug = TRUE;
1335 }
1336
1337 /**
1338 * call this function to load debug version of ExtCore. Use this for development only
1339 *
1340 * @return void
1341 */
1342 public function enableExtCoreDebug() {
1343 $this->enableExtCoreDebug = TRUE;
1344 }
1345
1346 /**
1347 * Adds Javascript Inline Label. This will occur in TYPO3.lang - object
1348 * The label can be used in scripts with TYPO3.lang.<key>
1349 * Need extJs loaded
1350 *
1351 * @param string $key
1352 * @param string $value
1353 * @return void
1354 */
1355 public function addInlineLanguageLabel($key, $value) {
1356 $this->inlineLanguageLabels[$key] = $value;
1357 }
1358
1359 /**
1360 * Adds Javascript Inline Label Array. This will occur in TYPO3.lang - object
1361 * The label can be used in scripts with TYPO3.lang.<key>
1362 * Array will be merged with existing array.
1363 * Need extJs loaded
1364 *
1365 * @param array $array
1366 * @return void
1367 */
1368 public function addInlineLanguageLabelArray(array $array) {
1369 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $array);
1370 }
1371
1372 /**
1373 * Gets labels to be used in JavaScript fetched from a locallang file.
1374 *
1375 * @param string Input is a file-reference (see t3lib_div::getFileAbsFileName). That file is expected to be a 'locallang.xml' file containing a valid XML TYPO3 language structure.
1376 * @param string $selectionPrefix: Prefix to select the correct labels (default: '')
1377 * @param string $stripFromSelectionName: Sub-prefix to be removed from label names in the result (default: '')
1378 * @param integer Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
1379 * @return void
1380 */
1381 public function addInlineLanguageLabelFile($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0) {
1382 $index = md5($fileRef . $selectionPrefix . $stripFromSelectionName);
1383 if ($fileRef && !isset($this->inlineLanguageLabelFiles[$index])) {
1384 $this->inlineLanguageLabelFiles[$index] = array(
1385 'fileRef' => $fileRef,
1386 'selectionPrefix' => $selectionPrefix,
1387 'stripFromSelectionName' => $stripFromSelectionName,
1388 'errorMode' => $errorMode
1389 );
1390 }
1391 }
1392
1393
1394 /**
1395 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1396 * The label can be used in scripts with TYPO3.setting.<key>
1397 * Need extJs loaded
1398 *
1399 * @param string $namespace
1400 * @param string $key
1401 * @param string $value
1402 * @return void
1403 */
1404 public function addInlineSetting($namespace, $key, $value) {
1405 if ($namespace) {
1406 if (strpos($namespace, '.')) {
1407 $parts = explode('.', $namespace);
1408 $a = &$this->inlineSettings;
1409 foreach ($parts as $part) {
1410 $a = &$a[$part];
1411 }
1412 $a[$key] = $value;
1413 } else {
1414 $this->inlineSettings[$namespace][$key] = $value;
1415 }
1416 } else {
1417 $this->inlineSettings[$key] = $value;
1418 }
1419 }
1420
1421 /**
1422 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1423 * The label can be used in scripts with TYPO3.setting.<key>
1424 * Array will be merged with existing array.
1425 * Need extJs loaded
1426 *
1427 * @param string $namespace
1428 * @param array $array
1429 * @return void
1430 */
1431 public function addInlineSettingArray($namespace, array $array) {
1432 if ($namespace) {
1433 if (strpos($namespace, '.')) {
1434 $parts = explode('.', $namespace);
1435 $a = &$this->inlineSettings;
1436 foreach ($parts as $part) {
1437 $a = &$a[$part];
1438 }
1439 $a = array_merge((array) $a, $array);
1440 } else {
1441 $this->inlineSettings[$namespace] = array_merge((array) $this->inlineSettings[$namespace], $array);
1442 }
1443 } else {
1444 $this->inlineSettings = array_merge($this->inlineSettings, $array);
1445 }
1446 }
1447
1448 /**
1449 * Adds content to body content
1450 *
1451 * @param string $content
1452 * @return void
1453 */
1454 public function addBodyContent($content) {
1455 $this->bodyContent .= $content;
1456 }
1457
1458 /*****************************************************/
1459 /* */
1460 /* Render Functions */
1461 /* */
1462 /* */
1463 /*****************************************************/
1464
1465 /**
1466 * render the section (Header or Footer)
1467 *
1468 * @param int $part section which should be rendered: self::PART_COMPLETE, self::PART_HEADER or self::PART_FOOTER
1469 * @return string content of rendered section
1470 */
1471 public function render($part = self::PART_COMPLETE) {
1472
1473 $jsFiles = '';
1474 $cssFiles = '';
1475 $cssInline = '';
1476 $jsInline = '';
1477 $jsFooterInline = '';
1478 $jsFooterLibs = '';
1479 $jsFooterFiles = '';
1480
1481 // preRenderHook for possible manuipulation
1482 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'])) {
1483 $params = array(
1484 'jsLibs' => &$this->jsLibs,
1485 'jsFooterLibs' => &$this->jsFooterLibs,
1486 'jsFiles' => &$this->jsFiles,
1487 'jsFooterFiles' => &$this->jsFooterFiles,
1488 'cssFiles' => &$this->cssFiles,
1489 'headerData' => &$this->headerData,
1490 'footerData' => &$this->footerData,
1491 'jsInline' => &$this->jsInline,
1492 'jsFooterInline' => &$this->jsFooterInline,
1493 'cssInline' => &$this->cssInline,
1494 );
1495 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'] as $hook) {
1496 t3lib_div::callUserFunction($hook, $params, $this);
1497 }
1498 }
1499
1500 $jsLibs = $this->renderJsLibraries();
1501
1502 if ($this->concatenateFiles || $this->concatenateJavascript || $this->concatenateCss) {
1503 // do the file concatenation
1504 $this->doConcatenate();
1505 }
1506 if ($this->compressCss || $this->compressJavascript) {
1507 // do the file compression
1508 $this->doCompress();
1509 }
1510
1511 $metaTags = implode(LF, $this->metaTags);
1512
1513 // remove ending slashes from static header block
1514 // if the page is beeing rendered as html (not xhtml)
1515 // and define variable $endingSlash for further use
1516 if ($this->getRenderXhtml()) {
1517 $endingSlash = ' /';
1518 } else {
1519 $this->metaCharsetTag = str_replace(' />', '>', $this->metaCharsetTag);
1520 $this->baseUrlTag = str_replace(' />', '>', $this->baseUrlTag);
1521 $this->shortcutTag = str_replace(' />', '>', $this->shortcutTag);
1522 $endingSlash = '';
1523 }
1524
1525 if (count($this->cssFiles)) {
1526 foreach ($this->cssFiles as $name => $properties) {
1527 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1528 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1529 $tag = '<link rel="' . htmlspecialchars($properties['rel']) . '" type="text/css" href="' .
1530 htmlspecialchars($properties['file']) . '" media="' . htmlspecialchars($properties['media']) . '"' .
1531 ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '') .
1532 $endingSlash . '>';
1533 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1534 $tag = str_replace('|', $tag, $properties['allWrap']);
1535 }
1536 if ($properties['forceOnTop']) {
1537 $cssFiles = $tag . LF . $cssFiles;
1538 } else {
1539 $cssFiles .= LF . $tag;
1540 }
1541 }
1542 }
1543
1544 if (count($this->cssInline)) {
1545 foreach ($this->cssInline as $name => $properties) {
1546 if ($properties['forceOnTop']) {
1547 $cssInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $cssInline;
1548 } else {
1549 $cssInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1550 }
1551 }
1552 $cssInline = $this->inlineCssWrap[0] . $cssInline . $this->inlineCssWrap[1];
1553 }
1554
1555 if (count($this->jsLibs)) {
1556 foreach ($this->jsLibs as $name => $properties) {
1557 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1558 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1559 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"></script>';
1560 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1561 $tag = str_replace('|', $tag, $properties['allWrap']);
1562 }
1563 if ($properties['forceOnTop']) {
1564 if ($properties['section'] === self::PART_HEADER) {
1565 $jsLibs = $tag . LF . $jsLibs;
1566 } else {
1567 $jsFooterLibs = $tag . LF . $jsFooterLibs;
1568 }
1569 } else {
1570 if ($properties['section'] === self::PART_HEADER) {
1571 $jsLibs .= LF . $tag;
1572 } else {
1573 $jsFooterLibs .= LF . $tag;
1574 }
1575 }
1576 }
1577 }
1578
1579 if (count($this->jsFiles)) {
1580 foreach ($this->jsFiles as $name => $properties) {
1581 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1582 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1583 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"></script>';
1584 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1585 $tag = str_replace('|', $tag, $properties['allWrap']);
1586 }
1587 if ($properties['forceOnTop']) {
1588 if ($properties['section'] === self::PART_HEADER) {
1589 $jsFiles = $tag . LF . $jsFiles;
1590 } else {
1591 $jsFooterFiles = $tag . LF . $jsFooterFiles;
1592 }
1593 } else {
1594 if ($properties['section'] === self::PART_HEADER) {
1595 $jsFiles .= LF . $tag;
1596 } else {
1597 $jsFooterFiles .= LF . $tag;
1598 }
1599 }
1600 }
1601 }
1602
1603 if (count($this->jsInline)) {
1604 foreach ($this->jsInline as $name => $properties) {
1605 if ($properties['forceOnTop']) {
1606 if ($properties['section'] === self::PART_HEADER) {
1607 $jsInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsInline;
1608 } else {
1609 $jsFooterInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsFooterInline;
1610 }
1611 } else {
1612 if ($properties['section'] === self::PART_HEADER) {
1613 $jsInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1614 } else {
1615 $jsFooterInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1616 }
1617 }
1618 }
1619 }
1620
1621
1622 if ($jsInline) {
1623 $jsInline = $this->inlineJavascriptWrap[0] . $jsInline . $this->inlineJavascriptWrap[1];
1624 }
1625
1626 if ($jsFooterInline) {
1627 $jsFooterInline = $this->inlineJavascriptWrap[0] . $jsFooterInline . $this->inlineJavascriptWrap[1];
1628 }
1629
1630
1631 // get template
1632 $templateFile = t3lib_div::getFileAbsFileName($this->templateFile, TRUE);
1633 $template = t3lib_div::getUrl($templateFile);
1634
1635 if ($this->removeLineBreaksFromTemplate) {
1636 $template = strtr($template, array(LF => '', CR => ''));
1637 }
1638 if ($part != self::PART_COMPLETE) {
1639 $templatePart = explode('###BODY###', $template);
1640 $template = $templatePart[$part - 1];
1641 }
1642
1643 if ($this->moveJsFromHeaderToFooter) {
1644 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
1645 $jsLibs = '';
1646 $jsFooterFiles = $jsFiles . LF . $jsFooterFiles;
1647 $jsFiles = '';
1648 $jsFooterInline = $jsInline . LF . $jsFooterInline;
1649 $jsInline = '';
1650 }
1651
1652 // postRenderHook for possible manipulation
1653 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'])) {
1654 $params = array (
1655 'jsLibs' => &$jsLibs,
1656 'jsFiles' => &$jsFiles,
1657 'jsFooterFiles' => &$jsFooterFiles,
1658 'cssFiles' => &$cssFiles,
1659 'headerData' => &$this->headerData,
1660 'footerData' => &$this->footerData,
1661 'jsInline' => &$jsInline,
1662 'cssInline' => &$cssInline,
1663 'xmlPrologAndDocType' => &$this->xmlPrologAndDocType,
1664 'htmlTag' => &$this->htmlTag,
1665 'headTag' => &$this->headTag,
1666 'charSet' => &$this->charSet,
1667 'metaCharsetTag' => &$this->metaCharsetTag,
1668 'shortcutTag' => &$this->shortcutTag,
1669 'inlineComments' => &$this->inlineComments,
1670 'baseUrl' => &$this->baseUrl,
1671 'baseUrlTag' => &$this->baseUrlTag,
1672 'favIcon' => &$this->favIcon,
1673 'iconMimeType' => &$this->iconMimeType,
1674 'titleTag' => &$this->titleTag,
1675 'title' => &$this->title,
1676 'metaTags' => &$metaTags,
1677 'jsFooterInline' => &$jsFooterInline,
1678 'jsFooterLibs' => &$jsFooterLibs,
1679 'bodyContent' => &$this->bodyContent,
1680 );
1681 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'] as $hook) {
1682 t3lib_div::callUserFunction($hook, $params, $this);
1683 }
1684 }
1685
1686 $markerArray = array(
1687 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1688 'HTMLTAG' => $this->htmlTag,
1689 'HEADTAG' => $this->headTag,
1690 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1691 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1692 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1693 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1694 'CSS_INCLUDE' => $cssFiles,
1695 'CSS_INLINE' => $cssInline,
1696 'JS_INLINE' => $jsInline,
1697 'JS_INCLUDE' => $jsFiles,
1698 'JS_LIBS' => $jsLibs,
1699 'TITLE' => $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '',
1700 'META' => $metaTags,
1701 'HEADERDATA' => $this->headerData ? implode(LF, $this->headerData) : '',
1702 'FOOTERDATA' => $this->footerData ? implode(LF, $this->footerData) : '',
1703 'JS_LIBS_FOOTER' => $jsFooterLibs,
1704 'JS_INCLUDE_FOOTER' => $jsFooterFiles,
1705 'JS_INLINE_FOOTER' => $jsFooterInline,
1706 'BODY' => $this->bodyContent,
1707 );
1708
1709 $markerArray = array_map('trim', $markerArray);
1710
1711 $this->reset();
1712 return trim(t3lib_parsehtml::substituteMarkerArray($template, $markerArray, '###|###'));
1713 }
1714
1715 /**
1716 * helper function for render the javascript libraries
1717 *
1718 * @return string content with javascript libraries
1719 */
1720 protected function renderJsLibraries() {
1721 $out = '';
1722
1723 if ($this->addSvg) {
1724 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->svgPath . 'svg.js') .
1725 '" data-path="' . $this->backPath . $this->svgPath .
1726 '"' . ($this->enableSvgDebug ? ' data-debug="true"' : '') . '></script>';
1727 }
1728
1729 if ($this->addPrototype) {
1730 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->prototypePath . 'prototype.js') .
1731 '" type="text/javascript"></script>' . LF;
1732 unset($this->jsFiles[$this->backPath . $this->prototypePath . 'prototype.js']);
1733 }
1734
1735 if ($this->addScriptaculous) {
1736 $mods = array();
1737 foreach ($this->addScriptaculousModules as $key => $value) {
1738 if ($this->addScriptaculousModules[$key]) {
1739 $mods[] = $key;
1740 }
1741 }
1742 // resolve dependencies
1743 if (in_array('dragdrop', $mods) || in_array('controls', $mods)) {
1744 $mods = array_merge(array('effects'), $mods);
1745 }
1746
1747 if (count($mods)) {
1748 foreach ($mods as $module) {
1749 $out .= '<script src="' . $this->processJsFile($this->backPath .
1750 $this->scriptaculousPath . $module . '.js') . '" type="text/javascript"></script>' . LF;
1751 unset($this->jsFiles[$this->backPath . $this->scriptaculousPath . $module . '.js']);
1752 }
1753 }
1754 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->scriptaculousPath .
1755 'scriptaculous.js') . '" type="text/javascript"></script>' . LF;
1756 unset($this->jsFiles[$this->backPath . $this->scriptaculousPath . 'scriptaculous.js']);
1757 }
1758
1759 // include extCore, but only if ExtJS is not included
1760 if ($this->addExtCore && !$this->addExtJS) {
1761 $out .= '<script src="' . $this->processJsFile($this->backPath .
1762 $this->extCorePath . 'ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js') .
1763 '" type="text/javascript"></script>' . LF;
1764 unset($this->jsFiles[$this->backPath . $this->extCorePath . 'ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js']);
1765 }
1766
1767 // include extJS
1768 if ($this->addExtJS) {
1769 // use the base adapter all the time
1770 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->extJsPath .
1771 'adapter/' . ($this->enableExtJsDebug ?
1772 str_replace('.js', '-debug.js', $this->extJSadapter) : $this->extJSadapter)) .
1773 '" type="text/javascript"></script>' . LF;
1774 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->extJsPath .
1775 'ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js') .
1776 '" type="text/javascript"></script>' . LF;
1777
1778 // add extJS localization
1779 $localeMap = $this->csConvObj->isoArray; // load standard ISO mapping and modify for use with ExtJS
1780 $localeMap[''] = 'en';
1781 $localeMap['default'] = 'en';
1782 $localeMap['gr'] = 'el_GR'; // Greek
1783 $localeMap['no'] = 'no_BO'; // Norwegian Bokmaal
1784 $localeMap['se'] = 'se_SV'; // Swedish
1785
1786
1787 $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang;
1788 // TODO autoconvert file from UTF8 to current BE charset if necessary!!!!
1789 $extJsLocaleFile = $this->extJsPath . 'locale/ext-lang-' . $extJsLang . '.js';
1790 if (file_exists(PATH_typo3 . $extJsLocaleFile)) {
1791 $out .= '<script src="' . $this->processJsFile($this->backPath .
1792 $extJsLocaleFile) . '" type="text/javascript" charset="utf-8"></script>' . LF;
1793 }
1794
1795
1796 // remove extjs from JScodeLibArray
1797 unset(
1798 $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all.js'],
1799 $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all-debug.js']
1800 );
1801 }
1802
1803 if (count($this->inlineLanguageLabelFiles)) {
1804 foreach ($this->inlineLanguageLabelFiles as $languageLabelFile) {
1805 $this->includeLanguageFileForInline(
1806 $languageLabelFile['fileRef'],
1807 $languageLabelFile['selectionPrefix'],
1808 $languageLabelFile['stripFromSelectionName'],
1809 $languageLabelFile['$errorMode']
1810 );
1811 }
1812 }
1813 unset($this->inlineLanguageLabelFiles);
1814
1815 // Convert labels/settings back to UTF-8 since json_encode() only works with UTF-8:
1816 if ($this->getCharSet() !== 'utf-8') {
1817 if ($this->inlineLanguageLabels) {
1818 $this->csConvObj->convArray($this->inlineLanguageLabels, $this->getCharSet(), 'utf-8');
1819 }
1820 if ($this->inlineSettings) {
1821 $this->csConvObj->convArray($this->inlineSettings, $this->getCharSet(), 'utf-8');
1822 }
1823 }
1824
1825 $inlineSettings = $this->inlineLanguageLabels ? 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' : '';
1826 $inlineSettings .= $this->inlineSettings ? 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' : '';
1827
1828 if ($this->addExtCore || $this->addExtJS) {
1829 // set clear.gif, move it on top, add handler code
1830 $code = '';
1831 if (count($this->extOnReadyCode)) {
1832 foreach ($this->extOnReadyCode as $block) {
1833 $code .= $block;
1834 }
1835 }
1836
1837 $out .= $this->inlineJavascriptWrap[0] . '
1838 Ext.ns("TYPO3");
1839 Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(t3lib_div::locationHeaderUrl($this->backPath . 'gfx/clear.gif')) . '";' . LF .
1840 $inlineSettings .
1841 'Ext.onReady(function() {' .
1842 ($this->enableExtJSQuickTips ? 'Ext.QuickTips.init();' . LF : '') . $code .
1843 ' });' . $this->inlineJavascriptWrap[1];
1844 unset ($this->extOnReadyCode);
1845
1846 // Include TYPO3.l10n object
1847 if (TYPO3_MODE === 'BE') {
1848 $out .= '<script src="' . $this->processJsFile($this->backPath . 'sysext/lang/res/js/be/typo3lang.js') . '" type="text/javascript" charset="utf-8"></script>' . LF;
1849 }
1850
1851 if ($this->extJStheme) {
1852 if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) {
1853 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'all', '', TRUE, TRUE);
1854 } else {
1855 $this->addCssFile($this->backPath . $this->extJsPath . 'resources/css/xtheme-blue.css', 'stylesheet', 'all', '', TRUE, TRUE);
1856 }
1857 }
1858 if ($this->extJScss) {
1859 if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) {
1860 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'all', '', TRUE, TRUE);
1861 } else {
1862 $this->addCssFile($this->backPath . $this->extJsPath . 'resources/css/ext-all-notheme.css', 'stylesheet', 'all', '', TRUE, TRUE);
1863 }
1864 }
1865 } else {
1866 if ($inlineSettings) {
1867 $out .= $this->inlineJavascriptWrap[0] . $inlineSettings . $this->inlineJavascriptWrap[1];
1868 }
1869 }
1870
1871 return $out;
1872 }
1873
1874 protected function includeLanguageFileForInline($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0) {
1875 if (!isset($this->lang) || !isset($this->charSet)) {
1876 throw new RuntimeException('Language and character encoding are not set.', 1284906026);
1877 }
1878
1879 $labelsFromFile = array();
1880 $allLabels = t3lib_div::readLLfile($fileRef, $this->lang, $this->charSet, $errorMode);
1881
1882 // Regular expression to strip the selection prefix and possibly something from the label name:
1883 $labelPattern = '#^' . preg_quote($selectionPrefix, '#') . '(' . preg_quote($stripFromSelectionName, '#') . ')?#';
1884
1885 if ($allLabels !== FALSE) {
1886 // Merge language specific translations:
1887 if ($this->lang !== 'default' && isset($allLabels[$this->lang])) {
1888 $labels = array_merge($allLabels['default'], $allLabels[$this->lang]);
1889 } else {
1890 $labels = $allLabels['default'];
1891 }
1892
1893 // Iterate through all locallang labels:
1894 foreach ($labels as $label => $value) {
1895 if ($selectionPrefix === '') {
1896 $labelsFromFile[$label] = $value;
1897 } elseif (strpos($label, $selectionPrefix) === 0) {
1898 $key = preg_replace($labelPattern, '', $label);
1899 $labelsFromFile[$label] = $value;
1900 }
1901 }
1902
1903 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $labelsFromFile);
1904 }
1905 }
1906
1907 /*****************************************************/
1908 /* */
1909 /* Tools */
1910 /* */
1911 /* */
1912 /*****************************************************/
1913
1914 /**
1915 * Concatenate files into one file
1916 * registered handler
1917 *
1918 * @return void
1919 */
1920 protected function doConcatenate() {
1921 $this->doConcatenateCss();
1922 $this->doConcatenateJavaScript();
1923 }
1924
1925 /**
1926 * Concatenate JavaScript files according to the configuration.
1927 *
1928 * @return void
1929 */
1930 protected function doConcatenateJavaScript() {
1931 if ($this->concatenateFiles || $this->concatenateJavascript) {
1932 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'])) {
1933 // use external concatenation routine
1934 $params = array(
1935 'jsLibs' => &$this->jsLibs,
1936 'jsFiles' => &$this->jsFiles,
1937 'jsFooterFiles' => &$this->jsFooterFiles,
1938 'headerData' => &$this->headerData,
1939 'footerData' => &$this->footerData,
1940 );
1941 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'], $params, $this);
1942 } else {
1943 $this->jsLibs = $this->getCompressor()->concatenateJsFiles($this->jsLibs);
1944 $this->jsFiles = $this->getCompressor()->concatenateJsFiles($this->jsFiles);
1945 $this->jsFooterFiles = $this->getCompressor()->concatenateJsFiles($this->jsFooterFiles);
1946 }
1947 }
1948 }
1949
1950 /**
1951 * Concatenate CSS files according to configuration.
1952 *
1953 * @return void
1954 */
1955 protected function doConcatenateCss() {
1956 if ($this->concatenateFiles || $this->concatenateCss) {
1957 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'])) {
1958 // use external concatenation routine
1959 $params = array(
1960 'cssFiles' => &$this->cssFiles,
1961 'headerData' => &$this->headerData,
1962 'footerData' => &$this->footerData,
1963 );
1964 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'], $params, $this);
1965 } else {
1966 $cssOptions = array();
1967 if (TYPO3_MODE === 'BE') {
1968 $cssOptions = array('baseDirectories' => $GLOBALS['TBE_TEMPLATE']->getSkinStylesheetDirectories());
1969 }
1970 $this->cssFiles = $this->getCompressor()->concatenateCssFiles($this->cssFiles, $cssOptions);
1971 }
1972 }
1973 }
1974
1975 /**
1976 * Compresses inline code
1977 *
1978 * @return void
1979 */
1980 protected function doCompress() {
1981 $this->doCompressJavaScript();
1982 $this->doCompressCss();
1983 }
1984
1985 /**
1986 * Compresses CSS according to configuration.
1987 *
1988 * @return void
1989 */
1990 protected function doCompressCss() {
1991 if ($this->compressCss) {
1992 // use external compression routine
1993 $params = array(
1994 'cssInline' => &$this->cssInline,
1995 'cssFiles' => &$this->cssFiles,
1996 'headerData' => &$this->headerData,
1997 'footerData' => &$this->footerData,
1998 );
1999
2000 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'])) {
2001 // use external concatenation routine
2002 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this);
2003 } else {
2004 $this->cssFiles = $this->getCompressor()->compressCssFiles($this->cssFiles);
2005 }
2006 }
2007 }
2008
2009 /**
2010 * Compresses JavaScript according to configuration.
2011 *
2012 * @return void
2013 */
2014 protected function doCompressJavaScript() {
2015 if ($this->compressJavascript) {
2016 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'])) {
2017 // use external compression routine
2018 $params = array(
2019 'jsInline' => &$this->jsInline,
2020 'jsFooterInline' => &$this->jsFooterInline,
2021 'jsLibs' => &$this->jsLibs,
2022 'jsFiles' => &$this->jsFiles,
2023 'jsFooterFiles' => &$this->jsFooterFiles,
2024 'headerData' => &$this->headerData,
2025 'footerData' => &$this->footerData,
2026 );
2027 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this);
2028 } else {
2029 // traverse the arrays, compress files
2030 if (count($this->jsInline)) {
2031 foreach ($this->jsInline as $name => $properties) {
2032 if ($properties['compress']) {
2033 $error = '';
2034 $this->jsInline[$name]['code'] = t3lib_div::minifyJavaScript($properties['code'], $error);
2035 if ($error) {
2036 $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error . LF;
2037 }
2038 }
2039 }
2040 }
2041 $this->jsLibs = $this->getCompressor()->compressJsFiles($this->jsLibs);
2042 $this->jsFiles = $this->getCompressor()->compressJsFiles($this->jsFiles);
2043 $this->jsFooterFiles = $this->getCompressor()->compressJsFiles($this->jsFooterFiles);
2044 }
2045 }
2046 }
2047
2048 /**
2049 * Returns instance of t3lib_Compressor
2050 *
2051 * @return t3lib_Compressor Instance of t3lib_Compressor
2052 */
2053 protected function getCompressor() {
2054 if ($this->compressor === NULL) {
2055 $this->compressor = t3lib_div::makeInstance('t3lib_Compressor');
2056 }
2057 return $this->compressor;
2058 }
2059
2060 /**
2061 * Processes a Javascript file dependent on the current context
2062 *
2063 * Adds the version number for Frontend, compresses the file for Backend
2064 *
2065 * @param string $filename Filename
2066 * @return string New filename
2067 */
2068 protected function processJsFile($filename) {
2069 switch (TYPO3_MODE) {
2070 case 'FE':
2071 if ($this->compressJavascript) {
2072 $filename = $this->getCompressor()->compressJsFile($filename);
2073 } else {
2074 $filename = t3lib_div::createVersionNumberedFilename($filename);
2075 }
2076 break;
2077 case 'BE':
2078 if ($this->compressJavascript) {
2079 $filename = $this->getCompressor()->compressJsFile($filename);
2080 }
2081 break;
2082 }
2083 return $filename;
2084 }
2085
2086 }
2087
2088 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php'])) {
2089 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php']);
2090 }
2091
2092 ?>