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