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