[BUGFIX] Some methods in t3lib_TSparser should be static
[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
1514 $metaTags = implode(LF, $this->metaTags);
1515
1516 // remove ending slashes from static header block
1517 // if the page is beeing rendered as html (not xhtml)
1518 // and define variable $endingSlash for further use
1519 if ($this->getRenderXhtml()) {
1520 $endingSlash = ' /';
1521 } else {
1522 $this->metaCharsetTag = str_replace(' />', '>', $this->metaCharsetTag);
1523 $this->baseUrlTag = str_replace(' />', '>', $this->baseUrlTag);
1524 $this->shortcutTag = str_replace(' />', '>', $this->shortcutTag);
1525 $endingSlash = '';
1526 }
1527
1528 if (count($this->cssFiles)) {
1529 foreach ($this->cssFiles as $name => $properties) {
1530 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1531 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1532 $tag = '<link rel="' . htmlspecialchars($properties['rel']) . '" type="text/css" href="' .
1533 htmlspecialchars($properties['file']) . '" media="' . htmlspecialchars($properties['media']) . '"' .
1534 ($properties['title'] ? ' title="' . htmlspecialchars($properties['title']) . '"' : '') .
1535 $endingSlash . '>';
1536 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1537 $tag = str_replace('|', $tag, $properties['allWrap']);
1538 }
1539 if ($properties['forceOnTop']) {
1540 $cssFiles = $tag . LF . $cssFiles;
1541 } else {
1542 $cssFiles .= LF . $tag;
1543 }
1544 }
1545 }
1546
1547 if (count($this->cssInline)) {
1548 foreach ($this->cssInline as $name => $properties) {
1549 if ($properties['forceOnTop']) {
1550 $cssInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $cssInline;
1551 } else {
1552 $cssInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1553 }
1554 }
1555 $cssInline = $this->inlineCssWrap[0] . $cssInline . $this->inlineCssWrap[1];
1556 }
1557
1558 if (count($this->jsLibs)) {
1559 foreach ($this->jsLibs as $name => $properties) {
1560 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1561 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1562 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"></script>';
1563 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1564 $tag = str_replace('|', $tag, $properties['allWrap']);
1565 }
1566 if ($properties['forceOnTop']) {
1567 if ($properties['section'] === self::PART_HEADER) {
1568 $jsLibs = $tag . LF . $jsLibs;
1569 } else {
1570 $jsFooterLibs = $tag . LF . $jsFooterLibs;
1571 }
1572 } else {
1573 if ($properties['section'] === self::PART_HEADER) {
1574 $jsLibs .= LF . $tag;
1575 } else {
1576 $jsFooterLibs .= LF . $tag;
1577 }
1578 }
1579 }
1580 }
1581
1582 if (count($this->jsFiles)) {
1583 foreach ($this->jsFiles as $name => $properties) {
1584 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1585 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1586 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . htmlspecialchars($properties['type']) . '"></script>';
1587 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1588 $tag = str_replace('|', $tag, $properties['allWrap']);
1589 }
1590 if ($properties['forceOnTop']) {
1591 if ($properties['section'] === self::PART_HEADER) {
1592 $jsFiles = $tag . LF . $jsFiles;
1593 } else {
1594 $jsFooterFiles = $tag . LF . $jsFooterFiles;
1595 }
1596 } else {
1597 if ($properties['section'] === self::PART_HEADER) {
1598 $jsFiles .= LF . $tag;
1599 } else {
1600 $jsFooterFiles .= LF . $tag;
1601 }
1602 }
1603 }
1604 }
1605
1606 if (count($this->jsInline)) {
1607 foreach ($this->jsInline as $name => $properties) {
1608 if ($properties['forceOnTop']) {
1609 if ($properties['section'] === self::PART_HEADER) {
1610 $jsInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsInline;
1611 } else {
1612 $jsFooterInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsFooterInline;
1613 }
1614 } else {
1615 if ($properties['section'] === self::PART_HEADER) {
1616 $jsInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1617 } else {
1618 $jsFooterInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1619 }
1620 }
1621 }
1622 }
1623
1624
1625 if ($jsInline) {
1626 $jsInline = $this->inlineJavascriptWrap[0] . $jsInline . $this->inlineJavascriptWrap[1];
1627 }
1628
1629 if ($jsFooterInline) {
1630 $jsFooterInline = $this->inlineJavascriptWrap[0] . $jsFooterInline . $this->inlineJavascriptWrap[1];
1631 }
1632
1633
1634 // get template
1635 $templateFile = t3lib_div::getFileAbsFileName($this->templateFile, TRUE);
1636 $template = t3lib_div::getUrl($templateFile);
1637
1638 if ($this->removeLineBreaksFromTemplate) {
1639 $template = strtr($template, array(LF => '', CR => ''));
1640 }
1641 if ($part != self::PART_COMPLETE) {
1642 $templatePart = explode('###BODY###', $template);
1643 $template = $templatePart[$part - 1];
1644 }
1645
1646 if ($this->moveJsFromHeaderToFooter) {
1647 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
1648 $jsLibs = '';
1649 $jsFooterFiles = $jsFiles . LF . $jsFooterFiles;
1650 $jsFiles = '';
1651 $jsFooterInline = $jsInline . LF . $jsFooterInline;
1652 $jsInline = '';
1653 }
1654
1655 // postRenderHook for possible manipulation
1656 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'])) {
1657 $params = array (
1658 'jsLibs' => &$jsLibs,
1659 'jsFiles' => &$jsFiles,
1660 'jsFooterFiles' => &$jsFooterFiles,
1661 'cssFiles' => &$cssFiles,
1662 'headerData' => &$this->headerData,
1663 'footerData' => &$this->footerData,
1664 'jsInline' => &$jsInline,
1665 'cssInline' => &$cssInline,
1666 'xmlPrologAndDocType' => &$this->xmlPrologAndDocType,
1667 'htmlTag' => &$this->htmlTag,
1668 'headTag' => &$this->headTag,
1669 'charSet' => &$this->charSet,
1670 'metaCharsetTag' => &$this->metaCharsetTag,
1671 'shortcutTag' => &$this->shortcutTag,
1672 'inlineComments' => &$this->inlineComments,
1673 'baseUrl' => &$this->baseUrl,
1674 'baseUrlTag' => &$this->baseUrlTag,
1675 'favIcon' => &$this->favIcon,
1676 'iconMimeType' => &$this->iconMimeType,
1677 'titleTag' => &$this->titleTag,
1678 'title' => &$this->title,
1679 'metaTags' => &$metaTags,
1680 'jsFooterInline' => &$jsFooterInline,
1681 'jsFooterLibs' => &$jsFooterLibs,
1682 'bodyContent' => &$this->bodyContent,
1683 );
1684 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-postProcess'] as $hook) {
1685 t3lib_div::callUserFunction($hook, $params, $this);
1686 }
1687 }
1688
1689 $markerArray = array(
1690 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1691 'HTMLTAG' => $this->htmlTag,
1692 'HEADTAG' => $this->headTag,
1693 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1694 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1695 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1696 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1697 'CSS_INCLUDE' => $cssFiles,
1698 'CSS_INLINE' => $cssInline,
1699 'JS_INLINE' => $jsInline,
1700 'JS_INCLUDE' => $jsFiles,
1701 'JS_LIBS' => $jsLibs,
1702 'TITLE' => $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '',
1703 'META' => $metaTags,
1704 'HEADERDATA' => $this->headerData ? implode(LF, $this->headerData) : '',
1705 'FOOTERDATA' => $this->footerData ? implode(LF, $this->footerData) : '',
1706 'JS_LIBS_FOOTER' => $jsFooterLibs,
1707 'JS_INCLUDE_FOOTER' => $jsFooterFiles,
1708 'JS_INLINE_FOOTER' => $jsFooterInline,
1709 'BODY' => $this->bodyContent,
1710 );
1711
1712 $markerArray = array_map('trim', $markerArray);
1713
1714 $this->reset();
1715 return trim(t3lib_parsehtml::substituteMarkerArray($template, $markerArray, '###|###'));
1716 }
1717
1718 /**
1719 * helper function for render the javascript libraries
1720 *
1721 * @return string content with javascript libraries
1722 */
1723 protected function renderJsLibraries() {
1724 $out = '';
1725
1726 if ($this->addSvg) {
1727 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->svgPath . 'svg.js') .
1728 '" data-path="' . $this->backPath . $this->svgPath .
1729 '"' . ($this->enableSvgDebug ? ' data-debug="true"' : '') . '></script>';
1730 }
1731
1732 if ($this->addPrototype) {
1733 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->prototypePath . 'prototype.js') .
1734 '" type="text/javascript"></script>' . LF;
1735 unset($this->jsFiles[$this->backPath . $this->prototypePath . 'prototype.js']);
1736 }
1737
1738 if ($this->addScriptaculous) {
1739 $mods = array();
1740 foreach ($this->addScriptaculousModules as $key => $value) {
1741 if ($this->addScriptaculousModules[$key]) {
1742 $mods[] = $key;
1743 }
1744 }
1745 // resolve dependencies
1746 if (in_array('dragdrop', $mods) || in_array('controls', $mods)) {
1747 $mods = array_merge(array('effects'), $mods);
1748 }
1749
1750 if (count($mods)) {
1751 foreach ($mods as $module) {
1752 $out .= '<script src="' . $this->processJsFile($this->backPath .
1753 $this->scriptaculousPath . $module . '.js') . '" type="text/javascript"></script>' . LF;
1754 unset($this->jsFiles[$this->backPath . $this->scriptaculousPath . $module . '.js']);
1755 }
1756 }
1757 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->scriptaculousPath .
1758 'scriptaculous.js') . '" type="text/javascript"></script>' . LF;
1759 unset($this->jsFiles[$this->backPath . $this->scriptaculousPath . 'scriptaculous.js']);
1760 }
1761
1762 // include extCore, but only if ExtJS is not included
1763 if ($this->addExtCore && !$this->addExtJS) {
1764 $out .= '<script src="' . $this->processJsFile($this->backPath .
1765 $this->extCorePath . 'ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js') .
1766 '" type="text/javascript"></script>' . LF;
1767 unset($this->jsFiles[$this->backPath . $this->extCorePath . 'ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js']);
1768 }
1769
1770 // include extJS
1771 if ($this->addExtJS) {
1772 // use the base adapter all the time
1773 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->extJsPath .
1774 'adapter/' . ($this->enableExtJsDebug ?
1775 str_replace('.js', '-debug.js', $this->extJSadapter) : $this->extJSadapter)) .
1776 '" type="text/javascript"></script>' . LF;
1777 $out .= '<script src="' . $this->processJsFile($this->backPath . $this->extJsPath .
1778 'ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js') .
1779 '" type="text/javascript"></script>' . LF;
1780
1781 // add extJS localization
1782 $localeMap = $this->locales->getIsoMapping(); // load standard ISO mapping and modify for use with ExtJS
1783 $localeMap[''] = 'en';
1784 $localeMap['default'] = 'en';
1785 $localeMap['gr'] = 'el_GR'; // Greek
1786 $localeMap['no'] = 'no_BO'; // Norwegian Bokmaal
1787 $localeMap['se'] = 'se_SV'; // Swedish
1788
1789
1790 $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang;
1791 // TODO autoconvert file from UTF8 to current BE charset if necessary!!!!
1792 $extJsLocaleFile = $this->extJsPath . 'locale/ext-lang-' . $extJsLang . '.js';
1793 if (file_exists(PATH_typo3 . $extJsLocaleFile)) {
1794 $out .= '<script src="' . $this->processJsFile($this->backPath .
1795 $extJsLocaleFile) . '" type="text/javascript" charset="utf-8"></script>' . LF;
1796 }
1797
1798
1799 // remove extjs from JScodeLibArray
1800 unset(
1801 $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all.js'],
1802 $this->jsFiles[$this->backPath . $this->extJsPath . 'ext-all-debug.js']
1803 );
1804 }
1805
1806 if (count($this->inlineLanguageLabelFiles)) {
1807 foreach ($this->inlineLanguageLabelFiles as $languageLabelFile) {
1808 $this->includeLanguageFileForInline(
1809 $languageLabelFile['fileRef'],
1810 $languageLabelFile['selectionPrefix'],
1811 $languageLabelFile['stripFromSelectionName'],
1812 $languageLabelFile['$errorMode']
1813 );
1814 }
1815 }
1816 unset($this->inlineLanguageLabelFiles);
1817
1818 // Convert labels/settings back to UTF-8 since json_encode() only works with UTF-8:
1819 if ($this->getCharSet() !== 'utf-8') {
1820 if ($this->inlineLanguageLabels) {
1821 $this->csConvObj->convArray($this->inlineLanguageLabels, $this->getCharSet(), 'utf-8');
1822 }
1823 if ($this->inlineSettings) {
1824 $this->csConvObj->convArray($this->inlineSettings, $this->getCharSet(), 'utf-8');
1825 }
1826 }
1827
1828 $inlineSettings = $this->inlineLanguageLabels ? 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' : '';
1829 $inlineSettings .= $this->inlineSettings ? 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' : '';
1830
1831 if ($this->addExtCore || $this->addExtJS) {
1832 // set clear.gif, move it on top, add handler code
1833 $code = '';
1834 if (count($this->extOnReadyCode)) {
1835 foreach ($this->extOnReadyCode as $block) {
1836 $code .= $block;
1837 }
1838 }
1839
1840 $out .= $this->inlineJavascriptWrap[0] . '
1841 Ext.ns("TYPO3");
1842 Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(t3lib_div::locationHeaderUrl($this->backPath . 'gfx/clear.gif')) . '";' . LF .
1843 $inlineSettings .
1844 'Ext.onReady(function() {' .
1845 ($this->enableExtJSQuickTips ? 'Ext.QuickTips.init();' . LF : '') . $code .
1846 ' });' . $this->inlineJavascriptWrap[1];
1847 unset ($this->extOnReadyCode);
1848
1849 // Include TYPO3.l10n object
1850 if (TYPO3_MODE === 'BE') {
1851 $out .= '<script src="' . $this->processJsFile($this->backPath . 'sysext/lang/res/js/be/typo3lang.js') . '" type="text/javascript" charset="utf-8"></script>' . LF;
1852 }
1853
1854 if ($this->extJStheme) {
1855 if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) {
1856 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'all', '', TRUE, TRUE);
1857 } else {
1858 $this->addCssFile($this->backPath . $this->extJsPath . 'resources/css/xtheme-blue.css', 'stylesheet', 'all', '', TRUE, TRUE);
1859 }
1860 }
1861 if ($this->extJScss) {
1862 if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) {
1863 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'all', '', TRUE, TRUE);
1864 } else {
1865 $this->addCssFile($this->backPath . $this->extJsPath . 'resources/css/ext-all-notheme.css', 'stylesheet', 'all', '', TRUE, TRUE);
1866 }
1867 }
1868 } else {
1869 if ($inlineSettings) {
1870 $out .= $this->inlineJavascriptWrap[0] . $inlineSettings . $this->inlineJavascriptWrap[1];
1871 }
1872 }
1873
1874 return $out;
1875 }
1876
1877 protected function includeLanguageFileForInline($fileRef, $selectionPrefix = '', $stripFromSelectionName = '', $errorMode = 0) {
1878 if (!isset($this->lang) || !isset($this->charSet)) {
1879 throw new RuntimeException('Language and character encoding are not set.', 1284906026);
1880 }
1881
1882 $labelsFromFile = array();
1883 $allLabels = t3lib_div::readLLfile($fileRef, $this->lang, $this->charSet, $errorMode);
1884
1885 // Regular expression to strip the selection prefix and possibly something from the label name:
1886 $labelPattern = '#^' . preg_quote($selectionPrefix, '#') . '(' . preg_quote($stripFromSelectionName, '#') . ')?#';
1887
1888 if ($allLabels !== FALSE) {
1889 // Merge language specific translations:
1890 if ($this->lang !== 'default' && isset($allLabels[$this->lang])) {
1891 $labels = array_merge($allLabels['default'], $allLabels[$this->lang]);
1892 } else {
1893 $labels = $allLabels['default'];
1894 }
1895
1896 // Iterate through all locallang labels:
1897 foreach ($labels as $label => $value) {
1898 if ($selectionPrefix === '') {
1899 $labelsFromFile[$label] = $value;
1900 } elseif (strpos($label, $selectionPrefix) === 0) {
1901 $key = preg_replace($labelPattern, '', $label);
1902 $labelsFromFile[$label] = $value;
1903 }
1904 }
1905
1906 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $labelsFromFile);
1907 }
1908 }
1909
1910 /*****************************************************/
1911 /* */
1912 /* Tools */
1913 /* */
1914 /* */
1915 /*****************************************************/
1916
1917 /**
1918 * Concatenate files into one file
1919 * registered handler
1920 *
1921 * @return void
1922 */
1923 protected function doConcatenate() {
1924 $this->doConcatenateCss();
1925 $this->doConcatenateJavaScript();
1926 }
1927
1928 /**
1929 * Concatenate JavaScript files according to the configuration.
1930 *
1931 * @return void
1932 */
1933 protected function doConcatenateJavaScript() {
1934 if ($this->concatenateFiles || $this->concatenateJavascript) {
1935 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'])) {
1936 // use external concatenation routine
1937 $params = array(
1938 'jsLibs' => &$this->jsLibs,
1939 'jsFiles' => &$this->jsFiles,
1940 'jsFooterFiles' => &$this->jsFooterFiles,
1941 'headerData' => &$this->headerData,
1942 'footerData' => &$this->footerData,
1943 );
1944 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsConcatenateHandler'], $params, $this);
1945 } else {
1946 $this->jsLibs = $this->getCompressor()->concatenateJsFiles($this->jsLibs);
1947 $this->jsFiles = $this->getCompressor()->concatenateJsFiles($this->jsFiles);
1948 $this->jsFooterFiles = $this->getCompressor()->concatenateJsFiles($this->jsFooterFiles);
1949 }
1950 }
1951 }
1952
1953 /**
1954 * Concatenate CSS files according to configuration.
1955 *
1956 * @return void
1957 */
1958 protected function doConcatenateCss() {
1959 if ($this->concatenateFiles || $this->concatenateCss) {
1960 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'])) {
1961 // use external concatenation routine
1962 $params = array(
1963 'cssFiles' => &$this->cssFiles,
1964 'headerData' => &$this->headerData,
1965 'footerData' => &$this->footerData,
1966 );
1967 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssConcatenateHandler'], $params, $this);
1968 } else {
1969 $cssOptions = array();
1970 if (TYPO3_MODE === 'BE') {
1971 $cssOptions = array('baseDirectories' => $GLOBALS['TBE_TEMPLATE']->getSkinStylesheetDirectories());
1972 }
1973 $this->cssFiles = $this->getCompressor()->concatenateCssFiles($this->cssFiles, $cssOptions);
1974 }
1975 }
1976 }
1977
1978 /**
1979 * Compresses inline code
1980 *
1981 * @return void
1982 */
1983 protected function doCompress() {
1984 $this->doCompressJavaScript();
1985 $this->doCompressCss();
1986 }
1987
1988 /**
1989 * Compresses CSS according to configuration.
1990 *
1991 * @return void
1992 */
1993 protected function doCompressCss() {
1994 if ($this->compressCss) {
1995 // use external compression routine
1996 $params = array(
1997 'cssInline' => &$this->cssInline,
1998 'cssFiles' => &$this->cssFiles,
1999 'headerData' => &$this->headerData,
2000 'footerData' => &$this->footerData,
2001 );
2002
2003 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'])) {
2004 // use external concatenation routine
2005 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this);
2006 } else {
2007 $this->cssFiles = $this->getCompressor()->compressCssFiles($this->cssFiles);
2008 }
2009 }
2010 }
2011
2012 /**
2013 * Compresses JavaScript according to configuration.
2014 *
2015 * @return void
2016 */
2017 protected function doCompressJavaScript() {
2018 if ($this->compressJavascript) {
2019 if (!empty($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'])) {
2020 // use external compression routine
2021 $params = array(
2022 'jsInline' => &$this->jsInline,
2023 'jsFooterInline' => &$this->jsFooterInline,
2024 'jsLibs' => &$this->jsLibs,
2025 'jsFiles' => &$this->jsFiles,
2026 'jsFooterFiles' => &$this->jsFooterFiles,
2027 'headerData' => &$this->headerData,
2028 'footerData' => &$this->footerData,
2029 );
2030 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this);
2031 } else {
2032 // traverse the arrays, compress files
2033 if (count($this->jsInline)) {
2034 foreach ($this->jsInline as $name => $properties) {
2035 if ($properties['compress']) {
2036 $error = '';
2037 $this->jsInline[$name]['code'] = t3lib_div::minifyJavaScript($properties['code'], $error);
2038 if ($error) {
2039 $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error . LF;
2040 }
2041 }
2042 }
2043 }
2044 $this->jsLibs = $this->getCompressor()->compressJsFiles($this->jsLibs);
2045 $this->jsFiles = $this->getCompressor()->compressJsFiles($this->jsFiles);
2046 $this->jsFooterFiles = $this->getCompressor()->compressJsFiles($this->jsFooterFiles);
2047 }
2048 }
2049 }
2050
2051 /**
2052 * Returns instance of t3lib_Compressor
2053 *
2054 * @return t3lib_Compressor Instance of t3lib_Compressor
2055 */
2056 protected function getCompressor() {
2057 if ($this->compressor === NULL) {
2058 $this->compressor = t3lib_div::makeInstance('t3lib_Compressor');
2059 }
2060 return $this->compressor;
2061 }
2062
2063 /**
2064 * Processes a Javascript file dependent on the current context
2065 *
2066 * Adds the version number for Frontend, compresses the file for Backend
2067 *
2068 * @param string $filename Filename
2069 * @return string New filename
2070 */
2071 protected function processJsFile($filename) {
2072 switch (TYPO3_MODE) {
2073 case 'FE':
2074 if ($this->compressJavascript) {
2075 $filename = $this->getCompressor()->compressJsFile($filename);
2076 } else {
2077 $filename = t3lib_div::createVersionNumberedFilename($filename);
2078 }
2079 break;
2080 case 'BE':
2081 if ($this->compressJavascript) {
2082 $filename = $this->getCompressor()->compressJsFile($filename);
2083 }
2084 break;
2085 }
2086 return $filename;
2087 }
2088
2089 }
2090
2091 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php'])) {
2092 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php']);
2093 }
2094
2095 ?>