878e815aa8ef949bc1408e746ccb9276eedf313c
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / Menu / TextMenuContentObject.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 use TYPO3\CMS\Core\Utility\GeneralUtility;
17
18 use TYPO3\CMS\Core\Imaging\GraphicalFunctions;
19
20 /**
21 * Extension class creating text based menus
22 *
23 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
24 */
25 class TextMenuContentObject extends AbstractMenuContentObject {
26
27 /**
28 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
29 * Sets the result for the new "normal state" in $this->result
30 *
31 * @return void
32 * @see AbstractMenuContentObject::procesItemStates()
33 */
34 public function generate() {
35 $NOconf = array();
36 $splitCount = count($this->menuArr);
37 if ($splitCount) {
38 list($NOconf) = $this->procesItemStates($splitCount);
39 }
40 if (!empty($this->mconf['debugItemConf'])) {
41 echo '<h3>$NOconf:</h3>';
42 debug($NOconf);
43 }
44 $this->result = $NOconf;
45 }
46
47 /**
48 * Traverses the ->result array of menu items configuration (made by ->generate()) and renders each item.
49 * During the execution of this function many internal methods prefixed "extProc_" from this class is called and
50 * many of these are for now dummy functions. But they can be used for processing as they are used by the TMENU_LAYERS
51 * An instance of ContentObjectRenderer is also made and for each menu item rendered it is loaded with
52 * the record for that page so that any stdWrap properties that applies will have the current menu items record available.
53 *
54 * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
55 */
56 public function writeMenu() {
57 if (!is_array($this->result) || empty($this->result)) {
58 return '';
59 }
60
61 $this->WMresult = '';
62 $this->INPfixMD5 = substr(md5(microtime() . 'tmenu'), 0, 4);
63 $this->WMmenuItems = count($this->result);
64 $this->WMsubmenuObjSuffixes = $this->tmpl->splitConfArray(array('sOSuffix' => $this->mconf['submenuObjSuffixes']), $this->WMmenuItems);
65 $this->extProc_init();
66 foreach ($this->result as $key => $val) {
67 $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ']++;
68 $GLOBALS['TSFE']->register['count_MENUOBJ']++;
69 // Initialize the cObj with the page record of the menu item
70 $this->WMcObj->start($this->menuArr[$key], 'pages');
71 $this->I = array();
72 $this->I['key'] = $key;
73 $this->I['INPfix'] = ($this->imgNameNotRandom ? '' : '_' . $this->INPfixMD5) . '_' . $key;
74 $this->I['val'] = $val;
75 $this->I['title'] = isset($this->I['val']['stdWrap.']) ? $this->WMcObj->stdWrap($this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']), $this->I['val']['stdWrap.']) : $this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']);
76 $this->I['uid'] = $this->menuArr[$key]['uid'];
77 $this->I['mount_pid'] = $this->menuArr[$key]['mount_pid'];
78 $this->I['pid'] = $this->menuArr[$key]['pid'];
79 $this->I['spacer'] = $this->menuArr[$key]['isSpacer'];
80 // Set access key
81 if ($this->mconf['accessKey']) {
82 $this->I['accessKey'] = $this->accessKey($this->I['title']);
83 } else {
84 $this->I['accessKey'] = array();
85 }
86 // Make link tag
87 $this->I['val']['ATagParams'] = $this->WMcObj->getATagParams($this->I['val']);
88 if (isset($this->I['val']['additionalParams.'])) {
89 $this->I['val']['additionalParams'] = $this->WMcObj->stdWrap($this->I['val']['additionalParams'], $this->I['val']['additionalParams.']);
90 }
91 $this->I['linkHREF'] = $this->link($key, $this->I['val']['altTarget'], $this->mconf['forceTypeValue']);
92 // Title attribute of links:
93 $titleAttrValue = isset($this->I['val']['ATagTitle.']) ? $this->WMcObj->stdWrap($this->I['val']['ATagTitle'], $this->I['val']['ATagTitle.']) . $this->I['accessKey']['alt'] : $this->I['val']['ATagTitle'] . $this->I['accessKey']['alt'];
94 if ($titleAttrValue !== '') {
95 $this->I['linkHREF']['title'] = $titleAttrValue;
96 }
97
98 // Calling extra processing function
99 $this->extProc_beforeLinking($key);
100 // stdWrap for doNotLinkIt
101 if (isset($this->I['val']['doNotLinkIt.'])) {
102 $this->I['val']['doNotLinkIt'] = $this->WMcObj->stdWrap($this->I['val']['doNotLinkIt'], $this->I['val']['doNotLinkIt.']);
103 }
104 // Compile link tag
105 if (!$this->I['val']['doNotLinkIt']) {
106 $this->I['val']['doNotLinkIt'] = 0;
107 }
108 if (!$this->I['spacer'] && $this->I['val']['doNotLinkIt'] != 1) {
109 $this->setATagParts();
110 } else {
111 $this->I['A1'] = '';
112 $this->I['A2'] = '';
113 }
114 // ATagBeforeWrap processing:
115 if ($this->I['val']['ATagBeforeWrap']) {
116 $wrapPartsBefore = explode('|', $this->I['val']['linkWrap']);
117 $wrapPartsAfter = array('', '');
118 } else {
119 $wrapPartsBefore = array('', '');
120 $wrapPartsAfter = explode('|', $this->I['val']['linkWrap']);
121 }
122 if ($this->I['val']['stdWrap2'] || isset($this->I['val']['stdWrap2.'])) {
123 $stdWrap2 = isset($this->I['val']['stdWrap2.']) ? $this->WMcObj->stdWrap('|', $this->I['val']['stdWrap2.']) : '|';
124 $wrapPartsStdWrap = explode($this->I['val']['stdWrap2'] ? $this->I['val']['stdWrap2'] : '|', $stdWrap2);
125 } else {
126 $wrapPartsStdWrap = array('', '');
127 }
128 // Make before, middle and after parts
129 $this->I['parts'] = array();
130 $this->I['parts']['before'] = $this->getBeforeAfter('before');
131 $this->I['parts']['stdWrap2_begin'] = $wrapPartsStdWrap[0];
132 // stdWrap for doNotShowLink
133 if (isset($this->I['val']['doNotShowLink.'])) {
134 $this->I['val']['doNotShowLink'] = $this->WMcObj->stdWrap($this->I['val']['doNotShowLink'], $this->I['val']['doNotShowLink.']);
135 }
136 if (!$this->I['val']['doNotShowLink']) {
137 $this->I['parts']['notATagBeforeWrap_begin'] = $wrapPartsAfter[0];
138 $this->I['parts']['ATag_begin'] = $this->I['A1'];
139 $this->I['parts']['ATagBeforeWrap_begin'] = $wrapPartsBefore[0];
140 $this->I['parts']['title'] = $this->I['title'];
141 $this->I['parts']['ATagBeforeWrap_end'] = $wrapPartsBefore[1];
142 $this->I['parts']['ATag_end'] = $this->I['A2'];
143 $this->I['parts']['notATagBeforeWrap_end'] = $wrapPartsAfter[1];
144 }
145 $this->I['parts']['stdWrap2_end'] = $wrapPartsStdWrap[1];
146 $this->I['parts']['after'] = $this->getBeforeAfter('after');
147 // Passing I to a user function
148 if ($this->mconf['IProcFunc']) {
149 $this->I = $this->userProcess('IProcFunc', $this->I);
150 }
151 // Merge parts + beforeAllWrap
152 $this->I['theItem'] = implode('', $this->I['parts']);
153 $this->I['theItem'] = $this->extProc_beforeAllWrap($this->I['theItem'], $key);
154 // allWrap:
155 $allWrap = isset($this->I['val']['allWrap.']) ? $this->WMcObj->stdWrap($this->I['val']['allWrap'], $this->I['val']['allWrap.']) : $this->I['val']['allWrap'];
156 $this->I['theItem'] = $this->WMcObj->wrap($this->I['theItem'], $allWrap);
157 if ($this->I['val']['subst_elementUid']) {
158 $this->I['theItem'] = str_replace('{elementUid}', $this->I['uid'], $this->I['theItem']);
159 }
160 // allStdWrap:
161 if (is_array($this->I['val']['allStdWrap.'])) {
162 $this->I['theItem'] = $this->WMcObj->stdWrap($this->I['theItem'], $this->I['val']['allStdWrap.']);
163 }
164 // Calling extra processing function
165 $this->extProc_afterLinking($key);
166 }
167 return $this->extProc_finish();
168 }
169
170 /**
171 * Generates the before* and after* images for TMENUs
172 *
173 * @param string $pref Can be "before" or "after" and determines which kind of image to create (basically this is the prefix of the TypoScript properties that are read from the ->I['val'] array
174 * @return string The resulting HTML of the image, if any.
175 */
176 public function getBeforeAfter($pref) {
177 $res = '';
178 if ($imgInfo = $this->WMcObj->getImgResource($this->I['val'][$pref . 'Img'], $this->I['val'][$pref . 'Img.'])) {
179 $imgInfo[3] = GraphicalFunctions::pngToGifByImagemagick($imgInfo[3]);
180 $theName = $this->imgNamePrefix . $this->I['uid'] . $this->I['INPfix'] . $pref;
181 $name = ' ' . $this->nameAttribute . '="' . $theName . '"';
182 $GLOBALS['TSFE']->imagesOnPage[] = $imgInfo[3];
183 $res = '<img' . ' src="' . $GLOBALS['TSFE']->absRefPrefix . $imgInfo[3] . '"' . ' width="' . $imgInfo[0] . '"' . ' height="' . $imgInfo[1] . '"' . $name . ($this->I['val'][$pref . 'ImgTagParams'] ? ' ' . $this->I['val'][($pref . 'ImgTagParams')] : '') . $this->parent_cObj->getBorderAttr(' border="0"');
184 if (!strstr($res, 'alt="')) {
185 // Adding alt attribute if not set.
186 $res .= ' alt=""';
187 }
188 $res .= ' />';
189 if ($this->I['val'][$pref . 'ImgLink']) {
190 $res = $this->I['A1'] . $res . $this->I['A2'];
191 }
192 }
193 $processedPref = isset($this->I['val'][$pref . '.']) ? $this->WMcObj->stdWrap($this->I['val'][$pref], $this->I['val'][$pref . '.']) : $this->I['val'][$pref];
194 if (isset($this->I['val'][$pref . 'Wrap'])) {
195 return $this->WMcObj->wrap($res . $processedPref, $this->I['val'][$pref . 'Wrap']);
196 } else {
197 return $res . $processedPref;
198 }
199 }
200
201 /**
202 * Called right before the traversing of $this->result begins.
203 * Can be used for various initialization
204 *
205 * @return void
206 * @access private
207 * @see writeMenu()
208 */
209 public function extProc_init() {
210
211 }
212
213 /**
214 * Called right before the creation of the link for the menu item
215 *
216 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
217 * @return void
218 * @access private
219 * @see writeMenu()
220 */
221 public function extProc_beforeLinking($key) {
222
223 }
224
225 /**
226 * Called right after the creation of links for the menu item. This is also the last function call before the while-loop traversing menu items goes to the next item.
227 * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
228 *
229 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
230 * @return void
231 * @access private
232 * @see writeMenu()
233 */
234 public function extProc_afterLinking($key) {
235 // Add part to the accumulated result + fetch submenus
236 if (!$this->I['spacer']) {
237 $this->I['theItem'] .= $this->subMenu($this->I['uid'], $this->WMsubmenuObjSuffixes[$key]['sOSuffix']);
238 }
239 $part = isset($this->I['val']['wrapItemAndSub.']) ? $this->WMcObj->stdWrap($this->I['val']['wrapItemAndSub'], $this->I['val']['wrapItemAndSub.']) : $this->I['val']['wrapItemAndSub'];
240 $this->WMresult .= $part ? $this->WMcObj->wrap($this->I['theItem'], $part) : $this->I['theItem'];
241 }
242
243 /**
244 * Called before the "allWrap" happens on the menu item.
245 *
246 * @param string $item The current content of the menu item, $this->I['theItem'], passed along.
247 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
248 * @return string The modified version of $item, going back into $this->I['theItem']
249 * @access private
250 * @see writeMenu()
251 */
252 public function extProc_beforeAllWrap($item, $key) {
253 return $item;
254 }
255
256 /**
257 * Called before the writeMenu() function returns (only if a menu was generated)
258 *
259 * @return string The total menu content should be returned by this function
260 * @access private
261 * @see writeMenu()
262 */
263 public function extProc_finish() {
264 // stdWrap:
265 if (is_array($this->mconf['stdWrap.'])) {
266 $this->WMresult = $this->WMcObj->stdWrap($this->WMresult, $this->mconf['stdWrap.']);
267 }
268 return $this->WMcObj->wrap($this->WMresult, $this->mconf['wrap']) . $this->WMextraScript;
269 }
270
271 }