[TASK] Remove dependency to tab.js in FormEngine
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Template / DocumentTemplate.php
1 <?php
2 namespace TYPO3\CMS\Backend\Template;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Html\HtmlParser;
21 use TYPO3\CMS\Core\Page\PageRenderer;
22 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Fluid\View\StandaloneView;
25
26 /**
27 * TYPO3 Backend Template Class
28 *
29 * This class contains functions for starting and ending the HTML of backend modules
30 * It also contains methods for outputting sections of content.
31 * Further there are functions for making icons, links, setting form-field widths etc.
32 * Color scheme and stylesheet definitions are also available here.
33 * Finally this file includes the language class for TYPO3's backend.
34 *
35 * After this file $LANG and $TBE_TEMPLATE are global variables / instances of their respective classes.
36 * This file is typically included right after the init.php file,
37 * if language and layout is needed.
38 *
39 * Please refer to Inside TYPO3 for a discussion of how to use this API.
40 *
41 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
42 */
43 class DocumentTemplate {
44
45 // Vars you typically might want to/should set from outside after making instance of this class:
46 /**
47 * 'backPath' pointing back to the PATH_typo3
48 *
49 * @var string
50 */
51 public $backPath = '';
52
53 /**
54 * This can be set to the HTML-code for a formtag.
55 * Useful when you need a form to span the whole page; Inserted exactly after the body-tag.
56 *
57 * @var string
58 */
59 public $form = '';
60
61 /**
62 * Similar to $JScode (see below) but used as an associative array to prevent double inclusion of JS code.
63 * This is used to include certain external Javascript libraries before the inline JS code.
64 * <script>-Tags are not wrapped around automatically
65 *
66 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use pageRenderer directly
67 */
68 public $JScodeLibArray = array();
69
70 /**
71 * Additional header code (eg. a JavaScript section) could be accommulated in this var. It will be directly outputted in the header.
72 *
73 * @var string
74 */
75 public $JScode = '';
76
77 /**
78 * Additional header code for ExtJS. It will be included in document header and inserted in a Ext.onReady(function()
79 *
80 * @var string
81 */
82 public $extJScode = '';
83
84 /**
85 * Similar to $JScode but for use as array with associative keys to prevent double inclusion of JS code. a <script> tag is automatically wrapped around.
86 *
87 * @var array
88 */
89 public $JScodeArray = array('jumpToUrl' => '
90 function jumpToUrl(URL) {
91 window.location.href = URL;
92 return false;
93 }
94 ');
95
96 /**
97 * Additional 'page-end' code could be accumulated in this var. It will be outputted at the end of page before </body> and some other internal page-end code.
98 *
99 * @var string
100 */
101 public $postCode = '';
102
103 /**
104 * Doc-type used in the header. Default is xhtml_trans. You can also set it to 'html_3', 'xhtml_strict' or 'xhtml_frames'.
105 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is HTML5
106 */
107 public $docType = '';
108
109 /**
110 * HTML template with markers for module
111 *
112 * @var string
113 */
114 public $moduleTemplate = '';
115
116 /**
117 * The base file (not overlaid by TBE_STYLES) for the current module, useful for hooks when finding out which modules is rendered currently
118 *
119 * @var string
120 */
121 protected $moduleTemplateFilename = '';
122
123 /**
124 * Script ID
125 *
126 * @var string
127 */
128 public $scriptID = '';
129
130 /**
131 * Id which can be set for the body tag. Default value is based on script ID
132 *
133 * @var string
134 */
135 public $bodyTagId = '';
136
137 /**
138 * You can add additional attributes to the body-tag through this variable.
139 *
140 * @var string
141 */
142 public $bodyTagAdditions = '';
143
144 /**
145 * Additional CSS styles which will be added to the <style> section in the header
146 *
147 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the pageRenderer property for adding CSS styles
148 */
149 public $inDocStyles = '';
150
151 /**
152 * Additional CSS styles which will be added to the <style> section in the header
153 * used as array with associative keys to prevent double inclusion of CSS code
154 *
155 * @var array
156 */
157 public $inDocStylesArray = array();
158
159 /**
160 * Compensation for large documents (used in \TYPO3\CMS\Backend\Form\FormEngine)
161 *
162 * @var float
163 */
164 public $form_largeComp = 1.33;
165
166 /**
167 * If set, then a JavaScript section will be outputted in the bottom of page which will try and update the top.busy session expiry object.
168 *
169 * @var int
170 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
171 */
172 public $endJS = 1;
173
174 // TYPO3 Colorscheme.
175 // If you want to change this, please do so through a skin using the global var $GLOBALS['TBE_STYLES']
176
177 /**
178 * Light background color
179 *
180 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
181 */
182 public $bgColor = '#F7F3EF';
183
184 /**
185 * Steel-blue
186 *
187 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
188 */
189 public $bgColor2 = '#9BA1A8';
190
191 /**
192 * dok.color
193 *
194 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
195 */
196 public $bgColor3 = '#F6F2E6';
197
198 /**
199 * light tablerow background, brownish
200 *
201 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
202 */
203 public $bgColor4 = '#D9D5C9';
204
205 /**
206 * light tablerow background, greenish
207 *
208 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
209 */
210 public $bgColor5 = '#ABBBB4';
211
212 /**
213 * light tablerow background, yellowish, for section headers. Light.
214 *
215 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
216 */
217 public $bgColor6 = '#E7DBA8';
218
219 /**
220 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
221 */
222 public $hoverColor = '#254D7B';
223
224 /**
225 * Filename of stylesheet (relative to PATH_typo3)
226 *
227 * @var string
228 */
229 public $styleSheetFile = '';
230
231 /**
232 * Filename of stylesheet #2 - linked to right after the $this->styleSheetFile script (relative to PATH_typo3)
233 *
234 * @var string
235 */
236 public $styleSheetFile2 = '';
237
238 /**
239 * Filename of a post-stylesheet - included right after all inline styles.
240 *
241 * @var string
242 */
243 public $styleSheetFile_post = '';
244
245 /**
246 * Background image of page (relative to PATH_typo3)
247 *
248 * @var string
249 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use a stylesheet instead
250 */
251 public $backGroundImage = '';
252
253 /**
254 * Inline css styling set from TBE_STYLES array
255 *
256 * @var string
257 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use inDocStylesArray['TBEstyle']
258 */
259 public $inDocStyles_TBEstyle = '';
260
261 /**
262 * Whether to use the X-UA-Compatible meta tag
263 *
264 * @var bool
265 */
266 protected $useCompatibilityTag = TRUE;
267
268 /**
269 * X-Ua-Compatible version output in meta tag
270 *
271 * @var string
272 */
273 protected $xUaCompatibilityVersion = 'IE=edge';
274
275 // Skinning
276 /**
277 * stylesheets from core
278 *
279 * @var array
280 */
281 protected $stylesheetsCore = array(
282 'generatedSprites' => '../typo3temp/sprites/'
283 );
284
285 /**
286 * Include these CSS directories from skins by default
287 *
288 * @var array
289 */
290 protected $stylesheetsSkins = array(
291 'structure' => 'Resources/Public/Css/structure/',
292 'visual' => 'Resources/Public/Css/visual/'
293 );
294
295 /**
296 * JavaScript files loaded for every page in the Backend
297 *
298 * @var array
299 */
300 protected $jsFiles = array();
301
302 /**
303 * JavaScript files loaded for every page in the Backend, but explicitly excluded from concatenation (useful for libraries etc.)
304 *
305 * @var array
306 */
307 protected $jsFilesNoConcatenation = array();
308
309 /**
310 * Will output the parsetime of the scripts in milliseconds (for admin-users).
311 * Set this to FALSE when releasing TYPO3. Only for dev.
312 *
313 * @var bool
314 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
315 */
316 public $parseTimeFlag = FALSE;
317
318 /**
319 * internal character set, nowadays utf-8 for everything
320 *
321 * @var string
322 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, as it is always utf-8
323 */
324 protected $charset = 'utf-8';
325
326 /**
327 * Indicates if a <div>-output section is open
328 *
329 * @var int
330 * @internal
331 */
332 public $sectionFlag = 0;
333
334 /**
335 * (Default) Class for wrapping <DIV>-tag of page. Is set in class extensions.
336 *
337 * @var string
338 */
339 public $divClass = '';
340
341 /**
342 * @var string
343 */
344 public $pageHeaderBlock = '';
345
346 /**
347 * @var string
348 */
349 public $endOfPageJsBlock = '';
350
351 /**
352 * @var bool
353 */
354 public $hasDocheader = TRUE;
355
356 /**
357 * @var \TYPO3\CMS\Core\Page\PageRenderer
358 */
359 protected $pageRenderer;
360
361 /**
362 * Alternative template file
363 *
364 * @var string
365 */
366 protected $pageHeaderFooterTemplateFile = '';
367
368 /**
369 * @var bool
370 */
371 protected $extDirectStateProvider = FALSE;
372
373 /**
374 * Whether flashmessages should be rendered or not
375 *
376 * @var bool $showFlashMessages
377 */
378 public $showFlashMessages = TRUE;
379
380 const STATUS_ICON_ERROR = 3;
381 const STATUS_ICON_WARNING = 2;
382 const STATUS_ICON_NOTIFICATION = 1;
383 const STATUS_ICON_OK = -1;
384
385 /**
386 * Constructor
387 */
388 public function __construct() {
389 // Initializes the page rendering object:
390 $this->getPageRenderer();
391
392 // load Legacy CSS Support
393 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyCssClasses');
394
395 // Setting default scriptID:
396 if (($temp_M = (string)GeneralUtility::_GET('M')) && $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M]) {
397 $this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', $GLOBALS['TBE_MODULES']['_PATHS'][$temp_M] . 'index.php');
398 } else {
399 $this->scriptID = preg_replace('/^.*\\/(sysext|ext)\\//', 'ext/', \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(PATH_thisScript));
400 }
401 if (TYPO3_mainDir != 'typo3/' && substr($this->scriptID, 0, strlen(TYPO3_mainDir)) == TYPO3_mainDir) {
402 // This fixes if TYPO3_mainDir has been changed so the script ids are STILL "typo3/..."
403 $this->scriptID = 'typo3/' . substr($this->scriptID, strlen(TYPO3_mainDir));
404 }
405 $this->bodyTagId = preg_replace('/[^A-Za-z0-9-]/', '-', $this->scriptID);
406 // Individual configuration per script? If so, make a recursive merge of the arrays:
407 if (is_array($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID])) {
408 // Make copy
409 $ovr = $GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID];
410 // merge styles.
411 \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TBE_STYLES'], $ovr);
412 // Have to unset - otherwise the second instantiation will do it again!
413 unset($GLOBALS['TBE_STYLES']['scriptIDindex'][$this->scriptID]);
414 }
415 // Main Stylesheets:
416 if ($GLOBALS['TBE_STYLES']['stylesheet']) {
417 $this->styleSheetFile = $GLOBALS['TBE_STYLES']['stylesheet'];
418 }
419 if ($GLOBALS['TBE_STYLES']['stylesheet2']) {
420 $this->styleSheetFile2 = $GLOBALS['TBE_STYLES']['stylesheet2'];
421 }
422 if ($GLOBALS['TBE_STYLES']['styleSheetFile_post']) {
423 $this->styleSheetFile_post = $GLOBALS['TBE_STYLES']['styleSheetFile_post'];
424 }
425 if ($GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle']) {
426 $this->inDocStylesArray['TBEstyle'] = $GLOBALS['TBE_STYLES']['inDocStyles_TBEstyle'];
427 }
428 // include all stylesheets
429 foreach ($this->getSkinStylesheetDirectories() as $stylesheetDirectory) {
430 $this->addStylesheetDirectory($stylesheetDirectory);
431 }
432 // Background image
433 if ($GLOBALS['TBE_STYLES']['background']) {
434 GeneralUtility::deprecationLog('Usage of $TBE_STYLES["background"] is deprecated. Please use stylesheets directly.');
435 }
436 }
437
438 /**
439 * Gets instance of PageRenderer configured with the current language, file references and debug settings
440 *
441 * @return \TYPO3\CMS\Core\Page\PageRenderer
442 */
443 public function getPageRenderer() {
444 if (!isset($this->pageRenderer)) {
445 $this->pageRenderer = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Page\PageRenderer::class);
446 $this->pageRenderer->setLanguage($GLOBALS['LANG']->lang);
447 $this->pageRenderer->enableConcatenateFiles();
448 $this->pageRenderer->enableCompressCss();
449 $this->pageRenderer->enableCompressJavascript();
450 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
451 foreach ($this->jsFilesNoConcatenation as $file) {
452 $this->pageRenderer->addJsFile(
453 $GLOBALS['BACK_PATH'] . $file,
454 'text/javascript',
455 TRUE,
456 FALSE,
457 '',
458 TRUE
459 );
460 }
461 // Add all JavaScript files defined in $this->jsFiles to the PageRenderer
462 foreach ($this->jsFiles as $file) {
463 $this->pageRenderer->addJsFile($GLOBALS['BACK_PATH'] . $file);
464 }
465 }
466 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['debug'] === 1) {
467 $this->pageRenderer->enableDebugMode();
468 }
469 return $this->pageRenderer;
470 }
471
472 /**
473 * Sets inclusion of StateProvider
474 *
475 * @return void
476 */
477 public function setExtDirectStateProvider() {
478 $this->extDirectStateProvider = TRUE;
479 }
480
481 /*****************************************
482 *
483 * EVALUATION FUNCTIONS
484 * Various centralized processing
485 *
486 *****************************************/
487 /**
488 * Makes click menu link (context sensitive menu)
489 * Returns $str (possibly an <|img> tag/icon) wrapped in a link which will activate the context sensitive menu for the record ($table/$uid) or file ($table = file)
490 * The link will load the top frame with the parameter "&item" which is the table,uid and listFr arguments imploded by "|": rawurlencode($table.'|'.$uid.'|'.$listFr)
491 *
492 * @param string $str String to be wrapped in link, typ. image tag.
493 * @param string $table Table name/File path. If the icon is for a database record, enter the tablename from $GLOBALS['TCA']. If a file then enter the absolute filepath
494 * @param int $uid If icon is for database record this is the UID for the record from $table
495 * @param bool $listFr Tells the top frame script that the link is coming from a "list" frame which means a frame from within the backend content frame.
496 * @param string $addParams Additional GET parameters for the link to the ClickMenu AJAX request
497 * @param string $enDisItems Enable / Disable click menu items. Example: "+new,view" will display ONLY these two items (and any spacers in between), "new,view" will display all BUT these two items.
498 * @param bool $returnTagParameters If set, will return only the onclick JavaScript, not the whole link.
499 * @return string The link-wrapped input string.
500 */
501 public function wrapClickMenuOnIcon($content, $table, $uid = 0, $listFr = TRUE, $addParams = '', $enDisItems = '', $returnTagParameters = FALSE) {
502 $tagParameters = array(
503 'class' => 't3-js-clickmenutrigger',
504 'data-table' => $table,
505 'data-uid' => (int)$uid !== 0 ? (int)$uid : '',
506 'data-listframe' => $listFr,
507 'data-iteminfo' => str_replace('+', '%2B', $enDisItems),
508 'data-parameters' => $addParams,
509 );
510
511 if ($returnTagParameters) {
512 return $tagParameters;
513 } else {
514 return '<a href="#" ' . GeneralUtility::implodeAttributes($tagParameters, TRUE) . '>' . $content . '</a>';
515 }
516 }
517
518 /**
519 * Makes link to page $id in frontend (view page)
520 * Returns an icon which links to the frontend index.php document for viewing the page with id $id
521 * $id must be a page-uid
522 * If the BE_USER has access to Web>List then a link to that module is shown as well (with return-url)
523 *
524 * @param int $id The page id
525 * @param string $backPath The current "BACK_PATH" (the back relative to the typo3/ directory)
526 * @return string HTML string with linked icon(s)
527 */
528 public function viewPageIcon($id, $backPath) {
529 // If access to Web>List for user, then link to that module.
530 $str = BackendUtility::getListViewLink(array(
531 'id' => $id,
532 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
533 ), $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showList'));
534 // Make link to view page
535 $str .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick($id, $backPath, BackendUtility::BEgetRootLine($id))) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.showPage', TRUE) . '">' . IconUtility::getSpriteIcon('actions-document-view') . '</a>';
536 return $str;
537 }
538
539 /**
540 * Returns a URL with a command to TYPO3 Core Engine (tce_db.php)
541 * See description of the API elsewhere.
542 *
543 * @param string $params is a set of GET params to send to tce_db.php. Example: "&cmd[tt_content][123][move]=456" or "&data[tt_content][123][hidden]=1&data[tt_content][123][title]=Hello%20World
544 * @param string|int $redirectUrl Redirect URL, default is to use GeneralUtility::getIndpEnv('REQUEST_URI'), -1 means to generate an URL for JavaScript using T3_THIS_LOCATION
545 * @return string URL to tce_db.php + parameters (backpath is taken from $this->backPath)
546 * @see \TYPO3\CMS\Backend\Utility\BackendUtility::editOnClick()
547 */
548 public function issueCommand($params, $redirectUrl = '') {
549 /** @var BackendUserAuthentication $beUser */
550 $beUser = $GLOBALS['BE_USER'];
551 $urlParameters = [
552 'prErr' => 1,
553 'uPT' => 1,
554 'vC' => $beUser->veriCode()
555 ];
556 $url = BackendUtility::getModuleUrl('tce_db', $urlParameters) . $params . BackendUtility::getUrlToken('tceAction') . '&redirect=';
557 if ((int)$redirectUrl === -1) {
558 $url = GeneralUtility::quoteJSvalue($url) . '+T3_THIS_LOCATION';
559 } else {
560 $url .= rawurlencode($redirectUrl ?: GeneralUtility::getIndpEnv('REQUEST_URI'));
561 }
562 return $url;
563 }
564
565 /**
566 * Makes the header (icon+title) for a page (or other record). Used in most modules under Web>*
567 * $table and $row must be a tablename/record from that table
568 * $path will be shown as alt-text for the icon.
569 * The title will be truncated to 45 chars.
570 *
571 * @param string $table Table name
572 * @param array $row Record row
573 * @param string $path Alt text
574 * @param bool $noViewPageIcon Set $noViewPageIcon TRUE if you don't want a magnifier-icon for viewing the page in the frontend
575 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
576 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
577 * @return string HTML content
578 */
579 public function getHeader($table, $row, $path, $noViewPageIcon = FALSE, $tWrap = array('', ''), $enableClickMenu = TRUE) {
580 $viewPage = '';
581 if (is_array($row) && $row['uid']) {
582 $iconImgTag = IconUtility::getSpriteIconForRecord($table, $row, array('title' => htmlspecialchars($path)));
583 $title = strip_tags(BackendUtility::getRecordTitle($table, $row));
584 $viewPage = $noViewPageIcon ? '' : $this->viewPageIcon($row['uid'], $this->backPath);
585 if ($table == 'pages') {
586 $path .= ' - ' . BackendUtility::titleAttribForPages($row, '', 0);
587 }
588 } else {
589 $iconImgTag = IconUtility::getSpriteIcon('apps-pagetree-page-domain', array('title' => htmlspecialchars($path)));
590 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
591 }
592
593 if ($enableClickMenu) {
594 $iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, $table, $row['uid']);
595 }
596
597 return '<span class="typo3-moduleHeader">' . $iconImgTag . $viewPage . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($title, 45)) . $tWrap[1] . '</span>';
598 }
599
600 /**
601 * Like ->getHeader() but for files and folders
602 * Returns the icon with the path of the file/folder set in the alt/title attribute. Shows the name after the icon.
603 *
604 * @param \TYPO3\CMS\Core\Resource\ResourceInterface $resource
605 * @param array $tWrap is an array with indexes 0 and 1 each representing HTML-tags (start/end) which will wrap the title
606 * @param bool $enableClickMenu If TRUE, render click menu code around icon image
607 * @return string
608 */
609 public function getResourceHeader(\TYPO3\CMS\Core\Resource\ResourceInterface $resource, $tWrap = array('', ''), $enableClickMenu = TRUE) {
610 $path = $resource->getStorage()->getName() . $resource->getParentFolder()->getIdentifier();
611 $iconImgTag = IconUtility::getSpriteIconForResource($resource, array('title' => htmlspecialchars($path)));
612
613 if ($enableClickMenu && ($resource instanceof \TYPO3\CMS\Core\Resource\File)) {
614 $metaData = $resource->_getMetaData();
615 $iconImgTag = $this->wrapClickMenuOnIcon($iconImgTag, 'sys_file_metadata', $metaData['uid']);
616 }
617
618 return '<span class="typo3-moduleHeader">' . $iconImgTag . $tWrap[0] . htmlspecialchars(GeneralUtility::fixed_lgd_cs($resource->getName(), 45)) . $tWrap[1] . '</span>';
619 }
620
621 /**
622 * Returns a linked shortcut-icon which will call the shortcut frame and set a shortcut there back to the calling page/module
623 *
624 * @param string $gvList Is the list of GET variables to store (if any)
625 * @param string $setList Is the list of SET[] variables to store (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend modules
626 * @param string $modName Module name string
627 * @param string $motherModName Is used to enter the "parent module name" if the module is a submodule under eg. Web>* or File>*. You can also set this value to "1" in which case the currentLoadedModule is sent to the shortcut script (so - not a fixed value!) - that is used in file_edit and wizard_rte modules where those are really running as a part of another module.
628 * @return string HTML content
629 */
630 public function makeShortcutIcon($gvList, $setList, $modName, $motherModName = '') {
631 $storeUrl = $this->makeShortcutUrl($gvList, $setList);
632 $pathInfo = parse_url(GeneralUtility::getIndpEnv('REQUEST_URI'));
633 // Add the module identifier automatically if typo3/mod.php is used:
634 if (preg_match('/typo3\\/mod\\.php$/', $pathInfo['path']) && isset($GLOBALS['TBE_MODULES']['_PATHS'][$modName])) {
635 $storeUrl = '&M=' . $modName . $storeUrl;
636 }
637 if ((int)$motherModName === 1) {
638 $mMN = '&motherModName=\'+top.currentModuleLoaded+\'';
639 } elseif ($motherModName) {
640 $mMN = '&motherModName=' . rawurlencode($motherModName);
641 } else {
642 $mMN = '';
643 }
644 $confirmationText = GeneralUtility::quoteJSvalue($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark'));
645 $onClick = 'top.TYPO3.ShortcutMenu.createShortcut(' . GeneralUtility::quoteJSvalue(rawurlencode($modName)) . ', ' . GeneralUtility::quoteJSvalue(rawurlencode($pathInfo['path'] . '?' . $storeUrl) . $mMN) . ', ' . $confirmationText . ');return false;';
646 return '<a href="#" onclick="' . htmlspecialchars($onClick) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.makeBookmark', TRUE) . '">' . IconUtility::getSpriteIcon('actions-system-shortcut-new') . '</a>';
647 }
648
649 /**
650 * MAKE url for storing
651 * Internal func
652 *
653 * @param string $gvList Is the list of GET variables to store (if any)
654 * @param string $setList Is the list of SET[] variables to store (if any) - SET[] variables a stored in $GLOBALS["SOBE"]->MOD_SETTINGS for backend modules
655 * @return string
656 * @access private
657 * @see makeShortcutIcon()
658 */
659 public function makeShortcutUrl($gvList, $setList) {
660 $GET = GeneralUtility::_GET();
661 $storeArray = array_merge(GeneralUtility::compileSelectedGetVarsFromArray($gvList, $GET), array('SET' => GeneralUtility::compileSelectedGetVarsFromArray($setList, (array)$GLOBALS['SOBE']->MOD_SETTINGS)));
662 $storeUrl = GeneralUtility::implodeArrayForUrl('', $storeArray);
663 return $storeUrl;
664 }
665
666 /**
667 * Returns <input> attributes to set the width of an text-type input field.
668 * For client browsers with no CSS support the cols/size attribute is returned.
669 * For CSS compliant browsers (recommended) a ' style="width: ...px;"' is returned.
670 *
671 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
672 * @param bool $textarea A flag you can set for textareas - DEPRECATED as there is no difference any more between the two
673 * @param string $styleOverride A string which will be returned as attribute-value for style="" instead of the calculated width (if CSS is enabled)
674 * @return string Tag attributes for an <input> tag (regarding width)
675 */
676 public function formWidth($size = 48, $textarea = FALSE, $styleOverride = '') {
677 return ' style="' . ($styleOverride ?: 'width:' . ceil($size * 9.58) . 'px;') . '"';
678 }
679
680 /**
681 * This function is dedicated to textareas, which has the wrapping on/off option to observe.
682 * EXAMPLE:
683 * <textarea rows="10" wrap="off" '.$GLOBALS["TBE_TEMPLATE"]->formWidthText(48, "", "off").'>
684 * or
685 * <textarea rows="10" wrap="virtual" '.$GLOBALS["TBE_TEMPLATE"]->formWidthText(48, "", "virtual").'>
686 *
687 * @param int $size A relative number which multiplied with approx. 10 will lead to the width in pixels
688 * @param string $styleOverride A string which will be returned as attribute-value for style="" instead of the calculated width (if CSS is enabled)
689 * @param string $wrap Pass on the wrap-attribute value you use in your <textarea>! This will be used to make sure that some browsers will detect wrapping alright.
690 * @return string Tag attributes for an <input> tag (regarding width)
691 * @see formWidth()
692 * @deprecated since TYPO3 CMS 6.2, remove two versions later, as this is function is not needed anymore, use formWidth()
693 */
694 public function formWidthText($size = 48, $styleOverride = '', $wrap = '') {
695 GeneralUtility::logDeprecatedFunction();
696 return $this->formWidth($size, TRUE, $styleOverride);
697 }
698
699 /**
700 * Returns JavaScript variables setting the returnUrl and thisScript location for use by JavaScript on the page.
701 * Used in fx. db_list.php (Web>List)
702 *
703 * @param string $thisLocation URL to "this location" / current script
704 * @return string Urls are returned as JavaScript variables T3_RETURN_URL and T3_THIS_LOCATION
705 * @see typo3/db_list.php
706 */
707 public function redirectUrls($thisLocation = '') {
708 $thisLocation = $thisLocation ? $thisLocation : GeneralUtility::linkThisScript(array(
709 'CB' => '',
710 'SET' => '',
711 'cmd' => '',
712 'popViewId' => ''
713 ));
714 $out = '
715 var T3_RETURN_URL = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode(GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('returnUrl'))))) . ';
716 var T3_THIS_LOCATION = ' . GeneralUtility::quoteJSvalue(str_replace('%20', '', rawurlencode($thisLocation))) . '
717 ';
718 return $out;
719 }
720
721 /**
722 * Returns a formatted string of $tstamp
723 * Uses $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] and $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] to format date and time
724 *
725 * @param int $tstamp UNIX timestamp, seconds since 1970
726 * @param int $type How much data to show: $type = 1: hhmm, $type = 10: ddmmmyy
727 * @return string Formatted timestamp
728 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use the corresponding methods in BackendUtility
729 */
730 public function formatTime($tstamp, $type) {
731 GeneralUtility::logDeprecatedFunction();
732 $dateStr = '';
733 switch ($type) {
734 case 1:
735 $dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $tstamp);
736 break;
737 case 10:
738 $dateStr = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $tstamp);
739 break;
740 }
741 return $dateStr;
742 }
743
744 /**
745 * Returns script parsetime IF ->parseTimeFlag is set and user is "admin"
746 * Automatically outputted in page end
747 *
748 * @return string HTML formated with <p>-tags
749 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
750 */
751 public function parseTime() {
752 GeneralUtility::logDeprecatedFunction();
753 if ($this->parseTimeFlag && $GLOBALS['BE_USER']->isAdmin()) {
754 return '<p>(ParseTime: ' . (GeneralUtility::milliseconds() - $GLOBALS['PARSETIME_START']) . ' ms</p>
755 <p>REQUEST_URI-length: ' . strlen(GeneralUtility::getIndpEnv('REQUEST_URI')) . ')</p>';
756 }
757 }
758
759 /**
760 * Defines whether to use the X-UA-Compatible meta tag.
761 *
762 * @param bool $useCompatibilityTag Whether to use the tag
763 * @return void
764 */
765 public function useCompatibilityTag($useCompatibilityTag = TRUE) {
766 $this->useCompatibilityTag = (bool)$useCompatibilityTag;
767 }
768
769 /*****************************************
770 *
771 * PAGE BUILDING FUNCTIONS.
772 * Use this to build the HTML of your backend modules
773 *
774 *****************************************/
775 /**
776 * Returns page start
777 * This includes the proper header with charset, title, meta tag and beginning body-tag.
778 *
779 * @param string $title HTML Page title for the header
780 * @param bool $includeCsh flag for including CSH
781 * @return string Returns the whole header section of a HTML-document based on settings in internal variables (like styles, javascript code, charset, generator and docType)
782 * @see endPage()
783 */
784 public function startPage($title, $includeCsh = TRUE) {
785 // hook pre start page
786 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'])) {
787 $preStartPageHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preStartPageHook'];
788 if (is_array($preStartPageHook)) {
789 $hookParameters = array(
790 'title' => &$title
791 );
792 foreach ($preStartPageHook as $hookFunction) {
793 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
794 }
795 }
796 }
797 $this->pageRenderer->backPath = $this->backPath;
798 // alternative template for Header and Footer
799 if ($this->pageHeaderFooterTemplateFile) {
800 $file = GeneralUtility::getFileAbsFileName($this->pageHeaderFooterTemplateFile, TRUE);
801 if ($file) {
802 $this->pageRenderer->setTemplateFile($file);
803 }
804 }
805
806
807
808 // Disable rendering of XHTML tags
809 $this->pageRenderer->setRenderXhtml(FALSE);
810
811 $languageCode = $this->pageRenderer->getLanguage() === 'default' ? 'en' : $this->pageRenderer->getLanguage();
812 $this->pageRenderer->setHtmlTag('<html lang="' . $languageCode . '">');
813
814 // Include the JS for the Context Sensitive Help
815 // @todo: right now this is a hard dependency on csh manual, as the whole help system should be moved to
816 // the extension. The core provides a API for adding help, and rendering help, but the rendering
817 // should be up to the extension itself
818 if ($includeCsh && ExtensionManagementUtility::isLoaded('cshmanual')) {
819 $this->loadCshJavascript();
820 }
821
822 $headerStart = '<!DOCTYPE html>';
823 $this->pageRenderer->setXmlPrologAndDocType($headerStart);
824 $this->pageRenderer->setHeadTag('<head>' . LF . '<!-- TYPO3 Script ID: ' . htmlspecialchars($this->scriptID) . ' -->');
825 header('Content-Type:text/html;charset=utf-8');
826 $this->pageRenderer->setCharSet('utf-8');
827 $this->pageRenderer->addMetaTag($this->generator());
828 $this->pageRenderer->addMetaTag('<meta name="robots" content="noindex,follow">');
829 $this->pageRenderer->addMetaTag('<meta charset="utf-8">');
830 $this->pageRenderer->addMetaTag('<meta name="viewport" content="width=device-width, initial-scale=1">');
831 $this->pageRenderer->setFavIcon($this->getBackendFavicon());
832 if ($this->useCompatibilityTag) {
833 $this->pageRenderer->addMetaTag($this->xUaCompatible($this->xUaCompatibilityVersion));
834 }
835 $this->pageRenderer->setTitle($title);
836 // add docstyles
837 $this->docStyle();
838 if ($this->extDirectStateProvider) {
839 $this->pageRenderer->addJsFile($this->backPath . 'sysext/backend/Resources/Public/JavaScript/ExtDirect.StateProvider.js');
840 }
841 // Add jsCode for overriding the console with a debug panel connection
842 $this->pageRenderer->addJsInlineCode('consoleOverrideWithDebugPanel', 'if (typeof top.Ext === "object") {
843 top.Ext.onReady(function() {
844 if (typeof console === "undefined") {
845 if (top && top.TYPO3 && top.TYPO3.Backend && top.TYPO3.Backend.DebugConsole) {
846 console = top.TYPO3.Backend.DebugConsole;
847 } else {
848 console = {
849 log: Ext.log,
850 info: Ext.log,
851 warn: Ext.log,
852 error: Ext.log
853 };
854 }
855 }
856 });
857 }
858 ', FALSE);
859 $this->pageRenderer->addHeaderData($this->JScode);
860 foreach ($this->JScodeArray as $name => $code) {
861 $this->pageRenderer->addJsInlineCode($name, $code, FALSE);
862 }
863 if (count($this->JScodeLibArray)) {
864 GeneralUtility::deprecationLog('DocumentTemplate->JScodeLibArray is deprecated since TYPO3 CMS 7. Use the functionality within pageRenderer directly');
865 foreach ($this->JScodeLibArray as $library) {
866 $this->pageRenderer->addHeaderData($library);
867 }
868 }
869 if ($this->extJScode) {
870 $this->pageRenderer->addExtOnReadyCode($this->extJScode);
871 }
872
873 // Load jquery and twbs JS libraries on every backend request
874 $this->pageRenderer->loadJquery();
875 // Note: please do not reference "bootstrap" outside of the TYPO3 Core (not in your own extensions)
876 // as this is preliminary as long as Twitter bootstrap does not support AMD modules
877 // this logic will be changed once Twitter bootstrap 4 is included
878 $this->pageRenderer->addJsFile($this->backPath . 'sysext/core/Resources/Public/JavaScript/Contrib/bootstrap/bootstrap.js');
879
880 // hook for additional headerData
881 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'])) {
882 $preHeaderRenderHook = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['preHeaderRenderHook'];
883 if (is_array($preHeaderRenderHook)) {
884 $hookParameters = array(
885 'pageRenderer' => &$this->pageRenderer
886 );
887 foreach ($preHeaderRenderHook as $hookFunction) {
888 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $this);
889 }
890 }
891 }
892 // Construct page header.
893 $str = $this->pageRenderer->render(PageRenderer::PART_HEADER);
894 $this->JScode = ($this->extJScode = '');
895 $this->JScodeArray = array();
896 $this->endOfPageJsBlock = $this->pageRenderer->render(PageRenderer::PART_FOOTER);
897 $str .= $this->docBodyTagBegin() . ($this->divClass ? '
898
899 <!-- Wrapping DIV-section for whole page BEGIN -->
900 <div class="' . $this->divClass . '">
901 ' : '') . trim($this->form);
902 return $str;
903 }
904
905 /**
906 * Returns page end; This includes finishing form, div, body and html tags.
907 *
908 * @return string The HTML end of a page
909 * @see startPage()
910 */
911 public function endPage() {
912 $str = $this->sectionEnd() . $this->postCode . $this->wrapScriptTags(BackendUtility::getUpdateSignalCode()) . ($this->form ? '
913 </form>' : '');
914 // If something is in buffer like debug, put it to end of page
915 if (ob_get_contents()) {
916 $str .= ob_get_clean();
917 if (!headers_sent()) {
918 header('Content-Encoding: None');
919 }
920 }
921 $str .= ($this->divClass ? '
922
923 <!-- Wrapping DIV-section for whole page END -->
924 </div>' : '') . $this->endOfPageJsBlock;
925
926 // Logging: Can't find better place to put it:
927 if (TYPO3_DLOG) {
928 GeneralUtility::devLog('END of BACKEND session', \TYPO3\CMS\Backend\Template\DocumentTemplate::class, 0, array('_FLUSH' => TRUE));
929 }
930 return $str;
931 }
932
933 /**
934 * Shortcut for render the complete page of a module
935 *
936 * @param string $title page title
937 * @param string $content page content
938 * @param bool $includeCsh flag for including csh code
939 * @return string complete page
940 */
941 public function render($title, $content, $includeCsh = TRUE) {
942 $pageContent = $this->startPage($title, $includeCsh);
943 $pageContent .= $content;
944 $pageContent .= $this->endPage();
945 return $this->insertStylesAndJS($pageContent);
946 }
947
948 /**
949 * Returns the header-bar in the top of most backend modules
950 * Closes section if open.
951 *
952 * @param string $text The text string for the header
953 * @return string HTML content
954 */
955 public function header($text) {
956 $str = '
957
958 <!-- MAIN Header in page top -->
959 <h1>' . htmlspecialchars($text) . '</h1>
960 ';
961 return $this->sectionEnd() . $str;
962 }
963
964 /**
965 * Begins an output section and sets header and content
966 *
967 * @param string $label The header
968 * @param string $text The HTML-content
969 * @param bool $nostrtoupper A flag that will prevent the header from being converted to uppercase
970 * @param bool $sH Defines the type of header (if set, "<h3>" rather than the default "h4")
971 * @param int $type The number of an icon to show with the header (see the icon-function). -1,1,2,3
972 * @param bool $allowHTMLinHeader If set, HTML tags are allowed in $label (otherwise this value is by default htmlspecialchars()'ed)
973 * @return string HTML content
974 * @see icons(), sectionHeader()
975 */
976 public function section($label, $text, $nostrtoupper = FALSE, $sH = FALSE, $type = 0, $allowHTMLinHeader = FALSE) {
977 $str = '';
978 // Setting header
979 if ($label) {
980 if (!$allowHTMLinHeader) {
981 $label = htmlspecialchars($label);
982 }
983 $str .= $this->sectionHeader($this->icons($type) . $label, $sH, $nostrtoupper ? '' : ' class="uppercase"');
984 }
985 // Setting content
986 $str .= '
987
988 <!-- Section content -->
989 ' . $text;
990 return $this->sectionBegin() . $str;
991 }
992
993 /**
994 * Inserts a divider image
995 * Ends a section (if open) before inserting the image
996 *
997 * @param int $dist The margin-top/-bottom of the <hr> ruler.
998 * @return string HTML content
999 */
1000 public function divider($dist) {
1001 $dist = (int)$dist;
1002 $str = '
1003
1004 <!-- DIVIDER -->
1005 <hr style="margin-top: ' . $dist . 'px; margin-bottom: ' . $dist . 'px;" />
1006 ';
1007 return $this->sectionEnd() . $str;
1008 }
1009
1010 /**
1011 * Returns a blank <div>-section with a height
1012 *
1013 * @param int $dist Padding-top for the div-section (should be margin-top but konqueror (3.1) doesn't like it :-(
1014 * @return string HTML content
1015 */
1016 public function spacer($dist) {
1017 if ($dist > 0) {
1018 return '
1019
1020 <!-- Spacer element -->
1021 <div style="padding-top: ' . (int)$dist . 'px;"></div>
1022 ';
1023 }
1024 }
1025
1026 /**
1027 * Make a section header.
1028 * Begins a section if not already open.
1029 *
1030 * @param string $label The label between the <h3> or <h4> tags. (Allows HTML)
1031 * @param bool $sH If set, <h3> is used, otherwise <h4>
1032 * @param string $addAttrib Additional attributes to h-tag, eg. ' class=""'
1033 * @return string HTML content
1034 */
1035 public function sectionHeader($label, $sH = FALSE, $addAttrib = '') {
1036 $tag = $sH ? 'h2' : 'h3';
1037 if ($addAttrib && $addAttrib[0] !== ' ') {
1038 $addAttrib = ' ' . $addAttrib;
1039 }
1040 $str = '
1041
1042 <!-- Section header -->
1043 <' . $tag . $addAttrib . '>' . $label . '</' . $tag . '>
1044 ';
1045 return $this->sectionBegin() . $str;
1046 }
1047
1048 /**
1049 * Begins an output section.
1050 * Returns the <div>-begin tag AND sets the ->sectionFlag TRUE (if the ->sectionFlag is not already set!)
1051 * You can call this function even if a section is already begun since the function will only return something if the sectionFlag is not already set!
1052 *
1053 * @return string HTML content
1054 */
1055 public function sectionBegin() {
1056 if (!$this->sectionFlag) {
1057 $this->sectionFlag = 1;
1058 $str = '
1059
1060 <!-- ***********************
1061 Begin output section.
1062 *********************** -->
1063 <div>
1064 ';
1065 return $str;
1066 } else {
1067 return '';
1068 }
1069 }
1070
1071 /**
1072 * Ends and output section
1073 * Returns the </div>-end tag AND clears the ->sectionFlag (but does so only IF the sectionFlag is set - that is a section is 'open')
1074 * See sectionBegin() also.
1075 *
1076 * @return string HTML content
1077 */
1078 public function sectionEnd() {
1079 if ($this->sectionFlag) {
1080 $this->sectionFlag = 0;
1081 return '
1082 </div>
1083 <!-- *********************
1084 End output section.
1085 ********************* -->
1086 ';
1087 } else {
1088 return '';
1089 }
1090 }
1091
1092 /**
1093 * If a form-tag is defined in ->form then and end-tag for that <form> element is outputted
1094 * Further a JavaScript section is outputted which will update the top.busy session-expiry object (unless $this->endJS is set to FALSE)
1095 *
1096 * @return string HTML content (<script> tag section)
1097 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, nothing there to output anymore
1098 */
1099 public function endPageJS() {
1100 GeneralUtility::logDeprecatedFunction();
1101 return '';
1102 }
1103
1104 /**
1105 * Creates the bodyTag.
1106 * You can add to the bodyTag by $this->bodyTagAdditions
1107 *
1108 * @return string HTML body tag
1109 */
1110 public function docBodyTagBegin() {
1111 return '<body ' . trim(($this->bodyTagAdditions . ($this->bodyTagId ? ' id="' . $this->bodyTagId . '"' : ''))) . '>';
1112 }
1113
1114 /**
1115 * Outputting document style
1116 *
1117 * @return string HTML style section/link tags
1118 */
1119 public function docStyle() {
1120 // Implode it all:
1121 $inDocStyles = implode(LF, $this->inDocStylesArray);
1122
1123 // Reset styles so they won't be added again in insertStylesAndJS()
1124 $this->inDocStylesArray = array();
1125
1126 if ($this->styleSheetFile) {
1127 $this->pageRenderer->addCssFile($this->backPath . $this->styleSheetFile);
1128 }
1129 if ($this->styleSheetFile2) {
1130 $this->pageRenderer->addCssFile($this->backPath . $this->styleSheetFile2);
1131 }
1132
1133 if ($inDocStyles !== '') {
1134 $this->pageRenderer->addCssInlineBlock('inDocStyles', $inDocStyles . LF . '/*###POSTCSSMARKER###*/');
1135 }
1136
1137 if ($this->styleSheetFile_post) {
1138 $this->pageRenderer->addCssFile($this->backPath . $this->styleSheetFile_post);
1139 }
1140 }
1141
1142 /**
1143 * Insert additional style sheet link
1144 *
1145 * @param string $key some key identifying the style sheet
1146 * @param string $href uri to the style sheet file
1147 * @param string $title value for the title attribute of the link element
1148 * @param string $relation value for the rel attribute of the link element
1149 * @return void
1150 */
1151 public function addStyleSheet($key, $href, $title = '', $relation = 'stylesheet') {
1152 if (strpos($href, '://') !== FALSE || $href[0] === '/') {
1153 $file = $href;
1154 } else {
1155 $file = $this->backPath . $href;
1156 }
1157 $this->pageRenderer->addCssFile($file, $relation, 'screen', $title);
1158 }
1159
1160 /**
1161 * Add all *.css files of the directory $path to the stylesheets
1162 *
1163 * @param string $path directory to add
1164 * @return void
1165 */
1166 public function addStyleSheetDirectory($path) {
1167 // Calculation needed, when TYPO3 source is used via a symlink
1168 // absolute path to the stylesheets
1169 $filePath = dirname(GeneralUtility::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $path;
1170 // Clean the path
1171 $resolvedPath = GeneralUtility::resolveBackPath($filePath);
1172 // Read all files in directory and sort them alphabetically
1173 $files = GeneralUtility::getFilesInDir($resolvedPath, 'css', FALSE, 1);
1174 foreach ($files as $file) {
1175 $this->pageRenderer->addCssFile($GLOBALS['BACK_PATH'] . $path . $file, 'stylesheet', 'all');
1176 }
1177 }
1178
1179 /**
1180 * Insert post rendering document style into already rendered content
1181 * This is needed for extobjbase
1182 *
1183 * @param string $content style-content to insert.
1184 * @return string content with inserted styles
1185 */
1186 public function insertStylesAndJS($content) {
1187 $styles = LF . implode(LF, $this->inDocStylesArray);
1188 $content = str_replace('/*###POSTCSSMARKER###*/', $styles, $content);
1189
1190 // Insert accumulated JS
1191 $jscode = $this->JScode . LF . $this->wrapScriptTags(implode(LF, $this->JScodeArray));
1192 $content = str_replace('<!--###POSTJSMARKER###-->', $jscode, $content);
1193 return $content;
1194 }
1195
1196 /**
1197 * Returns an array of all stylesheet directories belonging to core and skins
1198 *
1199 * @return array Stylesheet directories
1200 */
1201 public function getSkinStylesheetDirectories() {
1202 $stylesheetDirectories = array();
1203 // Add default core stylesheets
1204 foreach ($this->stylesheetsCore as $stylesheetDir) {
1205 $stylesheetDirectories[] = $stylesheetDir;
1206 }
1207 // Stylesheets from skins
1208 // merge default css directories ($this->stylesheetsSkin) with additional ones and include them
1209 if (is_array($GLOBALS['TBE_STYLES']['skins'])) {
1210 // loop over all registered skins
1211 foreach ($GLOBALS['TBE_STYLES']['skins'] as $skinExtKey => $skin) {
1212 $skinStylesheetDirs = $this->stylesheetsSkins;
1213 // Skins can add custom stylesheetDirectories using
1214 // $GLOBALS['TBE_STYLES']['skins'][$_EXTKEY]['stylesheetDirectories']
1215 if (is_array($skin['stylesheetDirectories'])) {
1216 $skinStylesheetDirs = array_merge($skinStylesheetDirs, $skin['stylesheetDirectories']);
1217 }
1218 // Add all registered directories
1219 foreach ($skinStylesheetDirs as $stylesheetDir) {
1220 // for EXT:myskin/stylesheets/ syntax
1221 if (substr($stylesheetDir, 0, 4) === 'EXT:') {
1222 list($extKey, $path) = explode('/', substr($stylesheetDir, 4), 2);
1223 if (!empty($extKey) && ExtensionManagementUtility::isLoaded($extKey) && !empty($path)) {
1224 $stylesheetDirectories[] = ExtensionManagementUtility::extRelPath($extKey) . $path;
1225 }
1226 } else {
1227 // For relative paths
1228 $stylesheetDirectories[] = ExtensionManagementUtility::extRelPath($skinExtKey) . $stylesheetDir;
1229 }
1230 }
1231 }
1232 }
1233 return $stylesheetDirectories;
1234 }
1235
1236 /**
1237 * Returns generator meta tag
1238 *
1239 * @return string <meta> tag with name "generator
1240 */
1241 public function generator() {
1242 $str = 'TYPO3 ' . TYPO3_branch . ', ' . TYPO3_URL_GENERAL . ', &#169; Kasper Sk&#229;rh&#248;j ' . TYPO3_copyright_year . ', extensions are copyright of their respective owners.';
1243 return '<meta name="generator" content="' . $str . '" />';
1244 }
1245
1246 /**
1247 * Returns X-UA-Compatible meta tag
1248 *
1249 * @param string $content Content of the compatible tag (default: IE-8)
1250 * @return string <meta http-equiv="X-UA-Compatible" content="???" />
1251 */
1252 public function xUaCompatible($content = 'IE=8') {
1253 return '<meta http-equiv="X-UA-Compatible" content="' . $content . '" />';
1254 }
1255
1256 /*****************************************
1257 *
1258 * OTHER ELEMENTS
1259 * Tables, buttons, formatting dimmed/red strings
1260 *
1261 ******************************************/
1262 /**
1263 * Returns an image-tag with an 18x16 icon of the following types:
1264 *
1265 * $type:
1266 * -1: OK icon (Check-mark)
1267 * 1: Notice (Speach-bubble)
1268 * 2: Warning (Yellow triangle)
1269 * 3: Fatal error (Red stop sign)
1270 *
1271 * @param int $type See description
1272 * @param string $styleAttribValue Value for style attribute
1273 * @return string HTML image tag (if applicable)
1274 */
1275 public function icons($type, $styleAttribValue = '') {
1276 switch ($type) {
1277 case self::STATUS_ICON_ERROR:
1278 $icon = 'status-dialog-error';
1279 break;
1280 case self::STATUS_ICON_WARNING:
1281 $icon = 'status-dialog-warning';
1282 break;
1283 case self::STATUS_ICON_NOTIFICATION:
1284 $icon = 'status-dialog-notification';
1285 break;
1286 case self::STATUS_ICON_OK:
1287 $icon = 'status-dialog-ok';
1288 break;
1289 default:
1290 // Do nothing
1291 }
1292 if ($icon) {
1293 return IconUtility::getSpriteIcon($icon);
1294 }
1295 }
1296
1297 /**
1298 * Returns an <input> button with the $onClick action and $label
1299 *
1300 * @param string $onClick The value of the onclick attribute of the input tag (submit type)
1301 * @param string $label The label for the button (which will be htmlspecialchar'ed)
1302 * @return string A <input> tag of the type "submit
1303 */
1304 public function t3Button($onClick, $label) {
1305 $button = '<input class="btn btn-default" type="submit" onclick="' . htmlspecialchars($onClick) . '; return false;" value="' . htmlspecialchars($label) . '" />';
1306 return $button;
1307 }
1308
1309 /**
1310 * Dimmed-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be gray/dimmed
1311 *
1312 * @param string $string Input string
1313 * @return string Output string
1314 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use proper HTML directly
1315 */
1316 public function dfw($string) {
1317 GeneralUtility::logDeprecatedFunction();
1318 return '<span class="text-muted">' . $string . '</span>';
1319 }
1320
1321 /**
1322 * red-fontwrap. Returns the string wrapped in a <span>-tag defining the color to be red
1323 *
1324 * @param string $string Input string
1325 * @return string Output string
1326 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8, use proper HTML directly
1327 */
1328 public function rfw($string) {
1329 GeneralUtility::logDeprecatedFunction();
1330 return '<span class="text-danger">' . $string . '</span>';
1331 }
1332
1333 /**
1334 * Returns string wrapped in CDATA "tags" for XML / XHTML (wrap content of <script> and <style> sections in those!)
1335 *
1336 * @param string $string Input string
1337 * @return string Output string
1338 */
1339 public function wrapInCData($string) {
1340 $string = '/*<![CDATA[*/' . $string . '/*]]>*/';
1341 return $string;
1342 }
1343
1344 /**
1345 * Wraps the input string in script tags.
1346 * Automatic re-identing of the JS code is done by using the first line as ident reference.
1347 * This is nice for identing JS code with PHP code on the same level.
1348 *
1349 * @param string $string Input string
1350 * @param bool $linebreak Wrap script element in linebreaks? Default is TRUE.
1351 * @return string Output string
1352 */
1353 public function wrapScriptTags($string, $linebreak = TRUE) {
1354 if (trim($string)) {
1355 // <script wrapped in nl?
1356 $cr = $linebreak ? LF : '';
1357 // Remove nl from the beginning
1358 $string = ltrim($string, LF);
1359 // Re-ident to one tab using the first line as reference
1360 if ($string[0] === TAB) {
1361 $string = TAB . ltrim($string, TAB);
1362 }
1363 $string = $cr . '<script type="text/javascript">
1364 /*<![CDATA[*/
1365 ' . $string . '
1366 /*]]>*/
1367 </script>' . $cr;
1368 }
1369 return trim($string);
1370 }
1371
1372 // These vars defines the layout for the table produced by the table() function.
1373 // You can override these values from outside if you like.
1374 public $tableLayout = array(
1375 'defRow' => array(
1376 'defCol' => array('<td valign="top">', '</td>')
1377 )
1378 );
1379
1380 public $table_TR = '<tr>';
1381
1382 public $table_TABLE = '<table border="0" cellspacing="0" cellpadding="0" class="typo3-dblist" id="typo3-tmpltable">';
1383
1384 /**
1385 * Returns a table based on the input $data
1386 *
1387 * @param array $data Multidim array with first levels = rows, second levels = cells
1388 * @param array $layout If set, then this provides an alternative layout array instead of $this->tableLayout
1389 * @return string The HTML table.
1390 * @internal
1391 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1392 */
1393 public function table($data, $layout = NULL) {
1394 GeneralUtility::logDeprecatedFunction();
1395 $result = '';
1396 if (is_array($data)) {
1397 $tableLayout = is_array($layout) ? $layout : $this->tableLayout;
1398 $rowCount = 0;
1399 foreach ($data as $tableRow) {
1400 if ($rowCount % 2) {
1401 $layout = is_array($tableLayout['defRowOdd']) ? $tableLayout['defRowOdd'] : $tableLayout['defRow'];
1402 } else {
1403 $layout = is_array($tableLayout['defRowEven']) ? $tableLayout['defRowEven'] : $tableLayout['defRow'];
1404 }
1405 $rowLayout = is_array($tableLayout[$rowCount]) ? $tableLayout[$rowCount] : $layout;
1406 $rowResult = '';
1407 if (is_array($tableRow)) {
1408 $cellCount = 0;
1409 foreach ($tableRow as $tableCell) {
1410 $cellWrap = is_array($layout[$cellCount]) ? $layout[$cellCount] : $layout['defCol'];
1411 $cellWrap = is_array($rowLayout['defCol']) ? $rowLayout['defCol'] : $cellWrap;
1412 $cellWrap = is_array($rowLayout[$cellCount]) ? $rowLayout[$cellCount] : $cellWrap;
1413 $rowResult .= $cellWrap[0] . $tableCell . $cellWrap[1];
1414 $cellCount++;
1415 }
1416 }
1417 $rowWrap = is_array($layout['tr']) ? $layout['tr'] : array($this->table_TR, '</tr>');
1418 $rowWrap = is_array($rowLayout['tr']) ? $rowLayout['tr'] : $rowWrap;
1419 $result .= $rowWrap[0] . $rowResult . $rowWrap[1];
1420 $rowCount++;
1421 }
1422 $tableWrap = is_array($tableLayout['table']) ? $tableLayout['table'] : array($this->table_TABLE, '</table>');
1423 $result = $tableWrap[0] . $result . $tableWrap[1];
1424 }
1425 return $result;
1426 }
1427
1428 /**
1429 * Constructs a table with content from the $arr1, $arr2 and $arr3.
1430 *
1431 * @param array $arr1 Menu elements on first level
1432 * @param array $arr2 Secondary items
1433 * @param array $arr3 Third-level items
1434 * @return string HTML content, <table>...</table>
1435 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1436 */
1437 public function menuTable($arr1, $arr2 = array(), $arr3 = array()) {
1438 GeneralUtility::logDeprecatedFunction();
1439 $rows = max(array(count($arr1), count($arr2), count($arr3)));
1440 $menu = '
1441 <table border="0" cellpadding="0" cellspacing="0" id="typo3-tablemenu">';
1442 for ($a = 0; $a < $rows; $a++) {
1443 $menu .= '<tr>';
1444 $cls = array();
1445 $valign = 'middle';
1446 $cls[] = '<td valign="' . $valign . '">' . $arr1[$a][0] . '</td><td>' . $arr1[$a][1] . '</td>';
1447 if (count($arr2)) {
1448 $cls[] = '<td valign="' . $valign . '">' . $arr2[$a][0] . '</td><td>' . $arr2[$a][1] . '</td>';
1449 if (count($arr3)) {
1450 $cls[] = '<td valign="' . $valign . '">' . $arr3[$a][0] . '</td><td>' . $arr3[$a][1] . '</td>';
1451 }
1452 }
1453 $menu .= implode($cls, '<td>&nbsp;&nbsp;</td>');
1454 $menu .= '</tr>';
1455 }
1456 $menu .= '
1457 </table>
1458 ';
1459 return $menu;
1460 }
1461
1462 /**
1463 * Returns a one-row/two-celled table with $content and $menu side by side.
1464 * The table is a 100% width table and each cell is aligned left / right
1465 *
1466 * @param string $content Content cell content (left)
1467 * @param string $menu Menu cell content (right)
1468 * @return string HTML output
1469 */
1470 public function funcMenu($content, $menu) {
1471 return '
1472 <table border="0" cellpadding="0" cellspacing="0" width="100%" id="typo3-funcmenu">
1473 <tr>
1474 <td valign="top" nowrap="nowrap">' . $content . '</td>
1475 <td valign="top" align="right" nowrap="nowrap">' . $menu . '</td>
1476 </tr>
1477 </table>';
1478 }
1479
1480 /**
1481 * Includes a javascript library that exists in the core /typo3/ directory. The
1482 * backpath is automatically applied
1483 *
1484 * @param string $lib: Library name. Call it with the full path like "contrib/prototype/prototype.js" to load it
1485 * @return void
1486 */
1487 public function loadJavascriptLib($lib) {
1488 $this->pageRenderer->addJsFile($this->backPath . $lib);
1489 }
1490
1491 /**
1492 * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document
1493 *
1494 * @return void
1495 */
1496 public function getContextMenuCode() {
1497 $this->pageRenderer->loadJquery();
1498 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ClickMenu');
1499 }
1500
1501 /**
1502 * Includes the necessary javascript file for use on pages which have the
1503 * drag and drop functionality (legacy folder tree)
1504 *
1505 * @param string $table indicator of which table the drag and drop function should work on (pages or folders)
1506 * @param string $additionalJavaScriptCode adds more code to the additional javascript code
1507 * @return void
1508 */
1509 public function getDragDropCode($table, $additionalJavaScriptCode = '') {
1510 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function() {
1511 DragDrop.table = "' . $table . '";
1512 ' . $additionalJavaScriptCode . '
1513 }');
1514 }
1515
1516 /**
1517 * This loads everything needed for the Context Sensitive Help (CSH)
1518 *
1519 * @return void
1520 */
1521 protected function loadCshJavascript() {
1522 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
1523 $this->pageRenderer->addInlineSetting('ContextHelp', 'moduleUrl', BackendUtility::getModuleUrl('help_cshmanual'));
1524 }
1525
1526 /**
1527 * Creates a tab menu from an array definition
1528 *
1529 * Returns a tab menu for a module
1530 * Requires the JS function jumpToUrl() to be available
1531 *
1532 * @param mixed $mainParams is the "&id=" parameter value to be sent to the module, but it can be also a parameter array which will be passed instead of the &id=...
1533 * @param string $elementName it the form elements name, probably something like "SET[...]
1534 * @param string $currentValue is the value to be selected currently.
1535 * @param array $menuItems is an array with the menu items for the selector box
1536 * @param string $script is the script to send the &id to, if empty it's automatically found
1537 * @param string $addparams is additional parameters to pass to the script.
1538 * @return string HTML code for tab menu
1539 */
1540 public function getTabMenu($mainParams, $elementName, $currentValue, $menuItems, $script = '', $addparams = '') {
1541 $content = '';
1542 if (is_array($menuItems)) {
1543 if (!is_array($mainParams)) {
1544 $mainParams = array('id' => $mainParams);
1545 }
1546 $mainParams = GeneralUtility::implodeArrayForUrl('', $mainParams);
1547 if (!$script) {
1548 $script = basename(PATH_thisScript);
1549 }
1550 $menuDef = array();
1551 foreach ($menuItems as $value => $label) {
1552 $menuDef[$value]['isActive'] = (string)$currentValue === (string)$value;
1553 $menuDef[$value]['label'] = htmlspecialchars($label, ENT_COMPAT, 'UTF-8', FALSE);
1554 $menuDef[$value]['url'] = $script . '?' . $mainParams . $addparams . '&' . $elementName . '=' . $value;
1555 }
1556 $content = $this->getTabMenuRaw($menuDef);
1557 }
1558 return $content;
1559 }
1560
1561 /**
1562 * Creates the HTML content for the tab menu
1563 *
1564 * @param array $menuItems Menu items for tabs
1565 * @return string Table HTML
1566 * @access private
1567 */
1568 public function getTabMenuRaw($menuItems) {
1569 if (!is_array($menuItems)) {
1570 return '';
1571 }
1572
1573 $options = '';
1574 foreach ($menuItems as $id => $def) {
1575 $class = $def['isActive'] ? 'active' : '';
1576 $label = $def['label'];
1577 $url = htmlspecialchars($def['url']);
1578 $params = $def['addParams'];
1579
1580 $options .= '<li class="' . $class . '">' .
1581 '<a href="' . $url . '" ' . $params . '>' . $label . '</a>' .
1582 '</li>';
1583 }
1584
1585 return '<ul class="nav nav-tabs" role="tablist">' .
1586 $options .
1587 '</ul>';
1588
1589 }
1590
1591 /**
1592 * Creates a DYNAMIC tab-menu where the tabs or collapseable are rendered with bootstrap markup
1593 *
1594 * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
1595 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1596 * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open.
1597 * @param bool $collapseable If set, the tabs are rendered as headers instead over each sheet. Effectively this means there is no tab menu, but rather a foldout/foldin menu.
1598 * @param bool $wrapContent If set, the content is wrapped in div structure which provides a padding and border style. Set this FALSE to get unstyled content pane with fullsize content area.
1599 * @param bool $storeLastActiveTab If set, the last open tab is stored in local storage and will be re-open again. If you don't need this feature, e.g. for wizards like import/export you can disable this behaviour.
1600 * @return string
1601 */
1602 public function getDynamicTabMenu(array $menuItems, $identString, $defaultTabIndex = 1, $collapseable = FALSE, $wrapContent = TRUE, $storeLastActiveTab = TRUE) {
1603 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/Tabs');
1604 $templatePathAndFileName = 'EXT:backend/Resources/Private/Templates/DocumentTemplate/' . ($collapseable ? 'Collapse.html' : 'Tabs.html');
1605 $view = GeneralUtility::makeInstance(StandaloneView::class);
1606 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($templatePathAndFileName));
1607 $view->assignMultiple(array(
1608 'id' => $this->getDynTabMenuId($identString),
1609 'items' => $menuItems,
1610 'defaultTabIndex' => $defaultTabIndex,
1611 'wrapContent' => $wrapContent,
1612 'storeLastActiveTab' => $storeLastActiveTab,
1613 'BACK_PATH' => $GLOBALS['BACK_PATH']
1614 ));
1615 return $view->render();
1616 }
1617
1618 /**
1619 * Creates a DYNAMIC tab-menu where the tabs are switched between with DHTML.
1620 * Should work in MSIE, Mozilla, Opera and Konqueror. On Konqueror I did find a serious problem: <textarea> fields loose their content when you switch tabs!
1621 *
1622 * @param array $menuItems Numeric array where each entry is an array in itself with associative keys: "label" contains the label for the TAB, "content" contains the HTML content that goes into the div-layer of the tabs content. "description" contains description text to be shown in the layer. "linkTitle" is short text for the title attribute of the tab-menu link (mouse-over text of tab). "stateIcon" indicates a standard status icon (see ->icon(), values: -1, 1, 2, 3). "icon" is an image tag placed before the text.
1623 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1624 * @param int $toggle If "1", then enabling one tab does not hide the others - they simply toggles each sheet on/off. This makes most sense together with the $foldout option. If "-1" then it acts normally where only one tab can be active at a time BUT you can click a tab and it will close so you have no active tabs.
1625 * @param bool $foldout If set, the tabs are rendered as headers instead over each sheet. Effectively this means there is no tab menu, but rather a foldout/foldin menu. Make sure to set $toggle as well for this option.
1626 * @param bool $noWrap Deprecated - delivered by CSS
1627 * @param bool $fullWidth If set, the tabs will span the full width of their position
1628 * @param int $defaultTabIndex Default tab to open (for toggle <=0). Value corresponds to integer-array index + 1 (index zero is "1", index "1" is 2 etc.). A value of zero (or something non-existing) will result in no default tab open.
1629 * @param int $tabBehaviour If set to '1' empty tabs will be remove, If set to '2' empty tabs will be disabled. setting this option to '2' is deprecated since TYPO3 CMS 7, and will be removed iwth CMS 8
1630 * @return string JavaScript section for the HTML header.
1631 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
1632 */
1633 public function getDynTabMenu($menuItems, $identString, $toggle = 0, $foldout = FALSE, $noWrap = TRUE, $fullWidth = FALSE, $defaultTabIndex = 1, $tabBehaviour = 1) {
1634 GeneralUtility::logDeprecatedFunction();
1635 return $this->getDynamicTabMenu($menuItems, $identString, $defaultTabIndex, $foldout, $noWrap);
1636 }
1637
1638 /**
1639 * Creates the id for dynTabMenus.
1640 *
1641 * @param string $identString Identification string. This should be unique for every instance of a dynamic menu!
1642 * @return string The id with a short MD5 of $identString and prefixed "DTM-", like "DTM-2e8791854a
1643 */
1644 public function getDynTabMenuId($identString) {
1645 $id = 'DTM-' . GeneralUtility::shortMD5($identString);
1646 return $id;
1647 }
1648
1649 /**
1650 * Creates the version selector for the page id inputted.
1651 * Requires the core version management extension, "version" to be loaded.
1652 *
1653 * @param int $id Page id to create selector for.
1654 * @param bool $noAction If set, there will be no button for swapping page.
1655 * @return string
1656 */
1657 public function getVersionSelector($id, $noAction = FALSE) {
1658 if (
1659 ExtensionManagementUtility::isLoaded('version') &&
1660 !ExtensionManagementUtility::isLoaded('workspaces')
1661 ) {
1662 $versionGuiObj = GeneralUtility::makeInstance(\TYPO3\CMS\Version\View\VersionView::class);
1663 return $versionGuiObj->getVersionSelector($id, $noAction);
1664 }
1665 }
1666
1667 /**
1668 * Function to load a HTML template file with markers.
1669 * When calling from own extension, use syntax getHtmlTemplate('EXT:extkey/template.html')
1670 *
1671 * @param string $filename tmpl name, usually in the typo3/template/ directory
1672 * @return string HTML of template
1673 */
1674 public function getHtmlTemplate($filename) {
1675 // setting the name of the original HTML template
1676 $this->moduleTemplateFilename = $filename;
1677 if ($GLOBALS['TBE_STYLES']['htmlTemplates'][$filename]) {
1678 $filename = $GLOBALS['TBE_STYLES']['htmlTemplates'][$filename];
1679 }
1680 if (GeneralUtility::isFirstPartOfStr($filename, 'EXT:')) {
1681 $filename = GeneralUtility::getFileAbsFileName($filename, TRUE, TRUE);
1682 } elseif (!GeneralUtility::isAbsPath($filename)) {
1683 $filename = GeneralUtility::resolveBackPath($this->backPath . $filename);
1684 } elseif (!GeneralUtility::isAllowedAbsPath($filename)) {
1685 $filename = '';
1686 }
1687 $htmlTemplate = '';
1688 if ($filename !== '') {
1689 $htmlTemplate = GeneralUtility::getUrl($filename);
1690 }
1691 return $htmlTemplate;
1692 }
1693
1694 /**
1695 * Define the template for the module
1696 *
1697 * @param string $filename filename
1698 * @return void
1699 */
1700 public function setModuleTemplate($filename) {
1701 $this->moduleTemplate = $this->getHtmlTemplate($filename);
1702 }
1703
1704 /**
1705 * Put together the various elements for the module <body> using a static HTML
1706 * template
1707 *
1708 * @param array $pageRecord Record of the current page, used for page path and info
1709 * @param array $buttons HTML for all buttons
1710 * @param array $markerArray HTML for all other markers
1711 * @param array $subpartArray HTML for the subparts
1712 * @return string Composite HTML
1713 */
1714 public function moduleBody($pageRecord = array(), $buttons = array(), $markerArray = array(), $subpartArray = array()) {
1715 // Get the HTML template for the module
1716 $moduleBody = HtmlParser::getSubpart($this->moduleTemplate, '###FULLDOC###');
1717 // Add CSS
1718 $this->inDocStylesArray[] = 'html { overflow: hidden; }';
1719 // Get the page path for the docheader
1720 $markerArray['PAGEPATH'] = $this->getPagePath($pageRecord);
1721 // Get the page info for the docheader
1722 $markerArray['PAGEINFO'] = $this->getPageInfo($pageRecord);
1723 // Get all the buttons for the docheader
1724 $docHeaderButtons = $this->getDocHeaderButtons($buttons);
1725 // Merge docheader buttons with the marker array
1726 $markerArray = array_merge($markerArray, $docHeaderButtons);
1727 // replacing subparts
1728 foreach ($subpartArray as $marker => $content) {
1729 $moduleBody = HtmlParser::substituteSubpart($moduleBody, $marker, $content);
1730 }
1731 // adding flash messages
1732 if ($this->showFlashMessages) {
1733 $flashMessages = $this->getFlashMessages();
1734 if (!empty($flashMessages)) {
1735 $markerArray['FLASHMESSAGES'] = $flashMessages;
1736 // If there is no dedicated marker for the messages present
1737 // then force them to appear before the content
1738 if (strpos($moduleBody, '###FLASHMESSAGES###') === FALSE) {
1739 $moduleBody = str_replace('###CONTENT###', '###FLASHMESSAGES######CONTENT###', $moduleBody);
1740 }
1741 }
1742 }
1743 // Hook for adding more markers/content to the page, like the version selector
1744 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'])) {
1745 $params = array(
1746 'moduleTemplateFilename' => &$this->moduleTemplateFilename,
1747 'moduleTemplate' => &$this->moduleTemplate,
1748 'moduleBody' => &$moduleBody,
1749 'markers' => &$markerArray,
1750 'parentObject' => &$this
1751 );
1752 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['moduleBodyPostProcess'] as $funcRef) {
1753 GeneralUtility::callUserFunction($funcRef, $params, $this);
1754 }
1755 }
1756 // Replacing all markers with the finished markers and return the HTML content
1757 return HtmlParser::substituteMarkerArray($moduleBody, $markerArray, '###|###');
1758 }
1759
1760 /**
1761 * Get the default rendered FlashMessages from queue
1762 *
1763 * @return string
1764 */
1765 public function getFlashMessages() {
1766 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
1767 $flashMessageService = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Messaging\FlashMessageService::class);
1768 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
1769 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
1770 $flashMessages = $defaultFlashMessageQueue->renderFlashMessages();
1771 if (!empty($flashMessages)) {
1772 $flashMessages = '<div id="typo3-messages">' . $flashMessages . '</div>';
1773 }
1774 return $flashMessages;
1775 }
1776
1777 /**
1778 * Renders the FlashMessages from queue and returns them as AJAX.
1779 *
1780 * @param array $params Always empty.
1781 * @param \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj The AjaxRequestHandler object used to return content and set content types
1782 * @return void
1783 */
1784 public function renderFlashMessages(array $params, \TYPO3\CMS\Core\Http\AjaxRequestHandler $ajaxObj) {
1785 $ajaxObj->addContent('result', $this->getFlashMessages());
1786 $ajaxObj->setContentFormat('html');
1787 }
1788
1789 /**
1790 * Fill the button lists with the defined HTML
1791 *
1792 * @param array $buttons HTML for all buttons
1793 * @return array Containing HTML for both buttonlists
1794 */
1795 protected function getDocHeaderButtons($buttons) {
1796 $markers = array();
1797 // Fill buttons for left and right float
1798 $floats = array('left', 'right');
1799 foreach ($floats as $key) {
1800 // Get the template for each float
1801 $buttonTemplate = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUPS_' . strtoupper($key) . '###');
1802 // Fill the button markers in this float
1803 $buttonTemplate = HtmlParser::substituteMarkerArray($buttonTemplate, $buttons, '###|###', TRUE);
1804 // getting the wrap for each group
1805 $buttonWrap = HtmlParser::getSubpart($this->moduleTemplate, '###BUTTON_GROUP_WRAP###');
1806 // looping through the groups (max 6) and remove the empty groups
1807 for ($groupNumber = 1; $groupNumber < 6; $groupNumber++) {
1808 $buttonMarker = '###BUTTON_GROUP' . $groupNumber . '###';
1809 $buttonGroup = HtmlParser::getSubpart($buttonTemplate, $buttonMarker);
1810 if (trim($buttonGroup)) {
1811 if ($buttonWrap) {
1812 $buttonGroup = HtmlParser::substituteMarker($buttonWrap, '###BUTTONS###', $buttonGroup);
1813 }
1814 $buttonTemplate = HtmlParser::substituteSubpart($buttonTemplate, $buttonMarker, trim($buttonGroup));
1815 }
1816 }
1817 // Replace the marker with the template and remove all line breaks (for IE compat)
1818 $markers['BUTTONLIST_' . strtoupper($key)] = str_replace(LF, '', $buttonTemplate);
1819 }
1820 // Hook for manipulating docHeaderButtons
1821 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'])) {
1822 $params = array(
1823 'buttons' => $buttons,
1824 'markers' => &$markers,
1825 'pObj' => &$this
1826 );
1827 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/template.php']['docHeaderButtonsHook'] as $funcRef) {
1828 GeneralUtility::callUserFunction($funcRef, $params, $this);
1829 }
1830 }
1831 return $markers;
1832 }
1833
1834 /**
1835 * Generate the page path for docheader
1836 *
1837 * @param array $pageRecord Current page
1838 * @return string Page path
1839 */
1840 protected function getPagePath($pageRecord) {
1841 // Is this a real page
1842 if (is_array($pageRecord) && $pageRecord['uid']) {
1843 $title = substr($pageRecord['_thePathFull'], 0, -1);
1844 // Remove current page title
1845 $pos = strrpos($title, $pageRecord['title']);
1846 if ($pos !== FALSE) {
1847 $title = substr($title, 0, $pos);
1848 }
1849 } else {
1850 $title = '';
1851 }
1852 // Setting the path of the page
1853 $pagePath = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.path', TRUE) . ': <span class="typo3-docheader-pagePath">';
1854 // crop the title to title limit (or 50, if not defined)
1855 $cropLength = empty($GLOBALS['BE_USER']->uc['titleLen']) ? 50 : $GLOBALS['BE_USER']->uc['titleLen'];
1856 $croppedTitle = GeneralUtility::fixed_lgd_cs($title, -$cropLength);
1857 if ($croppedTitle !== $title) {
1858 $pagePath .= '<abbr title="' . htmlspecialchars($title) . '">' . htmlspecialchars($croppedTitle) . '</abbr>';
1859 } else {
1860 $pagePath .= htmlspecialchars($title);
1861 }
1862 $pagePath .= '</span>';
1863 return $pagePath;
1864 }
1865
1866 /**
1867 * Setting page icon with clickmenu + uid for docheader
1868 *
1869 * @param array $pageRecord Current page
1870 * @return string Page info
1871 */
1872 protected function getPageInfo($pageRecord) {
1873 // Add icon with clickmenu, etc:
1874 // If there IS a real page
1875 if (is_array($pageRecord) && $pageRecord['uid']) {
1876 $alttext = BackendUtility::getRecordIconAltText($pageRecord, 'pages');
1877 $iconImg = IconUtility::getSpriteIconForRecord('pages', $pageRecord, array('title' => $alttext));
1878 // Make Icon:
1879 $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, 'pages', $pageRecord['uid']);
1880 $uid = $pageRecord['uid'];
1881 $title = BackendUtility::getRecordTitle('pages', $pageRecord);
1882 } else {
1883 // On root-level of page tree
1884 // Make Icon
1885 $iconImg = IconUtility::getSpriteIcon('apps-pagetree-root', array('title' => htmlspecialchars($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'])));
1886 if ($GLOBALS['BE_USER']->user['admin']) {
1887 $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($iconImg, 'pages', 0);
1888 } else {
1889 $theIcon = $iconImg;
1890 }
1891 $uid = '0';
1892 $title = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
1893 }
1894 // Setting icon with clickmenu + uid
1895 $pageInfo = $theIcon . '<strong>' . htmlspecialchars($title) . '&nbsp;[' . $uid . ']</strong>';
1896 return $pageInfo;
1897 }
1898
1899 /**
1900 * Makes a collapseable section. See reports module for an example
1901 *
1902 * @param string $title
1903 * @param string $html
1904 * @param string $id
1905 * @param string $saveStatePointer
1906 * @return string
1907 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. Use HTML bootstrap classes, localStorage etc.
1908 */
1909 public function collapseableSection($title, $html, $id, $saveStatePointer = '') {
1910 GeneralUtility::logDeprecatedFunction();
1911 $hasSave = $saveStatePointer ? TRUE : FALSE;
1912 $collapsedStyle = ($collapsedClass = '');
1913 if ($hasSave) {
1914 /** @var $settings \TYPO3\CMS\Backend\User\ExtDirect\BackendUserSettingsDataProvider */
1915 $settings = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\User\ExtDirect\BackendUserSettingsDataProvider::class);
1916 $value = $settings->get($saveStatePointer . '.' . $id);
1917 if ($value) {
1918 $collapsedStyle = ' style="display: none"';
1919 $collapsedClass = ' collapsed';
1920 } else {
1921 $collapsedStyle = '';
1922 $collapsedClass = ' expanded';
1923 }
1924 }
1925 $this->pageRenderer->loadExtJS();
1926 $this->pageRenderer->addExtOnReadyCode('
1927 Ext.select("h2.section-header").each(function(element){
1928 element.on("click", function(event, tag) {
1929 var state = 0,
1930 el = Ext.fly(tag),
1931 div = el.next("div"),
1932 saveKey = el.getAttribute("rel");
1933 if (el.hasClass("collapsed")) {
1934 el.removeClass("collapsed").addClass("expanded");
1935 div.slideIn("t", {
1936 easing: "easeIn",
1937 duration: .5
1938 });
1939 } else {
1940 el.removeClass("expanded").addClass("collapsed");
1941 div.slideOut("t", {
1942 easing: "easeOut",
1943 duration: .5,
1944 remove: false,
1945 useDisplay: true
1946 });
1947 state = 1;
1948 }
1949 if (saveKey) {
1950 try {
1951 top.TYPO3.BackendUserSettings.ExtDirect.set(saveKey + "." + tag.id, state, function(response) {});
1952 } catch(e) {}
1953 }
1954 });
1955 });
1956 ');
1957 return '
1958 <h2 id="' . $id . '" class="section-header' . $collapsedClass . '" rel="' . $saveStatePointer . '"> ' . $title . '</h2>
1959 <div' . $collapsedStyle . '>' . $html . '</div>
1960 ';
1961 }
1962
1963 /**
1964 * Retrieves configured favicon for backend (with fallback)
1965 *
1966 * @return string
1967 */
1968 protected function getBackendFavicon() {
1969 return IconUtility::skinImg($this->backPath, 'gfx/favicon.ico', '', 1);
1970 }
1971
1972 }