Fixed issue #13670: Performance optimization: change while(list() to foreach() (thank...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_pagerenderer.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Steffen Kamper (info@sk-typo3.de)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * TYPO3 pageRender class (new in TYPO3 4.3.0)
30 * This class render the HTML of a webpage, usable for BE and FE
31 *
32 * @author Steffen Kamper <info@sk-typo3.de>
33 * @package TYPO3
34 * @subpackage t3lib
35 * $Id$
36 */
37 class t3lib_PageRenderer implements t3lib_Singleton {
38
39 protected $compressJavascript = FALSE;
40 protected $compressCss = FALSE;
41 protected $removeLineBreaksFromTemplate = FALSE;
42
43 protected $concatenateFiles = FALSE;
44
45 protected $moveJsFromHeaderToFooter = FALSE;
46
47 protected $csConvObj;
48 protected $lang;
49
50 /* @var t3lib_compressor Instance of t3lib_compressor */
51 protected $compressor;
52
53 // static array containing associative array for the included files
54 protected static $jsFiles = array ();
55 protected static $jsFooterFiles = array ();
56 protected static $jsLibs = array ();
57 protected static $jsFooterLibs = array ();
58 protected static $cssFiles = array ();
59
60 protected $title;
61 protected $charSet;
62 protected $favIcon;
63 protected $baseUrl;
64
65 protected $renderXhtml = TRUE;
66
67 // static header blocks
68 protected $xmlPrologAndDocType = '';
69 protected $metaTags = array ();
70 protected $inlineComments = array ();
71 protected $headerData = array ();
72 protected $footerData = array ();
73 protected $titleTag = '<title>|</title>';
74 protected $metaCharsetTag = '<meta http-equiv="Content-Type" content="text/html; charset=|" />';
75 protected $htmlTag = '<html>';
76 protected $headTag = '<head>';
77 protected $baseUrlTag = '<base href="|" />';
78 protected $iconMimeType = '';
79 protected $shortcutTag = '<link rel="shortcut icon" href="%1$s"%2$s />
80 <link rel="icon" href="%1$s"%2$s />';
81
82 // static inline code blocks
83 protected $jsInline = array ();
84 protected $extOnReadyCode = array ();
85 protected $cssInline = array ();
86
87 protected $bodyContent;
88
89 protected $templateFile;
90
91 protected $jsLibraryNames = array ('prototype', 'scriptaculous', 'extjs');
92
93 const PART_COMPLETE = 0;
94 const PART_HEADER = 1;
95 const PART_FOOTER = 2;
96
97 // internal flags for JS-libraries
98 protected $addPrototype = FALSE;
99 protected $addScriptaculous = FALSE;
100 protected $addScriptaculousModules = array ('builder' => FALSE, 'effects' => FALSE, 'dragdrop' => FALSE, 'controls' => FALSE, 'slider' => FALSE);
101 protected $addExtJS = FALSE;
102 protected $addExtCore = FALSE;
103 protected $extJSadapter = 'ext/ext-base.js';
104
105 protected $enableExtJsDebug = FALSE;
106 protected $enableExtCoreDebug = FALSE;
107
108 // available adapters for extJs
109 const EXTJS_ADAPTER_JQUERY = 'jquery';
110 const EXTJS_ADAPTER_PROTOTYPE = 'prototype';
111 const EXTJS_ADAPTER_YUI = 'yui';
112
113 protected $extJStheme = TRUE;
114 protected $extJScss = TRUE;
115
116 protected $enableExtJSQuickTips = false;
117
118 protected $inlineLanguageLabels = array ();
119 protected $inlineSettings = array ();
120
121 protected $inlineJavascriptWrap = array ();
122
123 // used by BE modules
124 public $backPath;
125
126 /**
127 * Constructor
128 *
129 * @param string $templateFile declare the used template file. Omit this parameter will use default template
130 * @param string $backPath relative path to typo3-folder. It varies for BE modules, in FE it will be typo3/
131 * @return void
132 */
133 public function __construct($templateFile = '', $backPath = NULL) {
134
135 $this->reset();
136 $this->csConvObj = t3lib_div::makeInstance('t3lib_cs');
137
138 if (strlen($templateFile)) {
139 $this->templateFile = $templateFile;
140 }
141 $this->backPath = isset($backPath) ? $backPath : $GLOBALS['BACK_PATH'];
142
143 $this->inlineJavascriptWrap = array(
144 '<script type="text/javascript">' . LF . '/*<![CDATA[*/' . LF . '<!-- ' . LF,
145 '// -->' . LF . '/*]]>*/' . LF . '</script>' . LF
146 );
147 $this->inlineCssWrap = array(
148 '<style type="text/css">' . LF . '/*<![CDATA[*/' . LF . '<!-- ' . LF,
149 '-->' . LF . '/*]]>*/' . LF . '</style>' . LF
150 );
151
152 }
153
154 /**
155 * reset all vars to initial values
156 *
157 * @return void
158 */
159 protected function reset() {
160 $this->templateFile = TYPO3_mainDir . 'templates/template_page_backend.html';
161 $this->jsFiles = array ();
162 $this->jsFooterFiles = array ();
163 $this->jsInline = array ();
164 $this->jsFooterInline = array ();
165 $this->jsLibs = array ();
166 $this->cssFiles = array ();
167 $this->cssInline = array ();
168 $this->metaTags = array ();
169 $this->inlineComments = array ();
170 $this->headerData = array ();
171 $this->footerData = array ();
172 $this->extOnReadyCode = array ();
173 }
174 /*****************************************************/
175 /* */
176 /* Public Setters */
177 /* */
178 /* */
179 /*****************************************************/
180
181 /**
182 * Sets the title
183 *
184 * @param string $title title of webpage
185 * @return void
186 */
187 public function setTitle($title) {
188 $this->title = $title;
189 }
190
191
192 /**
193 * Enables/disables rendering of XHTML code
194 *
195 * @param boolean $enable Enable XHTML
196 * @return void
197 */
198 public function setRenderXhtml($enable) {
199 $this->renderXhtml = $enable;
200 }
201
202 /**
203 * Sets xml prolog and docType
204 *
205 * @param string $xmlPrologAndDocType complete tags for xml prolog and docType
206 * @return void
207 */
208 public function setXmlPrologAndDocType($xmlPrologAndDocType) {
209 $this->xmlPrologAndDocType = $xmlPrologAndDocType;
210 }
211
212 /**
213 * Sets meta charset
214 *
215 * @param string $charSet used charset
216 * @return void
217 */
218 public function setCharSet($charSet) {
219 $this->charSet = $charSet;
220 }
221
222 /**
223 * Sets language
224 *
225 * @param string $lang used language
226 * @return void
227 */
228 public function setLanguage($lang) {
229 $this->lang = $lang;
230 }
231
232 /**
233 * Sets html tag
234 *
235 * @param string $htmlTag html tag
236 * @return void
237 */
238 public function setHtmlTag($htmlTag) {
239 $this->htmlTag = $htmlTag;
240 }
241
242 /**
243 * Sets head tag
244 *
245 * @param string $tag head tag
246 * @return void
247 */
248 public function setHeadTag($headTag) {
249 $this->headTag = $headTag;
250 }
251
252 /**
253 * Sets favicon
254 *
255 * @param string $favIcon
256 * @return void
257 */
258 public function setFavIcon($favIcon) {
259 $this->favIcon = $favIcon;
260 }
261
262 /**
263 * Sets icon mime type
264 *
265 * @param string $iconMimeType
266 * @return void
267 */
268 public function setIconMimeType($iconMimeType) {
269 $this->iconMimeType = $iconMimeType;
270 }
271
272 /**
273 * Sets base url
274 *
275 * @param string $url
276 * @return void
277 */
278 public function setBaseUrl($baseUrl) {
279 $this->baseUrl = $baseUrl;
280 }
281
282 /**
283 * Sets template file
284 *
285 * @param string $file
286 * @return void
287 */
288 public function setTemplateFile($file) {
289 $this->templateFile = $file;
290 }
291
292 /**
293 * Sets back path
294 *
295 * @param string $backPath
296 * @return void
297 */
298 public function setBackPath($backPath) {
299 $this->backPath = $backPath;
300 }
301
302 /**
303 * Sets Content for Body
304 *
305 * @param string $content
306 * @return void
307 */
308 public function setBodyContent($content) {
309 $this->bodyContent = $content;
310 }
311
312 /*****************************************************/
313 /* */
314 /* Public Enablers */
315 /* */
316 /* */
317 /*****************************************************/
318 /**
319 * Enables MoveJsFromHeaderToFooter
320 *
321 * @param void
322 * @return void
323 */
324 public function enableMoveJsFromHeaderToFooter() {
325 $this->moveJsFromHeaderToFooter = TRUE;
326 }
327
328 /**
329 * Enables compression of javascript
330 *
331 * @param void
332 * @return void
333 */
334 public function enableCompressJavascript() {
335 $this->compressJavascript = TRUE;
336 }
337
338 /**
339 * Enables compression of css
340 *
341 * @param void
342 * @return void
343 */
344 public function enableCompressCss() {
345 $this->compressCss = TRUE;
346 }
347
348 /**
349 /**
350 * Enables concatenation of js/css files
351 *
352 * @param void
353 * @return void
354 */
355 public function enableConcatenateFiles() {
356 $this->concatenateFiles = TRUE;
357 }
358
359 /**
360 * Sets removal of all line breaks in template
361 *
362 * @param void
363 * @return void
364 */
365 public function enableRemoveLineBreaksFromTemplate() {
366 $this->removeLineBreaksFromTemplate = TRUE;
367 }
368
369 /*****************************************************/
370 /* */
371 /* Public Getters */
372 /* */
373 /* */
374 /*****************************************************/
375
376 /**
377 * Gets the title
378 *
379 * @return string $title title of webpage
380 */
381 public function getTitle() {
382 return $this->title;
383 }
384
385 /**
386 * Gets the charSet
387 *
388 * @return string $charSet
389 */
390 public function getCharSet() {
391 return $this->charSet;
392 }
393
394 /**
395 * Gets the language
396 *
397 * @return string $lang
398 */
399 public function getLanguage() {
400 return $this->lang;
401 }
402
403 /**
404 * Returns rendering mode XHTML or HTML
405 *
406 * @return boolean TRUE if XHTML, FALSE if HTML
407 */
408 public function getRenderXhtml() {
409 return $this->renderXhtml;
410 }
411
412 /**
413 * Gets html tag
414 *
415 * @return string $htmlTag html tag
416 */
417 public function getHtmlTag() {
418 return $this->htmlTag;
419 }
420
421 /**
422 * Gets head tag
423 *
424 * @return string $tag head tag
425 */
426 public function getHeadTag() {
427 return $this->headTag;
428 }
429
430 /**
431 * Gets favicon
432 *
433 * @return string $favIcon
434 */
435 public function getFavIcon() {
436 return $this->favIcon;
437 }
438
439 /**
440 * Gets icon mime type
441 *
442 * @return string $iconMimeType
443 */
444 public function getIconMimeType() {
445 return $this->iconMimeType;
446 }
447
448 /**
449 * Gets base url
450 *
451 * @return string $url
452 */
453 public function getBaseUrl() {
454 return $this->baseUrl;
455 }
456
457 /**
458 * Gets template file
459 *
460 * @return string $file
461 */
462 public function getTemplateFile($file) {
463 return $this->templateFile;
464 }
465
466 /**
467 * Gets MoveJsFromHeaderToFooter
468 *
469 * @return boolean
470 */
471 public function getMoveJsFromHeaderToFooter() {
472 return $this->moveJsFromHeaderToFooter;
473 }
474
475 /**
476 * Gets compress of javascript
477 *
478 * @return boolean
479 */
480 public function getCompressJavascript() {
481 return $this->compressJavascript;
482 }
483
484 /**
485 * Gets compress of css
486 *
487 * @return boolean
488 */
489 public function getCompressCss() {
490 return $this->compressCss;
491 }
492
493 /**
494 * Gets concatenate of files
495 *
496 * @return boolean
497 */
498 public function getConcatenateFiles() {
499 return $this->concatenateFiles;
500 }
501
502 /**
503 * Gets remove of empty lines from template
504 *
505 * @return boolean
506 */
507 public function getRemoveLineBreaksFromTemplate() {
508 return $this->removeLineBreaksFromTemplate;
509 }
510
511 /**
512 * Gets content for body
513 *
514 * @return string
515 */
516 public function getBodyContent() {
517 return $this->bodyContent;
518 }
519
520 /*****************************************************/
521 /* */
522 /* Public Function to add Data */
523 /* */
524 /* */
525 /*****************************************************/
526
527 /**
528 * Adds meta data
529 *
530 * @param string $meta meta data (complete metatag)
531 * @return void
532 */
533 public function addMetaTag($meta) {
534 if (!in_array($meta, $this->metaTags)) {
535 $this->metaTags[] = $meta;
536 }
537 }
538
539 /**
540 * Adds inline HTML comment
541 *
542 * @param string $comment
543 * @return void
544 */
545 public function addInlineComment($comment) {
546 if (!in_array($comment, $this->inlineComments)) {
547 $this->inlineComments[] = $comment;
548 }
549 }
550
551 /**
552 * Adds header data
553 *
554 * @param string $data free header data for HTML header
555 * @return void
556 */
557 public function addHeaderData($data) {
558 if (!in_array($data, $this->headerData)) {
559 $this->headerData[] = $data;
560 }
561 }
562
563 /**
564 * Adds footer data
565 *
566 * @param string $data free header data for HTML header
567 * @return void
568 */
569 public function addFooterData($data) {
570 if (!in_array($data, $this->footerData)) {
571 $this->footerData[] = $data;
572 }
573 }
574
575 /* Javascript Files */
576
577 /**
578 * Adds JS Library. JS Library block is rendered on top of the JS files.
579 *
580 * @param string $name
581 * @param string $file
582 * @param string $type
583 * @param boolean $compress flag if library should be compressed
584 * @param boolean $forceOnTop flag if added library should be inserted at begin of this block
585 * @param string $allWrap
586 * @return void
587 */
588 public function addJsLibrary($name, $file, $type = 'text/javascript', $compress = FALSE, $forceOnTop = FALSE, $allWrap = '') {
589 if (!in_array(strtolower($name), $this->jsLibs)) {
590 $this->jsLibs[strtolower($name)] = array (
591 'file' => $file,
592 'type' => $type,
593 'section' => self::PART_HEADER,
594 'compress' => $compress,
595 'forceOnTop' => $forceOnTop,
596 'allWrap' => $allWrap
597 );
598 }
599
600 }
601
602 /**
603 * Adds JS Library to Footer. JS Library block is rendered on top of the Footer JS files.
604 *
605 * @param string $name
606 * @param string $file
607 * @param string $type
608 * @param boolean $compress flag if library should be compressed
609 * @param boolean $forceOnTop flag if added library should be inserted at begin of this block
610 * @param string $allWrap
611 * @return void
612 */
613 public function addJsFooterLibrary($name, $file, $type = 'text/javascript', $compress = FALSE, $forceOnTop = FALSE, $allWrap = '') {
614 if (!in_array(strtolower($name), $this->jsLibs)) {
615 $this->jsLibs[strtolower($name)] = array (
616 'file' => $file,
617 'type' => $type,
618 'section' => self::PART_FOOTER,
619 'compress' => $compress,
620 'forceOnTop' => $forceOnTop,
621 'allWrap' => $allWrap
622 );
623 }
624
625 }
626
627 /**
628 * Adds JS file
629 *
630 * @param string $file
631 * @param string $type
632 * @param boolean $compress
633 * @param boolean $forceOnTop
634 * @param string $allWrap
635 * @return void
636 */
637 public function addJsFile($file, $type = 'text/javascript', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '') {
638 if (!isset($this->jsFiles[$file])) {
639 $this->jsFiles[$file] = array (
640 'type' => $type,
641 'section' => self::PART_HEADER,
642 'compress' => $compress,
643 'forceOnTop' => $forceOnTop,
644 'allWrap' => $allWrap
645 );
646 }
647 }
648
649 /**
650 * Adds JS file to footer
651 *
652 * @param string $file
653 * @param string $type
654 * @param boolean $compress
655 * @param boolean $forceOnTop
656 * @return void
657 */
658 public function addJsFooterFile($file, $type = 'text/javascript', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '') {
659 if (!isset($this->jsFiles[$file])) {
660 $this->jsFiles[$file] = array (
661 'type' => $type,
662 'section' => self::PART_FOOTER,
663 'compress' => $compress,
664 'forceOnTop' => $forceOnTop,
665 'allWrap' => $allWrap
666 );
667 }
668 }
669
670 /*Javascript Inline Blocks */
671
672 /**
673 * Adds JS inline code
674 *
675 * @param string $name
676 * @param string $block
677 * @param boolean $compress
678 * @param boolean $forceOnTop
679 * @return void
680 */
681 public function addJsInlineCode($name, $block, $compress = TRUE, $forceOnTop = FALSE) {
682 if (!isset($this->jsInline[$name])) {
683 $this->jsInline[$name] = array (
684 'code' => $block . LF,
685 'section' => self::PART_HEADER,
686 'compress' => $compress,
687 'forceOnTop' => $forceOnTop
688 );
689 }
690 }
691
692 /**
693 * Adds JS inline code to footer
694 *
695 * @param string $name
696 * @param string $block
697 * @param boolean $compress
698 * @param boolean $forceOnTop
699 * @return void
700 */
701 public function addJsFooterInlineCode($name, $block, $compress = TRUE, $forceOnTop = FALSE) {
702 if (!isset($this->jsInline[$name])) {
703 $this->jsInline[$name] = array (
704 'code' => $block . LF,
705 'section' => self::PART_FOOTER,
706 'compress' => $compress,
707 'forceOnTop' => $forceOnTop
708 );
709 }
710 }
711
712 /**
713 * Adds Ext.onready code, which will be wrapped in Ext.onReady(function() {...});
714 *
715 * @param string $block javascript code
716 * @param boolean $forceOnTop position of the javascript code (TRUE for putting it on top, default is FALSE = bottom)
717 * @return void
718 */
719 public function addExtOnReadyCode($block, $forceOnTop = FALSE) {
720 if (!in_array($block, $this->extOnReadyCode)) {
721 if ($forceOnTop) {
722 array_unshift($this->extOnReadyCode, $block);
723 } else {
724 $this->extOnReadyCode[] = $block;
725 }
726 }
727 }
728
729 /* CSS Files */
730
731 /**
732 * Adds CSS file
733 *
734 * @param string $file
735 * @param string $rel
736 * @param string $media
737 * @param string $title
738 * @param boolean $compress
739 * @param boolean $forceOnTop
740 * @return void
741 */
742 public function addCssFile($file, $rel = 'stylesheet', $media = 'all', $title = '', $compress = TRUE, $forceOnTop = FALSE, $allWrap = '') {
743 if (!isset($this->cssFiles[$file])) {
744 $this->cssFiles[$file] = array (
745 'rel' => $rel,
746 'media' => $media,
747 'title' => $title,
748 'compress' => $compress,
749 'forceOnTop' => $forceOnTop,
750 'allWrap' => $allWrap
751 );
752 }
753 }
754
755 /*CSS Inline Blocks */
756
757 /**
758 * Adds CSS inline code
759 *
760 * @param string $name
761 * @param string $block
762 * @param boolean $compress
763 * @param boolean $forceOnTop
764 * @return void
765 */
766 public function addCssInlineBlock($name, $block, $compressed = FALSE, $forceOnTop = FALSE) {
767 if (!isset($this->cssInline[$name])) {
768 $this->cssInline[$name] = array (
769 'code' => $block,
770 'compress' => $compress,
771 'forceOnTop' => $forceOnTop
772 );
773 }
774 }
775
776 /* JS Libraries */
777
778 /**
779 * call function if you need the prototype library
780 *
781 * @return void
782 */
783 public function loadPrototype() {
784 $this->addPrototype = TRUE;
785 }
786
787 /**
788 * call function if you need the Scriptaculous library
789 *
790 * @param string $modules add modules you need. use "all" if you need complete modules
791 * @return void
792 */
793 public function loadScriptaculous($modules = 'all') {
794 // Scriptaculous require prototype, so load prototype too.
795 $this->addPrototype = TRUE;
796 $this->addScriptaculous = TRUE;
797 if ($modules) {
798 if ($modules == 'all') {
799 foreach ($this->addScriptaculousModules as $key => $value) {
800 $this->addScriptaculousModules[$key] = TRUE;
801 }
802 } else {
803 $mods = t3lib_div::trimExplode(',', $modules);
804 foreach ($mods as $mod) {
805 if (isset($this->addScriptaculousModules[strtolower($mod)])) {
806 $this->addScriptaculousModules[strtolower($mod)] = TRUE;
807 }
808 }
809 }
810 }
811 }
812
813 /**
814 * call this function if you need the extJS library
815 *
816 * @param boolean $css flag, if set the ext-css will be loaded
817 * @param boolean $theme flag, if set the ext-theme "grey" will be loaded
818 * @param string $adapter choose alternative adapter, possible values: yui, prototype, jquery
819 * @return void
820 */
821 public function loadExtJS($css = TRUE, $theme = TRUE, $adapter = '') {
822 if ($adapter) {
823 // empty $adapter will always load the ext adapter
824 switch (t3lib_div::strtolower(trim($adapter))) {
825 case self::EXTJS_ADAPTER_YUI :
826 $this->extJSadapter = 'yui/ext-yui-adapter.js';
827 break;
828 case self::EXTJS_ADAPTER_PROTOTYPE :
829 $this->extJSadapter = 'prototype/ext-prototype-adapter.js';
830 break;
831 case self::EXTJS_ADAPTER_JQUERY :
832 $this->extJSadapter = 'jquery/ext-jquery-adapter.js';
833 break;
834 }
835 }
836 $this->addExtJS = TRUE;
837 $this->extJStheme = $theme;
838 $this->extJScss = $css;
839
840 }
841
842 /**
843 * Enables ExtJs QuickTips
844 * Need extJs loaded
845 *
846 * @return void
847 *
848 */
849 public function enableExtJSQuickTips() {
850 $this->enableExtJSQuickTips = TRUE;
851 }
852
853
854 /**
855 * call function if you need the ExtCore library
856 *
857 * @return void
858 */
859 public function loadExtCore() {
860 $this->addExtCore = TRUE;
861 }
862
863 /**
864 * call this function to load debug version of ExtJS. Use this for development only
865 *
866 */
867 public function enableExtJsDebug() {
868 $this->enableExtJsDebug = TRUE;
869 }
870
871 /**
872 * call this function to load debug version of ExtCore. Use this for development only
873 *
874 * @return void
875 */
876 public function enableExtCoreDebug() {
877 $this->enableExtCoreDebug = TRUE;
878 }
879
880 /**
881 * Adds Javascript Inline Label. This will occur in TYPO3.lang - object
882 * The label can be used in scripts with TYPO3.lang.<key>
883 * Need extJs loaded
884 *
885 * @param string $key
886 * @param string $value
887 * @return void
888 */
889 public function addInlineLanguageLabel($key, $value) {
890 $this->inlineLanguageLabels[$key] = $value;
891 }
892
893 /**
894 * Adds Javascript Inline Label Array. This will occur in TYPO3.lang - object
895 * The label can be used in scripts with TYPO3.lang.<key>
896 * Array will be merged with existing array.
897 * Need extJs loaded
898 *
899 * @param array $array
900 * @return void
901 */
902 public function addInlineLanguageLabelArray(array $array) {
903 $this->inlineLanguageLabels = array_merge($this->inlineLanguageLabels, $array);
904 }
905
906 /**
907 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
908 * The label can be used in scripts with TYPO3.setting.<key>
909 * Need extJs loaded
910 *
911 * @param string $namespace
912 * @param string $key
913 * @param string $value
914 * @return void
915 */
916 public function addInlineSetting($namespace, $key, $value) {
917 if ($namespace) {
918 if (strpos($namespace, '.')) {
919 $parts = explode('.', $namespace);
920 $a = &$this->inlineSettings;
921 foreach ($parts as $part) {
922 $a = &$a[$part];
923 }
924 $a[$key] = $value;
925 } else {
926 $this->inlineSettings[$namespace][$key] = $value;
927 }
928 } else {
929 $this->inlineSettings[$key] = $value;
930 }
931 }
932
933 /**
934 * Adds Javascript Inline Setting. This will occur in TYPO3.settings - object
935 * The label can be used in scripts with TYPO3.setting.<key>
936 * Array will be merged with existing array.
937 * Need extJs loaded
938 *
939 * @param string $namespace
940 * @param array $array
941 * @return void
942 */
943 public function addInlineSettingArray($namespace, array $array) {
944 if ($namespace) {
945 if (strpos($namespace, '.')) {
946 $parts = explode('.', $namespace);
947 $a = &$this->inlineSettings;
948 foreach ($parts as $part) {
949 $a = &$a[$part];
950 }
951 $a = array_merge((array) $a, $array);
952 } else {
953 $this->inlineSettings[$namespace] = array_merge((array) $this->inlineSettings[$namespace], $array);
954 }
955 } else {
956 $this->inlineSettings = array_merge($this->inlineSettings, $array);
957 }
958 }
959
960 /**
961 * Adds content to body content
962 *
963 * @param string $content
964 * @return void
965 */
966 public function addBodyContent($content) {
967 $this->bodyContent .= $content;
968 }
969
970 /*****************************************************/
971 /* */
972 /* Render Functions */
973 /* */
974 /* */
975 /*****************************************************/
976
977 /**
978 * render the section (Header or Footer)
979 *
980 * @param int $part section which should be rendered: self::PART_COMPLETE, self::PART_HEADER or self::PART_FOOTER
981 * @return string content of rendered section
982 */
983 public function render($part = self::PART_COMPLETE) {
984
985 $jsFiles = '';
986 $cssFiles = '';
987 $cssInline = '';
988 $jsInline = '';
989 $jsFooterInline = '';
990 $jsFooterLibs = '';
991 $jsFooterFiles = '';
992 $noJS = FALSE;
993
994 // preRenderHook for possible manuipulation
995 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'])) {
996 $params = array (
997 'jsLibs' => &$this->jsLibs,
998 'jsFiles' => &$this->jsFiles,
999 'jsFooterFiles' => &$this->jsFooterFiles,
1000 'cssFiles' => &$this->cssFiles,
1001 'headerData' => &$this->headerData,
1002 'footerData' => &$this->footerData,
1003 'jsInline' => &$this->jsInline,
1004 'cssInline' => &$this->cssInline,
1005 );
1006 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_pagerenderer.php']['render-preProcess'] as $hook) {
1007 t3lib_div::callUserFunction($hook, $params, $this);
1008 }
1009 }
1010
1011 $jsLibs = $this->renderJsLibraries();
1012
1013 if ($this->concatenateFiles) {
1014 // do the file concatenation
1015 $this->doConcatenate();
1016 }
1017 if ($this->compressCss || $this->compressJavascript) {
1018 // do the file compression
1019 $this->doCompress();
1020 }
1021
1022 $metaTags = implode(LF, $this->metaTags);
1023
1024 // remove ending slashes from static header block
1025 // if the page is beeing rendered as html (not xhtml)
1026 // and define variable $endingSlash for further use
1027 if ($this->getRenderXhtml()) {
1028 $endingSlash = ' /';
1029 } else {
1030 $this->metaCharsetTag = str_replace(' />', '>', $this->metaCharsetTag);
1031 $this->baseUrlTag = str_replace(' />', '>', $this->baseUrlTag);
1032 $this->shortcutTag = str_replace(' />', '>', $this->shortcutTag);
1033 $endingSlash = '';
1034 }
1035
1036 if (count($this->cssFiles)) {
1037 foreach ($this->cssFiles as $file => $properties) {
1038 $file = t3lib_div::resolveBackPath($file);
1039 $file = t3lib_div::createVersionNumberedFilename($file);
1040 $tag = '<link rel="' . $properties['rel'] . '" type="text/css" href="' .
1041 htmlspecialchars($file) . '" media="' . $properties['media'] . '"' .
1042 ($properties['title'] ? ' title="' . $properties['title'] . '"' : '') .
1043 $endingSlash . '>';
1044 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1045 $tag = str_replace('|', $tag, $properties['allWrap']);
1046 }
1047 if ($properties['forceOnTop']) {
1048 $cssFiles = $tag . LF . $cssFiles;
1049 } else {
1050 $cssFiles .= LF . $tag;
1051 }
1052 }
1053 }
1054
1055 if (count($this->cssInline)) {
1056 foreach ($this->cssInline as $name => $properties) {
1057 if ($properties['forceOnTop']) {
1058 $cssInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $cssInline;
1059 } else {
1060 $cssInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1061 }
1062 }
1063 $cssInline = $this->inlineCssWrap[0] . $cssInline . $this->inlineCssWrap[1];
1064 }
1065
1066 if (count($this->jsLibs)) {
1067 foreach ($this->jsLibs as $name => $properties) {
1068 $properties['file'] = t3lib_div::resolveBackPath($properties['file']);
1069 $properties['file'] = t3lib_div::createVersionNumberedFilename($properties['file']);
1070 $tag = '<script src="' . htmlspecialchars($properties['file']) . '" type="' . $properties['type'] . '"></script>';
1071 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1072 $tag = str_replace('|', $tag, $properties['allWrap']);
1073 }
1074 if ($properties['forceOnTop']) {
1075 if ($properties['section'] === self::PART_HEADER) {
1076 $jsLibs = $tag . LF . $jsLibs;
1077 } else {
1078 $jsFooterLibs = $tag . LF . $jsFooterLibs;
1079 }
1080 } else {
1081 if ($properties['section'] === self::PART_HEADER) {
1082 $jsLibs .= LF . $tag;
1083 } else {
1084 $jsFooterLibs .= LF . $tag;
1085 }
1086 }
1087 }
1088 }
1089
1090 if (count($this->jsFiles)) {
1091 foreach ($this->jsFiles as $file => $properties) {
1092 $file = t3lib_div::resolveBackPath($file);
1093 $file = t3lib_div::createVersionNumberedFilename($file);
1094 $tag = '<script src="' . htmlspecialchars($file) . '" type="' . $properties['type'] . '"></script>';
1095 if ($properties['allWrap'] && strpos($properties['allWrap'], '|') !== FALSE) {
1096 $tag = str_replace('|', $tag, $properties['allWrap']);
1097 }
1098 if ($properties['forceOnTop']) {
1099 if ($properties['section'] === self::PART_HEADER) {
1100 $jsFiles = $tag . LF . $jsFiles;
1101 } else {
1102 $jsFooterFiles = $tag . LF . $jsFooterFiles;
1103 }
1104 } else {
1105 if ($properties['section'] === self::PART_HEADER) {
1106 $jsFiles .= LF . $tag;
1107 } else {
1108 $jsFooterFiles .= LF . $tag;
1109 }
1110 }
1111 }
1112 }
1113
1114 if (count($this->jsInline)) {
1115 foreach ($this->jsInline as $name => $properties) {
1116 if ($properties['forceOnTop']) {
1117 if ($properties['section'] === self::PART_HEADER) {
1118 $jsInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsInline;
1119 } else {
1120 $jsFooterInline = '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF . $jsFooterInline;
1121 }
1122 } else {
1123 if ($properties['section'] === self::PART_HEADER) {
1124 $jsInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1125 } else {
1126 $jsFooterInline .= '/*' . htmlspecialchars($name) . '*/' . LF . $properties['code'] . LF;
1127 }
1128 }
1129 }
1130 }
1131
1132
1133 if ($jsInline) {
1134 $jsInline = $this->inlineJavascriptWrap[0] . $jsInline . $this->inlineJavascriptWrap[1];
1135 }
1136
1137 if ($jsFooterInline) {
1138 $jsFooterInline = $this->inlineJavascriptWrap[0] . $jsFooterInline . $this->inlineJavascriptWrap[1];
1139 }
1140
1141
1142 // get template
1143 $templateFile = t3lib_div::getFileAbsFileName($this->templateFile, TRUE);
1144 $template = t3lib_div::getURL($templateFile);
1145
1146 if ($this->removeEmptyLinesFromTemplate) {
1147 $template = strtr($template, array(LF => '', CR => ''));
1148 }
1149 if ($part != self::PART_COMPLETE) {
1150 $templatePart = explode('###BODY###', $template);
1151 $template = $templatePart[$part - 1];
1152 }
1153
1154 if ($this->moveJsFromHeaderToFooter) {
1155 $jsFooterLibs = $jsLibs . LF . $jsFooterLibs;
1156 $jsLibs = '';
1157 $jsFooterFiles = $jsFiles . LF . $jsFooterFiles;
1158 $jsFiles = '';
1159 $jsFooterInline = $jsInline . LF . $jsFooterInline;
1160 $jsInline = '';
1161 }
1162
1163 $markerArray = array(
1164 'XMLPROLOG_DOCTYPE' => $this->xmlPrologAndDocType,
1165 'HTMLTAG' => $this->htmlTag,
1166 'HEADTAG' => $this->headTag,
1167 'METACHARSET' => $this->charSet ? str_replace('|', htmlspecialchars($this->charSet), $this->metaCharsetTag) : '',
1168 'INLINECOMMENT' => $this->inlineComments ? LF . LF . '<!-- ' . LF . implode(LF, $this->inlineComments) . '-->' . LF . LF : '',
1169 'BASEURL' => $this->baseUrl ? str_replace('|', $this->baseUrl, $this->baseUrlTag) : '',
1170 'SHORTCUT' => $this->favIcon ? sprintf($this->shortcutTag, htmlspecialchars($this->favIcon), $this->iconMimeType) : '',
1171 'CSS_INCLUDE' => $cssFiles,
1172 'CSS_INLINE' => $cssInline,
1173 'JS_INLINE' => $jsInline,
1174 'JS_INCLUDE' => $jsFiles,
1175 'JS_LIBS' => $jsLibs,
1176 'TITLE' => $this->title ? str_replace('|', htmlspecialchars($this->title), $this->titleTag) : '',
1177 'META' => $metaTags,
1178 'HEADERDATA' => $this->headerData ? implode(LF, $this->headerData) : '',
1179 'FOOTERDATA' => $this->footerData ? implode(LF, $this->footerData) : '',
1180 'JS_LIBS_FOOTER' => $jsFooterLibs,
1181 'JS_INCLUDE_FOOTER' => $jsFooterFiles,
1182 'JS_INLINE_FOOTER' => $jsFooterInline,
1183 'BODY' => $this->bodyContent,
1184 );
1185
1186 $markerArray = array_map('trim', $markerArray);
1187
1188 $this->reset();
1189 return trim(t3lib_parsehtml::substituteMarkerArray($template, $markerArray, '###|###'));
1190 }
1191
1192 /**
1193 * helper function for render the javascript libraries
1194 *
1195 * @return string content with javascript libraries
1196 */
1197 protected function renderJsLibraries() {
1198 $out = '';
1199
1200 if ($this->addPrototype) {
1201 $out .= '<script src="' . $this->processJsFile($this->backPath . 'contrib/prototype/prototype.js') .
1202 '" type="text/javascript"></script>' . LF;
1203 unset($this->jsFiles[$this->backPath . 'contrib/prototype/prototype.js']);
1204 }
1205
1206 if ($this->addScriptaculous) {
1207 $mods = array ();
1208 foreach ($this->addScriptaculousModules as $key => $value) {
1209 if ($this->addScriptaculousModules[$key]) {
1210 $mods[] = $key;
1211 }
1212 }
1213 // resolve dependencies
1214 if (in_array('dragdrop', $mods) || in_array('controls', $mods)) {
1215 $mods = array_merge(array('effects'), $mods);
1216 }
1217
1218 if (count($mods)) {
1219 foreach ($mods as $module) {
1220 $out .= '<script src="' . $this->processJsFile($this->backPath .
1221 'contrib/scriptaculous/' . $module . '.js') . '" type="text/javascript"></script>' . LF;
1222 unset($this->jsFiles[$this->backPath . 'contrib/scriptaculous/' . $module . '.js']);
1223 }
1224 }
1225 $out .= '<script src="' . $this->processJsFile($this->backPath .
1226 'contrib/scriptaculous/scriptaculous.js') . '" type="text/javascript"></script>' . LF;
1227 unset($this->jsFiles[$this->backPath . 'contrib/scriptaculous/scriptaculous.js']);
1228 }
1229
1230 // include extCore
1231 if ($this->addExtCore) {
1232 $out .= '<script src="' . $this->processJsFile($this->backPath .
1233 'contrib/extjs/ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js') .
1234 '" type="text/javascript"></script>' . LF;
1235 unset($this->jsFiles[$this->backPath . 'contrib/extjs/ext-core' . ($this->enableExtCoreDebug ? '-debug' : '') . '.js']);
1236 }
1237
1238 // include extJS
1239 if ($this->addExtJS) {
1240 // use the base adapter all the time
1241 $out .= '<script src="' . $this->processJsFile($this->backPath .
1242 'contrib/extjs/adapter/' . ($this->enableExtJsDebug ?
1243 str_replace('.js', '-debug.js', $this->extJSadapter) : $this->extJSadapter)) .
1244 '" type="text/javascript"></script>' . LF;
1245 $out .= '<script src="' . $this->processJsFile($this->backPath .
1246 'contrib/extjs/ext-all' . ($this->enableExtJsDebug ? '-debug' : '') . '.js') .
1247 '" type="text/javascript"></script>' . LF;
1248
1249 // add extJS localization
1250 $localeMap = $this->csConvObj->isoArray; // load standard ISO mapping and modify for use with ExtJS
1251 $localeMap[''] = 'en';
1252 $localeMap['default'] = 'en';
1253 $localeMap['gr'] = 'el_GR'; // Greek
1254 $localeMap['no'] = 'no_BO'; // Norwegian Bokmaal
1255 $localeMap['se'] = 'se_SV'; // Swedish
1256
1257
1258 $extJsLang = isset($localeMap[$this->lang]) ? $localeMap[$this->lang] : $this->lang;
1259 // TODO autoconvert file from UTF8 to current BE charset if necessary!!!!
1260 $extJsLocaleFile = 'contrib/extjs/locale/ext-lang-' . $extJsLang . '.js';
1261 if (file_exists(PATH_typo3 . $extJsLocaleFile)) {
1262 $out .= '<script src="' . $this->processJsFile($this->backPath .
1263 $extJsLocaleFile) . '" type="text/javascript" charset="utf-8"></script>' . LF;
1264 }
1265
1266
1267 // remove extjs from JScodeLibArray
1268 unset(
1269 $this->jsFiles[$this->backPath . 'contrib/extjs/ext-all.js'], $this->jsFiles[$this->backPath . 'contrib/extjs/ext-all-debug.js']
1270 );
1271 }
1272
1273 // Convert labels/settings back to UTF-8 since json_encode() only works with UTF-8:
1274 if ($this->getCharSet() !== 'utf-8') {
1275 if ($this->inlineLanguageLabels) {
1276 $this->csConvObj->convArray($this->inlineLanguageLabels, $this->getCharSet(), 'utf-8');
1277 }
1278 if ($this->inlineSettings) {
1279 $this->csConvObj->convArray($this->inlineSettings, $this->getCharSet(), 'utf-8');
1280 }
1281 }
1282
1283 $inlineSettings = $this->inlineLanguageLabels ? 'TYPO3.lang = ' . json_encode($this->inlineLanguageLabels) . ';' : '';
1284 $inlineSettings .= $this->inlineSettings ? 'TYPO3.settings = ' . json_encode($this->inlineSettings) . ';' : '';
1285
1286 if ($this->addExtCore || $this->addExtJS) {
1287 // set clear.gif, move it on top, add handler code
1288 $code = '';
1289 if (count($this->extOnReadyCode)) {
1290 foreach ($this->extOnReadyCode as $block) {
1291 $code .= $block;
1292 }
1293 }
1294
1295 $out .= $this->inlineJavascriptWrap[0] . '
1296 Ext.ns("TYPO3");
1297 Ext.BLANK_IMAGE_URL = "' . htmlspecialchars(t3lib_div::locationHeaderUrl($this->backPath . 'gfx/clear.gif')) . '";' . LF .
1298 $inlineSettings .
1299 'Ext.onReady(function() {' .
1300 ($this->enableExtJSQuickTips ? 'Ext.QuickTips.init();' . LF : '') . $code .
1301 ' });' . $this->inlineJavascriptWrap[1];
1302 unset ($this->extOnReadyCode);
1303
1304 if ($this->extJStheme) {
1305 if (isset($GLOBALS['TBE_STYLES']['extJS']['theme'])) {
1306 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['theme'], 'stylesheet', 'all', '', TRUE, TRUE);
1307 } else {
1308 $this->addCssFile($this->backPath . 'contrib/extjs/resources/css/xtheme-blue.css', 'stylesheet', 'all', '', TRUE, TRUE);
1309 }
1310 }
1311 if ($this->extJScss) {
1312 if (isset($GLOBALS['TBE_STYLES']['extJS']['all'])) {
1313 $this->addCssFile($this->backPath . $GLOBALS['TBE_STYLES']['extJS']['all'], 'stylesheet', 'all', '', TRUE, TRUE);
1314 } else {
1315 $this->addCssFile($this->backPath . 'contrib/extjs/resources/css/ext-all-notheme.css', 'stylesheet', 'all', '', TRUE, TRUE);
1316 }
1317 }
1318 } else {
1319 if ($inlineSettings) {
1320 $out .= $this->inlineJavascriptWrap[0] . $inlineSettings . $this->inlineJavascriptWrap[1];
1321 }
1322 }
1323
1324 return $out;
1325 }
1326
1327 /*****************************************************/
1328 /* */
1329 /* Tools */
1330 /* */
1331 /* */
1332 /*****************************************************/
1333
1334 /**
1335 * concatenate files into one file
1336 * registered handler
1337 *
1338 * @return void
1339 */
1340 protected function doConcatenate() {
1341 // traverse the arrays, concatenate in one file
1342 // then remove concatenated files from array and add the concatenated file
1343
1344 if ($this->concatenateFiles) {
1345 $params = array (
1346 'jsLibs' => &$this->jsLibs,
1347 'jsFiles' => &$this->jsFiles,
1348 'jsFooterFiles' => &$this->jsFooterFiles,
1349 'cssFiles' => &$this->cssFiles,
1350 'headerData' => &$this->headerData,
1351 'footerData' => &$this->footerData,
1352 );
1353
1354 if ($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['concatenateHandler']) {
1355 // use extern concatenate routine
1356 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['concatenateHandler'], $params, $this);
1357 } elseif (TYPO3_MODE === 'BE') {
1358 $cssOptions = array('baseDirectories' => $GLOBALS['TBE_TEMPLATE']->getSkinStylesheetDirectories());
1359 $this->cssFiles = $this->getCompressor()->concatenateCssFiles($this->cssFiles, $cssOptions);
1360 }
1361 }
1362 }
1363
1364 /**
1365 * compress inline code
1366 *
1367 * @return void
1368 */
1369 protected function doCompress() {
1370
1371 if ($this->compressJavascript && $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler']) {
1372 // use extern compress routine
1373 $params = array (
1374 'jsInline' => &$this->jsInline,
1375 'jsFooterInline' => &$this->jsFooterInline,
1376 'jsLibs' => &$this->jsLibs,
1377 'jsFiles' => &$this->jsFiles,
1378 'jsFooterFiles' => &$this->jsFooterFiles,
1379 'headerData' => &$this->headerData,
1380 'footerData' => &$this->footerData,
1381 );
1382 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['jsCompressHandler'], $params, $this);
1383 } else {
1384 // traverse the arrays, compress files
1385 $this->compressError = '';
1386
1387 if ($this->compressJavascript) {
1388 if (count($this->jsInline)) {
1389 foreach ($this->jsInline as $name => $properties) {
1390 if ($properties['compress']) {
1391 $error = '';
1392 $this->jsInline[$name]['code'] = t3lib_div::minifyJavaScript($properties['code'], $error);
1393 if ($error) {
1394 $this->compressError .= 'Error with minify JS Inline Block "' . $name . '": ' . $error . LF;
1395 }
1396 }
1397 }
1398 }
1399 if (TYPO3_MODE === 'BE') {
1400 $this->jsFiles = $this->getCompressor()->compressJsFiles($this->jsFiles);
1401 $this->jsFooterFiles = $this->getCompressor()->compressJsFiles($this->jsFooterFiles);
1402 }
1403 }
1404 }
1405 if ($this->compressCss) {
1406 // use extern compress routine
1407 $params = array (
1408 'cssInline' => &$this->cssInline,
1409 'cssFiles' => &$this->cssFiles,
1410 'headerData' => &$this->headerData,
1411 'footerData' => &$this->footerData,
1412 );
1413
1414 if ($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler']) {
1415 // use extern concatenate routine
1416 t3lib_div::callUserFunction($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['cssCompressHandler'], $params, $this);
1417 } elseif (TYPO3_MODE === 'BE') {
1418 $this->cssFiles = $this->getCompressor()->compressCssFiles($this->cssFiles);
1419 }
1420 }
1421 }
1422
1423 /**
1424 * Returns instance of t3lib_compressor
1425 *
1426 * @return t3lib_compressor Instance of t3lib_compressor
1427 */
1428 protected function getCompressor() {
1429 if ($this->compressor === NULL) {
1430 $this->compressor = t3lib_div::makeInstance('t3lib_compressor');
1431 }
1432 return $this->compressor;
1433 }
1434
1435 /**
1436 * Processes a Javascript file dependent on the current context
1437 *
1438 * Adds the version number for Frontend, compresses the file for Backend
1439 *
1440 * @param string $filename Filename
1441 * @return string new filename
1442 */
1443 protected function processJsFile($filename) {
1444 switch (TYPO3_MODE) {
1445 case 'FE':
1446 $filename = t3lib_div::createVersionNumberedFilename($filename);
1447 break;
1448 case 'BE':
1449 if ($this->compressJavascript) {
1450 $filename = $this->getCompressor()->compressJsFile($filename);
1451 }
1452 break;
1453 }
1454 return $filename;
1455 }
1456 }
1457
1458 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php']) {
1459 include_once ($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_pagerenderer.php']);
1460 }
1461 ?>