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