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