[TASK] Use ImageInfo class instead of direct PHP GD call
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / Menu / GraphicalMenuContentObject.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\Type\File\ImageInfo;
18 use TYPO3\CMS\Core\TypoScript\TypoScriptService;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
21 use TYPO3\CMS\Frontend\Imaging\GifBuilder;
22
23 /**
24 * Extension class creating graphic based menus (PNG or GIF files)
25 */
26 class GraphicalMenuContentObject extends AbstractMenuContentObject
27 {
28 /**
29 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
30 * Calls makeGifs() for all "normal" items and if configured for, also the "rollover" items.
31 *
32 * @see AbstractMenuContentObject::procesItemStates(), makeGifs()
33 */
34 public function generate()
35 {
36 $splitCount = count($this->menuArr);
37 if ($splitCount) {
38 list($NOconf, $ROconf) = $this->procesItemStates($splitCount);
39 //store initial count value
40 $tsfe = $this->getTypoScriptFrontendController();
41 $temp_HMENU_MENUOBJ = $tsfe->register['count_HMENU_MENUOBJ'];
42 $temp_MENUOBJ = $tsfe->register['count_MENUOBJ'];
43 // Now we generate the giffiles:
44 $this->makeGifs($NOconf, 'NO');
45 // store count from NO obj
46 $tempcnt_HMENU_MENUOBJ = $tsfe->register['count_HMENU_MENUOBJ'];
47 $tempcnt_MENUOBJ = $tsfe->register['count_MENUOBJ'];
48 if ($this->mconf['debugItemConf']) {
49 echo '<h3>$NOconf:</h3>';
50 debug($NOconf);
51 }
52 // RollOver
53 if ($ROconf) {
54 // Start recount for rollover with initial values
55 $tsfe->register['count_HMENU_MENUOBJ'] = $temp_HMENU_MENUOBJ;
56 $tsfe->register['count_MENUOBJ'] = $temp_MENUOBJ;
57 $this->makeGifs($ROconf, 'RO');
58 if ($this->mconf['debugItemConf']) {
59 echo '<h3>$ROconf:</h3>';
60 debug($ROconf);
61 }
62 }
63 // Use count from NO obj
64 $tsfe->register['count_HMENU_MENUOBJ'] = $tempcnt_HMENU_MENUOBJ;
65 $tsfe->register['count_MENUOBJ'] = $tempcnt_MENUOBJ;
66 }
67 }
68
69 /**
70 * Will traverse input array with configuration per-item and create corresponding GIF files for the menu.
71 * The data of the files are stored in $this->result
72 *
73 * @param array $conf Array with configuration for each item.
74 * @param string $resKey Type of images: normal ("NO") or rollover ("RO"). Valid values are "NO" and "RO
75 * @internal
76 * @see generate()
77 */
78 public function makeGifs($conf, $resKey)
79 {
80 $isGD = $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'];
81 if (!is_array($conf)) {
82 $conf = [];
83 }
84 $totalWH = [];
85 $items = count($conf);
86 $minDim = 0;
87 $maxDim = 0;
88 $Hcounter = 0;
89 $Wcounter = 0;
90 $Hobjs = [];
91 $Wobjs = [];
92 if ($isGD) {
93 // Generate the gif-files. the $menuArr is filled with some values like output_w, output_h, output_file
94 $Hobjs = $this->mconf['applyTotalH'];
95 if ($Hobjs) {
96 $Hobjs = GeneralUtility::intExplode(',', $Hobjs);
97 }
98 $Wobjs = $this->mconf['applyTotalW'];
99 if ($Wobjs) {
100 $Wobjs = GeneralUtility::intExplode(',', $Wobjs);
101 }
102 $minDim = $this->mconf['min'];
103 if ($minDim) {
104 $minDim = $this->parent_cObj->calcIntExplode(',', $minDim . ',');
105 }
106 $maxDim = $this->mconf['max'];
107 if ($maxDim) {
108 $maxDim = $this->parent_cObj->calcIntExplode(',', $maxDim . ',');
109 }
110 if ($minDim) {
111 $conf[$items] = $conf[$items - 1];
112 $this->menuArr[$items] = [];
113 $items = count($conf);
114 }
115 // TOTAL width
116 if ($this->mconf['useLargestItemX'] || $this->mconf['useLargestItemY'] || $this->mconf['distributeX'] || $this->mconf['distributeY']) {
117 $totalWH = $this->findLargestDims($conf, $items, $Hobjs, $Wobjs, $minDim, $maxDim);
118 }
119 }
120 $c = 0;
121 $maxFlag = 0;
122 $distributeAccu = ['H' => 0, 'W' => 0];
123 foreach ($conf as $key => $val) {
124 $this->getTypoScriptFrontendController()->register['count_HMENU_MENUOBJ']++;
125 $this->getTypoScriptFrontendController()->register['count_MENUOBJ']++;
126 if ($items === $c + 1 && $minDim) {
127 $Lobjs = $this->mconf['removeObjectsOfDummy'];
128 if ($Lobjs) {
129 $Lobjs = GeneralUtility::intExplode(',', $Lobjs);
130 foreach ($Lobjs as $remItem) {
131 unset($val[$remItem]);
132 unset($val[$remItem . '.']);
133 }
134 }
135 $flag = 0;
136 $tempXY = explode(',', $val['XY']);
137 if ($Wcounter < $minDim[0]) {
138 $tempXY[0] = $minDim[0] - $Wcounter;
139 $flag = 1;
140 }
141 if ($Hcounter < $minDim[1]) {
142 $tempXY[1] = $minDim[1] - $Hcounter;
143 $flag = 1;
144 }
145 $val['XY'] = implode(',', $tempXY);
146 if (!$flag) {
147 break;
148 }
149 }
150 $c++;
151 $gifCreator = null;
152 if ($isGD) {
153 // Pre-working the item
154 $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
155 $gifCreator->init();
156 $gifCreator->start($val, $this->menuArr[$key]);
157 // If useLargestItemH/W is specified
158 if (!empty($totalWH) && ($this->mconf['useLargestItemX'] || $this->mconf['useLargestItemY'])) {
159 $tempXY = explode(',', $gifCreator->setup['XY']);
160 if ($this->mconf['useLargestItemX']) {
161 $tempXY[0] = max($totalWH['W']);
162 }
163 if ($this->mconf['useLargestItemY']) {
164 $tempXY[1] = max($totalWH['H']);
165 }
166 // Regenerate the new values...
167 $val['XY'] = implode(',', $tempXY);
168 $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
169 $gifCreator->init();
170 $gifCreator->start($val, $this->menuArr[$key]);
171 }
172 // If distributeH/W is specified
173 if (!empty($totalWH) && ($this->mconf['distributeX'] || $this->mconf['distributeY'])) {
174 $tempXY = explode(',', $gifCreator->setup['XY']);
175 if ($this->mconf['distributeX']) {
176 $diff = $this->mconf['distributeX'] - $totalWH['W_total'] - $distributeAccu['W'];
177 $compensate = round($diff / ($items - $c + 1));
178 $distributeAccu['W'] += $compensate;
179 $tempXY[0] = $totalWH['W'][$key] + $compensate;
180 }
181 if ($this->mconf['distributeY']) {
182 $diff = $this->mconf['distributeY'] - $totalWH['H_total'] - $distributeAccu['H'];
183 $compensate = round($diff / ($items - $c + 1));
184 $distributeAccu['H'] += $compensate;
185 $tempXY[1] = $totalWH['H'][$key] + $compensate;
186 }
187 // Regenerate the new values...
188 $val['XY'] = implode(',', $tempXY);
189 $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
190 $gifCreator->init();
191 $gifCreator->start($val, $this->menuArr[$key]);
192 }
193 // If max dimensions are specified
194 if ($maxDim) {
195 $tempXY = explode(',', $val['XY']);
196 if ($maxDim[0] && $Wcounter + $gifCreator->XY[0] >= $maxDim[0]) {
197 $tempXY[0] = $maxDim[0] - $Wcounter;
198 $maxFlag = 1;
199 }
200 if ($maxDim[1] && $Hcounter + $gifCreator->XY[1] >= $maxDim[1]) {
201 $tempXY[1] = $maxDim[1] - $Hcounter;
202 $maxFlag = 1;
203 }
204 if ($maxFlag) {
205 $val['XY'] = implode(',', $tempXY);
206 $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
207 $gifCreator->init();
208 $gifCreator->start($val, $this->menuArr[$key]);
209 }
210 }
211 // displace
212 if ($Hobjs) {
213 foreach ($Hobjs as $index) {
214 if ($gifCreator->setup[$index] && $gifCreator->setup[$index . '.']) {
215 $oldOffset = explode(',', $gifCreator->setup[$index . '.']['offset']);
216 $gifCreator->setup[$index . '.']['offset'] = implode(',', $gifCreator->applyOffset($oldOffset, [0, -$Hcounter]));
217 }
218 }
219 }
220 if ($Wobjs) {
221 foreach ($Wobjs as $index) {
222 if ($gifCreator->setup[$index] && $gifCreator->setup[$index . '.']) {
223 $oldOffset = explode(',', $gifCreator->setup[$index . '.']['offset']);
224 $gifCreator->setup[$index . '.']['offset'] = implode(',', $gifCreator->applyOffset($oldOffset, [-$Wcounter, 0]));
225 }
226 }
227 }
228 }
229 // Finding alternative GIF names if any (by altImgResource)
230 $gifFileName = '';
231 if ($conf[$key]['altImgResource'] || is_array($conf[$key]['altImgResource.'])) {
232 $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
233 $cObj->start($this->menuArr[$key], 'pages');
234 $altImgInfo = $cObj->getImgResource($conf[$key]['altImgResource'], $conf[$key]['altImgResource.']);
235 $gifFileName = $altImgInfo[3];
236 }
237 // If an alternative name was NOT given, find the GIFBUILDER name.
238 if (!$gifFileName && $isGD) {
239 GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/assets/menu/');
240 $gifFileName = $gifCreator->fileName('assets/menu/');
241 }
242 $this->result[$resKey][$key] = $conf[$key];
243 // Generation of image file:
244 // File exists
245 if (file_exists($gifFileName)) {
246 $imageInfo = GeneralUtility::makeInstance(ImageInfo::class, $gifFileName);
247 $this->result[$resKey][$key]['output_w'] = (int)$imageInfo->getWidth();
248 $this->result[$resKey][$key]['output_h'] = (int)$imageInfo->getHeight();
249 $this->result[$resKey][$key]['output_file'] = $gifFileName;
250 } elseif ($isGD) {
251 // file is generated
252 $gifCreator->make();
253 $this->result[$resKey][$key]['output_w'] = $gifCreator->w;
254 $this->result[$resKey][$key]['output_h'] = $gifCreator->h;
255 $this->result[$resKey][$key]['output_file'] = $gifFileName;
256 $gifCreator->output($this->result[$resKey][$key]['output_file']);
257 $gifCreator->destroy();
258 }
259 // counter is increased
260 $Hcounter += $this->result[$resKey][$key]['output_h'];
261 // counter is increased
262 $Wcounter += $this->result[$resKey][$key]['output_w'];
263 if ($maxFlag) {
264 break;
265 }
266 }
267 }
268
269 /**
270 * Function searching for the largest width and height of the menu items to be generated.
271 * Uses some of the same code as makeGifs and even instantiates some gifbuilder objects BUT does not render the images - only reading out which width they would have.
272 * Remember to upgrade the code in here if the makeGifs function is updated.
273 *
274 * @param array $conf Same configuration array as passed to makeGifs()
275 * @param int $items The number of menu items
276 * @param array $Hobjs Array with "applyTotalH" numbers (unused)
277 * @param array $Wobjs Array with "applyTotalW" numbers (unused)
278 * @param array $minDim Array with "min" x/y
279 * @param array $maxDim Array with "max" x/y
280 * @return array Array with keys "H" and "W" which are in themselves arrays with the heights and widths of menu items inside. This can be used to find the max/min size of the menu items.
281 * @internal
282 * @see makeGifs()
283 */
284 public function findLargestDims($conf, $items, $Hobjs, $Wobjs, $minDim, $maxDim)
285 {
286 $items = (int)$items;
287 $totalWH = [
288 'W' => [],
289 'H' => [],
290 'W_total' => 0,
291 'H_total' => 0
292 ];
293 $Hcounter = 0;
294 $Wcounter = 0;
295 $c = 0;
296 $maxFlag = 0;
297 foreach ($conf as $key => $val) {
298 // SAME CODE AS makeGifs()! BEGIN
299 if ($items === $c + 1 && $minDim) {
300 $Lobjs = $this->mconf['removeObjectsOfDummy'];
301 if ($Lobjs) {
302 $Lobjs = GeneralUtility::intExplode(',', $Lobjs);
303 foreach ($Lobjs as $remItem) {
304 unset($val[$remItem]);
305 unset($val[$remItem . '.']);
306 }
307 }
308 $flag = 0;
309 $tempXY = explode(',', $val['XY']);
310 if ($Wcounter < $minDim[0]) {
311 $tempXY[0] = $minDim[0] - $Wcounter;
312 $flag = 1;
313 }
314 if ($Hcounter < $minDim[1]) {
315 $tempXY[1] = $minDim[1] - $Hcounter;
316 $flag = 1;
317 }
318 $val['XY'] = implode(',', $tempXY);
319 if (!$flag) {
320 break;
321 }
322 }
323 $c++;
324 $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
325 $gifCreator->init();
326 $gifCreator->start($val, $this->menuArr[$key]);
327 if ($maxDim) {
328 $tempXY = explode(',', $val['XY']);
329 if ($maxDim[0] && $Wcounter + $gifCreator->XY[0] >= $maxDim[0]) {
330 $tempXY[0] = $maxDim[0] - $Wcounter;
331 $maxFlag = 1;
332 }
333 if ($maxDim[1] && $Hcounter + $gifCreator->XY[1] >= $maxDim[1]) {
334 $tempXY[1] = $maxDim[1] - $Hcounter;
335 $maxFlag = 1;
336 }
337 if ($maxFlag) {
338 $val['XY'] = implode(',', $tempXY);
339 $gifCreator = GeneralUtility::makeInstance(GifBuilder::class);
340 $gifCreator->init();
341 $gifCreator->start($val, $this->menuArr[$key]);
342 }
343 }
344 // SAME CODE AS makeGifs()! END
345 // Setting the width/height
346 $totalWH['W'][$key] = $gifCreator->XY[0];
347 $totalWH['H'][$key] = $gifCreator->XY[1];
348 $totalWH['W_total'] += $gifCreator->XY[0];
349 $totalWH['H_total'] += $gifCreator->XY[1];
350 // counter is increased
351 $Hcounter += $gifCreator->XY[1];
352 // counter is increased
353 $Wcounter += $gifCreator->XY[0];
354 if ($maxFlag) {
355 break;
356 }
357 }
358 return $totalWH;
359 }
360
361 /**
362 * Traverses the ->result['NO'] array of menu items configuration (made by ->generate()) and renders the HTML of each item (the images themselves was made with makeGifs() before this. See ->generate())
363 * During the execution of this function many internal methods prefixed "extProc_" from this class is called and many of these are for now dummy functions. But they can be used for processing as they are used by the GMENU_LAYERS
364 *
365 * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
366 */
367 public function writeMenu()
368 {
369 if (!is_array($this->menuArr) || empty($this->result) || !is_array($this->result['NO'])) {
370 return '';
371 }
372 $this->WMresult = '';
373 $this->INPfixMD5 = substr(md5(microtime() . $this->GMENU_fixKey), 0, 4);
374 $this->WMmenuItems = count($this->result['NO']);
375 $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
376 $this->WMsubmenuObjSuffixes = $typoScriptService->explodeConfigurationForOptionSplit(['sOSuffix' => $this->mconf['submenuObjSuffixes']], $this->WMmenuItems);
377 $this->extProc_init();
378 $tsfe = $this->getTypoScriptFrontendController();
379 if (!isset($tsfe->additionalJavaScript['JSImgCode'])) {
380 $tsfe->additionalJavaScript['JSImgCode'] = '';
381 }
382 for ($key = 0; $key < $this->WMmenuItems; $key++) {
383 if ($this->result['NO'][$key]['output_file']) {
384 // Initialize the cObj with the page record of the menu item
385 $this->WMcObj->start($this->menuArr[$key], 'pages');
386 $this->I = [];
387 $this->I['key'] = $key;
388 $this->I['INPfix'] = ($this->imgNameNotRandom ? '' : '_' . $this->INPfixMD5) . '_' . $key;
389 $this->I['val'] = $this->result['NO'][$key];
390 $this->I['title'] = $this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']);
391 $this->I['uid'] = $this->menuArr[$key]['uid'];
392 $this->I['mount_pid'] = $this->menuArr[$key]['mount_pid'];
393 $this->I['pid'] = $this->menuArr[$key]['pid'];
394 $this->I['spacer'] = $this->menuArr[$key]['isSpacer'];
395 if (!$this->I['uid'] && !$this->menuArr[$key]['_OVERRIDE_HREF']) {
396 $this->I['spacer'] = 1;
397 }
398 $this->I['noLink'] = $this->I['spacer'] || $this->I['val']['noLink'] || empty($this->menuArr[$key]);
399 // !count($this->menuArr[$key]) means that this item is a dummyItem
400 $this->I['name'] = '';
401 // Set access key
402 if ($this->mconf['accessKey']) {
403 $this->I['accessKey'] = $this->accessKey($this->I['title']);
404 } else {
405 $this->I['accessKey'] = [];
406 }
407 // Make link tag
408 $this->I['val']['ATagParams'] = $this->WMcObj->getATagParams($this->I['val']);
409 if (isset($this->I['val']['additionalParams.'])) {
410 $this->I['val']['additionalParams'] = $this->WMcObj->stdWrap($this->I['val']['additionalParams'], $this->I['val']['additionalParams.']);
411 }
412 $this->I['linkHREF'] = $this->link($key, $this->I['val']['altTarget'], $this->mconf['forceTypeValue']);
413 // Title attribute of links:
414 $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'];
415 if ($titleAttrValue !== '') {
416 $this->I['linkHREF']['title'] = $titleAttrValue;
417 }
418 // Set rollover
419 if ($this->result['RO'][$key] && !$this->I['noLink']) {
420 $this->I['theName'] = $this->imgNamePrefix . $this->I['uid'] . $this->I['INPfix'];
421 $this->I['name'] = ' ' . $this->nameAttribute . '="' . $this->I['theName'] . '"';
422 $this->I['linkHREF']['onMouseover'] = $this->WMfreezePrefix . 'over(' . GeneralUtility::quoteJSvalue($this->I['theName']) . ');';
423 $this->I['linkHREF']['onMouseout'] = $this->WMfreezePrefix . 'out(' . GeneralUtility::quoteJSvalue($this->I['theName']) . ');';
424 $tsfe->additionalJavaScript['JSImgCode'] .= LF . $this->I['theName'] . '_n=new Image(); ' . $this->I['theName'] . '_n.src = ' . GeneralUtility::quoteJSvalue($tsfe->absRefPrefix . $this->I['val']['output_file']) . '; ';
425 $tsfe->additionalJavaScript['JSImgCode'] .= LF . $this->I['theName'] . '_h=new Image(); ' . $this->I['theName'] . '_h.src = ' . GeneralUtility::quoteJSvalue($tsfe->absRefPrefix . $this->result['RO'][$key]['output_file']) . '; ';
426 $tsfe->imagesOnPage[] = $this->result['RO'][$key]['output_file'];
427 $tsfe->setJS('mouseOver');
428 $this->extProc_RO($key);
429 }
430 // Set altText
431 $this->I['altText'] = $this->I['title'] . $this->I['accessKey']['alt'];
432 // Calling extra processing function
433 $this->extProc_beforeLinking($key);
434 // Set linking
435 if (!$this->I['noLink']) {
436 $this->setATagParts();
437 } else {
438 $this->I['A1'] = '';
439 $this->I['A2'] = '';
440 }
441 $this->I['IMG'] = '<img src="' . $tsfe->absRefPrefix . $this->I['val']['output_file'] . '" width="' . $this->I['val']['output_w'] . '" height="' . $this->I['val']['output_h'] . '" ' . $this->parent_cObj->getBorderAttr('border="0"') . ($this->mconf['disableAltText'] ? '' : ' alt="' . htmlspecialchars($this->I['altText']) . '"') . $this->I['name'] . ($this->I['val']['imgParams'] ? ' ' . $this->I['val']['imgParams'] : '') . ' />';
442 // Make before, middle and after parts
443 $this->I['parts'] = [];
444 $this->I['parts']['ATag_begin'] = $this->I['A1'];
445 $this->I['parts']['image'] = $this->I['IMG'];
446 $this->I['parts']['ATag_end'] = $this->I['A2'];
447 // Passing I to a user function
448 if ($this->mconf['IProcFunc']) {
449 $this->I = $this->userProcess('IProcFunc', $this->I);
450 }
451 // Putting the item together.
452 // Merge parts + beforeAllWrap
453 $this->I['theItem'] = implode('', $this->I['parts']);
454 $this->I['theItem'] = $this->extProc_beforeAllWrap($this->I['theItem'], $key);
455 // wrap:
456 $this->I['theItem'] = $this->WMcObj->wrap($this->I['theItem'], $this->I['val']['wrap']);
457 // allWrap:
458 $allWrap = isset($this->I['val']['allWrap.']) ? $this->WMcObj->stdWrap($this->I['val']['allWrap'], $this->I['val']['allWrap.']) : $this->I['val']['allWrap'];
459 $this->I['theItem'] = $this->WMcObj->wrap($this->I['theItem'], $allWrap);
460 if ($this->I['val']['subst_elementUid']) {
461 $this->I['theItem'] = str_replace('{elementUid}', $this->I['uid'], $this->I['theItem']);
462 }
463 // allStdWrap:
464 if (is_array($this->I['val']['allStdWrap.'])) {
465 $this->I['theItem'] = $this->WMcObj->stdWrap($this->I['theItem'], $this->I['val']['allStdWrap.']);
466 }
467 $tsfe->imagesOnPage[] = $this->I['val']['output_file'];
468 $this->extProc_afterLinking($key);
469 }
470 }
471 return $this->extProc_finish();
472 }
473
474 /**
475 * Called right before the traversing of $this->result begins.
476 * Can be used for various initialization
477 *
478 * @internal
479 * @see writeMenu()
480 */
481 public function extProc_init()
482 {
483 }
484
485 /**
486 * Called after all processing for RollOver of an element has been done.
487 *
488 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found OR $this->result['RO'][$key] where the configuration for that elements RO version is found!
489 * @internal
490 * @see writeMenu()
491 */
492 public function extProc_RO($key)
493 {
494 }
495
496 /**
497 * Called right before the creation of the link for the menu item
498 *
499 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
500 * @internal
501 * @see writeMenu()
502 */
503 public function extProc_beforeLinking($key)
504 {
505 }
506
507 /**
508 * Called right after the creation of links for the menu item. This is also the last function call before the
509 * for-loop traversing menu items goes to the next item.
510 * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
511 * Further this calls the subMenu function in the parent class to create any submenu there might be.
512 *
513 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found
514 * @internal
515 * @see writeMenu(), AbstractMenuContentObject::subMenu()
516 */
517 public function extProc_afterLinking($key)
518 {
519 // Add part to the accumulated result + fetch submenus
520 if (!$this->I['spacer']) {
521 $this->I['theItem'] .= $this->subMenu($this->I['uid'], $this->WMsubmenuObjSuffixes[$key]['sOSuffix']);
522 }
523 $part = isset($this->I['val']['wrapItemAndSub.']) ? $this->WMcObj->stdWrap($this->I['val']['wrapItemAndSub'], $this->I['val']['wrapItemAndSub.']) : $this->I['val']['wrapItemAndSub'];
524 $this->WMresult .= $part ? $this->WMcObj->wrap($this->I['theItem'], $part) : $this->I['theItem'];
525 }
526
527 /**
528 * Called before the "wrap" happens on the menu item.
529 *
530 * @param string $item The current content of the menu item, $this->I['theItem'], passed along.
531 * @param int $key Pointer to $this->menuArr[$key] where the current menu element record is found (unused)
532 * @return string The modified version of $item, going back into $this->I['theItem']
533 * @internal
534 * @see writeMenu()
535 */
536 public function extProc_beforeAllWrap($item, $key)
537 {
538 return $item;
539 }
540
541 /**
542 * Called before the writeMenu() function returns (only if a menu was generated)
543 *
544 * @return string The total menu content should be returned by this function
545 * @internal
546 * @see writeMenu()
547 */
548 public function extProc_finish()
549 {
550 // stdWrap:
551 if (is_array($this->mconf['stdWrap.'])) {
552 $this->WMresult = $this->WMcObj->stdWrap($this->WMresult, $this->mconf['stdWrap.']);
553 }
554 return $this->WMcObj->wrap($this->WMresult, $this->mconf['wrap']) . $this->WMextraScript;
555 }
556 }