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