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