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