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