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