[FEATURE] Add hook to pagerenderer after compress/concatenate
[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 $this->jsFiles[$file] = array(
937 'file' => $file,
938 'type' => $type,
939 'section' => self::PART_HEADER,
940 'compress' => $compress,
941 'forceOnTop' => $forceOnTop,
942 'allWrap' => $allWrap,
943 'excludeFromConcatenation' => $excludeFromConcatenation,
944 );
945 }
946 }
947
948 /**
949 * Adds JS file to footer
950 *
951 * @param string $file File name
952 * @param string $type Content Type
953 * @param boolean $compress
954 * @param boolean $forceOnTop
955 * @param string $allWrap
956 * @param boolean $excludeFromConcatenation
957 * @return void
958 */
959 public function addJsFooterFile($file, $type = 'text/javascript', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
960 if (!$type) {
961 $type = 'text/javascript';
962 }
963 if (!isset($this->jsFiles[$file])) {
964 $this->jsFiles[$file] = array(
965 'file' => $file,
966 'type' => $type,
967 'section' => self::PART_FOOTER,
968 'compress' => $compress,
969 'forceOnTop' => $forceOnTop,
970 'allWrap' => $allWrap,
971 'excludeFromConcatenation' => $excludeFromConcatenation,
972 );
973 }
974 }
975
976 /*Javascript Inline Blocks */
977
978 /**
979 * Adds JS inline code
980 *
981 * @param string $name
982 * @param string $block
983 * @param boolean $compress
984 * @param boolean $forceOnTop
985 * @return void
986 */
987 public function addJsInlineCode($name, $block, $compress = TRUE, $forceOnTop = FALSE) {
988 if (!isset($this->jsInline[$name]) && !empty($block)) {
989 $this->jsInline[$name] = array(
990 'code' => $block . LF,
991 'section' => self::PART_HEADER,
992 'compress' => $compress,
993 'forceOnTop' => $forceOnTop
994 );
995 }
996 }
997
998 /**
999 * Adds JS inline code to footer
1000 *
1001 * @param string $name
1002 * @param string $block
1003 * @param boolean $compress
1004 * @param boolean $forceOnTop
1005 * @return void
1006 */
1007 public function addJsFooterInlineCode($name, $block, $compress = TRUE, $forceOnTop = FALSE) {
1008 if (!isset($this->jsInline[$name]) && !empty($block)) {
1009 $this->jsInline[$name] = array(
1010 'code' => $block . LF,
1011 'section' => self::PART_FOOTER,
1012 'compress' => $compress,
1013 'forceOnTop' => $forceOnTop
1014 );
1015 }
1016 }
1017
1018 /**
1019 * Adds Ext.onready code, which will be wrapped in Ext.onReady(function() {...});
1020 *
1021 * @param string $block javascript code
1022 * @param boolean $forceOnTop position of the javascript code (TRUE for putting it on top, default is FALSE = bottom)
1023 * @return void
1024 */
1025 public function addExtOnReadyCode($block, $forceOnTop = FALSE) {
1026 if (!in_array($block, $this->extOnReadyCode)) {
1027 if ($forceOnTop) {
1028 array_unshift($this->extOnReadyCode, $block);
1029 } else {
1030 $this->extOnReadyCode[] = $block;
1031 }
1032 }
1033 }
1034
1035 /**
1036 * Adds the ExtDirect code
1037 *
1038 * @param array $filterNamespaces limit the output to defined namespaces. If empty, all namespaces are generated
1039 * @return void
1040 */
1041 public function addExtDirectCode(array $filterNamespaces = array()) {
1042 if ($this->extDirectCodeAdded) {
1043 return;
1044 }
1045 $this->extDirectCodeAdded = TRUE;
1046
1047 if (count($filterNamespaces) === 0) {
1048 $filterNamespaces = array('TYPO3');
1049 }
1050
1051 // for ExtDirect we need flash message support
1052 $this->addJsFile(t3lib_div::resolveBackPath($this->backPath . '../t3lib/js/extjs/ux/flashmessages.js'));
1053
1054 // add language labels for ExtDirect
1055 if (TYPO3_MODE === 'FE') {
1056 $this->addInlineLanguageLabelArray(array(
1057 'extDirect_timeoutHeader' => $GLOBALS['TSFE']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutHeader'),
1058 'extDirect_timeoutMessage' => $GLOBALS['TSFE']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutMessage'),
1059 ));
1060 } else {
1061 $this->addInlineLanguageLabelArray(array(
1062 'extDirect_timeoutHeader' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutHeader'),
1063 'extDirect_timeoutMessage' => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:extDirect_timeoutMessage'),
1064 ));
1065 }
1066
1067 $token = $api = '';
1068 if (TYPO3_MODE === 'BE') {
1069 $formprotection = t3lib_formprotection_Factory::get();
1070 $token = $formprotection->generateToken('extDirect');
1071 }
1072
1073 /** @var $extDirect t3lib_extjs_ExtDirectApi */
1074 $extDirect = t3lib_div::makeInstance('t3lib_extjs_ExtDirectApi');
1075 $api = $extDirect->getApiPhp($filterNamespaces);
1076 if ($api) {
1077 $this->addJsInlineCode('TYPO3ExtDirectAPI', $api, FALSE);
1078 }
1079 // Note: we need to iterate thru the object, because the addProvider method
1080 // does this only with multiple arguments
1081 $this->addExtOnReadyCode('
1082 (function() {
1083 TYPO3.ExtDirectToken = "' . $token . '";
1084 for (var api in Ext.app.ExtDirectAPI) {
1085 var provider = Ext.Direct.addProvider(Ext.app.ExtDirectAPI[api]);
1086 provider.on("beforecall", function(provider, transaction, meta) {
1087 if (transaction.data) {
1088 transaction.data[transaction.data.length] = TYPO3.ExtDirectToken;
1089 } else {
1090 transaction.data = [TYPO3.ExtDirectToken];
1091 }
1092 });
1093
1094 provider.on("call", function(provider, transaction, meta) {
1095 if (transaction.isForm) {
1096 transaction.params.securityToken = TYPO3.ExtDirectToken;
1097 }
1098 });
1099 }
1100 })();
1101
1102 var extDirectDebug = function(message, header, group) {
1103 var TYPO3ViewportInstance = null;
1104
1105 if (top && top.TYPO3 && typeof top.TYPO3.Backend === "object") {
1106 TYPO3ViewportInstance = top.TYPO3.Backend;
1107 } else if (typeof TYPO3 === "object" && typeof TYPO3.Backend === "object") {
1108 TYPO3ViewportInstance = TYPO3.Backend;
1109 }
1110
1111 if (TYPO3ViewportInstance !== null) {
1112 TYPO3ViewportInstance.DebugConsole.addTab(message, header, group);
1113 } else if (typeof console === "object") {
1114 console.log(message);
1115 } else {
1116 document.write(message);
1117 }
1118 };
1119
1120 Ext.Direct.on("exception", function(event) {
1121 if (event.code === Ext.Direct.exceptions.TRANSPORT && !event.where) {
1122 TYPO3.Flashmessage.display(
1123 TYPO3.Severity.error,
1124 TYPO3.l10n.localize("extDirect_timeoutHeader"),
1125 TYPO3.l10n.localize("extDirect_timeoutMessage"),
1126 30
1127 );
1128 } else {
1129 var backtrace = "";
1130 if (event.code === "parse") {
1131 extDirectDebug(
1132 "<p>" + event.xhr.responseText + "<\/p>",
1133 event.type,
1134 "ExtDirect - Exception"
1135 );
1136 } else if (event.code === "router") {
1137 TYPO3.Flashmessage.display(
1138 TYPO3.Severity.error,
1139 event.code,
1140 event.message,
1141 30
1142 );
1143 } else if (event.where) {
1144 backtrace = "<p style=\"margin-top: 20px;\">" +
1145 "<strong>Backtrace:<\/strong><br \/>" +
1146 event.where.replace(/#/g, "<br \/>#") +
1147 "<\/p>";
1148 extDirectDebug(
1149 "<p>" + event.message + "<\/p>" + backtrace,
1150 event.method,
1151 "ExtDirect - Exception"
1152 );
1153 }
1154
1155
1156 }
1157 });
1158
1159 Ext.Direct.on("event", function(event, provider) {
1160 if (typeof event.debug !== "undefined" && event.debug !== "") {
1161 extDirectDebug(event.debug, event.method, "ExtDirect - Debug");
1162 }
1163 });
1164 ',
1165 TRUE
1166 );
1167 }
1168
1169 /* CSS Files */
1170
1171 /**
1172 * Adds CSS file
1173 *
1174 * @param string $file
1175 * @param string $rel
1176 * @param string $media
1177 * @param string $title
1178 * @param boolean $compress
1179 * @param boolean $forceOnTop
1180 * @param string $allWrap
1181 * @param boolean $excludeFromConcatenation
1182 * @return void
1183 */
1184 public function addCssFile($file, $rel = 'stylesheet', $media = 'all', $title = '', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '', $excludeFromConcatenation = FALSE) {
1185 if (!isset($this->cssFiles[$file])) {
1186 $this->cssFiles[$file] = array(
1187 'file' => $file,
1188 'rel' => $rel,
1189 'media' => $media,
1190 'title' => $title,
1191 'compress' => $compress,
1192 'forceOnTop' => $forceOnTop,
1193 'allWrap' => $allWrap,
1194 'excludeFromConcatenation' => $excludeFromConcatenation,
1195 );
1196 }
1197 }
1198
1199 /*CSS Inline Blocks */
1200
1201 /**
1202 * Adds CSS inline code
1203 *
1204 * @param string $name
1205 * @param string $block
1206 * @param boolean $compress
1207 * @param boolean $forceOnTop
1208 * @return void
1209 */
1210 public function addCssInlineBlock($name, $block, $compress = FALSE, $forceOnTop = FALSE) {
1211 if (!isset($this->cssInline[$name]) && !empty($block)) {
1212 $this->cssInline[$name] = array(
1213 'code' => $block,
1214 'compress' => $compress,
1215 'forceOnTop' => $forceOnTop
1216 );
1217 }
1218 }
1219
1220 /* JS Libraries */
1221
1222 /**
1223 * call function if you need the prototype library
1224 *
1225 * @return void
1226 */
1227 public function loadPrototype() {
1228 $this->addPrototype = TRUE;
1229 }
1230
1231 /**
1232 * call function if you need the Scriptaculous library
1233 *
1234 * @param string $modules add modules you need. use "all" if you need complete modules
1235 * @return void
1236 */
1237 public function loadScriptaculous($modules = 'all') {
1238 // Scriptaculous require prototype, so load prototype too.
1239 $this->addPrototype = TRUE;
1240 $this->addScriptaculous = TRUE;
1241 if ($modules) {
1242 if ($modules == 'all') {
1243 foreach ($this->addScriptaculousModules as $key => $value) {
1244 $this->addScriptaculousModules[$key] = TRUE;
1245 }
1246 } else {
1247 $mods = t3lib_div::trimExplode(',', $modules);
1248 foreach ($mods as $mod) {
1249 if (isset($this->addScriptaculousModules[strtolower($mod)])) {
1250 $this->addScriptaculousModules[strtolower($mod)] = TRUE;
1251 }
1252 }
1253 }
1254 }
1255 }
1256
1257 /**
1258 * call this function if you need the extJS library
1259 *
1260 * @param boolean $css flag, if set the ext-css will be loaded
1261 * @param boolean $theme flag, if set the ext-theme "grey" will be loaded
1262 * @param string $adapter choose alternative adapter, possible values: yui, prototype, jquery
1263 * @return void
1264 */
1265 public function loadExtJS($css = TRUE, $theme = TRUE, $adapter = '') {
1266 if ($adapter) {
1267 // empty $adapter will always load the ext adapter
1268 switch (t3lib_div::strtolower(trim($adapter))) {
1269 case self::EXTJS_ADAPTER_YUI :
1270 $this->extJSadapter = 'yui/ext-yui-adapter.js';
1271 break;
1272 case self::EXTJS_ADAPTER_PROTOTYPE :
1273 $this->extJSadapter = 'prototype/ext-prototype-adapter.js';
1274 break;
1275 case self::EXTJS_ADAPTER_JQUERY :
1276 $this->extJSadapter = 'jquery/ext-jquery-adapter.js';
1277 break;
1278 }
1279 }
1280 $this->addExtJS = TRUE;
1281 $this->extJStheme = $theme;
1282 $this->extJScss = $css;
1283
1284 }
1285
1286 /**
1287 * Enables ExtJs QuickTips
1288 * Need extJs loaded
1289 *
1290 * @return void
1291 *
1292 */
1293 public function enableExtJSQuickTips() {
1294 $this->enableExtJSQuickTips = TRUE;
1295 }
1296
1297
1298 /**
1299 * call function if you need the ExtCore library
1300 *
1301 * @return void
1302 */
1303 public function loadExtCore() {
1304 $this->addExtCore = TRUE;
1305 }
1306
1307 /**
1308 * call function if you need the SVG library
1309 *
1310 * @return void
1311 */
1312 public function loadSvg() {
1313 $this->addSvg = TRUE;
1314 }
1315
1316 /**
1317 * call this function to load debug version of ExtJS. Use this for development only
1318 *
1319 */
1320 public function enableSvgDebug() {
1321 $this->enableSvgDebug = TRUE;
1322 }
1323
1324 /**
1325 * call this function to force flash usage with SVG library
1326 *
1327 */
1328 public function svgForceFlash() {
1329 $this->addMetaTag('<meta name="svg.render.forceflash" content="true" />');
1330 }
1331
1332 /**
1333 * call this function to load debug version of ExtJS. Use this for development only
1334 *
1335 */
1336 public function enableExtJsDebug() {
1337 $this->enableExtJsDebug = TRUE;
1338 }
1339
1340 /**
1341 * call this function to load debug version of ExtCore. Use this for development only
1342 *
1343 * @return void
1344 */
1345 public function enableExtCoreDebug() {
1346 $this->enableExtCoreDebug = TRUE;
1347 }
1348
1349 /**
1350 * Adds Javascript Inline Label. This will occur in TYPO3.lang - object
1351 * The label can be used in scripts with TYPO3.lang.<key>
1352 * Need extJs loaded
1353 *
1354 * @param string $key
1355 * @param string $value
1356 * @return void
1357 */
1358 public function addInlineLanguageLabel($key, $value) {
1359 $this->inlineLanguageLabels[$key] = $value;
1360 }
1361
1362 /**
1363 * Adds Javascript Inline Label Array. This will occur in TYPO3.lang - object
1364 * The label can be used in scripts with TYPO3.lang.<key>
1365 * Array will be merged with existing array.
1366 * Need extJs loaded
1367 *
1368 * @param array $array
1369 * @return void
1370 */
1371 public function addInlineLanguageLabelArray(array $array) {
1372 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $array);
1373 }
1374
1375 /**
1376 * Gets labels to be used in JavaScript fetched from a locallang file.
1377 *
1378 * @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.
1379 * @param string $selectionPrefix: Prefix to select the correct labels (default: '')
1380 * @param string $stripFromSelectionName: Sub-prefix to be removed from label names in the result (default: '')
1381 * @param integer Error mode (when file could not be found): 0 - syslog entry, 1 - do nothing, 2 - throw an exception
1382 * @return void
1383 */
1384 public function addInlineLanguageLabelFile($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0) {
1385 $index = md5($fileRef . $selectionPrefix . $stripFromSelectionName);
1386 if ($fileRef && !isset($this->inlineLanguageLabelFiles[$index])) {
1387 $this->inlineLanguageLabelFiles[$index] = array(
1388 'fileRef' => $fileRef,
1389 'selectionPrefix' => $selectionPrefix,
1390 'stripFromSelectionName' => $stripFromSelectionName,
1391 'errorMode' => $errorMode
1392 );
1393 }
1394 }
1395
1396
1397 /**
1398 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1399 * The label can be used in scripts with TYPO3.setting.<key>
1400 * Need extJs loaded
1401 *
1402 * @param string $namespace
1403 * @param string $key
1404 * @param string $value
1405 * @return void
1406 */
1407 public function addInlineSetting($namespace, $key, $value) {
1408 if ($namespace) {
1409 if (strpos($namespace, '.')) {
1410 $parts = explode('.', $namespace);
1411 $a = &$this->inlineSettings;
1412 foreach ($parts as $part) {
1413 $a = &$a[$part];
1414 }
1415 $a[$key] = $value;
1416 } else {
1417 $this->inlineSettings[$namespace][$key] = $value;
1418 }
1419 } else {
1420 $this->inlineSettings[$key] = $value;
1421 }
1422 }
1423
1424 /**
1425 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
1426 * The label can be used in scripts with TYPO3.setting.<key>
1427 * Array will be merged with existing array.
1428 * Need extJs loaded
1429 *
1430 * @param string $namespace
1431 * @param array $array
1432 * @return void
1433 */
1434 public function addInlineSettingArray($namespace, array $array) {
1435 if ($namespace) {
1436 if (strpos($namespace, '.')) {
1437 $parts = explode('.', $namespace);
1438 $a = &$this->inlineSettings;
1439 foreach ($parts as $part) {
1440 $a = &$a[$part];
1441 }
1442 $a = array_merge((array) $a, $array);
1443 } else {
1444 $this->inlineSettings[$namespace] = array_merge((array) $this->inlineSettings[$namespace], $array);
1445 }
1446 } else {
1447 $this->inlineSettings = array_merge($this->inlineSettings, $array);
1448 }
1449 }
1450
1451 /**
1452 * Adds content to body content
1453 *
1454 * @param string $content
1455 * @return void
1456 */
1457 public function addBodyContent($content) {
1458 $this->bodyContent .= $content;
1459 }
1460
1461 /*****************************************************/
1462 /* */
1463 /* Render Functions */
1464 /* */
1465 /* */
1466 /*****************************************************/
1467
1468 /**
1469 * render the section (Header or Footer)
1470 *
1471 * @param int $part section which should be rendered: self::PART_COMPLETE, self::PART_HEADER or self::PART_FOOTER
1472 * @return string content of rendered section
1473 */
1474 public function render($part = self::PART_COMPLETE) {
1475
1476 $jsFiles = '';
1477 $cssFiles = '';
1478 $cssInline = '';
1479 $jsInline = '';
1480 $jsFooterInline = '';
1481 $jsFooterLibs = '';
1482 $jsFooterFiles = '';
1483
1484 // preRenderHook for possible manuipulation
1485 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'])) {
1486 $params = array(
1487 'jsLibs' => &$this->jsLibs,
1488 'jsFooterLibs' => &$this->jsFooterLibs,
1489 'jsFiles' => &$this->jsFiles,
1490 'jsFooterFiles' => &$this->jsFooterFiles,
1491 'cssFiles' => &$this->cssFiles,
1492 'headerData' => &$this->headerData,
1493 'footerData' => &$this->footerData,
1494 'jsInline' => &$this->jsInline,
1495 'jsFooterInline' => &$this->jsFooterInline,
1496 'cssInline' => &$this->cssInline,
1497 );
1498 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'] as $hook) {
1499 t3lib_div::callUserFunction($hook, $params, $this);
1500 }
1501 }
1502
1503 $jsLibs = $this->renderJsLibraries();
1504
1505 if ($this->concatenateFiles || $this->concatenateJavascript || $this->concatenateCss) {
1506 // do the file concatenation
1507 $this->doConcatenate();
1508 }
1509 if ($this->compressCss || $this->compressJavascript) {
1510 // do the file compression
1511 $this->doCompress();
1512 }
1513 // postTransform for possible manuipulation of concatenated and compressed files
1514 if(is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postTransform'])) {
1515 $params = array(
1516 'jsLibs' => &$this->jsLibs,
1517 'jsFooterLibs' => &$this->jsFooterLibs,
1518 'jsFiles' => &$this->jsFiles,
1519 'jsFooterFiles' => &$this->jsFooterFiles,
1520 'cssFiles' => &$this->cssFiles,
1521 'headerData' => &$this->headerData,
1522 'footerData' => &$this->footerData,
1523 'jsInline' => &$this->jsInline,
1524 'jsFooterInline' => &$this->jsFooterInline,
1525 'cssInline' => &$this->cssInline,
1526 );
1527 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postTransform'] as $hook) {
1528 t3lib_div::callUserFunction($hook, $params, $this);
1529 }
1530 }
1531 $metaTags = implode(LF, $this->metaTags);
1532
1533 // remove ending slashes from static header block
1534 // if the page is beeing rendered as html (not xhtml)
1535 // and define variable $endingSlash for further use
1536 if ($this->getRenderXhtml()) {
1537 $endingSlash = ' /';
1538 } else {
1539 $this->metaCharsetTag = str_replace(' />', '>', $this->metaCharsetTag);
1540 $this->baseUrlTag = str_replace(' />', '>', $this->baseUrlTag);
1541 $this->shortcutTag = str_replace(' />', '>', $this->shortcutTag);
1542 $endingSlash = '';
1543 }
1544
1545 if (count($this->cssFiles)) {
1546 foreach ($this->cssFiles as $name => $properties) {
1547 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1548 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1549 $tag = '<link rel="' . htmlspecialchars($properties['rel']) . '" type="text/css" href="' .
1550 htmlspecialchars($properties['file']) . '" media="' . htmlspecialchars($properties['media']) . '"' .
1551 ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '') .
1552 $endingSlash . '>';
1553 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1554 $tag = str_replace('|', $tag, $properties['allWrap']);
1555 }
1556 if ($properties['forceOnTop']) {
1557 $cssFiles = $tag . LF . $cssFiles;
1558 } else {
1559 $cssFiles .= LF . $tag;
1560 }
1561 }
1562 }
1563
1564 if (count($this->cssInline)) {
1565 foreach ($this->cssInline as $name => $properties) {
1566 if ($properties['forceOnTop']) {
1567 $cssInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $cssInline;
1568 } else {
1569 $cssInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1570 }
1571 }
1572 $cssInline = $this->inlineCssWrap[0] . $cssInline . $this->inlineCssWrap[1];
1573 }
1574
1575 if (count($this->jsLibs)) {
1576 foreach ($this->jsLibs as $name => $properties) {
1577 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1578 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1579 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"></script>';
1580 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1581 $tag = str_replace('|', $tag, $properties['allWrap']);
1582 }
1583 if ($properties['forceOnTop']) {
1584 if ($properties['section'] === self::PART_HEADER) {
1585 $jsLibs = $tag . LF . $jsLibs;
1586 } else {
1587 $jsFooterLibs = $tag . LF . $jsFooterLibs;
1588 }
1589 } else {
1590 if ($properties['section'] === self::PART_HEADER) {
1591 $jsLibs .= LF . $tag;
1592 } else {
1593 $jsFooterLibs .= LF . $tag;
1594 }
1595 }
1596 }
1597 }
1598
1599 if (count($this->jsFiles)) {
1600 foreach ($this->jsFiles as $name => $properties) {
1601 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1602 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1603 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"></script>';
1604 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1605 $tag = str_replace('|', $tag, $properties['allWrap']);
1606 }
1607 if ($properties['forceOnTop']) {
1608 if ($properties['section'] === self::PART_HEADER) {
1609 $jsFiles = $tag . LF . $jsFiles;
1610 } else {
1611 $jsFooterFiles = $tag . LF . $jsFooterFiles;
1612 }
1613 } else {
1614 if ($properties['section'] === self::PART_HEADER) {
1615 $jsFiles .= LF . $tag;
1616 } else {
1617 $jsFooterFiles .= LF . $tag;
1618 }
1619 }
1620 }
1621 }
1622
1623 if (count($this->jsInline)) {
1624 foreach ($this->jsInline as $name => $properties) {
1625 if ($properties['forceOnTop']) {
1626 if ($properties['section'] === self::PART_HEADER) {
1627 $jsInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsInline;
1628 } else {
1629 $jsFooterInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsFooterInline;
1630 }
1631 } else {
1632 if ($properties['section'] === self::PART_HEADER) {
1633 $jsInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1634 } else {
1635 $jsFooterInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1636 }
1637 }
1638 }
1639 }
1640
1641
1642 if ($jsInline) {
1643 $jsInline = $this->inlineJavascriptWrap[0] . $jsInline . $this->inlineJavascriptWrap[1];
1644 }
1645
1646 if ($jsFooterInline) {
1647 $jsFooterInline = $this->inlineJavascriptWrap[0] . $jsFooterInline . $this->inlineJavascriptWrap[1];
1648 }
1649
1650
1651 // get template
1652 $templateFile = t3lib_div::getFileAbsFileName($this->templateFile, TRUE);
1653 $template = t3lib_div::getUrl($templateFile);
1654
1655 if ($this->removeLineBreaksFromTemplate) {
1656 $template = strtr($template, array(LF => '', CR => ''));
1657 }
1658 if ($part != self::PART_COMPLETE) {
1659 $templatePart = explode('###BODY###', $template);
1660 $template = $templatePart[$part - 1];
1661 }
1662
1663 if ($this->moveJsFromHeaderToFooter) {
1664 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
1665 $jsLibs = '';
1666 $jsFooterFiles = $jsFiles . LF . $jsFooterFiles;
1667 $jsFiles = '';
1668 $jsFooterInline = $jsInline . LF . $jsFooterInline;
1669 $jsInline = '';
1670 }
1671
1672 // postRenderHook for possible manipulation
1673 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'])) {
1674 $params = array (
1675 'jsLibs' => &$jsLibs,
1676 'jsFiles' => &$jsFiles,
1677 'jsFooterFiles' => &$jsFooterFiles,
1678 'cssFiles' => &$cssFiles,
1679 'headerData' => &$this->headerData,
1680 'footerData' => &$this->footerData,
1681 'jsInline' => &$jsInline,
1682 'cssInline' => &$cssInline,
1683 'xmlPrologAndDocType' => &$this->xmlPrologAndDocType,
1684 'htmlTag' => &$this->htmlTag,
1685 'headTag' => &$this->headTag,
1686 'charSet' => &$this->charSet,
1687 'metaCharsetTag' => &$this->metaCharsetTag,
1688 'shortcutTag' => &$this->shortcutTag,
1689 'inlineComments' => &$this->inlineComments,
1690 'baseUrl' => &$this->baseUrl,
1691 'baseUrlTag' => &$this->baseUrlTag,
1692 'favIcon' => &$this->favIcon,
1693 'iconMimeType' => &$this->iconMimeType,
1694 'titleTag' => &$this->titleTag,
1695 'title' => &$this->title,
1696 'metaTags' => &$metaTags,
1697 'jsFooterInline' => &$jsFooterInline,
1698 'jsFooterLibs' => &$jsFooterLibs,
1699 'bodyContent' => &$this->bodyContent,
1700 );
1701 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'] as $hook) {
1702 t3lib_div::callUserFunction($hook, $params, $this);
1703 }
1704 }
1705
1706 $markerArray = array(
1707 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1708 'HTMLTAG' => $this->htmlTag,
1709 'HEADTAG' => $this->headTag,
1710 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1711 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1712 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1713 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1714 'CSS_INCLUDE' => $cssFiles,
1715 'CSS_INLINE' => $cssInline,
1716 'JS_INLINE' => $jsInline,
1717 'JS_INCLUDE' => $jsFiles,
1718 'JS_LIBS' => $jsLibs,
1719 'TITLE' => $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '',
1720 'META' => $metaTags,
1721 'HEADERDATA' => $this->headerData ? implode(LF, $this->headerData) : '',
1722 'FOOTERDATA' => $this->footerData ? implode(LF, $this->footerData) : '',
1723 'JS_LIBS_FOOTER' => $jsFooterLibs,
1724 'JS_INCLUDE_FOOTER' => $jsFooterFiles,
1725 'JS_INLINE_FOOTER' => $jsFooterInline,
1726 'BODY' => $this->bodyContent,
1727 );
1728
1729 $markerArray = array_map('trim', $markerArray);
1730
1731 $this->reset();
1732 return trim(t3lib_parsehtml::substituteMarkerArray($template, $markerArray, '###|###'));
1733 }
1734
1735 /**
1736 * helper function for render the javascript libraries
1737 *
1738 * @return string content with javascript libraries
1739 */
1740 protected function renderJsLibraries() {
1741 $out = '';
1742
1743 if ($this->addSvg) {
1744 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->svgPath . 'svg.js') .
1745 '" data-path="' . $this->backPath . $this->svgPath .
1746 '"' . ($this->enableSvgDebug ? ' data-debug="true"' : '') . '></script>';
1747 }
1748
1749 if ($this->addPrototype) {
1750 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->prototypePath . 'prototype.js') .
1751 '" type="text/javascript"></script>' . LF;
1752 unset($this->jsFiles[$this->backPath . $this->prototypePath . 'prototype.js']);
1753 }
1754
1755 if ($this->addScriptaculous) {
1756 $mods = array();
1757 foreach ($this->addScriptaculousModules as $key => $value) {
1758 if ($this->addScriptaculousModules[$key]) {
1759 $mods[] = $key;
1760 }
1761 }
1762 // resolve dependencies
1763 if (in_array('dragdrop', $mods) || in_array('controls', $mods)) {
1764 $mods = array_merge(array('effects'), $mods);
1765 }
1766
1767 if (count($mods)) {
1768 foreach ($mods as $module) {
1769 $out .= '<script src="' . $this->processJsFile($this->backPath .
1770 $this->scriptaculousPath . $module . '.js') . '" type="text/javascript"></script>' . LF;
1771 unset($this->jsFiles[$this->backPath . $this->scriptaculousPath . $module . '.js']);
1772 }
1773 }
1774 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->scriptaculousPath .
1775 'scriptaculous.js') . '" type="text/javascript"></script>' . LF;
1776 unset($this->jsFiles[$this->backPath . $this->scriptaculousPath . 'scriptaculous.js']);
1777 }
1778
1779 // include extCore, but only if ExtJS is not included
1780 if ($this->addExtCore && !$this->addExtJS) {
1781 $out .= '<script src="' . $this->processJsFile($this->backPath .
1782 $this->extCorePath . 'ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js') .
1783 '" type="text/javascript"></script>' . LF;
1784 unset($this->jsFiles[$this->backPath . $this->extCorePath . 'ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js']);
1785 }
1786
1787 // include extJS
1788 if ($this->addExtJS) {
1789 // use the base adapter all the time
1790 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->extJsPath .
1791 'adapter/' . ($this->enableExtJsDebug ?
1792 str_replace('.js', '-debug.js', $this->extJSadapter) : $this->extJSadapter)) .
1793 '" type="text/javascript"></script>' . LF;
1794 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->extJsPath .
1795 'ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js') .
1796 '" type="text/javascript"></script>' . LF;
1797
1798 // add extJS localization
1799 $localeMap = $this->locales->getIsoMapping(); // load standard ISO mapping and modify for use with ExtJS
1800 $localeMap[''] = 'en';
1801 $localeMap['default'] = 'en';
1802 $localeMap['gr'] = 'el_GR'; // Greek
1803 $localeMap['no'] = 'no_BO'; // Norwegian Bokmaal
1804 $localeMap['se'] = 'se_SV'; // Swedish
1805
1806
1807 $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang;
1808 // TODO autoconvert file from UTF8 to current BE charset if necessary!!!!
1809 $extJsLocaleFile = $this->extJsPath . 'locale/ext-lang-' . $extJsLang . '.js';
1810 if (file_exists(PATH_typo3 . $extJsLocaleFile)) {
1811 $out .= '<script src="' . $this->processJsFile($this->backPath .
1812 $extJsLocaleFile) . '" type="text/javascript" charset="utf-8"></script>' . LF;
1813 }
1814
1815
1816 // remove extjs from JScodeLibArray
1817 unset(
1818 $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all.js'],
1819 $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all-debug.js']
1820 );
1821 }
1822
1823 if (count($this->inlineLanguageLabelFiles)) {
1824 foreach ($this->inlineLanguageLabelFiles as $languageLabelFile) {
1825 $this->includeLanguageFileForInline(
1826 $languageLabelFile['fileRef'],
1827 $languageLabelFile['selectionPrefix'],
1828 $languageLabelFile['stripFromSelectionName'],
1829 $languageLabelFile['$errorMode']
1830 );
1831 }
1832 }
1833 unset($this->inlineLanguageLabelFiles);
1834
1835 // Convert labels/settings back to UTF-8 since json_encode() only works with UTF-8:
1836 if ($this->getCharSet() !== 'utf-8') {
1837 if ($this->inlineLanguageLabels) {
1838 $this->csConvObj->convArray($this->inlineLanguageLabels, $this->getCharSet(), 'utf-8');
1839 }
1840 if ($this->inlineSettings) {
1841 $this->csConvObj->convArray($this->inlineSettings, $this->getCharSet(), 'utf-8');
1842 }
1843 }
1844
1845 $inlineSettings = $this->inlineLanguageLabels ? 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' : '';
1846 $inlineSettings .= $this->inlineSettings ? 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' : '';
1847
1848 if ($this->addExtCore || $this->addExtJS) {
1849 // set clear.gif, move it on top, add handler code
1850 $code = '';
1851 if (count($this->extOnReadyCode)) {
1852 foreach ($this->extOnReadyCode as $block) {
1853 $code .= $block;
1854 }
1855 }
1856
1857 $out .= $this->inlineJavascriptWrap[0] . '
1858 Ext.ns("TYPO3");
1859 Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(t3lib_div::locationHeaderUrl($this->backPath . 'gfx/clear.gif')) . '";' . LF .
1860 $inlineSettings .
1861 'Ext.onReady(function() {' .
1862 ($this->enableExtJSQuickTips ? 'Ext.QuickTips.init();' . LF : '') . $code .
1863 ' });' . $this->inlineJavascriptWrap[1];
1864 unset ($this->extOnReadyCode);
1865
1866 // Include TYPO3.l10n object
1867 if (TYPO3_MODE === 'BE') {
1868 $out .= '<script src="' . $this->processJsFile($this->backPath . 'sysext/lang/res/js/be/typo3lang.js') . '" type="text/javascript" charset="utf-8"></script>' . LF;
1869 }
1870
1871 if ($this->extJStheme) {
1872 if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) {
1873 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'all', '', TRUE, TRUE);
1874 } else {
1875 $this->addCssFile($this->backPath . $this->extJsPath . 'resources/css/xtheme-blue.css', 'stylesheet', 'all', '', TRUE, TRUE);
1876 }
1877 }
1878 if ($this->extJScss) {
1879 if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) {
1880 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'all', '', TRUE, TRUE);
1881 } else {
1882 $this->addCssFile($this->backPath . $this->extJsPath . 'resources/css/ext-all-notheme.css', 'stylesheet', 'all', '', TRUE, TRUE);
1883 }
1884 }
1885 } else {
1886 if ($inlineSettings) {
1887 $out .= $this->inlineJavascriptWrap[0] . $inlineSettings . $this->inlineJavascriptWrap[1];
1888 }
1889 }
1890
1891 return $out;
1892 }
1893
1894 protected function includeLanguageFileForInline($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0) {
1895 if (!isset($this->lang) || !isset($this->charSet)) {
1896 throw new RuntimeException('Language and character encoding are not set.', 1284906026);
1897 }
1898
1899 $labelsFromFile = array();
1900 $allLabels = t3lib_div::readLLfile($fileRef, $this->lang, $this->charSet, $errorMode);
1901
1902 // Regular expression to strip the selection prefix and possibly something from the label name:
1903 $labelPattern = '#^' . preg_quote($selectionPrefix, '#') . '(' . preg_quote($stripFromSelectionName, '#') . ')?#';
1904
1905 if ($allLabels !== FALSE) {
1906 // Merge language specific translations:
1907 if ($this->lang !== 'default' && isset($allLabels[$this->lang])) {
1908 $labels = array_merge($allLabels['default'], $allLabels[$this->lang]);
1909 } else {
1910 $labels = $allLabels['default'];
1911 }
1912
1913 // Iterate through all locallang labels:
1914 foreach ($labels as $label => $value) {
1915 if ($selectionPrefix === '') {
1916 $labelsFromFile[$label] = $value;
1917 } elseif (strpos($label, $selectionPrefix) === 0) {
1918 $key = preg_replace($labelPattern, '', $label);
1919 $labelsFromFile[$label] = $value;
1920 }
1921 }
1922
1923 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $labelsFromFile);
1924 }
1925 }
1926
1927 /*****************************************************/
1928 /* */
1929 /* Tools */
1930 /* */
1931 /* */
1932 /*****************************************************/
1933
1934 /**
1935 * Concatenate files into one file
1936 * registered handler
1937 *
1938 * @return void
1939 */
1940 protected function doConcatenate() {
1941 $this->doConcatenateCss();
1942 $this->doConcatenateJavaScript();
1943 }
1944
1945 /**
1946 * Concatenate JavaScript files according to the configuration.
1947 *
1948 * @return void
1949 */
1950 protected function doConcatenateJavaScript() {
1951 if ($this->concatenateFiles || $this->concatenateJavascript) {
1952 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'])) {
1953 // use external concatenation routine
1954 $params = array(
1955 'jsLibs' => &$this->jsLibs,
1956 'jsFiles' => &$this->jsFiles,
1957 'jsFooterFiles' => &$this->jsFooterFiles,
1958 'headerData' => &$this->headerData,
1959 'footerData' => &$this->footerData,
1960 );
1961 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'], $params, $this);
1962 } else {
1963 $this->jsLibs = $this->getCompressor()->concatenateJsFiles($this->jsLibs);
1964 $this->jsFiles = $this->getCompressor()->concatenateJsFiles($this->jsFiles);
1965 $this->jsFooterFiles = $this->getCompressor()->concatenateJsFiles($this->jsFooterFiles);
1966 }
1967 }
1968 }
1969
1970 /**
1971 * Concatenate CSS files according to configuration.
1972 *
1973 * @return void
1974 */
1975 protected function doConcatenateCss() {
1976 if ($this->concatenateFiles || $this->concatenateCss) {
1977 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'])) {
1978 // use external concatenation routine
1979 $params = array(
1980 'cssFiles' => &$this->cssFiles,
1981 'headerData' => &$this->headerData,
1982 'footerData' => &$this->footerData,
1983 );
1984 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'], $params, $this);
1985 } else {
1986 $cssOptions = array();
1987 if (TYPO3_MODE === 'BE') {
1988 $cssOptions = array('baseDirectories' => $GLOBALS['TBE_TEMPLATE']->getSkinStylesheetDirectories());
1989 }
1990 $this->cssFiles = $this->getCompressor()->concatenateCssFiles($this->cssFiles, $cssOptions);
1991 }
1992 }
1993 }
1994
1995 /**
1996 * Compresses inline code
1997 *
1998 * @return void
1999 */
2000 protected function doCompress() {
2001 $this->doCompressJavaScript();
2002 $this->doCompressCss();
2003 }
2004
2005 /**
2006 * Compresses CSS according to configuration.
2007 *
2008 * @return void
2009 */
2010 protected function doCompressCss() {
2011 if ($this->compressCss) {
2012 // use external compression routine
2013 $params = array(
2014 'cssInline' => &$this->cssInline,
2015 'cssFiles' => &$this->cssFiles,
2016 'headerData' => &$this->headerData,
2017 'footerData' => &$this->footerData,
2018 );
2019
2020 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'])) {
2021 // use external concatenation routine
2022 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this);
2023 } else {
2024 $this->cssFiles = $this->getCompressor()->compressCssFiles($this->cssFiles);
2025 }
2026 }
2027 }
2028
2029 /**
2030 * Compresses JavaScript according to configuration.
2031 *
2032 * @return void
2033 */
2034 protected function doCompressJavaScript() {
2035 if ($this->compressJavascript) {
2036 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'])) {
2037 // use external compression routine
2038 $params = array(
2039 'jsInline' => &$this->jsInline,
2040 'jsFooterInline' => &$this->jsFooterInline,
2041 'jsLibs' => &$this->jsLibs,
2042 'jsFiles' => &$this->jsFiles,
2043 'jsFooterFiles' => &$this->jsFooterFiles,
2044 'headerData' => &$this->headerData,
2045 'footerData' => &$this->footerData,
2046 );
2047 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this);
2048 } else {
2049 // traverse the arrays, compress files
2050 if (count($this->jsInline)) {
2051 foreach ($this->jsInline as $name => $properties) {
2052 if ($properties['compress']) {
2053 $error = '';
2054 $this->jsInline[$name]['code'] = t3lib_div::minifyJavaScript($properties['code'], $error);
2055 if ($error) {
2056 $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error . LF;
2057 }
2058 }
2059 }
2060 }
2061 $this->jsLibs = $this->getCompressor()->compressJsFiles($this->jsLibs);
2062 $this->jsFiles = $this->getCompressor()->compressJsFiles($this->jsFiles);
2063 $this->jsFooterFiles = $this->getCompressor()->compressJsFiles($this->jsFooterFiles);
2064 }
2065 }
2066 }
2067
2068 /**
2069 * Returns instance of t3lib_Compressor
2070 *
2071 * @return t3lib_Compressor Instance of t3lib_Compressor
2072 */
2073 protected function getCompressor() {
2074 if ($this->compressor === NULL) {
2075 $this->compressor = t3lib_div::makeInstance('t3lib_Compressor');
2076 }
2077 return $this->compressor;
2078 }
2079
2080 /**
2081 * Processes a Javascript file dependent on the current context
2082 *
2083 * Adds the version number for Frontend, compresses the file for Backend
2084 *
2085 * @param string $filename Filename
2086 * @return string New filename
2087 */
2088 protected function processJsFile($filename) {
2089 switch (TYPO3_MODE) {
2090 case 'FE':
2091 if ($this->compressJavascript) {
2092 $filename = $this->getCompressor()->compressJsFile($filename);
2093 } else {
2094 $filename = t3lib_div::createVersionNumberedFilename($filename);
2095 }
2096 break;
2097 case 'BE':
2098 if ($this->compressJavascript) {
2099 $filename = $this->getCompressor()->compressJsFile($filename);
2100 }
2101 break;
2102 }
2103 return $filename;
2104 }
2105
2106 }
2107
2108 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php'])) {
2109 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php']);
2110 }
2111
2112 ?>