206100b0da07da6f3833537cb5a212449f16b899
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / Menu / JavaScriptMenuContentObject.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject\Menu;
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\Core\Utility\MathUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\ArrayUtility;
20
21 /**
22 * JavaScript/Selectorbox based menus
23 *
24 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
25 */
26 class JavaScriptMenuContentObject extends AbstractMenuContentObject {
27
28 /**
29 * @var int
30 */
31 public $levels = 0;
32
33 /**
34 * @var string
35 */
36 public $JSVarName = '';
37
38 /**
39 * @var string
40 */
41 public $JSMenuName = '';
42
43 /**
44 * Creates the HTML (mixture of a <form> and a JavaScript section) for the JavaScript menu (basically an array of selector boxes with onchange handlers)
45 *
46 * @return string The HTML code for the menu
47 */
48 public function writeMenu() {
49 if (!$this->id) {
50 return '';
51 }
52
53 $levels = MathUtility::forceIntegerInRange($this->mconf['levels'], 1, 5);
54 $this->levels = $levels;
55 $uniqueParam = GeneralUtility::shortMD5(microtime(), 5);
56 $this->JSVarName = 'eid' . $uniqueParam;
57 $this->JSMenuName = $this->mconf['menuName'] ?: 'JSmenu' . $uniqueParam;
58 $JScode = '
59 var ' . $this->JSMenuName . ' = new JSmenu(' . $levels . ', \'' . $this->JSMenuName . 'Form\');';
60 for ($a = 1; $a <= $levels; $a++) {
61 $JScode .= '
62 var ' . $this->JSVarName . $a . '=0;';
63 }
64 $JScode .= $this->generate_level($levels, 1, $this->id, $this->menuArr, $this->MP_array) . LF;
65 $GLOBALS['TSFE']->additionalHeaderData['JSMenuCode'] = '<script type="text/javascript" src="' . $GLOBALS['TSFE']->absRefPrefix . 'typo3/sysext/frontend/Resources/Public/JavaScript/jsfunc.menu.js"></script>';
66 $GLOBALS['TSFE']->additionalJavaScript['JSCode'] .= $JScode;
67 // Printing:
68 $allFormCode = '';
69 for ($a = 1; $a <= $this->levels; $a++) {
70 $formCode = '';
71 $levelConf = $this->mconf[$a . '.'];
72 $length = $levelConf['width'] ?: 14;
73 $lengthStr = '';
74 for ($b = 0; $b < $length; $b++) {
75 $lengthStr .= '_';
76 }
77 $height = $levelConf['elements'] ?: 5;
78 $formCode .= '<select name="selector' . $a . '" onchange="' . $this->JSMenuName . '.act(' . $a . ');"' . ($levelConf['additionalParams'] ? ' ' . $levelConf['additionalParams'] : '') . '>';
79 for ($b = 0; $b < $height; $b++) {
80 $formCode .= '<option value="0">';
81 if ($b === 0) {
82 $formCode .= $lengthStr;
83 }
84 $formCode .= '</option>';
85 }
86 $formCode .= '</select>';
87 $allFormCode .= $this->WMcObj->wrap($formCode, $levelConf['wrap']);
88 }
89 $formContent = $this->WMcObj->wrap($allFormCode, $this->mconf['wrap']);
90 $formCode = '<form action="" method="post" style="margin: 0 0 0 0;" name="' . $this->JSMenuName . 'Form">' . $formContent . '</form>';
91 $formCode .= '<script type="text/javascript"> /*<![CDATA[*/ ' . $this->JSMenuName . '.writeOut(1,' . $this->JSMenuName . '.openID,1); /*]]>*/ </script>';
92 return $this->WMcObj->wrap($formCode, $this->mconf['wrapAfterTags']);
93 }
94
95 /**
96 * Generates a number of lines of JavaScript code for a menu level.
97 * Calls itself recursively for additional levels.
98 *
99 * @param int $levels Number of levels to generate
100 * @param int $count Current level being generated - and if this number is less than $levels it will call itself recursively with $count incremented
101 * @param int $pid Page id of the starting point.
102 * @param array|string $menuItemArray $this->menuArr passed along
103 * @param array $MP_array Previous MP vars
104 * @return string JavaScript code lines.
105 * @access private
106 */
107 public function generate_level($levels, $count, $pid, $menuItemArray = '', $MP_array = array()) {
108 $count = (int)$count;
109 $levelConf = $this->mconf[$count . '.'];
110 // Translate PID to a mount page, if any:
111 $mount_info = $this->sys_page->getMountPointInfo($pid);
112 if (is_array($mount_info)) {
113 $MP_array[] = $mount_info['MPvar'];
114 $pid = $mount_info['mount_pid'];
115 }
116 // UIDs to ban:
117 $banUidArray = $this->getBannedUids();
118 // Initializing variables:
119 $var = $this->JSVarName;
120 $menuName = $this->JSMenuName;
121 $parent = $count === 1 ? 0 : $var . ($count - 1);
122 $prev = 0;
123 $c = 0;
124 $codeLines = '';
125 $menuItems = is_array($menuItemArray) ? $menuItemArray : $this->sys_page->getMenu($pid);
126 foreach ($menuItems as $uid => $data) {
127 // $data['_MP_PARAM'] contains MP param for overlay mount points (MPs with "substitute this page" set)
128 // if present: add param to copy of MP array (copy used for that submenu branch only)
129 $MP_array_sub = $MP_array;
130 if (array_key_exists('_MP_PARAM', $data) && $data['_MP_PARAM']) {
131 $MP_array_sub[] = $data['_MP_PARAM'];
132 }
133 // Set "&MP=" var:
134 $MP_var = implode(',', $MP_array_sub);
135 $MP_params = $MP_var ? '&MP=' . rawurlencode($MP_var) : '';
136 // If item is a spacer, $spacer is set
137 $spacer = GeneralUtility::inList($this->spacerIDList, $data['doktype']) ? 1 : 0;
138 // If the spacer-function is not enabled, spacers will not enter the $menuArr
139 if ($this->mconf['SPC'] || !$spacer) {
140 // Page may not be 'not_in_menu' or 'Backend User Section' + not in banned uid's
141 if (!GeneralUtility::inList($this->doktypeExcludeList, $data['doktype']) && (!$data['nav_hide'] || $this->conf['includeNotInMenu']) && !ArrayUtility::inArray($banUidArray, $uid)) {
142 if ($count < $levels) {
143 $addLines = $this->generate_level($levels, $count + 1, $data['uid'], '', $MP_array_sub);
144 } else {
145 $addLines = '';
146 }
147 $title = $data['title'];
148 $url = '';
149 $target = '';
150 if (!$addLines && !$levelConf['noLink'] || $levelConf['alwaysLink']) {
151 $LD = $this->menuTypoLink($data, $this->mconf['target'], '', '', array(), $MP_params, $this->mconf['forceTypeValue']);
152 // If access restricted pages should be shown in menus, change the link of such pages to link to a redirection page:
153 $this->changeLinksForAccessRestrictedPages($LD, $data, $this->mconf['target'], $this->mconf['forceTypeValue']);
154 $url = $this->getTypoScriptFrontendController()->baseUrlWrap($LD['totalURL']);
155 $target = $LD['target'];
156 }
157 $codeLines .= LF . $var . $count . '=' . $menuName . '.add(' . $parent . ',' . $prev . ',0,' . GeneralUtility::quoteJSvalue($title, TRUE) . ',' . GeneralUtility::quoteJSvalue($url, TRUE) . ',' . GeneralUtility::quoteJSvalue($target, TRUE) . ');';
158 // If the active one should be chosen...
159 $active = $levelConf['showActive'] && $this->isActive($data['uid'], $MP_var);
160 // If the first item should be shown
161 $first = !$c && $levelConf['showFirst'];
162 // do it...
163 if ($active || $first) {
164 if ($count === 1) {
165 $codeLines .= LF . $menuName . '.openID = ' . $var . $count . ';';
166 } else {
167 $codeLines .= LF . $menuName . '.entry[' . $parent . '].openID = ' . $var . $count . ';';
168 }
169 }
170 // Add submenu...
171 $codeLines .= $addLines;
172 $prev = $var . $count;
173 $c++;
174 }
175 }
176 }
177 if ($this->mconf['firstLabelGeneral'] && !$levelConf['firstLabel']) {
178 $levelConf['firstLabel'] = $this->mconf['firstLabelGeneral'];
179 }
180 if ($levelConf['firstLabel'] && $codeLines) {
181 $codeLines .= LF . $menuName . '.defTopTitle[' . $count . '] = ' . GeneralUtility::quoteJSvalue($levelConf['firstLabel'], TRUE) . ';';
182 }
183 return $codeLines;
184 }
185
186 }