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