[TASK] Clean up phpDoc comments in typo3/sysext/
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / tslib / class.tslib_menu.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Generating navigation / menus from TypoScript
29 *
30 * This file contains five classes, four of which are extensions to the main class, tslib_menu.
31 * The main class, tslib_menu, is also extended by other external PHP scripts such as the GMENU_LAYERS and GMENU_FOLDOUT scripts which creates pop-up menus.
32 * Notice that extension classes (like "tslib_tmenu") must have their suffix (here "tmenu") listed in $this->tmpl->menuclasses - otherwise they cannot be instantiated.
33 *
34 * Revised for TYPO3 3.6 June/2003 by Kasper Skårhøj
35 * XHTML compliant
36 *
37 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
38 */
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 /**
58 * Base class. The HMENU content object uses this (or more precisely one of the extension classes).
59 * Amoung others the class generates an array of menuitems. Thereafter functions from the subclasses are called.
60 * The class is ALWAYS used through extension classes (like tslib_gmenu or tslib_tmenu which are classics) and
61 *
62 * Example of usage (from tslib_cObj):
63 *
64 * $menu = t3lib_div::makeInstance('tslib_'.$cls);
65 * $menu->parent_cObj = $this;
66 * $menu->start($GLOBALS['TSFE']->tmpl, $GLOBALS['TSFE']->sys_page, '', $conf,1);
67 * $menu->makeMenu();
68 * $content.=$menu->writeMenu();
69 *
70 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
71 * @package TYPO3
72 * @subpackage tslib
73 * @see tslib_cObj::HMENU()
74 */
75 class tslib_menu {
76 var $menuNumber = 1; // tells you which menu-number this is. This is important when getting data from the setup
77 var $entryLevel = 0; // 0 = rootFolder
78 var $spacerIDList = '199'; // The doktype-number that defines a spacer
79 var $doktypeExcludeList = '6'; // doktypes that define which should not be included in a menu
80 var $alwaysActivePIDlist=array();
81 var $imgNamePrefix = 'img';
82 var $imgNameNotRandom=0;
83 var $debug = 0;
84
85 /**
86 * Loaded with the parent cObj-object when a new HMENU is made
87 *
88 * @var tslib_cObj
89 */
90 var $parent_cObj;
91 var $GMENU_fixKey='gmenu';
92 var $MP_array=array(); // accumulation of mount point data
93
94 // internal
95 var $conf = Array(); // HMENU configuration
96 var $mconf = Array(); // xMENU configuration (TMENU, GMENU etc)
97
98 /**
99 * template-object
100 *
101 * @var t3lib_TStemplate
102 */
103 var $tmpl;
104
105 /**
106 * sys_page-object, pagefunctions
107 *
108 * @var t3lib_pageSelect
109 */
110 var $sys_page;
111 var $id; // The base page-id of the menu.
112 var $nextActive; // Holds the page uid of the NEXT page in the root line from the page pointed to by entryLevel; Used to expand the menu automatically if in a certain root line.
113 var $menuArr; // The array of menuItems which is built
114 var $hash;
115 var $result = Array();
116 var $rL_uidRegister = ''; // Array: Is filled with an array of page uid numbers + RL parameters which are in the current root line (used to evaluate whether a menu item is in active state)
117 var $INPfixMD5;
118 var $I;
119 var $WMresult;
120 var $WMfreezePrefix;
121 var $WMmenuItems;
122 var $WMsubmenuObjSuffixes;
123 var $WMextraScript;
124 var $alternativeMenuTempArray=''; // Can be set to contain menu item arrays for sub-levels.
125 var $nameAttribute = 'name'; // Will be 'id' in XHTML-mode
126
127 /**
128 * The initialization of the object. This just sets some internal variables.
129 *
130 * @param object The $GLOBALS['TSFE']->tmpl object
131 * @param object The $GLOBALS['TSFE']->sys_page object
132 * @param integer A starting point page id. This should probably be blank since the 'entryLevel' value will be used then.
133 * @param array The TypoScript configuration for the HMENU cObject
134 * @param integer Menu number; 1,2,3. Should probably be '1'
135 * @param string Submenu Object suffix. This offers submenus a way to use alternative configuration for specific positions in the menu; By default "1 = TMENU" would use "1." for the TMENU configuration, but if this string is set to eg. "a" then "1a." would be used for configuration instead (while "1 = " is still used for the overall object definition of "TMENU")
136 * @return boolean Returns TRUE on success
137 * @see tslib_cObj::HMENU()
138 */
139 function start(&$tmpl, &$sys_page, $id, $conf, $menuNumber, $objSuffix='') {
140
141 // Init:
142 $this->conf = $conf;
143 $this->menuNumber = $menuNumber;
144 $this->mconf = $conf[$this->menuNumber.$objSuffix.'.'];
145 $this->debug=$GLOBALS['TSFE']->debug;
146
147 // In XHTML there is no "name" attribute anymore
148 switch ($GLOBALS['TSFE']->xhtmlDoctype) {
149 case 'xhtml_strict':
150 case 'xhtml_11':
151 case 'xhtml_2':
152 case 'html5':
153 $this->nameAttribute = 'id';
154 break;
155 default:
156 $this->nameAttribute = 'name';
157 break;
158 }
159
160 // Sets the internal vars. $tmpl MUST be the template-object. $sys_page MUST be the sys_page object
161 if ($this->conf[$this->menuNumber.$objSuffix] && is_object($tmpl) && is_object($sys_page)) {
162 $this->tmpl = $tmpl;
163 $this->sys_page = $sys_page;
164
165 // alwaysActivePIDlist initialized:
166 if (trim($this->conf['alwaysActivePIDlist']) || isset($this->conf['alwaysActivePIDlist.'])) {
167 if (isset($this->conf['alwaysActivePIDlist.'])) {
168 $this->conf['alwaysActivePIDlist'] = $this->parent_cObj->stdWrap($this->conf['alwaysActivePIDlist'], $this->conf['alwaysActivePIDlist.']);
169 }
170 $this->alwaysActivePIDlist = t3lib_div::intExplode(',', $this->conf['alwaysActivePIDlist']);
171 }
172
173 // 'not in menu' doktypes
174 if ($this->conf['excludeDoktypes']) {
175 $this->doktypeExcludeList = $GLOBALS['TYPO3_DB']->cleanIntList($this->conf['excludeDoktypes']);
176 }
177 // EntryLevel
178 $this->entryLevel = tslib_cObj::getKey (
179 isset($conf['entryLevel.'])
180 ? $this->parent_cObj->stdWrap($conf['entryLevel'], $conf['entryLevel.'])
181 : $conf['entryLevel'],
182 $this->tmpl->rootLine
183 );
184 // Set parent page: If $id not stated with start() then the base-id will be found from rootLine[$this->entryLevel]
185 if ($id) { // Called as the next level in a menu. It is assumed that $this->MP_array is set from parent menu.
186 $this->id = intval($id);
187 } else { // This is a BRAND NEW menu, first level. So we take ID from rootline and also find MP_array (mount points)
188 $this->id = intval($this->tmpl->rootLine[$this->entryLevel]['uid']);
189
190 // Traverse rootline to build MP_array of pages BEFORE the entryLevel
191 // (MP var for ->id is picked up in the next part of the code...)
192 foreach($this->tmpl->rootLine as $entryLevel => $levelRec) {
193 // For overlaid mount points, set the variable right now:
194 if ($levelRec['_MP_PARAM'] && $levelRec['_MOUNT_OL']) {
195 $this->MP_array[] = $levelRec['_MP_PARAM'];
196 }
197 // Break when entry level is reached:
198 if ($entryLevel>=$this->entryLevel) break;
199
200 // For normal mount points, set the variable for next level.
201 if ($levelRec['_MP_PARAM'] && !$levelRec['_MOUNT_OL']) {
202 $this->MP_array[] = $levelRec['_MP_PARAM'];
203 }
204 }
205 }
206
207 // Return FALSE if no page ID was set (thus no menu of subpages can be made).
208 if ($this->id<=0) {
209 return FALSE;
210 }
211
212 // Check if page is a mount point, and if so set id and MP_array
213 // (basically this is ONLY for non-overlay mode, but in overlay mode an ID with a mount point should never reach this point anyways, so no harm done...)
214 $mount_info = $this->sys_page->getMountPointInfo($this->id);
215 if (is_array($mount_info)) {
216 $this->MP_array[] = $mount_info['MPvar'];
217 $this->id = $mount_info['mount_pid'];
218 }
219
220 // Gather list of page uids in root line (for "isActive" evaluation). Also adds the MP params in the path so Mount Points are respected.
221 // (List is specific for this rootline, so it may be supplied from parent menus for speed...)
222 if (!is_array($this->rL_uidRegister)) {
223 $rl_MParray = array();
224 foreach($this->tmpl->rootLine as $v_rl) {
225 // For overlaid mount points, set the variable right now:
226 if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) {
227 $rl_MParray[] = $v_rl['_MP_PARAM'];
228 }
229
230 // Add to register:
231 $this->rL_uidRegister[] = 'ITEM:'.$v_rl['uid'].(count($rl_MParray) ? ':'.implode(',', $rl_MParray) : '');
232
233 // For normal mount points, set the variable for next level.
234 if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) {
235 $rl_MParray[] = $v_rl['_MP_PARAM'];
236 }
237 }
238 }
239
240 // Set $directoryLevel so the following evalution of the nextActive will not return
241 // an invalid value if .special=directory was set
242 $directoryLevel = 0;
243 if ($this->conf['special'] == 'directory') {
244 $value = isset($this->conf['special.']['value.'])
245 ? $this->parent_cObj->stdWrap($this->conf['special.']['value'], $this->conf['special.']['value.'])
246 : $this->conf['special.']['value'];
247 if ($value=='') {
248 $value=$GLOBALS['TSFE']->page['uid'];
249 }
250 $directoryLevel = intval($GLOBALS['TSFE']->tmpl->getRootlineLevel($value));
251 }
252
253 // Setting "nextActive": This is the page uid + MPvar of the NEXT page in rootline. Used to expand the menu if we are in the right branch of the tree
254 // Notice: The automatic expansion of a menu is designed to work only when no "special" modes (except "directory") are used.
255 $startLevel = $directoryLevel ? $directoryLevel : $this->entryLevel;
256 $currentLevel = $startLevel + $this->menuNumber;
257 if (is_array($this->tmpl->rootLine[$currentLevel])) {
258 $nextMParray = $this->MP_array;
259 if (!count($nextMParray) && !$this->tmpl->rootLine[$currentLevel]['_MOUNT_OL'] && $currentLevel > 0) {
260 // Make sure to slide-down any mount point information (_MP_PARAM) to children records in the rootline
261 // otherwise automatic expansion will not work
262 $parentRecord = $this->tmpl->rootLine[$currentLevel - 1];
263 if (isset($parentRecord['_MP_PARAM'])) {
264 $nextMParray[] = $parentRecord['_MP_PARAM'];
265 }
266 }
267
268 if ($this->tmpl->rootLine[$currentLevel]['_MOUNT_OL']) { // In overlay mode, add next level MPvars as well:
269 $nextMParray[] = $this->tmpl->rootLine[$currentLevel]['_MP_PARAM'];
270 }
271 $this->nextActive = $this->tmpl->rootLine[$currentLevel]['uid'] . (count($nextMParray) ? ':' . implode(',', $nextMParray) : '');
272 } else {
273 $this->nextActive = '';
274 }
275
276 // imgNamePrefix
277 if ($this->mconf['imgNamePrefix']) {
278 $this->imgNamePrefix=$this->mconf['imgNamePrefix'];
279 }
280 $this->imgNameNotRandom = $this->mconf['imgNameNotRandom'];
281
282 $retVal = TRUE;
283 } else {
284 $GLOBALS['TT']->setTSlogMessage('ERROR in menu', 3);
285 $retVal = FALSE;
286 }
287 return $retVal;
288 }
289
290 /**
291 * Creates the menu in the internal variables, ready for output.
292 * Basically this will read the page records needed and fill in the internal $this->menuArr
293 * Based on a hash of this array and some other variables the $this->result variable will be loaded either from cache OR by calling the generate() method of the class to create the menu for real.
294 *
295 * @return void
296 */
297 function makeMenu() {
298 if ($this->id) {
299
300 // Initializing showAccessRestrictedPages
301 if ($this->mconf['showAccessRestrictedPages']) {
302 // SAVING where_groupAccess
303 $SAVED_where_groupAccess = $this->sys_page->where_groupAccess;
304 $this->sys_page->where_groupAccess = ''; // Temporarily removing fe_group checking!
305 }
306
307 // Begin production of menu:
308 $temp = array();
309 $altSortFieldValue = trim($this->mconf['alternativeSortingField']);
310 $altSortField = $altSortFieldValue ? $altSortFieldValue : 'sorting';
311 if ($this->menuNumber==1 && $this->conf['special']) { // ... only for the FIRST level of a HMENU
312 $value = isset($this->conf['special.']['value.'])
313 ? $this->parent_cObj->stdWrap($this->conf['special.']['value'], $this->conf['special.']['value.'])
314 : $this->conf['special.']['value'];
315
316 switch($this->conf['special']) {
317 case 'userfunction':
318 $temp = $this->parent_cObj->callUserFunction(
319 $this->conf['special.']['userFunc'],
320 array_merge($this->conf['special.'], array('_altSortField'=>$altSortField)),
321 ''
322 );
323 if (!is_array($temp)) $temp=array();
324 break;
325 case 'language':
326 $temp = array();
327
328 // Getting current page record NOT overlaid by any translation:
329 $currentPageWithNoOverlay = $this->sys_page->getRawRecord('pages', $GLOBALS['TSFE']->page['uid']);
330
331 // Traverse languages set up:
332 $languageItems = t3lib_div::intExplode(',', $value);
333 foreach($languageItems as $sUid) {
334 // Find overlay record:
335 if ($sUid) {
336 $lRecs = $this->sys_page->getPageOverlay($GLOBALS['TSFE']->page['uid'], $sUid);
337 } else $lRecs=array();
338 // Checking if the "disabled" state should be set.
339 if (
340 (t3lib_div::hideIfNotTranslated($GLOBALS['TSFE']->page['l18n_cfg']) && $sUid && !count($lRecs)) // Blocking for all translations?
341 || ($GLOBALS['TSFE']->page['l18n_cfg']&1 && (!$sUid || !count($lRecs))) // Blocking default translation?
342 || (!$this->conf['special.']['normalWhenNoLanguage'] && $sUid && !count($lRecs))
343 ) {
344 $iState = $GLOBALS['TSFE']->sys_language_uid==$sUid ? 'USERDEF2' : 'USERDEF1';
345 } else {
346 $iState = $GLOBALS['TSFE']->sys_language_uid==$sUid ? 'ACT' : 'NO';
347 }
348
349 if ($this->conf['addQueryString']) {
350 $getVars = $this->parent_cObj->getQueryArguments($this->conf['addQueryString.'], array('L'=>$sUid), TRUE);
351 } else {
352 $getVars = '&L='.$sUid;
353 }
354
355 // Adding menu item:
356 $temp[] = array_merge(
357 array_merge($currentPageWithNoOverlay, $lRecs),
358 array(
359 'ITEM_STATE' => $iState,
360 '_ADD_GETVARS' => $getVars,
361 '_SAFE' => TRUE
362 )
363 );
364 }
365 break;
366 case 'directory':
367 if ($value=='') {
368 $value=$GLOBALS['TSFE']->page['uid'];
369 }
370 $items=t3lib_div::intExplode(',', $value);
371
372 foreach($items as $id) {
373 $MP = $this->tmpl->getFromMPmap($id);
374
375 // Checking if a page is a mount page and if so, change the ID and set the MP var properly.
376 $mount_info = $this->sys_page->getMountPointInfo($id);
377 if (is_array($mount_info)) {
378 if ($mount_info['overlay']) { // Overlays should already have their full MPvars calculated:
379 $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']);
380 $MP = $MP ? $MP : $mount_info['MPvar'];
381 } else {
382 $MP = ($MP ? $MP.',' : '').$mount_info['MPvar'];
383 }
384 $id = $mount_info['mount_pid'];
385 }
386
387 // Get sub-pages:
388 $res = $this->parent_cObj->exec_getQuery('pages', Array('pidInList'=>$id, 'orderBy'=>$altSortField));
389 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
390 $GLOBALS['TSFE']->sys_page->versionOL('pages', $row);
391
392 if (is_array($row)) {
393 // Keep mount point?
394 $mount_info = $this->sys_page->getMountPointInfo($row['uid'], $row);
395 if (is_array($mount_info) && $mount_info['overlay']) { // There is a valid mount point.
396 $mp_row = $this->sys_page->getPage($mount_info['mount_pid']); // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
397 if (count($mp_row)) {
398 $row = $mp_row;
399 $row['_MP_PARAM'] = $mount_info['MPvar'];
400 } else unset($row); // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
401 }
402
403 // Add external MP params, then the row:
404 if (is_array($row)) {
405 if ($MP) $row['_MP_PARAM'] = $MP.($row['_MP_PARAM'] ? ','.$row['_MP_PARAM'] : '');
406 $temp[$row['uid']] = $this->sys_page->getPageOverlay($row);
407 }
408 }
409 }
410 }
411 break;
412 case 'list':
413 if ($value=='') {
414 $value=$this->id;
415 }
416 $loadDB = t3lib_div::makeInstance('FE_loadDBGroup');
417 $loadDB->start($value, 'pages');
418 $loadDB->additionalWhere['pages']=tslib_cObj::enableFields('pages');
419 $loadDB->getFromDB();
420
421 foreach($loadDB->itemArray as $val) {
422 $MP = $this->tmpl->getFromMPmap($val['id']);
423
424 // Keep mount point?
425 $mount_info = $this->sys_page->getMountPointInfo($val['id']);
426 if (is_array($mount_info) && $mount_info['overlay']) { // There is a valid mount point.
427 $mp_row = $this->sys_page->getPage($mount_info['mount_pid']); // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
428 if (count($mp_row)) {
429 $row = $mp_row;
430 $row['_MP_PARAM'] = $mount_info['MPvar'];
431
432 if ($mount_info['overlay']) { // Overlays should already have their full MPvars calculated:
433 $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']);
434 if ($MP) unset($row['_MP_PARAM']);
435 }
436 } else unset($row); // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
437 } else {
438 $row = $loadDB->results['pages'][$val['id']];
439 }
440
441 //Add versioning overlay for current page (to respect workspaces)
442 if (is_array($row)) {
443 $this->sys_page->versionOL('pages', $row, TRUE);
444 }
445
446 // Add external MP params, then the row:
447 if (is_array($row)) {
448 if ($MP) $row['_MP_PARAM'] = $MP.($row['_MP_PARAM'] ? ','.$row['_MP_PARAM'] : '');
449 $temp[] = $this->sys_page->getPageOverlay($row);
450 }
451 }
452 break;
453 case 'updated':
454 if ($value=='') {
455 $value=$GLOBALS['TSFE']->page['uid'];
456 }
457 $items=t3lib_div::intExplode(',', $value);
458 if (t3lib_utility_Math::canBeInterpretedAsInteger($this->conf['special.']['depth'])) {
459 $depth = t3lib_utility_Math::forceIntegerInRange($this->conf['special.']['depth'], 1, 20); // Tree depth
460 } else {
461 $depth=20;
462 }
463 $limit = t3lib_utility_Math::forceIntegerInRange($this->conf['special.']['limit'], 0, 100); // max number of items
464 $maxAge = intval(tslib_cObj::calc($this->conf['special.']['maxAge']));
465 if (!$limit) $limit=10;
466 $mode = $this->conf['special.']['mode']; // *'auto', 'manual', 'tstamp'
467 // Get id's
468 $id_list_arr = Array();
469
470 foreach($items as $id) {
471 $bA = t3lib_utility_Math::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100);
472 $id_list_arr[] = tslib_cObj::getTreeList(-1*$id, $depth-1+$bA, $bA-1);
473 }
474 $id_list = implode(',', $id_list_arr);
475 // Get sortField (mode)
476 switch($mode) {
477 case 'starttime':
478 $sortField = 'starttime';
479 break;
480 case 'lastUpdated':
481 case 'manual':
482 $sortField = 'lastUpdated';
483 break;
484 case 'tstamp':
485 $sortField = 'tstamp';
486 break;
487 case 'crdate':
488 $sortField = 'crdate';
489 break;
490 default:
491 $sortField = 'SYS_LASTCHANGED';
492 break;
493 }
494 // Get
495 $extraWhere = ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0').$this->getDoktypeExcludeWhere();
496
497 if ($this->conf['special.']['excludeNoSearchPages']) {
498 $extraWhere.= ' AND pages.no_search=0';
499 }
500 if ($maxAge>0) {
501 $extraWhere.=' AND '.$sortField.'>'.($GLOBALS['SIM_ACCESS_TIME']-$maxAge);
502 }
503
504 $res = $this->parent_cObj->exec_getQuery('pages', Array(
505 'pidInList' =>'0',
506 'uidInList' => $id_list,
507 'where' => $sortField . '>=0' . $extraWhere,
508 'orderBy' => ($altSortFieldValue ? $altSortFieldValue : $sortField . ' desc'),
509 'max' => $limit)
510 );
511 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
512 $GLOBALS['TSFE']->sys_page->versionOL('pages', $row);
513 if (is_array($row)) {
514 $temp[$row['uid']]=$this->sys_page->getPageOverlay($row);
515 }
516 }
517 break;
518 case 'keywords':
519 list($value)=t3lib_div::intExplode(',', $value);
520 if (!$value) {
521 $value=$GLOBALS['TSFE']->page['uid'];
522 }
523 if ($this->conf['special.']['setKeywords'] || $this->conf['special.']['setKeywords.']) {
524 $kw = isset($this->conf['special.']['setKeywords.'])
525 ? $this->parent_cObj->stdWrap($this->conf['special.']['setKeywords'], $this->conf['special.']['setKeywords.'])
526 : $this->conf['special.']['setKeywords'];
527 } else {
528 $value_rec=$this->sys_page->getPage($value); // The page record of the 'value'.
529
530 $kfieldSrc = $this->conf['special.']['keywordsField.']['sourceField'] ? $this->conf['special.']['keywordsField.']['sourceField'] : 'keywords';
531 $kw = trim(tslib_cObj::keywords($value_rec[$kfieldSrc])); // keywords.
532 }
533
534 $mode = $this->conf['special.']['mode']; // *'auto', 'manual', 'tstamp'
535 switch($mode) {
536 case 'starttime':
537 $sortField = 'starttime';
538 break;
539 case 'lastUpdated':
540 case 'manual':
541 $sortField = 'lastUpdated';
542 break;
543 case 'tstamp':
544 $sortField = 'tstamp';
545 break;
546 case 'crdate':
547 $sortField = 'crdate';
548 break;
549 default:
550 $sortField = 'SYS_LASTCHANGED';
551 break;
552 }
553
554 // depth, limit, extra where
555 if (t3lib_utility_Math::canBeInterpretedAsInteger($this->conf['special.']['depth'])) {
556 $depth = t3lib_utility_Math::forceIntegerInRange($this->conf['special.']['depth'], 0, 20); // Tree depth
557 } else {
558 $depth=20;
559 }
560 $limit = t3lib_utility_Math::forceIntegerInRange($this->conf['special.']['limit'], 0, 100); // max number of items
561 $extraWhere = ' AND pages.uid<>'.$value.($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0').$this->getDoktypeExcludeWhere();
562 if ($this->conf['special.']['excludeNoSearchPages']) {
563 $extraWhere.= ' AND pages.no_search=0';
564 }
565 // start point
566 $eLevel = tslib_cObj::getKey(
567 isset($this->conf['special.']['entryLevel.'])
568 ? $this->parent_cObj->stdWrap($this->conf['special.']['entryLevel'], $this->conf['special.']['entryLevel.'])
569 : $this->conf['special.']['entryLevel'],
570 $this->tmpl->rootLine
571 );
572 $startUid = intval($this->tmpl->rootLine[$eLevel]['uid']);
573
574 // which field is for keywords
575 $kfield = 'keywords';
576 if ( $this->conf['special.']['keywordsField'] ) {
577 list($kfield) = explode(' ', trim ($this->conf['special.']['keywordsField']));
578 }
579
580 // If there are keywords and the startuid is present.
581 if ($kw && $startUid) {
582 $bA = t3lib_utility_Math::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100);
583 $id_list=tslib_cObj::getTreeList(-1*$startUid, $depth-1+$bA, $bA-1);
584
585 $kwArr = explode(',', $kw);
586 foreach($kwArr as $word) {
587 $word = trim($word);
588 if ($word) {
589 $keyWordsWhereArr[] = $kfield.' LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($word, 'pages').'%\'';
590 }
591 }
592 $res = $this->parent_cObj->exec_getQuery('pages', Array('pidInList'=>'0', 'uidInList'=>$id_list, 'where'=>'('.implode(' OR ', $keyWordsWhereArr).')'.$extraWhere, 'orderBy'=>($altSortFieldValue ? $altSortFieldValue : $sortField.' desc'), 'max'=>$limit));
593 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
594 $GLOBALS['TSFE']->sys_page->versionOL('pages', $row);
595 if (is_array($row)) {
596 $temp[$row['uid']]=$this->sys_page->getPageOverlay($row);
597 }
598 }
599 }
600 break;
601 case 'rootline':
602 $range = isset($this->conf['special.']['range.'])
603 ? $this->parent_cObj->stdWrap($this->conf['special.']['range'], $this->conf['special.']['range.'])
604 : $this->conf['special.']['range'];
605 $begin_end = explode('|', $range);
606 $begin_end[0] = intval($begin_end[0]);
607 if (!t3lib_utility_Math::canBeInterpretedAsInteger($begin_end[1])) {
608 $begin_end[1] = -1;
609 }
610
611 $beginKey = tslib_cObj::getKey ($begin_end[0], $this->tmpl->rootLine);
612 $endKey = tslib_cObj::getKey ($begin_end[1], $this->tmpl->rootLine);
613 if ($endKey<$beginKey) {$endKey=$beginKey;}
614
615 $rl_MParray = array();
616 foreach($this->tmpl->rootLine as $k_rl => $v_rl) {
617 // For overlaid mount points, set the variable right now:
618 if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) {
619 $rl_MParray[] = $v_rl['_MP_PARAM'];
620 }
621 // Traverse rootline:
622 if ($k_rl>=$beginKey && $k_rl<=$endKey) {
623 $temp_key=$k_rl;
624 $temp[$temp_key]=$this->sys_page->getPage($v_rl['uid']);
625 if (count($temp[$temp_key])) {
626 if (!$temp[$temp_key]['target']) { // If there are no specific target for the page, put the level specific target on.
627 $temp[$temp_key]['target'] = $this->conf['special.']['targets.'][$k_rl];
628 $temp[$temp_key]['_MP_PARAM'] = implode(',', $rl_MParray);
629 }
630 } else unset($temp[$temp_key]);
631 }
632 // For normal mount points, set the variable for next level.
633 if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) {
634 $rl_MParray[] = $v_rl['_MP_PARAM'];
635 }
636 }
637 // Reverse order of elements (e.g. "1,2,3,4" gets "4,3,2,1"):
638 if (isset($this->conf['special.']['reverseOrder']) && $this->conf['special.']['reverseOrder']) {
639 $temp = array_reverse($temp);
640 $rl_MParray = array_reverse($rl_MParray);
641 }
642 break;
643 case 'browse':
644 list($value)=t3lib_div::intExplode(',', $value);
645 if (!$value) {
646 $value=$GLOBALS['TSFE']->page['uid'];
647 }
648 if ($value!=$this->tmpl->rootLine[0]['uid']) { // Will not work out of rootline
649 $recArr=array();
650 $value_rec=$this->sys_page->getPage($value); // The page record of the 'value'.
651 if ($value_rec['pid']) { // 'up' page cannot be outside rootline
652 $recArr['up']=$this->sys_page->getPage($value_rec['pid']); // The page record of 'up'.
653 }
654 if ($recArr['up']['pid'] && $value_rec['pid']!=$this->tmpl->rootLine[0]['uid']) { // If the 'up' item was NOT level 0 in rootline...
655 $recArr['index']=$this->sys_page->getPage($recArr['up']['pid']); // The page record of "index".
656 }
657
658 // prev / next is found
659 $prevnext_menu = $this->sys_page->getMenu($value_rec['pid'], '*', $altSortField);
660 $lastKey=0;
661 $nextActive=0;
662 foreach ($prevnext_menu as $k_b => $v_b) {
663 if ($nextActive) {
664 $recArr['next']=$v_b;
665 $nextActive=0;
666 }
667 if ($v_b['uid']==$value) {
668 if ($lastKey) {
669 $recArr['prev']=$prevnext_menu[$lastKey];
670 }
671 $nextActive=1;
672 }
673 $lastKey=$k_b;
674 }
675 reset($prevnext_menu);
676 $recArr['first']=pos($prevnext_menu);
677 end($prevnext_menu);
678 $recArr['last']=pos($prevnext_menu);
679
680 // prevsection / nextsection is found
681 if (is_array($recArr['index'])) { // You can only do this, if there is a valid page two levels up!
682 $prevnextsection_menu = $this->sys_page->getMenu($recArr['index']['uid'], '*', $altSortField);
683 $lastKey=0;
684 $nextActive=0;
685 foreach ($prevnextsection_menu as $k_b => $v_b) {
686 if ($nextActive) {
687 $sectionRec_temp = $this->sys_page->getMenu($v_b['uid'], '*', $altSortField);
688 if (count($sectionRec_temp)) {
689 reset($sectionRec_temp);
690 $recArr['nextsection']=pos($sectionRec_temp);
691 end ($sectionRec_temp);
692 $recArr['nextsection_last']=pos($sectionRec_temp);
693 $nextActive=0;
694 }
695 }
696 if ($v_b['uid']==$value_rec['pid']) {
697 if ($lastKey) {
698 $sectionRec_temp = $this->sys_page->getMenu($prevnextsection_menu[$lastKey]['uid'], '*', $altSortField);
699 if (count($sectionRec_temp)) {
700 reset($sectionRec_temp);
701 $recArr['prevsection']=pos($sectionRec_temp);
702 end ($sectionRec_temp);
703 $recArr['prevsection_last']=pos($sectionRec_temp);
704 }
705 }
706 $nextActive=1;
707 }
708 $lastKey=$k_b;
709 }
710 }
711 if ($this->conf['special.']['items.']['prevnextToSection']) {
712 if (!is_array($recArr['prev']) && is_array($recArr['prevsection_last'])) {
713 $recArr['prev']=$recArr['prevsection_last'];
714 }
715 if (!is_array($recArr['next']) && is_array($recArr['nextsection'])) {
716 $recArr['next']=$recArr['nextsection'];
717 }
718 }
719
720 $items = explode('|', $this->conf['special.']['items']);
721 $c=0;
722 foreach ($items as $k_b => $v_b) {
723 $v_b=strtolower(trim($v_b));
724 if (intval($this->conf['special.'][$v_b.'.']['uid'])) {
725 $recArr[$v_b] = $this->sys_page->getPage(intval($this->conf['special.'][$v_b.'.']['uid'])); // fetches the page in case of a hardcoded pid in template
726 }
727 if (is_array($recArr[$v_b])) {
728 $temp[$c]=$recArr[$v_b];
729 if ($this->conf['special.'][$v_b.'.']['target']) {
730 $temp[$c]['target']=$this->conf['special.'][$v_b.'.']['target'];
731 }
732 $tmpSpecialFields = $this->conf['special.'][$v_b.'.']['fields.'];
733 if (is_array($tmpSpecialFields)) {
734 foreach ($tmpSpecialFields as $fk => $val) {
735 $temp[$c][$fk]=$val;
736 }
737 }
738 $c++;
739 }
740 }
741 }
742 break;
743 }
744 if ($this->mconf['sectionIndex']) {
745 $sectionIndexes = array();
746
747 foreach ($temp as $page) {
748 $sectionIndexes = $sectionIndexes + $this->sectionIndex($altSortField, $page['uid']);
749 }
750
751 $temp = $sectionIndexes;
752 }
753 } elseif (is_array($this->alternativeMenuTempArray)) { // Setting $temp array if not level 1.
754 $temp = $this->alternativeMenuTempArray;
755 } elseif ($this->mconf['sectionIndex']) {
756 $temp = $this->sectionIndex($altSortField);
757 } else { // Default:
758 $temp = $this->sys_page->getMenu($this->id, '*', $altSortField); // gets the menu
759 }
760
761 $c=0;
762 $c_b=0;
763
764 $minItems = intval($this->mconf['minItems'] ? $this->mconf['minItems'] : $this->conf['minItems']);
765 $maxItems = intval($this->mconf['maxItems'] ? $this->mconf['maxItems'] : $this->conf['maxItems']);
766 $begin = tslib_cObj::calc($this->mconf['begin'] ? $this->mconf['begin'] : $this->conf['begin']);
767
768 $minItemsConf = isset($this->mconf['minItems.'])
769 ? $this->mconf['minItems.']
770 : (isset($this->conf['minItems.']) ? $this->conf['minItems.'] : NULL);
771 $minItems = is_array($minItemsConf)
772 ? $this->parent_cObj->stdWrap($minItems, $minItemsConf)
773 : $minItems;
774
775 $maxItemsConf = isset($this->mconf['maxItems.'])
776 ? $this->mconf['maxItems.']
777 : (isset($this->conf['maxItems.']) ? $this->conf['maxItems.'] : NULL);
778 $maxItems = is_array($maxItemsConf)
779 ? $this->parent_cObj->stdWrap($maxItems, $maxItemsConf)
780 : $maxItems;
781
782 $beginConf = isset($this->mconf['begin.'])
783 ? $this->mconf['begin.']
784 : (isset($this->conf['begin.']) ? $this->conf['begin.'] : NULL);
785 $begin = is_array($beginConf)
786 ? $this->parent_cObj->stdWrap($begin, $beginConf)
787 : $begin;
788
789 $banUidArray = $this->getBannedUids();
790
791 // Fill in the menuArr with elements that should go into the menu:
792 $this->menuArr = Array();
793 foreach($temp as $data) {
794 $spacer = (t3lib_div::inList($this->spacerIDList, $data['doktype']) || !strcmp($data['ITEM_STATE'], 'SPC')) ? 1 : 0; // if item is a spacer, $spacer is set
795 if ($this->filterMenuPages($data, $banUidArray, $spacer)) {
796 $c_b++;
797 if ($begin<=$c_b) { // If the beginning item has been reached.
798 $this->menuArr[$c] = $data;
799 $this->menuArr[$c]['isSpacer'] = $spacer;
800 $c++;
801 if ($maxItems && $c>=$maxItems) {
802 break;
803 }
804 }
805 }
806 }
807
808 // Fill in fake items, if min-items is set.
809 if ($minItems) {
810 while($c<$minItems) {
811 $this->menuArr[$c] = Array(
812 'title' => '...',
813 'uid' => $GLOBALS['TSFE']->id
814 );
815 $c++;
816 }
817 }
818 // Passing the menuArr through a user defined function:
819 if ($this->mconf['itemArrayProcFunc']) {
820 if (!is_array($this->parentMenuArr)) {$this->parentMenuArr=array();}
821 $this->menuArr = $this->userProcess('itemArrayProcFunc', $this->menuArr);
822 }
823 // Setting number of menu items
824 $GLOBALS['TSFE']->register['count_menuItems'] = count($this->menuArr);
825
826 $this->hash = md5(serialize($this->menuArr).serialize($this->mconf).serialize($this->tmpl->rootLine).serialize($this->MP_array));
827
828 // Get the cache timeout:
829 if ($this->conf['cache_period']) {
830 $cacheTimeout = $this->conf['cache_period'];
831 } else {
832 $cacheTimeout = $GLOBALS['TSFE']->get_cache_timeout();
833 }
834
835 $serData = $this->sys_page->getHash($this->hash);
836 if (!$serData) {
837 $this->generate();
838 $this->sys_page->storeHash($this->hash, serialize($this->result), 'MENUDATA', $cacheTimeout);
839 } else {
840 $this->result = unserialize($serData);
841 }
842
843 // End showAccessRestrictedPages
844 if ($this->mconf['showAccessRestrictedPages']) {
845 // RESTORING where_groupAccess
846 $this->sys_page->where_groupAccess = $SAVED_where_groupAccess;
847 }
848 }
849 }
850
851 /**
852 * Checks if a page is OK to include in the final menu item array. Pages can be excluded if the doktype is wrong, if they are hidden in navigation, have a uid in the list of banned uids etc.
853 *
854 * @param array Array of menu items
855 * @param array Array of page uids which are to be excluded
856 * @param boolean If set, then the page is a spacer.
857 * @return boolean Returns TRUE if the page can be safely included.
858 */
859 function filterMenuPages(&$data, $banUidArray, $spacer) {
860
861 $includePage = TRUE;
862 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/tslib/class.tslib_menu.php']['filterMenuPages'])) {
863 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/tslib/class.tslib_menu.php']['filterMenuPages'] as $classRef) {
864 $hookObject = t3lib_div::getUserObj($classRef);
865
866 if (!($hookObject instanceof tslib_menu_filterMenuPagesHook)) {
867 throw new UnexpectedValueException('$hookObject must implement interface tslib_menu_filterMenuPagesHook', 1269877402);
868 }
869
870 $includePage = $includePage && $hookObject->processFilter($data, $banUidArray, $spacer, $this);
871 }
872 }
873 if (!$includePage) {
874 return FALSE;
875 }
876
877 if ($data['_SAFE']) return TRUE;
878
879 $uid = $data['uid'];
880 if ($this->mconf['SPC'] || !$spacer) { // If the spacer-function is not enabled, spacers will not enter the $menuArr
881 if (!t3lib_div::inList($this->doktypeExcludeList, $data['doktype'])) { // Page may not be 'not_in_menu' or 'Backend User Section'
882 if (!$data['nav_hide'] || $this->conf['includeNotInMenu']) { // Not hidden in navigation
883 if (!t3lib_div::inArray($banUidArray, $uid)) { // not in banned uid's
884
885 // Checks if the default language version can be shown:
886 // Block page is set, if l18n_cfg allows plus: 1) Either default language or 2) another language but NO overlay record set for page!
887 $blockPage = $data['l18n_cfg']&1 && (!$GLOBALS['TSFE']->sys_language_uid || ($GLOBALS['TSFE']->sys_language_uid && !$data['_PAGES_OVERLAY']));
888 if (!$blockPage) {
889
890 // Checking if a page should be shown in the menu depending on whether a translation exists:
891 $tok = TRUE;
892 if ($GLOBALS['TSFE']->sys_language_uid && t3lib_div::hideIfNotTranslated($data['l18n_cfg'])) { // There is an alternative language active AND the current page requires a translation:
893 if (!$data['_PAGES_OVERLAY']) {
894 $tok = FALSE;
895 }
896 }
897
898 // Continue if token is TRUE:
899 if ($tok) {
900
901 // Checking if "&L" should be modified so links to non-accessible pages will not happen.
902 if ($this->conf['protectLvar']) {
903 $languageUid = intval($GLOBALS['TSFE']->config['config']['sys_language_uid']);
904 if ($languageUid && ($this->conf['protectLvar']=='all' || t3lib_div::hideIfNotTranslated($data['l18n_cfg']))) {
905 $olRec = $GLOBALS['TSFE']->sys_page->getPageOverlay($data['uid'], $languageUid);
906 if (!count($olRec)) {
907 // If no pages_language_overlay record then page can NOT be accessed in the language pointed to by "&L" and therefore we protect the link by setting "&L=0"
908 $data['_ADD_GETVARS'].= '&L=0';
909 }
910 }
911 }
912
913 return TRUE;
914 }
915 }
916 }
917 }
918 }
919 }
920 }
921
922 /**
923 * Generating the per-menu-item configuration arrays based on the settings for item states (NO, RO, ACT, CUR etc) set in ->mconf (config for the current menu object)
924 * Basically it will produce an individual array for each menu item based on the item states. BUT in addition the "optionSplit" syntax for the values is ALSO evaluated here so that all property-values are "option-splitted" and the output will thus be resolved.
925 * Is called from the "generate" functions in the extension classes. The function is processor intensive due to the option split feature in particular. But since the generate function is not always called (since the ->result array may be cached, see makeMenu) it doesn't hurt so badly.
926 *
927 * @param integer Number of menu items in the menu
928 * @return array An array with two keys: array($NOconf,$ROconf) - where $NOconf contains the resolved configuration for each item when NOT rolled-over and $ROconf contains the ditto for the mouseover state (if any)
929 * @access private
930 */
931 function procesItemStates($splitCount) {
932
933 // Prepare normal settings
934 if (!is_array($this->mconf['NO.']) && $this->mconf['NO']) $this->mconf['NO.']=array(); // Setting a blank array if NO=1 and there are no properties.
935 $NOconf = $this->tmpl->splitConfArray($this->mconf['NO.'], $splitCount);
936
937 // Prepare rollOver settings, overriding normal settings
938 $ROconf=array();
939 if ($this->mconf['RO']) {
940 $ROconf = $this->tmpl->splitConfArray($this->mconf['RO.'], $splitCount);
941 }
942
943 // Prepare IFSUB settings, overriding normal settings
944 // IFSUB is TRUE if there exist submenu items to the current item
945 if ($this->mconf['IFSUB']) {
946 $IFSUBinit = 0; // Flag: If $IFSUB is generated
947 foreach ($NOconf as $key => $val) {
948 if ($this->isItemState('IFSUB', $key)) {
949 if (!$IFSUBinit) { // if this is the first IFSUB element, we must generate IFSUB.
950 $IFSUBconf = $this->tmpl->splitConfArray($this->mconf['IFSUB.'], $splitCount);
951 if ($this->mconf['IFSUBRO']) {
952 $IFSUBROconf = $this->tmpl->splitConfArray($this->mconf['IFSUBRO.'], $splitCount);
953 }
954 $IFSUBinit = 1;
955 }
956 $NOconf[$key] = $IFSUBconf[$key]; // Substitute normal with ifsub
957 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
958 $ROconf[$key] = $IFSUBROconf[$key] ? $IFSUBROconf[$key] : $IFSUBconf[$key]; // If RollOver on active then apply this
959 }
960 }
961 }
962 }
963 // Prepare active settings, overriding normal settings
964 if ($this->mconf['ACT']) {
965 $ACTinit = 0; // Flag: If $ACT is generated
966 foreach ($NOconf as $key => $val) { // Find active
967 if ($this->isItemState('ACT', $key)) {
968 if (!$ACTinit) { // if this is the first 'active', we must generate ACT.
969 $ACTconf = $this->tmpl->splitConfArray($this->mconf['ACT.'], $splitCount);
970 // Prepare active rollOver settings, overriding normal active settings
971 if ($this->mconf['ACTRO']) {
972 $ACTROconf = $this->tmpl->splitConfArray($this->mconf['ACTRO.'], $splitCount);
973 }
974 $ACTinit = 1;
975 }
976 $NOconf[$key] = $ACTconf[$key]; // Substitute normal with active
977 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
978 $ROconf[$key] = $ACTROconf[$key] ? $ACTROconf[$key] : $ACTconf[$key]; // If RollOver on active then apply this
979 }
980 }
981 }
982 }
983 // Prepare ACT (active)/IFSUB settings, overriding normal settings
984 // ACTIFSUB is TRUE if there exist submenu items to the current item and the current item is active
985 if ($this->mconf['ACTIFSUB']) {
986 $ACTIFSUBinit = 0; // Flag: If $ACTIFSUB is generated
987 foreach ($NOconf as $key => $val) { // Find active
988 if ($this->isItemState('ACTIFSUB', $key)) {
989 if (!$ACTIFSUBinit) { // if this is the first 'active', we must generate ACTIFSUB.
990 $ACTIFSUBconf = $this->tmpl->splitConfArray($this->mconf['ACTIFSUB.'], $splitCount);
991 // Prepare active rollOver settings, overriding normal active settings
992 if ($this->mconf['ACTIFSUBRO']) {
993 $ACTIFSUBROconf = $this->tmpl->splitConfArray($this->mconf['ACTIFSUBRO.'], $splitCount);
994 }
995 $ACTIFSUBinit = 1;
996 }
997 $NOconf[$key] = $ACTIFSUBconf[$key]; // Substitute normal with active
998 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
999 $ROconf[$key] = $ACTIFSUBROconf[$key] ? $ACTIFSUBROconf[$key] : $ACTIFSUBconf[$key]; // If RollOver on active then apply this
1000 }
1001 }
1002 }
1003 }
1004 // Prepare CUR (current) settings, overriding normal settings
1005 // CUR is TRUE if the current page equals the item here!
1006 if ($this->mconf['CUR']) {
1007 $CURinit = 0; // Flag: If $CUR is generated
1008 foreach ($NOconf as $key => $val) {
1009 if ($this->isItemState('CUR', $key)) {
1010 if (!$CURinit) { // if this is the first 'current', we must generate CUR. Basically this control is just inherited from the other implementations as current would only exist one time and thats it (unless you use special-features of HMENU)
1011 $CURconf = $this->tmpl->splitConfArray($this->mconf['CUR.'], $splitCount);
1012 if ($this->mconf['CURRO']) {
1013 $CURROconf = $this->tmpl->splitConfArray($this->mconf['CURRO.'], $splitCount);
1014 }
1015 $CURinit = 1;
1016 }
1017 $NOconf[$key] = $CURconf[$key]; // Substitute normal with current
1018 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1019 $ROconf[$key] = $CURROconf[$key] ? $CURROconf[$key] : $CURconf[$key]; // If RollOver on active then apply this
1020 }
1021 }
1022 }
1023 }
1024 // Prepare CUR (current)/IFSUB settings, overriding normal settings
1025 // CURIFSUB is TRUE if there exist submenu items to the current item and the current page equals the item here!
1026 if ($this->mconf['CURIFSUB']) {
1027 $CURIFSUBinit = 0; // Flag: If $CURIFSUB is generated
1028 foreach ($NOconf as $key => $val) {
1029 if ($this->isItemState('CURIFSUB', $key)) {
1030 if (!$CURIFSUBinit) { // if this is the first 'current', we must generate CURIFSUB.
1031 $CURIFSUBconf = $this->tmpl->splitConfArray($this->mconf['CURIFSUB.'], $splitCount);
1032 // Prepare current rollOver settings, overriding normal current settings
1033 if ($this->mconf['CURIFSUBRO']) {
1034 $CURIFSUBROconf = $this->tmpl->splitConfArray($this->mconf['CURIFSUBRO.'], $splitCount);
1035 }
1036 $CURIFSUBinit = 1;
1037 }
1038 $NOconf[$key] = $CURIFSUBconf[$key]; // Substitute normal with active
1039 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the current
1040 $ROconf[$key] = $CURIFSUBROconf[$key] ? $CURIFSUBROconf[$key] : $CURIFSUBconf[$key]; // If RollOver on current then apply this
1041 }
1042 }
1043 }
1044 }
1045 // Prepare active settings, overriding normal settings
1046 if ($this->mconf['USR']) {
1047 $USRinit = 0; // Flag: If $USR is generated
1048 foreach ($NOconf as $key => $val) { // Find active
1049 if ($this->isItemState('USR', $key)) {
1050 if (!$USRinit) { // if this is the first active, we must generate USR.
1051 $USRconf = $this->tmpl->splitConfArray($this->mconf['USR.'], $splitCount);
1052 // Prepare active rollOver settings, overriding normal active settings
1053 if ($this->mconf['USRRO']) {
1054 $USRROconf = $this->tmpl->splitConfArray($this->mconf['USRRO.'], $splitCount);
1055 }
1056 $USRinit = 1;
1057 }
1058 $NOconf[$key] = $USRconf[$key]; // Substitute normal with active
1059 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1060 $ROconf[$key] = $USRROconf[$key] ? $USRROconf[$key] : $USRconf[$key]; // If RollOver on active then apply this
1061 }
1062 }
1063 }
1064 }
1065 // Prepare spacer settings, overriding normal settings
1066 if ($this->mconf['SPC']) {
1067 $SPCinit = 0; // Flag: If $SPC is generated
1068 foreach ($NOconf as $key => $val) { // Find spacers
1069 if ($this->isItemState('SPC', $key)) {
1070 if (!$SPCinit) { // if this is the first spacer, we must generate SPC.
1071 $SPCconf = $this->tmpl->splitConfArray($this->mconf['SPC.'], $splitCount);
1072 $SPCinit = 1;
1073 }
1074 $NOconf[$key] = $SPCconf[$key]; // Substitute normal with spacer
1075 }
1076 }
1077 }
1078 // Prepare Userdefined settings
1079 if ($this->mconf['USERDEF1']) {
1080 $USERDEF1init = 0; // Flag: If $USERDEF1 is generated
1081 foreach ($NOconf as $key => $val) { // Find active
1082 if ($this->isItemState('USERDEF1', $key)) {
1083 if (!$USERDEF1init) { // if this is the first active, we must generate USERDEF1.
1084 $USERDEF1conf = $this->tmpl->splitConfArray($this->mconf['USERDEF1.'], $splitCount);
1085 // Prepare active rollOver settings, overriding normal active settings
1086 if ($this->mconf['USERDEF1RO']) {
1087 $USERDEF1ROconf = $this->tmpl->splitConfArray($this->mconf['USERDEF1RO.'], $splitCount);
1088 }
1089 $USERDEF1init = 1;
1090 }
1091 $NOconf[$key] = $USERDEF1conf[$key]; // Substitute normal with active
1092 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1093 $ROconf[$key] = $USERDEF1ROconf[$key] ? $USERDEF1ROconf[$key] : $USERDEF1conf[$key]; // If RollOver on active then apply this
1094 }
1095 }
1096 }
1097 }
1098 // Prepare Userdefined settings
1099 if ($this->mconf['USERDEF2']) {
1100 $USERDEF2init = 0; // Flag: If $USERDEF2 is generated
1101 foreach ($NOconf as $key => $val) { // Find active
1102 if ($this->isItemState('USERDEF2', $key)) {
1103 if (!$USERDEF2init) { // if this is the first active, we must generate USERDEF2.
1104 $USERDEF2conf = $this->tmpl->splitConfArray($this->mconf['USERDEF2.'], $splitCount);
1105 // Prepare active rollOver settings, overriding normal active settings
1106 if ($this->mconf['USERDEF2RO']) {
1107 $USERDEF2ROconf = $this->tmpl->splitConfArray($this->mconf['USERDEF2RO.'], $splitCount);
1108 }
1109 $USERDEF2init = 1;
1110 }
1111 $NOconf[$key] = $USERDEF2conf[$key]; // Substitute normal with active
1112 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1113 $ROconf[$key] = $USERDEF2ROconf[$key] ? $USERDEF2ROconf[$key] : $USERDEF2conf[$key]; // If RollOver on active then apply this
1114 }
1115 }
1116 }
1117 }
1118
1119 return array($NOconf, $ROconf);
1120 }
1121
1122 /**
1123 * Creates the URL, target and onclick values for the menu item link. Returns them in an array as key/value pairs for <A>-tag attributes
1124 * This function doesn't care about the url, because if we let the url be redirected, it will be logged in the stat!!!
1125 *
1126 * @param integer Pointer to a key in the $this->menuArr array where the value for that key represents the menu item we are linking to (page record)
1127 * @param string Alternative target
1128 * @param integer Alternative type
1129 * @return array Returns an array with A-tag attributes as key/value pairs (HREF, TARGET and onClick)
1130 * @access private
1131 */
1132 function link($key, $altTarget='', $typeOverride='') {
1133
1134 // Mount points:
1135 $MP_var = $this->getMPvar($key);
1136 $MP_params = $MP_var ? '&MP='.rawurlencode($MP_var) : '';
1137
1138 // Setting override ID
1139 if ($this->mconf['overrideId'] || $this->menuArr[$key]['overrideId']) {
1140 $overrideArray = array();
1141 // If a user script returned the value overrideId in the menu array we use that as page id
1142 $overrideArray['uid'] = $this->mconf['overrideId']?$this->mconf['overrideId']:$this->menuArr[$key]['overrideId'];
1143 $overrideArray['alias'] = '';
1144 $MP_params = ''; // clear MP parameters since ID was changed.
1145 } else {
1146 $overrideArray='';
1147 }
1148
1149 // Setting main target:
1150 if ($altTarget) {
1151 $mainTarget = $altTarget;
1152 } elseif ($this->mconf['target.']) {
1153 $mainTarget = $this->parent_cObj->stdWrap($this->mconf['target'], $this->mconf['target.']);
1154 } else {
1155 $mainTarget = $this->mconf['target'];
1156 }
1157
1158 // Creating link:
1159 if ($this->mconf['collapse'] && $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key))) {
1160 $thePage = $this->sys_page->getPage($this->menuArr[$key]['pid']);
1161 $LD = $this->menuTypoLink($thePage, $mainTarget, '', '', $overrideArray, $this->mconf['addParams'].$MP_params.$this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
1162 } else {
1163 $LD = $this->menuTypoLink($this->menuArr[$key], $mainTarget, '', '', $overrideArray, $this->mconf['addParams'].$MP_params.$this->I['val']['additionalParams'].$this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
1164 }
1165
1166 // Override URL if using "External URL" as doktype with a valid e-mail address:
1167 if ($this->menuArr[$key]['doktype'] == t3lib_pageSelect::DOKTYPE_LINK && $this->menuArr[$key]['urltype'] == 3 && t3lib_div::validEmail($this->menuArr[$key]['url'])) {
1168 // Create mailto-link using tslib_cObj::typolink (concerning spamProtectEmailAddresses):
1169 $LD['totalURL'] = $this->parent_cObj->typoLink_URL(array('parameter' => $this->menuArr[$key]['url']));
1170 $LD['target'] = '';
1171 }
1172
1173 // Override url if current page is a shortcut
1174 if ($this->menuArr[$key]['doktype'] == t3lib_pageSelect::DOKTYPE_SHORTCUT
1175 && $this->menuArr[$key]['shortcut_mode'] != t3lib_pageSelect::SHORTCUT_MODE_RANDOM_SUBPAGE) {
1176
1177 $shortcut = NULL;
1178 try {
1179 $shortcut = $GLOBALS['TSFE']->getPageShortcut(
1180 $this->menuArr[$key]['shortcut'],
1181 $this->menuArr[$key]['shortcut_mode'],
1182 $this->menuArr[$key]['uid']
1183 );
1184 } catch (Exception $ex) {
1185 // shortcut configuration is wrong and Exception is thrown
1186 // this will be catched with the next is_array() check
1187 }
1188
1189 if (!is_array($shortcut)) {
1190 return array();
1191 }
1192
1193 // Only setting url, not target
1194 $LD['totalURL'] = $this->parent_cObj->typoLink_URL(array(
1195 'parameter' => $shortcut['uid'],
1196 'additionalParams' => $this->mconf['addParams'] . $MP_params . $this->I['val']['additionalParams'] . $this->menuArr[$key]['_ADD_GETVARS'],
1197 ));
1198 }
1199
1200 // Manipulation in case of access restricted pages:
1201 $this->changeLinksForAccessRestrictedPages($LD, $this->menuArr[$key], $mainTarget, $typeOverride);
1202
1203 // Overriding URL / Target if set to do so:
1204 if ($this->menuArr[$key]['_OVERRIDE_HREF']) {
1205 $LD['totalURL'] = $this->menuArr[$key]['_OVERRIDE_HREF'];
1206 if ($this->menuArr[$key]['_OVERRIDE_TARGET']) $LD['target'] = $this->menuArr[$key]['_OVERRIDE_TARGET'];
1207 }
1208
1209 // OnClick open in windows.
1210 $onClick='';
1211 if ($this->mconf['JSWindow']) {
1212 $conf=$this->mconf['JSWindow.'];
1213 $url=$LD['totalURL'];
1214 $LD['totalURL'] = '#';
1215 $onClick= 'openPic(\''.$GLOBALS['TSFE']->baseUrlWrap($url).'\',\''.($conf['newWindow']?md5($url):'theNewPage').'\',\''.$conf['params'].'\'); return false;';
1216 $GLOBALS['TSFE']->setJS('openPic');
1217 }
1218
1219 // look for type and popup
1220 // following settings are valid in field target:
1221 // 230 will add type=230 to the link
1222 // 230 500x600 will add type=230 to the link and open in popup window with 500x600 pixels
1223 // 230 _blank will add type=230 to the link and open with target "_blank"
1224 // 230x450:resizable=0,location=1 will open in popup window with 500x600 pixels with settings "resizable=0,location=1"
1225 $matches = array();
1226 $targetIsType = $LD['target'] && (string) intval($LD['target']) == trim($LD['target']) ? intval($LD['target']) : FALSE;
1227 if (preg_match('/([0-9]+[\s])?(([0-9]+)x([0-9]+))?(:.+)?/s', $LD['target'], $matches) || $targetIsType) {
1228 // has type?
1229 if (intval($matches[1]) || $targetIsType) {
1230 $LD['totalURL'] = $this->parent_cObj->URLqMark(
1231 $LD['totalURL'],
1232 '&type=' . ($targetIsType ? $targetIsType : intval($matches[1]))
1233 );
1234 $LD['target'] = $targetIsType ? '' : trim(substr($LD['target'], strlen($matches[1]) + 1));
1235 }
1236 // open in popup window?
1237 if ($matches[3] && $matches[4]) {
1238 $JSparamWH = 'width=' . $matches[3] . ',height=' . $matches[4] . ($matches[5] ? ',' . substr($matches[5], 1) : '');
1239 $onClick = 'vHWin=window.open(\'' . $LD['totalURL'] . '\',\'FEopenLink\',\'' . $JSparamWH . '\');vHWin.focus();return false;';
1240 $LD['target'] = '';
1241 }
1242 }
1243
1244 // out:
1245 $list = array();
1246 $list['HREF'] = strlen($LD['totalURL']) ? $LD['totalURL'] : $GLOBALS['TSFE']->baseUrl; // Added this check: What it does is to enter the baseUrl (if set, which it should for "realurl" based sites) as URL if the calculated value is empty. The problem is that no link is generated with a blank URL and blank URLs might appear when the realurl encoding is used and a link to the frontpage is generated.
1247 $list['TARGET'] = $LD['target'];
1248 $list['onClick'] = $onClick;
1249
1250 return $list;
1251 }
1252
1253 /**
1254 * Will change $LD (passed by reference) if the page is access restricted
1255 *
1256 * @param array $LD, the array from the linkData() function
1257 * @param array Page array
1258 * @param string Main target value
1259 * @param string Type number override if any
1260 * @return void ($LD passed by reference might be changed.)
1261 */
1262 function changeLinksForAccessRestrictedPages(&$LD, $page, $mainTarget, $typeOverride) {
1263
1264 // If access restricted pages should be shown in menus, change the link of such pages to link to a redirection page:
1265 if ($this->mconf['showAccessRestrictedPages'] && $this->mconf['showAccessRestrictedPages']!=='NONE' && !$GLOBALS['TSFE']->checkPageGroupAccess($page)) {
1266 $thePage = $this->sys_page->getPage($this->mconf['showAccessRestrictedPages']);
1267
1268 $addParams = $this->mconf['showAccessRestrictedPages.']['addParams'];
1269 $addParams = str_replace('###RETURN_URL###', rawurlencode($LD['totalURL']), $addParams);
1270 $addParams = str_replace('###PAGE_ID###', $page['uid'], $addParams);
1271 $LD = $this->menuTypoLink($thePage, $mainTarget, '', '', '', $addParams, $typeOverride);
1272 }
1273 }
1274
1275 /**
1276 * Creates a submenu level to the current level - if configured for.
1277 *
1278 * @param integer Page id of the current page for which a submenu MAY be produced (if conditions are met)
1279 * @param string Object prefix, see ->start()
1280 * @return string HTML content of the submenu
1281 * @access private
1282 */
1283 function subMenu($uid, $objSuffix='') {
1284
1285 // Setting alternative menu item array if _SUB_MENU has been defined in the current ->menuArr
1286 $altArray = '';
1287 if (is_array($this->menuArr[$this->I['key']]['_SUB_MENU']) && count($this->menuArr[$this->I['key']]['_SUB_MENU'])) {
1288 $altArray = $this->menuArr[$this->I['key']]['_SUB_MENU'];
1289 }
1290
1291 // Make submenu if the page is the next active
1292 $cls = strtolower($this->conf[($this->menuNumber+1).$objSuffix]);
1293 $subLevelClass = ($cls && t3lib_div::inList($this->tmpl->menuclasses, $cls)) ? $cls : '';
1294
1295 // stdWrap for expAll
1296 if (isset($this->mconf['expAll.'])) {
1297 $this->mconf['expAll'] = $this->parent_cObj->stdWrap($this->mconf['expAll'], $this->mconf['expAll.']);
1298 }
1299
1300 if ($subLevelClass && ($this->mconf['expAll'] || $this->isNext($uid, $this->getMPvar($this->I['key'])) || is_array($altArray)) && !$this->mconf['sectionIndex']) {
1301 $submenu = t3lib_div::makeInstance('tslib_'.$subLevelClass);
1302 $submenu->entryLevel = $this->entryLevel+1;
1303 $submenu->rL_uidRegister = $this->rL_uidRegister;
1304 $submenu->MP_array = $this->MP_array;
1305 if ($this->menuArr[$this->I['key']]['_MP_PARAM']) {
1306 $submenu->MP_array[] = $this->menuArr[$this->I['key']]['_MP_PARAM'];
1307 }
1308
1309 // especially scripts that build the submenu needs the parent data
1310 $submenu->parent_cObj = $this->parent_cObj;
1311 $submenu->parentMenuArr = $this->menuArr;
1312
1313 // Setting alternativeMenuTempArray (will be effective only if an array)
1314 if (is_array($altArray)) {
1315 $submenu->alternativeMenuTempArray = $altArray;
1316 }
1317
1318 if ($submenu->start($this->tmpl, $this->sys_page, $uid, $this->conf, $this->menuNumber+1, $objSuffix)) {
1319 $submenu->makeMenu();
1320 // Memorize the current menu item count
1321 $tempCountMenuObj = $GLOBALS['TSFE']->register['count_MENUOBJ'];
1322 // Reset the menu item count for the submenu
1323 $GLOBALS['TSFE']->register['count_MENUOBJ'] = 0;
1324 $content = $submenu->writeMenu();
1325 // Restore the item count now that the submenu has been handled
1326 $GLOBALS['TSFE']->register['count_MENUOBJ'] = $tempCountMenuObj;
1327 $GLOBALS['TSFE']->register['count_menuItems'] = count($this->menuArr);
1328 return $content;
1329 }
1330 }
1331 }
1332
1333 /**
1334 * Returns TRUE if the page with UID $uid is the NEXT page in root line (which means a submenu should be drawn)
1335 *
1336 * @param integer Page uid to evaluate.
1337 * @param string MPvar for the current position of item.
1338 * @return boolean TRUE if page with $uid is active
1339 * @access private
1340 * @see subMenu()
1341 */
1342 function isNext($uid, $MPvar='') {
1343
1344 // Check for always active PIDs:
1345 if (count($this->alwaysActivePIDlist) && in_array($uid, $this->alwaysActivePIDlist)) {
1346 return TRUE;
1347 }
1348
1349 $testUid = $uid.($MPvar?':'.$MPvar:'');
1350 if ($uid && $testUid==$this->nextActive) {
1351 return TRUE;
1352 }
1353 }
1354
1355 /**
1356 * Returns TRUE if the page with UID $uid is active (in the current rootline)
1357 *
1358 * @param integer Page uid to evaluate.
1359 * @param string MPvar for the current position of item.
1360 * @return boolean TRUE if page with $uid is active
1361 * @access private
1362 */
1363 function isActive($uid, $MPvar='') {
1364
1365 // Check for always active PIDs:
1366 if (count($this->alwaysActivePIDlist) && in_array($uid, $this->alwaysActivePIDlist)) {
1367 return TRUE;
1368 }
1369
1370 $testUid = $uid.($MPvar?':'.$MPvar:'');
1371 if ($uid && in_array('ITEM:'.$testUid, $this->rL_uidRegister)) {
1372 return TRUE;
1373 }
1374 }
1375
1376 /**
1377 * Returns TRUE if the page with UID $uid is the CURRENT page (equals $GLOBALS['TSFE']->id)
1378 *
1379 * @param integer Page uid to evaluate.
1380 * @param string MPvar for the current position of item.
1381 * @return boolean TRUE if page $uid = $GLOBALS['TSFE']->id
1382 * @access private
1383 */
1384 function isCurrent($uid, $MPvar='') {
1385 $testUid = $uid.($MPvar?':'.$MPvar:'');
1386 if ($uid && !strcmp(end($this->rL_uidRegister), 'ITEM:'.$testUid)) {
1387 return TRUE;
1388 }
1389 }
1390
1391 /**
1392 * Returns TRUE if there is a submenu with items for the page id, $uid
1393 * Used by the item states "IFSUB", "ACTIFSUB" and "CURIFSUB" to check if there is a submenu
1394 *
1395 * @param int $uid Page uid for which to search for a submenu
1396 * @return boolean Returns TRUE if there was a submenu with items found
1397 * @access private
1398 */
1399 function isSubMenu($uid) {
1400 // Looking for a mount-pid for this UID since if that
1401 // exists we should look for a subpages THERE and not in the input $uid;
1402 $mount_info = $this->sys_page->getMountPointInfo($uid);
1403 if (is_array($mount_info)) {
1404 $uid = $mount_info['mount_pid'];
1405 }
1406
1407 $recs = $this->sys_page->getMenu(
1408 $uid,
1409 'uid,pid,doktype,mount_pid,mount_pid_ol,nav_hide,shortcut,shortcut_mode,l18n_cfg'
1410 );
1411
1412 $hasSubPages = FALSE;
1413 foreach ($recs as $theRec) {
1414 // no valid subpage if the document type is excluded from the menu
1415 if (t3lib_div::inList($this->doktypeExcludeList, $theRec['doktype'])) {
1416 continue;
1417 }
1418
1419 // no valid subpage if the page is hidden inside menus and
1420 // it wasn't forced to show such entries
1421 if ($theRec['nav_hide'] && !$this->conf['includeNotInMenu']) {
1422 continue;
1423 }
1424
1425 // no valid subpage if the default language should be shown and the page settings
1426 // are excluding the visibility of the default language
1427 if (!$GLOBALS['TSFE']->sys_language_uid && t3lib_div::hideIfDefaultLanguage($theRec['l18n_cfg'])) {
1428 continue;
1429 }
1430
1431 // no valid subpage if the alternative language should be shown and the page settings
1432 // are requiring a valid overlay but it doesn't exists
1433 $hideIfNotTranslated = t3lib_div::hideIfNotTranslated($theRec['l18n_cfg']);
1434 if ($GLOBALS['TSFE']->sys_language_uid && $hideIfNotTranslated && !$theRec['_PAGES_OVERLAY']) {
1435 continue;
1436 }
1437
1438 $hasSubPages = TRUE;
1439 break;
1440 }
1441
1442 return $hasSubPages;
1443 }
1444
1445 /**
1446 * Used by procesItemStates() to evaluate if a menu item (identified by $key) is in a certain state.
1447 *
1448 * @param string The item state to evaluate (SPC, IFSUB, ACT etc... but no xxxRO states of course)
1449 * @param integer Key pointing to menu item from ->menuArr
1450 * @return boolean True (integer!=0) if match, otherwise FALSE (=0, zero)
1451 * @access private
1452 * @see procesItemStates()
1453 */
1454 function isItemState($kind, $key) {
1455 $natVal=0;
1456 if ($this->menuArr[$key]['ITEM_STATE']) { // If any value is set for ITEM_STATE the normal evaluation is discarded
1457 if (!strcmp($this->menuArr[$key]['ITEM_STATE'], $kind)) {$natVal=1;}
1458 } else {
1459 switch($kind) {
1460 case 'SPC':
1461 $natVal = $this->menuArr[$key]['isSpacer'];
1462 break;
1463 case 'IFSUB':
1464 $natVal = $this->isSubMenu($this->menuArr[$key]['uid']);
1465 break;
1466 case 'ACT':
1467 $natVal = $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key));
1468 break;
1469 case 'ACTIFSUB':
1470 $natVal = $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key)) && $this->isSubMenu($this->menuArr[$key]['uid']);
1471 break;
1472 case 'CUR':
1473 $natVal = $this->isCurrent($this->menuArr[$key]['uid'], $this->getMPvar($key));
1474 break;
1475 case 'CURIFSUB':
1476 $natVal = $this->isCurrent($this->menuArr[$key]['uid'], $this->getMPvar($key)) && $this->isSubMenu($this->menuArr[$key]['uid']);
1477 break;
1478 case 'USR':
1479 $natVal = $this->menuArr[$key]['fe_group'];
1480 break;
1481 }
1482 }
1483
1484 return $natVal;
1485 }
1486
1487 /**
1488 * Creates an access-key for a TMENU/GMENU menu item based on the menu item titles first letter
1489 *
1490 * @param string Menu item title.
1491 * @return array Returns an array with keys "code" ("accesskey" attribute for the img-tag) and "alt" (text-addition to the "alt" attribute) if an access key was defined. Otherwise array was empty
1492 * @access private
1493 */
1494 function accessKey($title) {
1495 // The global array ACCESSKEY is used to globally control if letters are already used!!
1496 $result = Array();
1497
1498 $title = trim(strip_tags($title));
1499 $titleLen = strlen($title);
1500 for ($a=0;$a<$titleLen;$a++) {
1501 $key = strtoupper(substr($title, $a, 1));
1502 if (preg_match('/[A-Z]/', $key) && !isset($GLOBALS['TSFE']->accessKey[$key])) {
1503 $GLOBALS['TSFE']->accessKey[$key] = 1;
1504 $result['code'] = ' accesskey="'.$key.'"';
1505 $result['alt'] = ' (ALT+'.$key.')';
1506 $result['key'] = $key;
1507 break;
1508 }
1509 }
1510 return $result;
1511 }
1512
1513 /**
1514 * Calls a user function for processing of internal data.
1515 * Used for the properties "IProcFunc" and "itemArrayProcFunc"
1516 *
1517 * @param string Key pointing for the property in the current ->mconf array holding possibly parameters to pass along to the function/method. Currently the keys used are "IProcFunc" and "itemArrayProcFunc".
1518 * @param mixed A variable to pass to the user function and which should be returned again from the user function. The idea is that the user function modifies this variable according to what you want to achieve and then returns it. For "itemArrayProcFunc" this variable is $this->menuArr, for "IProcFunc" it is $this->I
1519 * @return mixed The processed $passVar
1520 * @access private
1521 */
1522 function userProcess($mConfKey, $passVar) {
1523 if ($this->mconf[$mConfKey]) {
1524 $funcConf = $this->mconf[$mConfKey.'.'];
1525 $funcConf['parentObj'] = $this;
1526 $passVar = $this->parent_cObj->callUserFunction($this->mconf[$mConfKey], $funcConf, $passVar);
1527 }
1528 return $passVar;
1529 }
1530
1531 /**
1532 * Creates the <A> tag parts for the current item (in $this->I, [A1] and [A2]) based on other information in this array (like $this->I['linkHREF'])
1533 *
1534 * @return void
1535 * @access private
1536 */
1537 function setATagParts() {
1538 $this->I['A1'] = '<a '.t3lib_div::implodeAttributes($this->I['linkHREF'], 1).' '.$this->I['val']['ATagParams'].$this->I['accessKey']['code'].'>';
1539 $this->I['A2'] = '</a>';
1540 }
1541
1542 /**
1543 * Returns the title for the navigation
1544 *
1545 * @param string The current page title
1546 * @param string The current value of the navigation title
1547 * @return string Returns the navigation title if it is NOT blank, otherwise the page title.
1548 * @access private
1549 */
1550 function getPageTitle($title, $nav_title) {
1551 return strcmp(trim($nav_title), '') ? $nav_title : $title;
1552 }
1553
1554 /**
1555 * Return MPvar string for entry $key in ->menuArr
1556 *
1557 * @param integer Pointer to element in ->menuArr
1558 * @param string Implode token.
1559 * @return string MP vars for element.
1560 * @see link()
1561 */
1562 function getMPvar($key) {
1563 if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1564 $localMP_array = $this->MP_array;
1565 if ($this->menuArr[$key]['_MP_PARAM']) $localMP_array[] = $this->menuArr[$key]['_MP_PARAM']; // NOTICE: "_MP_PARAM" is allowed to be a commalist of PID pairs!
1566 $MP_params = count($localMP_array) ? implode(',', $localMP_array) : '';
1567 return $MP_params;
1568 }
1569 }
1570
1571 /**
1572 * Returns where clause part to exclude 'not in menu' pages
1573 *
1574 * @return string where clause part.
1575 * @access private
1576 */
1577 function getDoktypeExcludeWhere() {
1578 return $this->doktypeExcludeList ? ' AND pages.doktype NOT IN ('.$this->doktypeExcludeList.')' : '';
1579 }
1580
1581 /**
1582 * Returns an array of banned UIDs (from excludeUidList)
1583 *
1584 * @return array Array of banned UIDs
1585 * @access private
1586 */
1587 function getBannedUids() {
1588 $banUidArray = array();
1589
1590 if (trim($this->conf['excludeUidList'])) {
1591 $banUidList = str_replace('current', $GLOBALS['TSFE']->page['uid'], $this->conf['excludeUidList']);
1592 $banUidArray = t3lib_div::intExplode(',', $banUidList);
1593 }
1594
1595 return $banUidArray;
1596 }
1597
1598 /**
1599 * Calls typolink to create menu item links.
1600 *
1601 * @param array $page Page record (uid points where to link to)
1602 * @param string $oTarget Target frame/window
1603 * @param boolean $no_cache TRUE if caching should be disabled
1604 * @param string $script Alternative script name
1605 * @param array $overrideArray Array to override values in $page
1606 * @param string $addParams Parameters to add to URL
1607 * @param array $typeOverride "type" value
1608 * @return array See linkData
1609 */
1610 function menuTypoLink($page, $oTarget, $no_cache, $script, $overrideArray = '', $addParams = '', $typeOverride = '') {
1611 $conf = array(
1612 'parameter' => is_array($overrideArray) && $overrideArray['uid'] ? $overrideArray['uid'] : $page['uid'],
1613 );
1614 if ($typeOverride && t3lib_utility_Math::canBeInterpretedAsInteger($typeOverride)) {
1615 $conf['parameter'] .= ',' . $typeOverride;
1616 }
1617 if ($addParams) {
1618 $conf['additionalParams'] = $addParams;
1619 }
1620 if ($no_cache) {
1621 $conf['no_cache'] = TRUE;
1622 }
1623 if ($oTarget) {
1624 $conf['target'] = $oTarget;
1625 }
1626 if ($page['sectionIndex_uid']) {
1627 $conf['section'] = $page['sectionIndex_uid'];
1628 }
1629
1630 $this->parent_cObj->typoLink('|', $conf);
1631 $LD = $this->parent_cObj->lastTypoLinkLD;
1632 $LD['totalURL'] = $this->parent_cObj->lastTypoLinkUrl;
1633 return $LD;
1634 }
1635
1636 /**
1637 * Generates a list of content objects with sectionIndex enabled
1638 * available on a specific page
1639 *
1640 * Used for menu's with sectionIndex enabled
1641 *
1642 * @param string $altSortField Alternative sorting field
1643 * @param integer $pid The page id to search for sections
1644 * @return array
1645 */
1646 protected function sectionIndex($altSortField, $pid = NULL) {
1647 $where = 'colPos=0';
1648
1649 if (!$pid) {
1650 $pid = $this->id;
1651 if ($GLOBALS['TSFE']->sys_language_uid && count($this->sys_page->getPageOverlay($pid))) {
1652 $where .= ' AND sys_language_uid=' . intval($GLOBALS['TSFE']->sys_language_uid);
1653 } else {
1654 $where .= ' AND sys_language_uid=0';
1655 }
1656 }
1657
1658 $selectSetup = array(
1659 'pidInList' => $pid,
1660 'orderBy' => $altSortField,
1661 'where' => $where,
1662 'andWhere' => 'sectionIndex<>0'
1663 );
1664 switch ($this->mconf['sectionIndex.']['type']) {
1665 case 'all':
1666 unset($selectSetup['andWhere']);
1667 break;
1668 case 'header':
1669 $selectSetup['andWhere'] .= ' AND header_layout<>100 AND header!=""';
1670 break;
1671 }
1672 $basePageRow = $this->sys_page->getPage($pid);
1673 $result = array();
1674 if (is_array($basePageRow)) {
1675 $res = $this->parent_cObj->exec_getQuery('tt_content', $selectSetup);
1676
1677 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1678 $GLOBALS['TSFE']->sys_page->versionOL('tt_content', $row);
1679
1680 if (is_array($row)) {
1681 $result[$row['uid']] = $basePageRow;
1682 $result[$row['uid']]['title'] = $row['header'];
1683 $result[$row['uid']]['nav_title'] = $row['header'];
1684 $result[$row['uid']]['subtitle'] = $row['subheader'];
1685 $result[$row['uid']]['starttime'] = $row['starttime'];
1686 $result[$row['uid']]['endtime'] = $row['endtime'];
1687 $result[$row['uid']]['fe_group'] = $row['fe_group'];
1688 $result[$row['uid']]['media'] = $row['media'];
1689
1690 $result[$row['uid']]['header_layout'] = $row['header_layout'];
1691 $result[$row['uid']]['bodytext'] = $row['bodytext'];
1692 $result[$row['uid']]['image'] = $row['image'];
1693
1694 $result[$row['uid']]['sectionIndex_uid'] = $row['uid'];
1695 }
1696 }
1697
1698 if (is_resource($res)) {
1699 $GLOBALS['TYPO3_DB']->sql_free_result($res);
1700 }
1701 }
1702
1703 return $result;
1704 }
1705
1706 }
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726 /**
1727 * Extension class creating text based menus
1728 *
1729 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
1730 * @package TYPO3
1731 * @subpackage tslib
1732 */
1733 class tslib_tmenu extends tslib_menu {
1734
1735 /**
1736 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
1737 * Sets the result for the new "normal state" in $this->result
1738 *
1739 * @return void
1740 * @see tslib_menu::procesItemStates()
1741 */
1742 function generate() {
1743 $splitCount = count($this->menuArr);
1744 if ($splitCount) {
1745 list($NOconf) = $this->procesItemStates($splitCount);
1746 }
1747 if ($this->mconf['debugItemConf']) {
1748 echo '<h3>$NOconf:</h3>';
1749 debug($NOconf);
1750 }
1751 $this->result = $NOconf;
1752 }
1753
1754 /**
1755 * Traverses the ->result array of menu items configuration (made by ->generate()) and renders each item.
1756 * 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 TMENU_LAYERS
1757 * An instance of tslib_cObj is also made and for each menu item rendered it is loaded with the record for that page so that any stdWrap properties that applies will have the current menu items record available.
1758 *
1759 * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
1760 */
1761 function writeMenu() {
1762 if (is_array($this->result) && count($this->result)) {
1763 $this->WMcObj = t3lib_div::makeInstance('tslib_cObj'); // Create new tslib_cObj for our use
1764 $this->WMresult = '';
1765 $this->INPfixMD5 = substr(md5(microtime().'tmenu'), 0, 4);
1766 $this->WMmenuItems = count($this->result);
1767
1768 $this->WMsubmenuObjSuffixes = $this->tmpl->splitConfArray(array('sOSuffix'=>$this->mconf['submenuObjSuffixes']), $this->WMmenuItems);
1769
1770 $this->extProc_init();
1771 foreach ($this->result as $key => $val) {
1772 $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ']++;
1773 $GLOBALS['TSFE']->register['count_MENUOBJ']++;
1774
1775 $this->WMcObj->start($this->menuArr[$key], 'pages'); // Initialize the cObj with the page record of the menu item
1776
1777 $this->I = array();
1778 $this->I['key'] = $key;
1779 $this->I['INPfix'] = ($this->imgNameNotRandom ? '' : '_'.$this->INPfixMD5).'_'.$key;
1780 $this->I['val'] = $val;
1781 $this->I['title'] = isset($this->I['val']['stdWrap.'])
1782 ? $this->WMcObj->stdWrap($this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']), $this->I['val']['stdWrap.'])
1783 : $this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']);
1784 $this->I['uid'] = $this->menuArr[$key]['uid'];
1785 $this->I['mount_pid'] = $this->menuArr[$key]['mount_pid'];
1786 $this->I['pid'] = $this->menuArr[$key]['pid'];
1787 $this->I['spacer'] = $this->menuArr[$key]['isSpacer'];
1788
1789 // Set access key
1790 if ($this->mconf['accessKey']) {
1791 $this->I['accessKey'] = $this->accessKey($this->I['title']);
1792 } else {
1793 $this->I['accessKey'] = Array();
1794 }
1795
1796 // Make link tag
1797 $this->I['val']['ATagParams'] = $this->WMcObj->getATagParams($this->I['val']);
1798 if (isset($this->I['val']['additionalParams.'])) {
1799 $this->I['val']['additionalParams'] = $this->WMcObj->stdWrap($this->I['val']['additionalParams'], $this->I['val']['additionalParams.']);
1800 }
1801 $this->I['linkHREF'] = $this->link($key, $this->I['val']['altTarget'], $this->mconf['forceTypeValue']);
1802
1803 // Title attribute of links:
1804 $titleAttrValue = isset($this->I['val']['ATagTitle.'])
1805 ? $this->WMcObj->stdWrap($this->I['val']['ATagTitle'], $this->I['val']['ATagTitle.']) . $this->I['accessKey']['alt']
1806 : $this->I['val']['ATagTitle'].$this->I['accessKey']['alt'];
1807 if (strlen($titleAttrValue)) {
1808 $this->I['linkHREF']['title'] = $titleAttrValue;
1809 }
1810
1811 // Make link:
1812 if ($this->I['val']['RO']) {
1813 $this->I['theName'] = $this->imgNamePrefix.$this->I['uid'].$this->I['INPfix'];
1814 $over='';
1815 $out ='';
1816 if ($this->I['val']['beforeROImg']) {
1817 $over.= $this->WMfreezePrefix."over('".$this->I['theName']."before');";
1818 $out.= $this->WMfreezePrefix."out('".$this->I['theName']."before');";
1819 }
1820 if ($this->I['val']['afterROImg']) {
1821 $over.= $this->WMfreezePrefix."over('".$this->I['theName']."after');";
1822 $out.= $this->WMfreezePrefix."out('".$this->I['theName']."after');";
1823 }
1824 $this->I['linkHREF']['onMouseover']=$over;
1825 $this->I['linkHREF']['onMouseout']=$out;
1826 if ($over || $out) $GLOBALS['TSFE']->setJS('mouseOver');
1827
1828 // Change background color:
1829 if ($this->I['val']['RO_chBgColor']) {
1830 $this->addJScolorShiftFunction();
1831 $chBgP = t3lib_div::trimExplode('|', $this->I['val']['RO_chBgColor']);
1832 $this->I['linkHREF']['onMouseover'].="changeBGcolor('".$chBgP[2].$this->I['uid']."', '".$chBgP[0]."');";
1833 $this->I['linkHREF']['onMouseout'].="changeBGcolor('".$chBgP[2].$this->I['uid']."', '".$chBgP[1]."');";
1834 }
1835
1836 $this->extProc_RO($key);
1837 }
1838
1839
1840 // Calling extra processing function
1841 $this->extProc_beforeLinking($key);
1842
1843 // stdWrap for doNotLinkIt
1844 if (isset($this->I['val']['doNotLinkIt.'])) {
1845 $this->I['val']['doNotLinkIt'] = $this->WMcObj->stdWrap($this->I['val']['doNotLinkIt'], $this->I['val']['doNotLinkIt.']);
1846 }
1847
1848 // Compile link tag
1849 if (!$this->I['val']['doNotLinkIt']) {$this->I['val']['doNotLinkIt']=0;}
1850 if (!$this->I['spacer'] && $this->I['val']['doNotLinkIt']!=1) {
1851 $this->setATagParts();
1852 } else {
1853 $this->I['A1'] = '';
1854 $this->I['A2'] = '';
1855 }
1856
1857 // ATagBeforeWrap processing:
1858 if ($this->I['val']['ATagBeforeWrap']) {
1859 $wrapPartsBefore = explode('|', $this->I['val']['linkWrap']);
1860 $wrapPartsAfter = array('', '');
1861 } else {
1862 $wrapPartsBefore = array('', '');
1863 $wrapPartsAfter = explode('|', $this->I['val']['linkWrap']);
1864 }
1865 if ($this->I['val']['stdWrap2'] || isset($this->I['val']['stdWrap2.'])) {
1866 $stdWrap2 = isset($this->I['val']['stdWrap2.'])
1867 ? $this->WMcObj->stdWrap('|', $this->I['val']['stdWrap2.'])
1868 : '|';
1869 $wrapPartsStdWrap = explode($this->I['val']['stdWrap2'] ? $this->I['val']['stdWrap2'] : '|', $stdWrap2);
1870 } else {$wrapPartsStdWrap = array('', '');}
1871
1872 // Make before, middle and after parts
1873 $this->I['parts'] = array();
1874 $this->I['parts']['before']=$this->getBeforeAfter('before');
1875 $this->I['parts']['stdWrap2_begin']=$wrapPartsStdWrap[0];
1876
1877 // stdWrap for doNotShowLink
1878 if (isset($this->I['val']['doNotShowLink.'])) {
1879 $this->I['val']['doNotShowLink'] = $this->WMcObj->stdWrap($this->I['val']['doNotShowLink'], $this->I['val']['doNotShowLink.']);
1880 }
1881
1882 if (!$this->I['val']['doNotShowLink']) {
1883 $this->I['parts']['notATagBeforeWrap_begin'] = $wrapPartsAfter[0];
1884 $this->I['parts']['ATag_begin'] = $this->I['A1'];
1885 $this->I['parts']['ATagBeforeWrap_begin'] = $wrapPartsBefore[0];
1886 $this->I['parts']['title'] = $this->I['title'];
1887 $this->I['parts']['ATagBeforeWrap_end'] = $wrapPartsBefore[1];
1888 $this->I['parts']['ATag_end'] = $this->I['A2'];
1889 $this->I['parts']['notATagBeforeWrap_end'] = $wrapPartsAfter[1];
1890 }
1891 $this->I['parts']['stdWrap2_end']=$wrapPartsStdWrap[1];
1892 $this->I['parts']['after']=$this->getBeforeAfter('after');
1893
1894 // Passing I to a user function
1895 if ($this->mconf['IProcFunc']) {
1896 $this->I = $this->userProcess('IProcFunc', $this->I);
1897 }
1898
1899 // Merge parts + beforeAllWrap
1900 $this->I['theItem']= implode('', $this->I['parts']);
1901 $this->I['theItem']= $this->extProc_beforeAllWrap($this->I['theItem'], $key);
1902
1903 // allWrap:
1904 $allWrap = isset($this->I['val']['allWrap.'])
1905 ? $this->WMcObj->stdWrap($this->I['val']['allWrap'], $this->I['val']['allWrap.'])
1906 : $this->I['val']['allWrap'];
1907 $this->I['theItem'] = $this->tmpl->wrap($this->I['theItem'], $allWrap);
1908
1909 if ($this->I['val']['subst_elementUid']) $this->I['theItem'] = str_replace('{elementUid}', $this->I['uid'], $this->I['theItem']);
1910
1911 // allStdWrap:
1912 if (is_array($this->I['val']['allStdWrap.'])) {
1913 $this->I['theItem'] = $this->WMcObj->stdWrap($this->I['theItem'], $this->I['val']['allStdWrap.']);
1914 }
1915
1916 // Calling extra processing function
1917 $this->extProc_afterLinking($key);
1918 }
1919 return $this->extProc_finish();
1920 }
1921 }
1922
1923 /**
1924 * Generates the before* and after* images for TMENUs
1925 *
1926 * @param string 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
1927 * @return string The resulting HTML of the image, if any.
1928 */
1929 function getBeforeAfter($pref) {
1930 $res = '';
1931 if ($imgInfo = $this->WMcObj->getImgResource($this->I['val'][$pref.'Img'], $this->I['val'][$pref.'Img.'])) {
1932 $imgInfo[3] = t3lib_div::png_to_gif_by_imagemagick($imgInfo[3]);
1933 if ($this->I['val']['RO'] && $this->I['val'][$pref.'ROImg'] && !$this->I['spacer']) {
1934 $imgROInfo = $this->WMcObj->getImgResource($this->I['val'][$pref.'ROImg'], $this->I['val'][$pref.'ROImg.']);
1935 $imgROInfo[3] = t3lib_div::png_to_gif_by_imagemagick($imgROInfo[3]);
1936 if ($imgROInfo) {
1937 $theName = $this->imgNamePrefix.$this->I['uid'].$this->I['INPfix'].$pref;
1938 $name = ' '.$this->nameAttribute.'="'.$theName.'"';
1939 $GLOBALS['TSFE']->JSImgCode.= LF.$theName.'_n=new Image(); '.$theName.'_n.src = "'.$GLOBALS['TSFE']->absRefPrefix.$imgInfo[3].'"; ';
1940 $GLOBALS['TSFE']->JSImgCode.= LF.$theName.'_h=new Image(); '.$theName.'_h.src = "'.$GLOBALS['TSFE']->absRefPrefix.$imgROInfo[3].'"; ';
1941 }
1942 }
1943 $GLOBALS['TSFE']->imagesOnPage[]=$imgInfo[3];
1944 $res='<img' .
1945 ' src="' . $GLOBALS['TSFE']->absRefPrefix . $imgInfo[3] . '"' .
1946 ' width="' . $imgInfo[0] . '"' .
1947 ' height="' . $imgInfo[1] . '"' .
1948 $name .
1949 ($this->I['val'][$pref.'ImgTagParams'] ? ' ' . $this->I['val'][$pref.'ImgTagParams'] : '') .
1950 tslib_cObj::getBorderAttr(' border="0"');
1951 if (!strstr($res, 'alt="')) {
1952 $res .= ' alt=""'; // Adding alt attribute if not set.
1953 }
1954 $res.=' />';
1955 if ($this->I['val'][$pref.'ImgLink']) {
1956 $res=$this->I['A1'].$res.$this->I['A2'];
1957 }
1958 }
1959 $processedPref = isset($this->I['val'][$pref . '.'])
1960 ? $this->WMcObj->stdWrap($this->I['val'][$pref], $this->I['val'][$pref . '.'])
1961 : $this->I['val'][$pref];
1962 if (isset($this->I['val'][$pref . 'Wrap'])) {
1963 return $this->tmpl->wrap($res . $processedPref, $this->I['val'][$pref . 'Wrap']);
1964 } else {
1965 return $res . $processedPref;
1966 }
1967 }
1968
1969 /**
1970 * Adds a JavaScript function to the $GLOBALS['TSFE']->additionalJavaScript array
1971 *
1972 * @return void
1973 * @access private
1974 * @see writeMenu()
1975 */
1976 function addJScolorShiftFunction() {
1977 $GLOBALS['TSFE']->additionalJavaScript['TMENU:changeBGcolor()']='
1978 function changeBGcolor(id,color) { //
1979 if (document.getElementById && document.getElementById(id)) {
1980 document.getElementById(id).style.background = color;
1981 return true;
1982 } else if (document.layers && document.layers[id]) {
1983 document.layers[id].bgColor = color;
1984 return true;
1985 }
1986 }
1987 ';
1988 }
1989
1990 /**
1991 * Called right before the traversing of $this->result begins.
1992 * Can be used for various initialization
1993 *
1994 * @return void
1995 * @access private
1996 * @see writeMenu(), tslib_tmenu_layers::extProc_init()
1997 */
1998 function extProc_init() {
1999 }
2000
2001 /**
2002 * Called after all processing for RollOver of an element has been done.
2003 *
2004 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2005 * @return void
2006 * @access private
2007 * @see writeMenu(), tslib_tmenu_layers::extProc_RO()
2008 */
2009 function extProc_RO($key) {
2010 }
2011
2012 /**
2013 * Called right before the creation of the link for the menu item
2014 *
2015 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2016 * @return void
2017 * @access private
2018 * @see writeMenu(), tslib_tmenu_layers::extProc_beforeLinking()
2019 */
2020 function extProc_beforeLinking($key) {
2021 }
2022
2023 /**
2024 * 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.
2025 * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
2026 *
2027 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2028 * @return void
2029 * @access private
2030 * @see writeMenu(), tslib_tmenu_layers::extProc_afterLinking()
2031 */
2032 function extProc_afterLinking($key) {
2033 // Add part to the accumulated result + fetch submenus
2034 if (!$this->I['spacer']) {
2035 $this->I['theItem'].= $this->subMenu($this->I['uid'], $this->WMsubmenuObjSuffixes[$key]['sOSuffix']);
2036 }
2037 $part = isset($this->I['val']['wrapItemAndSub.'])
2038 ? $this->WMcObj->stdWrap($this->I['val']['wrapItemAndSub'], $this->I['val']['wrapItemAndSub.'])
2039 : $this->I['val']['wrapItemAndSub'];
2040 $this->WMresult.= $part ? $this->tmpl->wrap($this->I['theItem'], $part) : $this->I['theItem'];
2041 }
2042
2043 /**
2044 * Called before the "allWrap" happens on the menu item.
2045 *
2046 * @param string The current content of the menu item, $this->I['theItem'], passed along.
2047 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2048 * @return string The modified version of $item, going back into $this->I['theItem']
2049 * @access private
2050 * @see writeMenu(), tslib_tmenu_layers::extProc_beforeAllWrap()
2051 */
2052 function extProc_beforeAllWrap($item, $key) {
2053 return $item;
2054 }
2055
2056 /**
2057 * Called before the writeMenu() function returns (only if a menu was generated)
2058 *
2059 * @return string The total menu content should be returned by this function
2060 * @access private
2061 * @see writeMenu(), tslib_tmenu_layers::extProc_finish()
2062 */
2063 function extProc_finish() {
2064 // stdWrap:
2065 if (is_array($this->mconf['stdWrap.'])) {
2066 $this->WMresult = $this->WMcObj->stdWrap($this->WMresult, $this->mconf['stdWrap.']);
2067 }
2068 return $this->tmpl->wrap($this->WMresult, $this->mconf['wrap']).$this->WMextraScript;
2069 }
2070 }
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095 /**
2096 * Extension class creating graphic based menus (PNG or GIF files)
2097 *
2098 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
2099 * @package TYPO3
2100 * @subpackage tslib
2101 */
2102 class tslib_gmenu extends tslib_menu {
2103
2104 /**
2105 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
2106 * Calls makeGifs() for all "normal" items and if configured for, also the "rollover" items.
2107 *
2108 * @return void
2109 * @see tslib_menu::procesItemStates(), makeGifs()
2110 */
2111 function generate() {
2112 $splitCount = count($this->menuArr);
2113 if ($splitCount) {
2114 list($NOconf,$ROconf) = $this->procesItemStates($splitCount);
2115
2116 //store initial count value
2117 $temp_HMENU_MENUOBJ = $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ'];
2118 $temp_MENUOBJ = $GLOBALS['TSFE']->register['count_MENUOBJ'];
2119 // Now we generate the giffiles:
2120 $this->makeGifs($NOconf, 'NO');
2121 // store count from NO obj
2122 $tempcnt_HMENU_MENUOBJ = $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ'];
2123 $tempcnt_MENUOBJ = $GLOBALS['TSFE']->register['count_MENUOBJ'];
2124
2125 if ($this->mconf['debugItemConf']) {
2126 echo '<h3>$NOconf:</h3>';
2127 debug($NOconf);
2128 }
2129 if ($ROconf) { // RollOver
2130 //start recount for rollover with initial values
2131 $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ']= $temp_HMENU_MENUOBJ;
2132 $GLOBALS['TSFE']->register['count_MENUOBJ']= $temp_MENUOBJ;
2133 $this->makeGifs($ROconf, 'RO');
2134 if ($this->mconf['debugItemConf']) {
2135 echo '<h3>$ROconf:</h3>';
2136 debug($ROconf);
2137 }
2138 }
2139 // use count from NO obj
2140 $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ'] = $tempcnt_HMENU_MENUOBJ;
2141 $GLOBALS['TSFE']->register['count_MENUOBJ'] = $tempcnt_MENUOBJ;
2142 }
2143 }
2144
2145 /**
2146 * Will traverse input array with configuratoin per-item and create corresponding GIF files for the menu.
2147 * The data of the files are stored in $this->result
2148 *
2149 * @param array Array with configuration for each item.
2150 * @param string Type of images: normal ("NO") or rollover ("RO"). Valid values are "NO" and "RO"
2151 * @return void
2152 * @access private
2153 * @see generate()
2154 */
2155 function makeGifs($conf, $resKey) {
2156 $isGD = $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'];
2157
2158 if (!is_array($conf)) {
2159 $conf = Array();
2160 }
2161
2162 $totalWH=array();
2163 $items = count($conf);
2164 if ($isGD) {
2165 // generate the gif-files. the $menuArr is filled with some values like output_w, output_h, output_file
2166 $Hcounter = 0;
2167 $Wcounter = 0;
2168 $Hobjs = $this->mconf['applyTotalH'];
2169 if ($Hobjs) {$Hobjs = t3lib_div::intExplode(',', $Hobjs);}
2170 $Wobjs = $this->mconf['applyTotalW'];
2171 if ($Wobjs) {$Wobjs = t3lib_div::intExplode(',', $Wobjs);}
2172 $minDim = $this->mconf['min'];
2173 if ($minDim) {$minDim = tslib_cObj::calcIntExplode(',', $minDim.',');}
2174 $maxDim = $this->mconf['max'];
2175 if ($maxDim) {$maxDim = tslib_cObj::calcIntExplode(',', $maxDim.',');}
2176
2177 if ($minDim) {
2178 $conf[$items]=$conf[$items-1];
2179 $this->menuArr[$items]=Array();
2180 $items = count($conf);
2181 }
2182
2183 // TOTAL width
2184 if ($this->mconf['useLargestItemX'] || $this->mconf['useLargestItemY'] || $this->mconf['distributeX'] || $this->mconf['distributeY']) {
2185 $totalWH = $this->findLargestDims($conf, $items, $Hobjs, $Wobjs, $minDim, $maxDim);
2186 }
2187 }
2188
2189 $c=0;
2190 $maxFlag=0;
2191 $distributeAccu=array('H'=>0, 'W'=>0);
2192 foreach ($conf as $key => $val) {
2193 $GLOBALS['TSFE']->register['count_HMENU_MENUOBJ']++;
2194 $GLOBALS['TSFE']->register['count_MENUOBJ']++;
2195
2196 if ($items==($c+1) && $minDim) {
2197 $Lobjs = $this->mconf['removeObjectsOfDummy'];
2198 if ($Lobjs) {
2199 $Lobjs = t3lib_div::intExplode(',', $Lobjs);
2200 foreach ($Lobjs as $remItem) {
2201 unset($val[$remItem]);
2202 unset($val[$remItem.'.']);
2203 }
2204 }
2205
2206 $flag =0;
2207 $tempXY = explode(',', $val['XY']);
2208 if ($Wcounter<$minDim[0]) {
2209 $tempXY[0] = $minDim[0] - $Wcounter;
2210 $flag = 1;
2211 }
2212 if ($Hcounter<$minDim[1]) {
2213 $tempXY[1] = $minDim[1] - $Hcounter;
2214 $flag = 1;
2215 }
2216 $val['XY'] = implode(',', $tempXY);
2217 if (!$flag){break;}
2218 }
2219 $c++;
2220
2221
2222 if ($isGD) {
2223 // Pre-working the item
2224 $gifCreator = t3lib_div::makeInstance('tslib_gifBuilder');
2225 $gifCreator->init();
2226 $gifCreator->start($val, $this->menuArr[$key]);
2227
2228 // If useLargestItemH/W is specified
2229 if (count($totalWH) && ($this->mconf['useLargestItemX'] || $this->mconf['useLargestItemY'])) {
2230 $tempXY = explode(',', $gifCreator->setup['XY']);
2231 if ($this->mconf['useLargestItemX']) {$tempXY[0] = max($totalWH['W']);}
2232 if ($this->mconf['useLargestItemY']) {$tempXY[1] = max($totalWH['H']);}
2233 // regenerate the new values...
2234 $val['XY'] = implode(',', $tempXY);
2235 $gifCreator = t3lib_div::makeInstance('tslib_gifBuilder');
2236 $gifCreator->init();
2237 $gifCreator->start($val, $this->menuArr[$key]);
2238 }
2239
2240 // If distributeH/W is specified
2241 if (count($totalWH) && ($this->mconf['distributeX'] || $this->mconf['distributeY'])) {
2242 $tempXY = explode(',', $gifCreator->setup['XY']);
2243
2244 if ($this->mconf['distributeX']) {
2245 $diff = $this->mconf['distributeX']-$totalWH['W_total']-$distributeAccu['W'];
2246 $compensate = round($diff /($items-$c+1));
2247 $distributeAccu['W']+=$compensate;
2248 $tempXY[0] = $totalWH['W'][$key]+$compensate;
2249 }
2250 if ($this->mconf['distributeY']) {
2251 $diff = $this->mconf['distributeY']-$totalWH['H_total']-$distributeAccu['H'];
2252 $compensate = round($diff /($items-$c+1));
2253 $distributeAccu['H']+=$compensate;
2254 $tempXY[1] = $totalWH['H'][$key]+$compensate;
2255 }
2256 // regenerate the new values...
2257 $val['XY'] = implode(',', $tempXY);
2258 $gifCreator = t3lib_div::makeInstance('tslib_gifBuilder');
2259 $gifCreator->init();
2260 $gifCreator->start($val, $this->menuArr[$key]);
2261 }
2262
2263 // If max dimensions are specified
2264 if ($maxDim) {
2265 $tempXY = explode(',', $val['XY']);
2266 if ($maxDim[0] && $Wcounter + $gifCreator->XY[0] >= $maxDim[0]) {
2267 $tempXY[0] == $maxDim[0] - $Wcounter;
2268 $maxFlag = 1;
2269 }
2270 if ($maxDim[1] && $Hcounter + $gifCreator->XY[1] >= $maxDim[1]) {
2271 $tempXY[1] = $maxDim[1] - $Hcounter;
2272 $maxFlag = 1;
2273 }
2274 if ($maxFlag) {
2275 $val['XY'] = implode(',', $tempXY);
2276 $gifCreator = t3lib_div::makeInstance('tslib_gifBuilder');
2277 $gifCreator->init();
2278 $gifCreator->start($val, $this->menuArr[$key]);
2279 }
2280 }
2281
2282
2283
2284
2285 // displace
2286 if ($Hobjs) {
2287 foreach ($Hobjs as $index) {
2288 if ($gifCreator->setup[$index] && $gifCreator->setup[$index.'.']) {
2289 $oldOffset = explode(',', $gifCreator->setup[$index.'.']['offset']);
2290 $gifCreator->setup[$index.'.']['offset'] = implode(',', $gifCreator->applyOffset($oldOffset, Array(0, -$Hcounter)));
2291 }
2292 }
2293 }
2294
2295 if ($Wobjs) {
2296 foreach ($Wobjs as $index) {
2297 if ($gifCreator->setup[$index] && $gifCreator->setup[$index.'.']) {
2298 $oldOffset = explode(',', $gifCreator->setup[$index.'.']['offset']);
2299 $gifCreator->setup[$index.'.']['offset'] = implode(',', $gifCreator->applyOffset($oldOffset, Array(-$Wcounter, 0)));
2300 }
2301 }
2302 }
2303 }
2304
2305 // Finding alternative GIF names if any (by altImgResource)
2306 $gifFileName='';
2307 if ($conf[$key]['altImgResource'] || is_array($conf[$key]['altImgResource.'])) {
2308 if (!is_object($cObj)) {$cObj=t3lib_div::makeInstance('tslib_cObj');}
2309 $cObj->start($this->menuArr[$key], 'pages');
2310 $altImgInfo = $cObj->getImgResource($conf[$key]['altImgResource'], $conf[$key]['altImgResource.']);
2311 $gifFileName=$altImgInfo[3];
2312 }
2313
2314 // If an alternative name was NOT given, find the GIFBUILDER name.
2315 if (!$gifFileName && $isGD) {
2316 $gifCreator->createTempSubDir('menu/');
2317 $gifFileName = $gifCreator->fileName('menu/');
2318 }
2319
2320 $this->result[$resKey][$key] = $conf[$key];
2321
2322 // Generation of image file:
2323 if (file_exists($gifFileName)) { // File exists
2324 $info = @getimagesize($gifFileName);
2325 $this->result[$resKey][$key]['output_w']=intval($info[0]);
2326 $this->result[$resKey][$key]['output_h']=intval($info[1]);
2327 $this->result[$resKey][$key]['output_file'] = $gifFileName;
2328 } elseif ($isGD) { // file is generated
2329 $gifCreator->make();
2330 $this->result[$resKey][$key]['output_w']=$gifCreator->w;
2331 $this->result[$resKey][$key]['output_h']=$gifCreator->h;
2332 $this->result[$resKey][$key]['output_file'] = $gifFileName;
2333 $gifCreator->output($this->result[$resKey][$key]['output_file']);
2334 $gifCreator->destroy();
2335 }
2336
2337 $this->result[$resKey][$key]['output_file'] = t3lib_div::png_to_gif_by_imagemagick($this->result[$resKey][$key]['output_file']);
2338
2339 $Hcounter+=$this->result[$resKey][$key]['output_h']; // counter is increased
2340 $Wcounter+=$this->result[$resKey][$key]['output_w']; // counter is increased
2341
2342 if ($maxFlag) break;
2343 }
2344 }
2345
2346 /**
2347 * Function searching for the largest width and height of the menu items to be generated.
2348 * 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.
2349 * Remember to upgrade the code in here if the makeGifs function is updated.
2350 *
2351 * @param array Same configuration array as passed to makeGifs()
2352 * @param integer The number of menu items
2353 * @param array Array with "applyTotalH" numbers
2354 * @param array Array with "applyTotalW" numbers
2355 * @param array Array with "min" x/y
2356 * @param array Array with "max" x/y
2357 * @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.
2358 * @access private
2359 * @see makeGifs()
2360 */
2361 function findLargestDims($conf, $items, $Hobjs, $Wobjs, $minDim, $maxDim) {
2362 $totalWH = array(
2363 'W' => array(),
2364 'H' => array(),
2365 'W_total' => 0,
2366 'H_total' => 0
2367 );
2368
2369 $Hcounter = 0;
2370 $Wcounter = 0;
2371 $c=0;
2372 $maxFlag=0;
2373 foreach ($conf as $key => $val) {
2374 // SAME CODE AS makeGifs()! BEGIN
2375 if ($items==($c+1) && $minDim) {
2376 $Lobjs = $this->mconf['removeObjectsOfDummy'];
2377 if ($Lobjs) {
2378 $Lobjs = t3lib_div::intExplode(',', $Lobjs);
2379 foreach ($Lobjs as $remItem) {
2380 unset($val[$remItem]);
2381 unset($val[$remItem.'.']);
2382 }
2383 }
2384
2385 $flag =0;
2386 $tempXY = explode(',', $val['XY']);
2387 if ($Wcounter < $minDim[0]) {
2388 $tempXY[0] = $minDim[0] - $Wcounter;
2389 $flag = 1;
2390 }
2391 if ($Hcounter < $minDim[1]) {
2392 $tempXY[1] = $minDim[1] - $Hcounter;
2393 $flag = 1;
2394 }
2395 $val['XY'] = implode(',', $tempXY);
2396 if (!$flag){break;}
2397 }
2398 $c++;
2399
2400 $gifCreator = t3lib_div::makeInstance('tslib_gifBuilder');
2401 $gifCreator->init();
2402 $gifCreator->start($val, $this->menuArr[$key]);
2403 if ($maxDim) {
2404 $tempXY = explode(',', $val['XY']);
2405 if ($maxDim[0] && $Wcounter + $gifCreator->XY[0] >= $maxDim[0]) {
2406 $tempXY[0] == $maxDim[0] - $Wcounter;
2407 $maxFlag = 1;
2408 }
2409 if ($maxDim[1] && $Hcounter + $gifCreator->XY[1] >= $maxDim[1]) {
2410 $tempXY[1] = $maxDim[1] - $Hcounter;
2411 $maxFlag = 1;
2412 }
2413 if ($maxFlag) {
2414 $val['XY'] = implode(',', $tempXY);
2415 $gifCreator = t3lib_div::makeInstance('tslib_gifBuilder');
2416 $gifCreator->init();
2417 $gifCreator->start($val, $this->menuArr[$key]);
2418 }
2419 }
2420 // SAME CODE AS makeGifs()! END
2421
2422 // Setting the width/height
2423 $totalWH['W'][$key]=$gifCreator->XY[0];
2424 $totalWH['H'][$key]=$gifCreator->XY[1];
2425 $totalWH['W_total']+=$gifCreator->XY[0];
2426 $totalWH['H_total']+=$gifCreator->XY[1];
2427
2428 $Hcounter+=$gifCreator->XY[1]; // counter is increased
2429 $Wcounter+=$gifCreator->XY[0]; // counter is increased
2430
2431 if ($maxFlag){break;}
2432 }
2433 return $totalWH;
2434 }
2435
2436 /**
2437 * 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())
2438 * 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
2439 *
2440 * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
2441 */
2442 function writeMenu() {
2443 if (is_array($this->menuArr) && is_array($this->result) && count($this->result) && is_array($this->result['NO'])) {
2444 $this->WMcObj = t3lib_div::makeInstance('tslib_cObj'); // Create new tslib_cObj for our use
2445 $this->WMresult = '';
2446 $this->INPfixMD5 = substr(md5(microtime().$this->GMENU_fixKey), 0, 4);
2447 $this->WMmenuItems = count($this->result['NO']);
2448
2449 $this->WMsubmenuObjSuffixes = $this->tmpl->splitConfArray(array('sOSuffix'=>$this->mconf['submenuObjSuffixes']), $this->WMmenuItems);
2450
2451 $this->extProc_init();
2452 for ($key=0;$key<$this->WMmenuItems;$key++) {
2453 if ($this->result['NO'][$key]['output_file']) {
2454 $this->WMcObj->start($this->menuArr[$key], 'pages'); // Initialize the cObj with the page record of the menu item
2455
2456 $this->I = array();
2457 $this->I['key'] = $key;
2458 $this->I['INPfix']= ($this->imgNameNotRandom ? '' : '_'.$this->INPfixMD5).'_'.$key;
2459 $this->I['val'] = $this->result['NO'][$key];
2460 $this->I['title'] = $this->getPageTitle($this->menuArr[$key]['title'], $this->menuArr[$key]['nav_title']);
2461 $this->I['uid'] = $this->menuArr[$key]['uid'];
2462 $this->I['mount_pid'] = $this->menuArr[$key]['mount_pid'];
2463 $this->I['pid'] = $this->menuArr[$key]['pid'];
2464 $this->I['spacer'] = $this->menuArr[$key]['isSpacer'];
2465 if (!$this->I['uid'] && !$this->menuArr[$key]['_OVERRIDE_HREF']) {$this->I['spacer']=1;}
2466 $this->I['noLink'] = ($this->I['spacer'] || $this->I['val']['noLink'] || !count($this->menuArr[$key])); // !count($this->menuArr[$key]) means that this item is a dummyItem
2467 $this->I['name'] = '';
2468
2469 // Set access key
2470 if ($this->mconf['accessKey']) {
2471 $this->I['accessKey'] = $this->accessKey($this->I['title']);
2472 } else {
2473 $this->I['accessKey'] = array();
2474 }
2475
2476 // Make link tag
2477 $this->I['val']['ATagParams'] = $this->WMcObj->getATagParams($this->I['val']);
2478 if (isset($this->I['val']['additionalParams.'])) {
2479 $this->I['val']['additionalParams'] = $this->WMcObj->stdWrap($this->I['val']['additionalParams'], $this->I['val']['additionalParams.']);
2480 }
2481 $this->I['linkHREF'] = $this->link($key, $this->I['val']['altTarget'], $this->mconf['forceTypeValue']);
2482
2483 // Title attribute of links:
2484 $titleAttrValue = isset($this->I['val']['ATagTitle.'])
2485 ? $this->WMcObj->stdWrap($this->I['val']['ATagTitle'], $this->I['val']['ATagTitle.']) . $this->I['accessKey']['alt']
2486 : $this->I['val']['ATagTitle'].$this->I['accessKey']['alt'];
2487 if (strlen($titleAttrValue)) {
2488 $this->I['linkHREF']['title'] = $titleAttrValue;
2489 }
2490
2491 // Set rollover
2492 if ($this->result['RO'][$key] && !$this->I['noLink']) {
2493 $this->I['theName'] = $this->imgNamePrefix.$this->I['uid'].$this->I['INPfix'];
2494 $this->I['name'] = ' '.$this->nameAttribute.'="'.$this->I["theName"].'"';
2495 $this->I['linkHREF']['onMouseover']=$this->WMfreezePrefix.'over(\''.$this->I['theName'].'\');';
2496 $this->I['linkHREF']['onMouseout']=$this->WMfreezePrefix.'out(\''.$this->I['theName'].'\');';
2497 $GLOBALS['TSFE']->JSImgCode.= LF.$this->I['theName'].'_n=new Image(); '.$this->I['theName'].'_n.src = "'.$GLOBALS['TSFE']->absRefPrefix.$this->I['val']['output_file'].'"; ';
2498 $GLOBALS['TSFE']->JSImgCode.= LF.$this->I['theName'].'_h=new Image(); '.$this->I['theName'].'_h.src = "'.$GLOBALS['TSFE']->absRefPrefix.$this->result['RO'][$key]['output_file'].'"; ';
2499 $GLOBALS['TSFE']->imagesOnPage[]=$this->result['RO'][$key]['output_file'];
2500 $GLOBALS['TSFE']->setJS('mouseOver');
2501 $this->extProc_RO($key);
2502 }
2503
2504 // Set altText
2505 $this->I['altText'] = $this->I['title'].$this->I['accessKey']['alt'];
2506
2507 // Calling extra processing function
2508 $this->extProc_beforeLinking($key);
2509
2510 // Set linking
2511 if (!$this->I['noLink']) {
2512 $this->setATagParts();
2513 } else {
2514 $this->I['A1'] = '';
2515 $this->I['A2'] = '';
2516 }
2517 $this->I['IMG'] = '<img src="'.$GLOBALS['TSFE']->absRefPrefix.$this->I['val']['output_file'].'" width="'.$this->I['val']['output_w'].'" height="'.$this->I['val']['output_h'].'" '.tslib_cObj::getBorderAttr('border="0"').($this->mconf['disableAltText'] ? '' : ' alt="'.htmlspecialchars($this->I['altText']).'"').$this->I['name'].($this->I['val']['imgParams']?' '.$this->I['val']['imgParams']:'').' />';
2518
2519 // Make before, middle and after parts
2520 $this->I['parts'] = array();
2521 $this->I['parts']['ATag_begin'] = $this->I['A1'];
2522 $this->I['parts']['image'] = $this->I['IMG'];
2523 $this->I['parts']['ATag_end'] = $this->I['A2'];
2524
2525 // Passing I to a user function
2526 if ($this->mconf['IProcFunc']) {
2527 $this->I = $this->userProcess('IProcFunc', $this->I);
2528 }
2529
2530 // Putting the item together.
2531 // Merge parts + beforeAllWrap
2532 $this->I['theItem']= implode('', $this->I['parts']);
2533 $this->I['theItem']= $this->extProc_beforeAllWrap($this->I['theItem'], $key);
2534
2535 // wrap:
2536 $this->I['theItem']= $this->tmpl->wrap($this->I['theItem'], $this->I['val']['wrap']);
2537
2538 // allWrap:
2539 $allWrap = isset($this->I['val']['allWrap.'])
2540 ? $this->WMcObj->stdWrap($this->I['val']['allWrap'], $this->I['val']['allWrap.'])
2541 : $this->I['val']['allWrap'];
2542 $this->I['theItem'] = $this->tmpl->wrap($this->I['theItem'], $allWrap);
2543
2544 if ($this->I['val']['subst_elementUid']) $this->I['theItem'] = str_replace('{elementUid}', $this->I['uid'], $this->I['theItem']);
2545
2546 // allStdWrap:
2547 if (is_array($this->I['val']['allStdWrap.'])) {
2548 $this->I['theItem'] = $this->WMcObj->stdWrap($this->I['theItem'], $this->I['val']['allStdWrap.']);
2549 }
2550
2551 $GLOBALS['TSFE']->imagesOnPage[]=$this->I['val']['output_file'];
2552
2553 $this->extProc_afterLinking($key);
2554 }
2555 }
2556 return $this->extProc_finish();
2557 }
2558 }
2559
2560 /**
2561 * Called right before the traversing of $this->result begins.
2562 * Can be used for various initialization
2563 *
2564 * @return void
2565 * @access private
2566 * @see writeMenu(), tslib_gmenu_layers::extProc_init()
2567 */
2568 function extProc_init() {
2569 }
2570
2571 /**
2572 * Called after all processing for RollOver of an element has been done.
2573 *
2574 * @param integer 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!
2575 * @return void
2576 * @access private
2577 * @see writeMenu(), tslib_gmenu_layers::extProc_RO()
2578 */
2579 function extProc_RO($key) {
2580 }
2581
2582 /**
2583 * Called right before the creation of the link for the menu item
2584 *
2585 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2586 * @return void
2587 * @access private
2588 * @see writeMenu(), tslib_gmenu_layers::extProc_beforeLinking()
2589 */
2590 function extProc_beforeLinking($key) {
2591 }
2592
2593 /**
2594 * Called right after the creation of links for the menu item. This is also the last function call before the for-loop traversing menu items goes to the next item.
2595 * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
2596 * Further this calls the subMenu function in the parent class to create any submenu there might be.
2597 *
2598 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2599 * @return void
2600 * @access private
2601 * @see writeMenu(), tslib_gmenu_layers::extProc_afterLinking(), tslib_menu::subMenu()
2602 */
2603 function extProc_afterLinking($key) {
2604 // Add part to the accumulated result + fetch submenus
2605 if (!$this->I['spacer']) {
2606 $this->I['theItem'].= $this->subMenu($this->I['uid'], $this->WMsubmenuObjSuffixes[$key]['sOSuffix']);
2607 }
2608 $part = isset($this->I['val']['wrapItemAndSub.'])
2609 ? $this->WMcObj->stdWrap($this->I['val']['wrapItemAndSub'], $this->I['val']['wrapItemAndSub.'])
2610 : $this->I['val']['wrapItemAndSub'];
2611 $this->WMresult.= $part ? $this->tmpl->wrap($this->I['theItem'], $part) : $this->I['theItem'];
2612 }
2613
2614
2615 /**
2616 * Called before the "wrap" happens on the menu item.
2617 *
2618 * @param string The current content of the menu item, $this->I['theItem'], passed along.
2619 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2620 * @return string The modified version of $item, going back into $this->I['theItem']
2621 * @access private
2622 * @see writeMenu(), tslib_gmenu_layers::extProc_beforeAllWrap()
2623 */
2624 function extProc_beforeAllWrap($item, $key) {
2625 return $item;
2626 }
2627
2628 /**
2629 * Called before the writeMenu() function returns (only if a menu was generated)
2630 *
2631 * @return string The total menu content should be returned by this function
2632 * @access private
2633 * @see writeMenu(), tslib_gmenu_layers::extProc_finish()
2634 */
2635 function extProc_finish() {