2 /***************************************************************
5 * (c) 1999-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
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.
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.
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.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
28 * Generating navigation / menus from TypoScript
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.
35 * Revised for TYPO3 3.6 June/2003 by Kasper Skaarhoj
38 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
41 * [CLASS/FUNCTION INDEX of SCRIPT]
45 * 146: class tslib_menu
46 * 211: function start(&$tmpl,&$sys_page,$id,$conf,$menuNumber,$objSuffix='')
47 * 357: function makeMenu()
48 * 909: function includeMakeMenu($conf,$altSortField)
49 * 925: function filterMenuPages(&$data,$banUidArray,$spacer)
50 * 981: function procesItemStates($splitCount)
51 * 1191: function link($key,$altTarget='',$typeOverride='')
52 * 1263: function changeLinksForAccessRestrictedPages(&$LD, $page, $mainTarget, $typeOverride)
53 * 1284: function subMenu($uid, $objSuffix='')
54 * 1330: function isNext($uid, $MPvar='')
55 * 1351: function isActive($uid, $MPvar='')
56 * 1372: function isCurrent($uid, $MPvar='')
57 * 1387: function isSubMenu($uid)
58 * 1412: function isItemState($kind,$key)
59 * 1452: function accessKey($title)
60 * 1480: function userProcess($mConfKey,$passVar)
61 * 1495: function setATagParts()
62 * 1508: function getPageTitle($title,$nav_title)
63 * 1520: function getMPvar($key)
64 * 1535: function getDoktypeExcludeWhere()
65 * 1545: function getBannedUids()
66 * 1568: function menuTypoLink($page, $oTarget, $no_cache, $script, $overrideArray = '', $addParams = '', $typeOverride = '')
69 * 1618: class tslib_tmenu extends tslib_menu
70 * 1627: function generate()
71 * 1643: function writeMenu()
72 * 1796: function getBeforeAfter($pref)
73 * 1826: function addJScolorShiftFunction()
74 * 1848: function extProc_init()
75 * 1859: function extProc_RO($key)
76 * 1870: function extProc_beforeLinking($key)
77 * 1882: function extProc_afterLinking($key)
78 * 1900: function extProc_beforeAllWrap($item,$key)
79 * 1911: function extProc_finish()
82 * 1951: class tslib_gmenu extends tslib_menu
83 * 1960: function generate()
84 * 1998: function makeGifs($conf, $resKey)
85 * 2196: function findLargestDims($conf,$items,$Hobjs,$Wobjs,$minDim,$maxDim)
86 * 2268: function writeMenu()
87 * 2392: function extProc_init()
88 * 2403: function extProc_RO($key)
89 * 2414: function extProc_beforeLinking($key)
90 * 2427: function extProc_afterLinking($key)
91 * 2444: function extProc_beforeAllWrap($item,$key)
92 * 2455: function extProc_finish()
95 * 2493: class tslib_imgmenu extends tslib_menu
96 * 2502: function generate()
97 * 2520: function makeImageMap($conf)
98 * 2706: function writeMenu()
101 * 2749: class tslib_jsmenu extends tslib_menu
102 * 2756: function generate()
103 * 2764: function writeMenu()
104 * 2825: function generate_level($levels,$count,$pid,$menuItemArray='',$MP_array=array())
106 * TOTAL FUNCTIONS: 47
107 * (This index is automatically created/updated by the extension "extdeveval")
129 * Base class. The HMENU content object uses this (or more precisely one of the extension classes).
130 * Amoung others the class generates an array of menuitems. Thereafter functions from the subclasses are called.
131 * The class is ALWAYS used through extension classes (like tslib_gmenu or tslib_tmenu which are classics) and
133 * Example of usage (from tslib_cObj):
135 * $menu = t3lib_div::makeInstance('tslib_'.$cls);
136 * $menu->parent_cObj = $this;
137 * $menu->start($GLOBALS['TSFE']->tmpl,$GLOBALS['TSFE']->sys_page,'',$conf,1);
139 * $content.=$menu->writeMenu();
141 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
144 * @see tslib_cObj::HMENU()
147 var $menuNumber = 1; // tells you which menu-number this is. This is important when getting data from the setup
148 var $entryLevel = 0; // 0 = rootFolder
149 var $spacerIDList = '199'; // The doktype-number that defines a spacer
150 // @TODO: RFC #7370: doktype 2&5 are deprecated since TYPO3 4.2-beta1
151 var $doktypeExcludeList = '5,6'; // doktypes that define which should not be included in a menu
152 var $alwaysActivePIDlist=array();
153 var $imgNamePrefix = 'img';
154 var $imgNameNotRandom=0;
158 * Loaded with the parent cObj-object when a new HMENU is made
163 var $GMENU_fixKey='gmenu';
164 var $MP_array=array(); // accumulation of mount point data
167 var $conf = Array(); // HMENU configuration
168 var $mconf = Array(); // xMENU configuration (TMENU, GMENU etc)
173 * @var t3lib_TStemplate
178 * sys_page-object, pagefunctions
180 * @var t3lib_pageSelect
183 var $id; // The base page-id of the menu.
184 var $nextActive; // Holds the page uid of the NEXT page in the root line from the page pointed to by entryLevel; Used to expand the menu automatically if in a certain root line.
185 var $menuArr; // The array of menuItems which is built
187 var $result = Array();
188 var $rL_uidRegister = ''; // Array: Is filled with an array of page uid numbers + RL parameters which are in the current root line (used to evaluate whether a menu item is in active state)
194 var $WMsubmenuObjSuffixes;
196 var $alternativeMenuTempArray=''; // Can be set to contain menu item arrays for sub-levels.
197 var $nameAttribute = 'name'; // Will be 'id' in XHTML-mode
200 * The initialization of the object. This just sets some internal variables.
202 * @param object The $GLOBALS['TSFE']->tmpl object
203 * @param object The $GLOBALS['TSFE']->sys_page object
204 * @param integer A starting point page id. This should probably be blank since the 'entryLevel' value will be used then.
205 * @param array The TypoScript configuration for the HMENU cObject
206 * @param integer Menu number; 1,2,3. Should probably be '1'
207 * @param string Submenu Object suffix. This offers submenus a way to use alternative configuration for specific positions in the menu; By default "1 = TMENU" would use "1." for the TMENU configuration, but if this string is set to eg. "a" then "1a." would be used for configuration instead (while "1 = " is still used for the overall object definition of "TMENU")
208 * @return boolean Returns true on success
209 * @see tslib_cObj::HMENU()
211 function start(&$tmpl,&$sys_page,$id,$conf,$menuNumber,$objSuffix='') {
215 $this->menuNumber
= $menuNumber;
216 $this->mconf
= $conf[$this->menuNumber
.$objSuffix.'.'];
217 $this->debug
=$GLOBALS['TSFE']->debug
;
219 // In XHTML there is no "name" attribute anymore
220 switch ($GLOBALS['TSFE']->xhtmlDoctype
) {
224 $this->nameAttribute
= 'id';
227 $this->nameAttribute
= 'name';
231 // Sets the internal vars. $tmpl MUST be the template-object. $sys_page MUST be the sys_page object
232 if ($this->conf
[$this->menuNumber
.$objSuffix] && is_object($tmpl) && is_object($sys_page)) {
234 $this->sys_page
= $sys_page;
236 // alwaysActivePIDlist initialized:
237 if (trim($this->conf
['alwaysActivePIDlist']) ||
isset($this->conf
['alwaysActivePIDlist.'])) {
238 if (isset($this->conf
['alwaysActivePIDlist.'])) {
239 $this->conf
['alwaysActivePIDlist'] = $this->parent_cObj
->stdWrap(
240 $this->conf
['alwaysActivePIDlist'],
241 $this->conf
['alwaysActivePIDlist.']
244 $this->alwaysActivePIDlist
= t3lib_div
::intExplode(',', $this->conf
['alwaysActivePIDlist']);
247 // 'not in menu' doktypes
248 if($this->conf
['excludeDoktypes']) {
249 $this->doktypeExcludeList
= $GLOBALS['TYPO3_DB']->cleanIntList($this->conf
['excludeDoktypes']);
251 if($this->conf
['includeNotInMenu']) {
252 $exclDoktypeArr = t3lib_div
::trimExplode(',',$this->doktypeExcludeList
,1);
253 // @TODO: RFC #7370: doktype 2&5 are deprecated since TYPO3 4.2-beta1
254 $exclDoktypeArr = t3lib_div
::removeArrayEntryByValue($exclDoktypeArr,'5');
255 $this->doktypeExcludeList
= implode(',',$exclDoktypeArr);
258 $this->entryLevel
= tslib_cObj
::getKey (
259 $this->parent_cObj
->stdWrap($conf['entryLevel'], $conf['entryLevel.']),
260 $this->tmpl
->rootLine
262 // Set parent page: If $id not stated with start() then the base-id will be found from rootLine[$this->entryLevel]
263 if ($id) { // Called as the next level in a menu. It is assumed that $this->MP_array is set from parent menu.
264 $this->id
= intval($id);
265 } else { // This is a BRAND NEW menu, first level. So we take ID from rootline and also find MP_array (mount points)
266 $this->id
= intval($this->tmpl
->rootLine
[$this->entryLevel
]['uid']);
268 // Traverse rootline to build MP_array of pages BEFORE the entryLevel
269 // (MP var for ->id is picked up in the next part of the code...)
270 foreach($this->tmpl
->rootLine
as $entryLevel => $levelRec) {
271 // For overlaid mount points, set the variable right now:
272 if ($levelRec['_MP_PARAM'] && $levelRec['_MOUNT_OL']) {
273 $this->MP_array
[] = $levelRec['_MP_PARAM'];
275 // Break when entry level is reached:
276 if ($entryLevel>=$this->entryLevel
) break;
278 // For normal mount points, set the variable for next level.
279 if ($levelRec['_MP_PARAM'] && !$levelRec['_MOUNT_OL']) {
280 $this->MP_array
[] = $levelRec['_MP_PARAM'];
285 // Return false if no page ID was set (thus no menu of subpages can be made).
290 // Check if page is a mount point, and if so set id and MP_array
291 // (basically this is ONLY for non-overlay mode, but in overlay mode an ID with a mount point should never reach this point anyways, so no harm done...)
292 $mount_info = $this->sys_page
->getMountPointInfo($this->id
);
293 if (is_array($mount_info)) {
294 $this->MP_array
[] = $mount_info['MPvar'];
295 $this->id
= $mount_info['mount_pid'];
298 // Gather list of page uids in root line (for "isActive" evaluation). Also adds the MP params in the path so Mount Points are respected.
299 // (List is specific for this rootline, so it may be supplied from parent menus for speed...)
300 if (!is_array($this->rL_uidRegister
)) {
301 $rl_MParray = array();
302 foreach($this->tmpl
->rootLine
as $v_rl) {
303 // For overlaid mount points, set the variable right now:
304 if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) {
305 $rl_MParray[] = $v_rl['_MP_PARAM'];
309 $this->rL_uidRegister
[] = 'ITEM:'.$v_rl['uid'].(count($rl_MParray) ?
':'.implode(',',$rl_MParray) : '');
311 // For normal mount points, set the variable for next level.
312 if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) {
313 $rl_MParray[] = $v_rl['_MP_PARAM'];
318 // Set $directoryLevel so the following evalution of the nextActive will not return
319 // an invalid value if .special=directory was set
321 if ($this->conf
['special'] == 'directory') {
322 $value = $GLOBALS['TSFE']->cObj
->stdWrap($this->conf
['special.']['value'], $this->conf
['special.']['value.']);
324 $value=$GLOBALS['TSFE']->page
['uid'];
326 $directoryLevel = intval($GLOBALS['TSFE']->tmpl
->getRootlineLevel($value));
329 // 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
330 // Notice: The automatic expansion of a menu is designed to work only when no "special" modes (except "directory") are used.
331 $startLevel = $directoryLevel ?
$directoryLevel : $this->entryLevel
;
332 $currentLevel = $startLevel +
$this->menuNumber
;
333 if (is_array($this->tmpl
->rootLine
[$currentLevel])) {
334 $nextMParray = $this->MP_array
;
335 if (!count($nextMParray) && !$this->tmpl
->rootLine
[$currentLevel]['_MOUNT_OL'] && $currentLevel > 0) {
336 // Make sure to slide-down any mount point information (_MP_PARAM) to children records in the rootline
337 // otherwise automatic expansion will not work
338 $parentRecord = $this->tmpl
->rootLine
[$currentLevel - 1];
339 if (isset($parentRecord['_MP_PARAM'])) {
340 $nextMParray[] = $parentRecord['_MP_PARAM'];
344 if ($this->tmpl
->rootLine
[$currentLevel]['_MOUNT_OL']) { // In overlay mode, add next level MPvars as well:
345 $nextMParray[] = $this->tmpl
->rootLine
[$currentLevel]['_MP_PARAM'];
347 $this->nextActive
= $this->tmpl
->rootLine
[$currentLevel]['uid'] . (count($nextMParray) ?
':' . implode(',', $nextMParray) : '');
349 $this->nextActive
= '';
353 if ($this->mconf
['imgNamePrefix']) {
354 $this->imgNamePrefix
=$this->mconf
['imgNamePrefix'];
356 $this->imgNameNotRandom
= $this->mconf
['imgNameNotRandom'];
360 $GLOBALS['TT']->setTSlogMessage('ERROR in menu',3);
367 * Creates the menu in the internal variables, ready for output.
368 * Basically this will read the page records needed and fill in the internal $this->menuArr
369 * 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.
373 function makeMenu() {
376 // Initializing showAccessRestrictedPages
377 if ($this->mconf
['showAccessRestrictedPages']) {
378 // SAVING where_groupAccess
379 $SAVED_where_groupAccess = $this->sys_page
->where_groupAccess
;
380 $this->sys_page
->where_groupAccess
= ''; // Temporarily removing fe_group checking!
383 // Begin production of menu:
385 $altSortFieldValue = trim($this->mconf
['alternativeSortingField']);
386 $altSortField = $altSortFieldValue ?
$altSortFieldValue : 'sorting';
387 if ($this->menuNumber
==1 && $this->conf
['special']) { // ... only for the FIRST level of a HMENU
388 $value = $this->parent_cObj
->stdWrap($this->conf
['special.']['value'], $this->conf
['special.']['value.']);
390 switch($this->conf
['special']) {
392 $temp = $this->includeMakeMenu($this->conf
['special.'],$altSortField);
395 $temp = $this->parent_cObj
->callUserFunction(
396 $this->conf
['special.']['userFunc'],
397 array_merge($this->conf
['special.'],array('_altSortField'=>$altSortField)),
400 if (!is_array($temp)) $temp=array();
405 // Getting current page record NOT overlaid by any translation:
406 $currentPageWithNoOverlay = $this->sys_page
->getRawRecord('pages',$GLOBALS['TSFE']->page
['uid']);
408 // Traverse languages set up:
409 $languageItems = t3lib_div
::intExplode(',',$value);
410 foreach($languageItems as $sUid) {
411 // Find overlay record:
413 $lRecs = $this->sys_page
->getPageOverlay($GLOBALS['TSFE']->page
['uid'],$sUid);
414 } else $lRecs=array();
415 // Checking if the "disabled" state should be set.
417 (t3lib_div
::hideIfNotTranslated($GLOBALS['TSFE']->page
['l18n_cfg']) && $sUid && !count($lRecs)) // Blocking for all translations?
418 ||
($GLOBALS['TSFE']->page
['l18n_cfg']&1 && (!$sUid ||
!count($lRecs))) // Blocking default translation?
419 ||
(!$this->conf
['special.']['normalWhenNoLanguage'] && $sUid && !count($lRecs))
421 $iState = $GLOBALS['TSFE']->sys_language_uid
==$sUid ?
'USERDEF2' : 'USERDEF1';
423 $iState = $GLOBALS['TSFE']->sys_language_uid
==$sUid ?
'ACT' : 'NO';
426 if ($this->conf
['addQueryString']) {
427 $getVars = $this->parent_cObj
->getQueryArguments($this->conf
['addQueryString.'],array('L'=>$sUid),true);
429 $getVars = '&L='.$sUid;
433 $temp[] = array_merge(
434 array_merge($currentPageWithNoOverlay, $lRecs),
436 'ITEM_STATE' => $iState,
437 '_ADD_GETVARS' => $getVars,
445 $value=$GLOBALS['TSFE']->page
['uid'];
447 $items=t3lib_div
::intExplode(',',$value);
449 foreach($items as $id) {
450 $MP = $this->tmpl
->getFromMPmap($id);
452 // Checking if a page is a mount page and if so, change the ID and set the MP var properly.
453 $mount_info = $this->sys_page
->getMountPointInfo($id);
454 if (is_array($mount_info)) {
455 if ($mount_info['overlay']) { // Overlays should already have their full MPvars calculated:
456 $MP = $this->tmpl
->getFromMPmap($mount_info['mount_pid']);
457 $MP = $MP ?
$MP : $mount_info['MPvar'];
459 $MP = ($MP ?
$MP.',' : '').$mount_info['MPvar'];
461 $id = $mount_info['mount_pid'];
465 $res = $GLOBALS['TSFE']->cObj
->exec_getQuery('pages',Array('pidInList'=>$id,'orderBy'=>$altSortField));
466 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
467 $GLOBALS['TSFE']->sys_page
->versionOL('pages',$row);
469 if (is_array($row)) {
471 $mount_info = $this->sys_page
->getMountPointInfo($row['uid'], $row);
472 if (is_array($mount_info) && $mount_info['overlay']) { // There is a valid mount point.
473 $mp_row = $this->sys_page
->getPage($mount_info['mount_pid']); // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
474 if (count($mp_row)) {
476 $row['_MP_PARAM'] = $mount_info['MPvar'];
477 } else unset($row); // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
480 // Add external MP params, then the row:
481 if (is_array($row)) {
482 if ($MP) $row['_MP_PARAM'] = $MP.($row['_MP_PARAM'] ?
','.$row['_MP_PARAM'] : '');
483 $temp[$row['uid']] = $this->sys_page
->getPageOverlay($row);
493 $loadDB = t3lib_div
::makeInstance('FE_loadDBGroup');
494 $loadDB->start($value, 'pages');
495 $loadDB->additionalWhere
['pages']=tslib_cObj
::enableFields('pages');
496 $loadDB->getFromDB();
498 foreach($loadDB->itemArray
as $val) {
499 $MP = $this->tmpl
->getFromMPmap($val['id']);
502 $mount_info = $this->sys_page
->getMountPointInfo($val['id']);
503 if (is_array($mount_info) && $mount_info['overlay']) { // There is a valid mount point.
504 $mp_row = $this->sys_page
->getPage($mount_info['mount_pid']); // Using "getPage" is OK since we need the check for enableFields AND for type 2 of mount pids we DO require a doktype < 200!
505 if (count($mp_row)) {
507 $row['_MP_PARAM'] = $mount_info['MPvar'];
509 if ($mount_info['overlay']) { // Overlays should already have their full MPvars calculated:
510 $MP = $this->tmpl
->getFromMPmap($mount_info['mount_pid']);
511 if ($MP) unset($row['_MP_PARAM']);
513 } else unset($row); // If the mount point could not be fetched with respect to enableFields, unset the row so it does not become a part of the menu!
515 $row = $loadDB->results
['pages'][$val['id']];
518 // Add external MP params, then the row:
519 if (is_array($row)) {
520 if ($MP) $row['_MP_PARAM'] = $MP.($row['_MP_PARAM'] ?
','.$row['_MP_PARAM'] : '');
521 $temp[] = $this->sys_page
->getPageOverlay($row);
527 $value=$GLOBALS['TSFE']->page
['uid'];
529 $items=t3lib_div
::intExplode(',',$value);
530 if (t3lib_div
::testInt($this->conf
['special.']['depth'])) {
531 $depth = t3lib_div
::intInRange($this->conf
['special.']['depth'],1,20); // Tree depth
535 $limit = t3lib_div
::intInRange($this->conf
['special.']['limit'],0,100); // max number of items
536 $maxAge = intval(tslib_cObj
::calc($this->conf
['special.']['maxAge']));
537 if (!$limit) $limit=10;
538 $mode = $this->conf
['special.']['mode']; // *'auto', 'manual', 'tstamp'
540 $id_list_arr = Array();
542 foreach($items as $id) {
543 $bA = t3lib_div
::intInRange($this->conf
['special.']['beginAtLevel'],0,100);
544 $id_list_arr[] = tslib_cObj
::getTreeList(-1*$id,$depth-1+
$bA,$bA-1);
546 $id_list = implode(',',$id_list_arr);
547 // Get sortField (mode)
550 $sortField = 'starttime';
554 $sortField = 'lastUpdated';
557 $sortField = 'tstamp';
560 $sortField = 'crdate';
563 $sortField = 'SYS_LASTCHANGED';
567 $extraWhere = ($this->conf
['includeNotInMenu'] ?
'' : ' AND pages.nav_hide=0').$this->getDoktypeExcludeWhere();
569 if ($this->conf
['special.']['excludeNoSearchPages']) {
570 $extraWhere.= ' AND pages.no_search=0';
573 $extraWhere.=' AND '.$sortField.'>'.($GLOBALS['SIM_ACCESS_TIME']-$maxAge);
576 $res = $GLOBALS['TSFE']->cObj
->exec_getQuery('pages',Array('pidInList'=>'0', 'uidInList'=>$id_list, 'where'=>$sortField.'>=0'.$extraWhere, 'orderBy'=>($altSortFieldValue ?
$altSortFieldValue : $sortField.' desc'),'max'=>$limit));
577 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
578 $GLOBALS['TSFE']->sys_page
->versionOL('pages',$row);
579 if (is_array($row)) {
580 $temp[$row['uid']]=$this->sys_page
->getPageOverlay($row);
585 list($value)=t3lib_div
::intExplode(',',$value);
587 $value=$GLOBALS['TSFE']->page
['uid'];
589 if ($this->conf
['special.']['setKeywords'] ||
$this->conf
['special.']['setKeywords.']) {
590 $kw = $this->parent_cObj
->stdWrap($this->conf
['special.']['setKeywords'], $this->conf
['special.']['setKeywords.']);
592 $value_rec=$this->sys_page
->getPage($value); // The page record of the 'value'.
594 $kfieldSrc = $this->conf
['special.']['keywordsField.']['sourceField'] ?
$this->conf
['special.']['keywordsField.']['sourceField'] : 'keywords';
595 $kw = trim(tslib_cObj
::keywords($value_rec[$kfieldSrc])); // keywords.
598 $mode = $this->conf
['special.']['mode']; // *'auto', 'manual', 'tstamp'
601 $sortField = 'starttime';
605 $sortField = 'lastUpdated';
608 $sortField = 'tstamp';
611 $sortField = 'crdate';
614 $sortField = 'SYS_LASTCHANGED';
618 // depth, limit, extra where
619 if (t3lib_div
::testInt($this->conf
['special.']['depth'])) {
620 $depth = t3lib_div
::intInRange($this->conf
['special.']['depth'],0,20); // Tree depth
624 $limit = t3lib_div
::intInRange($this->conf
['special.']['limit'],0,100); // max number of items
625 $extraWhere = ' AND pages.uid!='.$value.($this->conf
['includeNotInMenu'] ?
'' : ' AND pages.nav_hide=0').$this->getDoktypeExcludeWhere();
626 if ($this->conf
['special.']['excludeNoSearchPages']) {
627 $extraWhere.= ' AND pages.no_search=0';
630 $eLevel = tslib_cObj
::getKey(
631 $this->parent_cObj
->stdWrap($this->conf
['special.']['entryLevel'], $this->conf
['special.']['entryLevel.']),
632 $this->tmpl
->rootLine
634 $startUid = intval($this->tmpl
->rootLine
[$eLevel]['uid']);
636 // which field is for keywords
637 $kfield = 'keywords';
638 if ( $this->conf
['special.']['keywordsField'] ) {
639 list($kfield) = explode(' ',trim ($this->conf
['special.']['keywordsField']));
642 // If there are keywords and the startuid is present.
643 if ($kw && $startUid) {
644 $bA = t3lib_div
::intInRange($this->conf
['special.']['beginAtLevel'],0,100);
645 $id_list=tslib_cObj
::getTreeList(-1*$startUid,$depth-1+
$bA,$bA-1);
647 $kwArr = explode(',',$kw);
648 foreach($kwArr as $word) {
651 $keyWordsWhereArr[] = $kfield.' LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($word, 'pages').'%\'';
654 $res = $GLOBALS['TSFE']->cObj
->exec_getQuery('pages',Array('pidInList'=>'0', 'uidInList'=>$id_list, 'where'=>'('.implode(' OR ',$keyWordsWhereArr).')'.$extraWhere, 'orderBy'=>($altSortFieldValue ?
$altSortFieldValue : $sortField.' desc'),'max'=>$limit));
655 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
656 $GLOBALS['TSFE']->sys_page
->versionOL('pages',$row);
657 if (is_array($row)) {
658 $temp[$row['uid']]=$this->sys_page
->getPageOverlay($row);
664 $begin_end = explode('|', $this->parent_cObj
->stdWrap($this->conf
['special.']['range'], $this->conf
['special.']['range.']));
665 $begin_end[0] = intval($begin_end[0]);
666 if (!t3lib_div
::testInt($begin_end[1])) {
670 $beginKey = tslib_cObj
::getKey ($begin_end[0],$this->tmpl
->rootLine
);
671 $endKey = tslib_cObj
::getKey ($begin_end[1],$this->tmpl
->rootLine
);
672 if ($endKey<$beginKey) {$endKey=$beginKey;}
674 $rl_MParray = array();
675 foreach($this->tmpl
->rootLine
as $k_rl => $v_rl) {
676 // For overlaid mount points, set the variable right now:
677 if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) {
678 $rl_MParray[] = $v_rl['_MP_PARAM'];
680 // Traverse rootline:
681 if ($k_rl>=$beginKey && $k_rl<=$endKey) {
683 $temp[$temp_key]=$this->sys_page
->getPage($v_rl['uid']);
684 if (count($temp[$temp_key])) {
685 if (!$temp[$temp_key]['target']) { // If there are no specific target for the page, put the level specific target on.
686 $temp[$temp_key]['target'] = $this->conf
['special.']['targets.'][$k_rl];
687 $temp[$temp_key]['_MP_PARAM'] = implode(',',$rl_MParray);
689 } else unset($temp[$temp_key]);
691 // For normal mount points, set the variable for next level.
692 if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) {
693 $rl_MParray[] = $v_rl['_MP_PARAM'];
696 // Reverse order of elements (e.g. "1,2,3,4" gets "4,3,2,1"):
697 if (isset($this->conf
['special.']['reverseOrder']) && $this->conf
['special.']['reverseOrder']) {
698 $temp = array_reverse($temp);
699 $rl_MParray = array_reverse($rl_MParray);
703 list($value)=t3lib_div
::intExplode(',',$value);
705 $value=$GLOBALS['TSFE']->page
['uid'];
707 if ($value!=$this->tmpl
->rootLine
[0]['uid']) { // Will not work out of rootline
709 $value_rec=$this->sys_page
->getPage($value); // The page record of the 'value'.
710 if ($value_rec['pid']) { // 'up' page cannot be outside rootline
711 $recArr['up']=$this->sys_page
->getPage($value_rec['pid']); // The page record of 'up'.
713 if ($recArr['up']['pid'] && $value_rec['pid']!=$this->tmpl
->rootLine
[0]['uid']) { // If the 'up' item was NOT level 0 in rootline...
714 $recArr['index']=$this->sys_page
->getPage($recArr['up']['pid']); // The page record of "index".
717 // prev / next is found
718 $prevnext_menu = $this->sys_page
->getMenu($value_rec['pid'],'*',$altSortField);
721 foreach ($prevnext_menu as $k_b => $v_b) {
723 $recArr['next']=$v_b;
726 if ($v_b['uid']==$value) {
728 $recArr['prev']=$prevnext_menu[$lastKey];
734 reset($prevnext_menu);
735 $recArr['first']=pos($prevnext_menu);
737 $recArr['last']=pos($prevnext_menu);
739 // prevsection / nextsection is found
740 if (is_array($recArr['index'])) { // You can only do this, if there is a valid page two levels up!
741 $prevnextsection_menu = $this->sys_page
->getMenu($recArr['index']['uid'],'*',$altSortField);
744 foreach ($prevnextsection_menu as $k_b => $v_b) {
746 $sectionRec_temp = $this->sys_page
->getMenu($v_b['uid'],'*',$altSortField);
747 if (count($sectionRec_temp)) {
748 reset($sectionRec_temp);
749 $recArr['nextsection']=pos($sectionRec_temp);
750 end ($sectionRec_temp);
751 $recArr['nextsection_last']=pos($sectionRec_temp);
755 if ($v_b['uid']==$value_rec['pid']) {
757 $sectionRec_temp = $this->sys_page
->getMenu($prevnextsection_menu[$lastKey]['uid'],'*',$altSortField);
758 if (count($sectionRec_temp)) {
759 reset($sectionRec_temp);
760 $recArr['prevsection']=pos($sectionRec_temp);
761 end ($sectionRec_temp);
762 $recArr['prevsection_last']=pos($sectionRec_temp);
770 if ($this->conf
['special.']['items.']['prevnextToSection']) {
771 if (!is_array($recArr['prev']) && is_array($recArr['prevsection_last'])) {
772 $recArr['prev']=$recArr['prevsection_last'];
774 if (!is_array($recArr['next']) && is_array($recArr['nextsection'])) {
775 $recArr['next']=$recArr['nextsection'];
779 $items = explode('|',$this->conf
['special.']['items']);
781 foreach ($items as $k_b => $v_b) {
782 $v_b=strtolower(trim($v_b));
783 if (intval($this->conf
['special.'][$v_b.'.']['uid'])) {
784 $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
786 if (is_array($recArr[$v_b])) {
787 $temp[$c]=$recArr[$v_b];
788 if ($this->conf
['special.'][$v_b.'.']['target']) {
789 $temp[$c]['target']=$this->conf
['special.'][$v_b.'.']['target'];
791 $tmpSpecialFields = $this->conf
['special.'][$v_b.'.']['fields.'];
792 if (is_array($tmpSpecialFields)) {
793 foreach ($tmpSpecialFields as $fk => $val) {
803 } elseif (is_array($this->alternativeMenuTempArray
)) { // Setting $temp array if not level 1.
804 $temp = $this->alternativeMenuTempArray
;
805 } elseif ($this->mconf
['sectionIndex']) {
806 if ($GLOBALS['TSFE']->sys_language_uid
&& count($this->sys_page
->getPageOverlay($this->id
))) {
807 $sys_language_uid = intval($GLOBALS['TSFE']->sys_language_uid
);
808 } else $sys_language_uid=0;
810 $selectSetup = Array(
811 'pidInList'=>$this->id
,
812 'orderBy'=>$altSortField,
813 'where' => 'colPos=0 AND sys_language_uid='.$sys_language_uid,
814 'andWhere' => 'sectionIndex!=0'
816 switch($this->mconf
['sectionIndex.']['type']) {
818 unset($selectSetup['andWhere']);
821 $selectSetup['andWhere'] .= ' AND header_layout!=100 AND header!=""';
824 $basePageRow=$this->sys_page
->getPage($this->id
);
825 if (is_array($basePageRow)) {
826 $res = $GLOBALS['TSFE']->cObj
->exec_getQuery('tt_content', $selectSetup);
827 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
828 $GLOBALS['TSFE']->sys_page
->versionOL('tt_content',$row);
830 if (is_array($row)) {
831 $temp[$row['uid']] = $basePageRow;
832 $temp[$row['uid']]['title'] = $row['header'];
833 $temp[$row['uid']]['nav_title'] = $row['header'];
834 $temp[$row['uid']]['subtitle'] = $row['subheader'];
835 $temp[$row['uid']]['starttime'] = $row['starttime'];
836 $temp[$row['uid']]['endtime'] = $row['endtime'];
837 $temp[$row['uid']]['fe_group'] = $row['fe_group'];
838 $temp[$row['uid']]['media'] = $row['media'];
840 $temp[$row['uid']]['header_layout'] = $row['header_layout'];
841 $temp[$row['uid']]['bodytext'] = $row['bodytext'];
842 $temp[$row['uid']]['image'] = $row['image'];
844 $temp[$row['uid']]['sectionIndex_uid'] = $row['uid'];
849 $temp = $this->sys_page
->getMenu($this->id
,'*',$altSortField); // gets the menu
854 $minItems = intval($this->mconf
['minItems'] ?
$this->mconf
['minItems'] : $this->conf
['minItems']);
855 $maxItems = intval($this->mconf
['maxItems'] ?
$this->mconf
['maxItems'] : $this->conf
['maxItems']);
856 $begin = tslib_cObj
::calc($this->mconf
['begin'] ?
$this->mconf
['begin'] : $this->conf
['begin']);
858 $banUidArray = $this->getBannedUids();
860 // Fill in the menuArr with elements that should go into the menu:
861 $this->menuArr
= Array();
862 foreach($temp as $data) {
863 $spacer = (t3lib_div
::inList($this->spacerIDList
,$data['doktype']) ||
!strcmp($data['ITEM_STATE'],'SPC')) ?
1 : 0; // if item is a spacer, $spacer is set
864 if ($this->filterMenuPages($data, $banUidArray, $spacer)) {
866 if ($begin<=$c_b) { // If the beginning item has been reached.
867 $this->menuArr
[$c] = $data;
868 $this->menuArr
[$c]['isSpacer'] = $spacer;
870 if ($maxItems && $c>=$maxItems) {
877 // Fill in fake items, if min-items is set.
879 while($c<$minItems) {
880 $this->menuArr
[$c] = Array(
882 'uid' => $GLOBALS['TSFE']->id
887 // Setting number of menu items
888 $GLOBALS['TSFE']->register
['count_menuItems'] = count($this->menuArr
);
889 // Passing the menuArr through a user defined function:
890 if ($this->mconf
['itemArrayProcFunc']) {
891 if (!is_array($this->parentMenuArr
)) {$this->parentMenuArr
=array();}
892 $this->menuArr
= $this->userProcess('itemArrayProcFunc',$this->menuArr
);
894 $this->hash
= md5(serialize($this->menuArr
).serialize($this->mconf
).serialize($this->tmpl
->rootLine
).serialize($this->MP_array
));
896 // Get the cache timeout:
897 if ($this->conf
['cache_period']) {
898 $cacheTimeout = $this->conf
['cache_period'];
900 $cacheTimeout = $GLOBALS['TSFE']->get_cache_timeout();
903 $serData = $this->sys_page
->getHash($this->hash
);
906 $this->sys_page
->storeHash($this->hash
, serialize($this->result
), 'MENUDATA', $cacheTimeout);
908 $this->result
= unserialize($serData);
911 // End showAccessRestrictedPages
912 if ($this->mconf
['showAccessRestrictedPages']) {
913 // RESTORING where_groupAccess
914 $this->sys_page
->where_groupAccess
= $SAVED_where_groupAccess;
920 * Includes the PHP script defined for the HMENU special type "userdefined".
921 * This script is supposed to populate the array $menuItemsArray with a set of page records comprising the menu.
922 * The "userdefined" type is deprecated since "userfunction" has arrived since and is a better choice for many reasons (like using classes/functions for rendering the menu)
924 * @param array TypoScript parameters for "special.". In particular the property "file" is reserved and specifies the file to include. Seems like any other property can be used freely by the script.
925 * @param string The sorting field. Can be used from the script in the $incFile.
926 * @return array An array with the menu items
927 * @deprecated since TYPO3 3.6, this function will be removed in TYPO3 4.5, use HMENU of type "userfunction" instead of "userdefined"
930 function includeMakeMenu($conf,$altSortField) {
931 t3lib_div
::logDeprecatedFunction();
933 $incFile = $GLOBALS['TSFE']->tmpl
->getFileName($conf['file']);
934 if ($incFile && $GLOBALS['TSFE']->checkFileInclude($incFile)) {
937 return is_array($menuItemsArray) ?
$menuItemsArray : array();
941 * 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.
943 * @param array Array of menu items
944 * @param array Array of page uids which are to be excluded
945 * @param boolean If set, then the page is a spacer.
946 * @return boolean Returns true if the page can be safely included.
948 function filterMenuPages(&$data,$banUidArray,$spacer) {
950 if ($data['_SAFE']) return TRUE;
953 if ($this->mconf
['SPC'] ||
!$spacer) { // If the spacer-function is not enabled, spacers will not enter the $menuArr
954 if (!t3lib_div
::inList($this->doktypeExcludeList
,$data['doktype'])) { // Page may not be 'not_in_menu' or 'Backend User Section'
955 if (!$data['nav_hide'] ||
$this->conf
['includeNotInMenu']) { // Not hidden in navigation
956 if (!t3lib_div
::inArray($banUidArray,$uid)) { // not in banned uid's
958 // Checks if the default language version can be shown:
959 // Block page is set, if l18n_cfg allows plus: 1) Either default language or 2) another language but NO overlay record set for page!
960 $blockPage = $data['l18n_cfg']&1 && (!$GLOBALS['TSFE']->sys_language_uid ||
($GLOBALS['TSFE']->sys_language_uid
&& !$data['_PAGES_OVERLAY']));
963 // Checking if a page should be shown in the menu depending on whether a translation exists:
965 if ($GLOBALS['TSFE']->sys_language_uid
&& t3lib_div
::hideIfNotTranslated($data['l18n_cfg'])) { // There is an alternative language active AND the current page requires a translation:
966 if (!$data['_PAGES_OVERLAY']) {
971 // Continue if token is true:
974 // Checking if "&L" should be modified so links to non-accessible pages will not happen.
975 if ($this->conf
['protectLvar']) {
976 $languageUid = intval($GLOBALS['TSFE']->config
['config']['sys_language_uid']);
977 if ($languageUid && ($this->conf
['protectLvar']=='all' || t3lib_div
::hideIfNotTranslated($data['l18n_cfg']))) {
978 $olRec = $GLOBALS['TSFE']->sys_page
->getPageOverlay($data['uid'], $languageUid);
979 if (!count($olRec)) {
980 // 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"
981 $data['_ADD_GETVARS'].= '&L=0';
996 * 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)
997 * 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.
998 * 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.
1000 * @param integer Number of menu items in the menu
1001 * @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)
1004 function procesItemStates($splitCount) {
1006 // Prepare normal settings
1007 if (!is_array($this->mconf
['NO.']) && $this->mconf
['NO']) $this->mconf
['NO.']=array(); // Setting a blank array if NO=1 and there are no properties.
1008 $NOconf = $this->tmpl
->splitConfArray($this->mconf
['NO.'],$splitCount);
1010 // Prepare rollOver settings, overriding normal settings
1012 if ($this->mconf
['RO']) {
1013 $ROconf = $this->tmpl
->splitConfArray($this->mconf
['RO.'],$splitCount);
1016 // Prepare IFSUB settings, overriding normal settings
1017 // IFSUB is true if there exist submenu items to the current item
1018 if ($this->mconf
['IFSUB']) {
1019 $IFSUBinit = 0; // Flag: If $IFSUB is generated
1020 foreach ($NOconf as $key => $val) {
1021 if ($this->isItemState('IFSUB',$key)) {
1022 if (!$IFSUBinit) { // if this is the first IFSUB element, we must generate IFSUB.
1023 $IFSUBconf = $this->tmpl
->splitConfArray($this->mconf
['IFSUB.'],$splitCount);
1024 if ($this->mconf
['IFSUBRO']) {
1025 $IFSUBROconf = $this->tmpl
->splitConfArray($this->mconf
['IFSUBRO.'],$splitCount);
1029 $NOconf[$key] = $IFSUBconf[$key]; // Substitute normal with ifsub
1030 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1031 $ROconf[$key] = $IFSUBROconf[$key] ?
$IFSUBROconf[$key] : $IFSUBconf[$key]; // If RollOver on active then apply this
1036 // Prepare active settings, overriding normal settings
1037 if ($this->mconf
['ACT']) {
1038 $ACTinit = 0; // Flag: If $ACT is generated
1039 foreach ($NOconf as $key => $val) { // Find active
1040 if ($this->isItemState('ACT',$key)) {
1041 if (!$ACTinit) { // if this is the first 'active', we must generate ACT.
1042 $ACTconf = $this->tmpl
->splitConfArray($this->mconf
['ACT.'],$splitCount);
1043 // Prepare active rollOver settings, overriding normal active settings
1044 if ($this->mconf
['ACTRO']) {
1045 $ACTROconf = $this->tmpl
->splitConfArray($this->mconf
['ACTRO.'],$splitCount);
1049 $NOconf[$key] = $ACTconf[$key]; // Substitute normal with active
1050 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1051 $ROconf[$key] = $ACTROconf[$key] ?
$ACTROconf[$key] : $ACTconf[$key]; // If RollOver on active then apply this
1056 // Prepare ACT (active)/IFSUB settings, overriding normal settings
1057 // ACTIFSUB is true if there exist submenu items to the current item and the current item is active
1058 if ($this->mconf
['ACTIFSUB']) {
1059 $ACTIFSUBinit = 0; // Flag: If $ACTIFSUB is generated
1060 foreach ($NOconf as $key => $val) { // Find active
1061 if ($this->isItemState('ACTIFSUB',$key)) {
1062 if (!$ACTIFSUBinit) { // if this is the first 'active', we must generate ACTIFSUB.
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);
1070 $NOconf[$key] = $ACTIFSUBconf[$key]; // Substitute normal with active
1071 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1072 $ROconf[$key] = $ACTIFSUBROconf[$key] ?
$ACTIFSUBROconf[$key] : $ACTIFSUBconf[$key]; // If RollOver on active then apply this
1077 // Prepare CUR (current) settings, overriding normal settings
1078 // CUR is true if the current page equals the item here!
1079 if ($this->mconf
['CUR']) {
1080 $CURinit = 0; // Flag: If $CUR is generated
1081 foreach ($NOconf as $key => $val) {
1082 if ($this->isItemState('CUR',$key)) {
1083 if (!$CURinit) { // if this is the first 'current', we must generate CUR. Basically this control is just inherited from the other implementations as current would only exist one time and thats it (unless you use special-features of HMENU)
1084 $CURconf = $this->tmpl
->splitConfArray($this->mconf
['CUR.'],$splitCount);
1085 if ($this->mconf
['CURRO']) {
1086 $CURROconf = $this->tmpl
->splitConfArray($this->mconf
['CURRO.'],$splitCount);
1090 $NOconf[$key] = $CURconf[$key]; // Substitute normal with current
1091 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1092 $ROconf[$key] = $CURROconf[$key] ?
$CURROconf[$key] : $CURconf[$key]; // If RollOver on active then apply this
1097 // Prepare CUR (current)/IFSUB settings, overriding normal settings
1098 // CURIFSUB is true if there exist submenu items to the current item and the current page equals the item here!
1099 if ($this->mconf
['CURIFSUB']) {
1100 $CURIFSUBinit = 0; // Flag: If $CURIFSUB is generated
1101 foreach ($NOconf as $key => $val) {
1102 if ($this->isItemState('CURIFSUB',$key)) {
1103 if (!$CURIFSUBinit) { // if this is the first 'current', we must generate CURIFSUB.
1104 $CURIFSUBconf = $this->tmpl
->splitConfArray($this->mconf
['CURIFSUB.'],$splitCount);
1105 // Prepare current rollOver settings, overriding normal current settings
1106 if ($this->mconf
['CURIFSUBRO']) {
1107 $CURIFSUBROconf = $this->tmpl
->splitConfArray($this->mconf
['CURIFSUBRO.'],$splitCount);
1111 $NOconf[$key] = $CURIFSUBconf[$key]; // Substitute normal with active
1112 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the current
1113 $ROconf[$key] = $CURIFSUBROconf[$key] ?
$CURIFSUBROconf[$key] : $CURIFSUBconf[$key]; // If RollOver on current then apply this
1118 // Prepare active settings, overriding normal settings
1119 if ($this->mconf
['USR']) {
1120 $USRinit = 0; // Flag: If $USR is generated
1121 foreach ($NOconf as $key => $val) { // Find active
1122 if ($this->isItemState('USR',$key)) {
1123 if (!$USRinit) { // if this is the first active, we must generate USR.
1124 $USRconf = $this->tmpl
->splitConfArray($this->mconf
['USR.'],$splitCount);
1125 // Prepare active rollOver settings, overriding normal active settings
1126 if ($this->mconf
['USRRO']) {
1127 $USRROconf = $this->tmpl
->splitConfArray($this->mconf
['USRRO.'],$splitCount);
1131 $NOconf[$key] = $USRconf[$key]; // Substitute normal with active
1132 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1133 $ROconf[$key] = $USRROconf[$key] ?
$USRROconf[$key] : $USRconf[$key]; // If RollOver on active then apply this
1138 // Prepare spacer settings, overriding normal settings
1139 if ($this->mconf
['SPC']) {
1140 $SPCinit = 0; // Flag: If $SPC is generated
1141 foreach ($NOconf as $key => $val) { // Find spacers
1142 if ($this->isItemState('SPC',$key)) {
1143 if (!$SPCinit) { // if this is the first spacer, we must generate SPC.
1144 $SPCconf = $this->tmpl
->splitConfArray($this->mconf
['SPC.'],$splitCount);
1147 $NOconf[$key] = $SPCconf[$key]; // Substitute normal with spacer
1151 // Prepare Userdefined settings
1152 if ($this->mconf
['USERDEF1']) {
1153 $USERDEF1init = 0; // Flag: If $USERDEF1 is generated
1154 foreach ($NOconf as $key => $val) { // Find active
1155 if ($this->isItemState('USERDEF1',$key)) {
1156 if (!$USERDEF1init) { // if this is the first active, we must generate USERDEF1.
1157 $USERDEF1conf = $this->tmpl
->splitConfArray($this->mconf
['USERDEF1.'],$splitCount);
1158 // Prepare active rollOver settings, overriding normal active settings
1159 if ($this->mconf
['USERDEF1RO']) {
1160 $USERDEF1ROconf = $this->tmpl
->splitConfArray($this->mconf
['USERDEF1RO.'],$splitCount);
1164 $NOconf[$key] = $USERDEF1conf[$key]; // Substitute normal with active
1165 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1166 $ROconf[$key] = $USERDEF1ROconf[$key] ?
$USERDEF1ROconf[$key] : $USERDEF1conf[$key]; // If RollOver on active then apply this
1171 // Prepare Userdefined settings
1172 if ($this->mconf
['USERDEF2']) {
1173 $USERDEF2init = 0; // Flag: If $USERDEF2 is generated
1174 foreach ($NOconf as $key => $val) { // Find active
1175 if ($this->isItemState('USERDEF2',$key)) {
1176 if (!$USERDEF2init) { // if this is the first active, we must generate USERDEF2.
1177 $USERDEF2conf = $this->tmpl
->splitConfArray($this->mconf
['USERDEF2.'],$splitCount);
1178 // Prepare active rollOver settings, overriding normal active settings
1179 if ($this->mconf
['USERDEF2RO']) {
1180 $USERDEF2ROconf = $this->tmpl
->splitConfArray($this->mconf
['USERDEF2RO.'],$splitCount);
1184 $NOconf[$key] = $USERDEF2conf[$key]; // Substitute normal with active
1185 if ($ROconf) { // If rollOver on normal, we must apply a state for rollOver on the active
1186 $ROconf[$key] = $USERDEF2ROconf[$key] ?
$USERDEF2ROconf[$key] : $USERDEF2conf[$key]; // If RollOver on active then apply this
1192 return array($NOconf,$ROconf);
1196 * 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
1197 * This function doesn't care about the url, because if we let the url be redirected, it will be logged in the stat!!!
1199 * @param integer Pointer to a key in the $this->menuArr array where the value for that key represents the menu item we are linking to (page record)
1200 * @param string Alternative target
1201 * @param integer Alternative type
1202 * @return array Returns an array with A-tag attributes as key/value pairs (HREF, TARGET and onClick)
1205 function link($key,$altTarget='',$typeOverride='') {
1208 $MP_var = $this->getMPvar($key);
1209 $MP_params = $MP_var ?
'&MP='.rawurlencode($MP_var) : '';
1211 // Setting override ID
1212 if ($this->mconf
['overrideId'] ||
$this->menuArr
[$key]['overrideId']) {
1213 $overrideArray = array();
1214 // If a user script returned the value overrideId in the menu array we use that as page id
1215 $overrideArray['uid'] = $this->mconf
['overrideId']?
$this->mconf
['overrideId']:$this->menuArr
[$key]['overrideId'];
1216 $overrideArray['alias'] = '';
1217 $MP_params = ''; // clear MP parameters since ID was changed.
1222 // Setting main target:
1223 $mainTarget = $altTarget ?
$altTarget : $this->mconf
['target'];
1226 if ($this->mconf
['collapse'] && $this->isActive($this->menuArr
[$key]['uid'], $this->getMPvar($key))) {
1227 $thePage = $this->sys_page
->getPage($this->menuArr
[$key]['pid']);
1228 $LD = $this->menuTypoLink($thePage,$mainTarget,'','',$overrideArray, $this->mconf
['addParams'].$MP_params.$this->menuArr
[$key]['_ADD_GETVARS'], $typeOverride);
1230 $LD = $this->menuTypoLink($this->menuArr
[$key],$mainTarget,'','',$overrideArray, $this->mconf
['addParams'].$MP_params.$this->I
['val']['additionalParams'].$this->menuArr
[$key]['_ADD_GETVARS'], $typeOverride);
1233 // Override URL if using "External URL" as doktype with a valid e-mail address:
1234 if ($this->menuArr
[$key]['doktype'] == 3 && $this->menuArr
[$key]['urltype'] == 3 && t3lib_div
::validEmail($this->menuArr
[$key]['url'])) {
1235 // Create mailto-link using tslib_cObj::typolink (concerning spamProtectEmailAddresses):
1236 $LD['totalURL'] = $this->parent_cObj
->typoLink_URL(array('parameter' => $this->menuArr
[$key]['url']));
1240 // Manipulation in case of access restricted pages:
1241 $this->changeLinksForAccessRestrictedPages($LD,$this->menuArr
[$key],$mainTarget,$typeOverride);
1243 // Overriding URL / Target if set to do so:
1244 if ($this->menuArr
[$key]['_OVERRIDE_HREF']) {
1245 $LD['totalURL'] = $this->menuArr
[$key]['_OVERRIDE_HREF'];
1246 if ($this->menuArr
[$key]['_OVERRIDE_TARGET']) $LD['target'] = $this->menuArr
[$key]['_OVERRIDE_TARGET'];
1249 // OnClick open in windows.
1251 if ($this->mconf
['JSWindow']) {
1252 $conf=$this->mconf
['JSWindow.'];
1253 $url=$LD['totalURL'];
1254 $LD['totalURL'] = '#';
1255 $onClick= 'openPic(\''.$GLOBALS['TSFE']->baseUrlWrap($url).'\',\''.($conf['newWindow']?
md5($url):'theNewPage').'\',\''.$conf['params'].'\'); return false;';
1256 $GLOBALS['TSFE']->setJS('openPic');
1259 // look for type and popup
1260 // following settings are valid in field target:
1261 // 230 will add type=230 to the link
1262 // 230 500x600 will add type=230 to the link and open in popup window with 500x600 pixels
1263 // 230 _blank will add type=230 to the link and open with target "_blank"
1264 // 230x450:resizable=0,location=1 will open in popup window with 500x600 pixels with settings "resizable=0,location=1"
1266 $targetIsType = $LD['target'] && (string) intval($LD['target']) == trim($LD['target']) ?
intval($LD['target']) : FALSE;
1267 if (preg_match('/([0-9]+[\s])?(([0-9]+)x([0-9]+))?(:.+)?/s', $LD['target'], $matches) ||
$targetIsType) {
1269 if(intval($matches[1]) ||
$targetIsType) {
1270 $LD['totalURL'] .= '&type=' . ($targetIsType ?
$targetIsType : intval($matches[1]));
1271 $LD['target'] = $targetIsType ?
'' : trim(substr($LD['target'], strlen($matches[1]) +
1));
1273 // open in popup window?
1274 if ($matches[3] && $matches[4]) {
1275 $JSparamWH = 'width=' . $matches[3] . ',height=' . $matches[4] . ($matches[5] ?
',' . substr($matches[5], 1) : '');
1276 $onClick = 'vHWin=window.open(\'' . $LD['totalURL'] . '\',\'FEopenLink\',\'' . $JSparamWH . '\');vHWin.focus();return false;';
1283 $list['HREF'] = strlen($LD['totalURL']) ?
$LD['totalURL'] : $GLOBALS['TSFE']->baseUrl
; // Added this check: What it does is to enter the baseUrl (if set, which it should for "realurl" based sites) as URL if the calculated value is empty. The problem is that no link is generated with a blank URL and blank URLs might appear when the realurl encoding is used and a link to the frontpage is generated.
1284 $list['TARGET'] = $LD['target'];
1285 $list['onClick'] = $onClick;
1291 * Will change $LD (passed by reference) if the page is access restricted
1293 * @param array $LD, the array from the linkData() function
1294 * @param array Page array
1295 * @param string Main target value
1296 * @param string Type number override if any
1297 * @return void ($LD passed by reference might be changed.)
1299 function changeLinksForAccessRestrictedPages(&$LD, $page, $mainTarget, $typeOverride) {
1301 // If access restricted pages should be shown in menus, change the link of such pages to link to a redirection page:
1302 if ($this->mconf
['showAccessRestrictedPages'] && $this->mconf
['showAccessRestrictedPages']!=='NONE' && !$GLOBALS['TSFE']->checkPageGroupAccess($page)) {
1303 $thePage = $this->sys_page
->getPage($this->mconf
['showAccessRestrictedPages']);
1305 $addParams = $this->mconf
['showAccessRestrictedPages.']['addParams'];
1306 $addParams = str_replace('###RETURN_URL###',rawurlencode($LD['totalURL']),$addParams);
1307 $addParams = str_replace('###PAGE_ID###',$page['uid'],$addParams);
1308 $LD = $this->menuTypoLink($thePage,$mainTarget,'','','', $addParams, $typeOverride);
1313 * Creates a submenu level to the current level - if configured for.
1315 * @param integer Page id of the current page for which a submenu MAY be produced (if conditions are met)
1316 * @param string Object prefix, see ->start()
1317 * @return string HTML content of the submenu
1320 function subMenu($uid, $objSuffix='') {
1322 // Setting alternative menu item array if _SUB_MENU has been defined in the current ->menuArr
1324 if (is_array($this->menuArr
[$this->I
['key']]['_SUB_MENU']) && count($this->menuArr
[$this->I
['key']]['_SUB_MENU'])) {
1325 $altArray = $this->menuArr
[$this->I
['key']]['_SUB_MENU'];
1328 // Make submenu if the page is the next active
1329 $cls = strtolower($this->conf
[($this->menuNumber+
1).$objSuffix]);
1330 $subLevelClass = ($cls && t3lib_div
::inList($this->tmpl
->menuclasses
,$cls)) ?
$cls : '';
1332 // stdWrap for expAll
1333 if (isset($this->mconf
['expAll.'])) {
1334 $this->mconf
['expAll'] = $this->parent_cObj
->stdWrap($this->mconf
['expAll'], $this->mconf
['expAll.']);
1337 if ($subLevelClass && ($this->mconf
['expAll'] ||
$this->isNext($uid, $this->getMPvar($this->I
['key'])) ||
is_array($altArray)) && !$this->mconf
['sectionIndex']) {
1338 $submenu = t3lib_div
::makeInstance('tslib_'.$subLevelClass);
1339 $submenu->entryLevel
= $this->entryLevel+
1;
1340 $submenu->rL_uidRegister
= $this->rL_uidRegister
;
1341 $submenu->MP_array
= $this->MP_array
;
1342 if ($this->menuArr
[$this->I
['key']]['_MP_PARAM']) {
1343 $submenu->MP_array
[] = $this->menuArr
[$this->I
['key']]['_MP_PARAM'];
1346 // especially scripts that build the submenu needs the parent data
1347 $submenu->parent_cObj
= $this->parent_cObj
;
1348 $submenu->parentMenuArr
= $this->menuArr
;
1350 // Setting alternativeMenuTempArray (will be effective only if an array)
1351 if (is_array($altArray)) {
1352 $submenu->alternativeMenuTempArray
= $altArray;
1355 if ($submenu->start($this->tmpl
, $this->sys_page
, $uid, $this->conf
, $this->menuNumber+
1, $objSuffix)) {
1356 $submenu->makeMenu();
1357 return $submenu->writeMenu();
1363 * Returns true if the page with UID $uid is the NEXT page in root line (which means a submenu should be drawn)
1365 * @param integer Page uid to evaluate.
1366 * @param string MPvar for the current position of item.
1367 * @return boolean True if page with $uid is active
1371 function isNext($uid, $MPvar='') {
1373 // Check for always active PIDs:
1374 if (count($this->alwaysActivePIDlist
) && in_array($uid,$this->alwaysActivePIDlist
)) {
1378 $testUid = $uid.($MPvar?
':'.$MPvar:'');
1379 if ($uid && $testUid==$this->nextActive
) {
1385 * Returns true if the page with UID $uid is active (in the current rootline)
1387 * @param integer Page uid to evaluate.
1388 * @param string MPvar for the current position of item.
1389 * @return boolean True if page with $uid is active
1392 function isActive($uid, $MPvar='') {
1394 // Check for always active PIDs:
1395 if (count($this->alwaysActivePIDlist
) && in_array($uid,$this->alwaysActivePIDlist
)) {
1399 $testUid = $uid.($MPvar?
':'.$MPvar:'');
1400 if ($uid && in_array('ITEM:'.$testUid, $this->rL_uidRegister
)) {
1406 * Returns true if the page with UID $uid is the CURRENT page (equals $GLOBALS['TSFE']->id)
1408 * @param integer Page uid to evaluate.
1409 * @param string MPvar for the current position of item.
1410 * @return boolean True if page $uid = $GLOBALS['TSFE']->id
1413 function isCurrent($uid, $MPvar='') {
1414 $testUid = $uid.($MPvar?
':'.$MPvar:'');
1415 if ($uid && !strcmp(end($this->rL_uidRegister
),'ITEM:'.$testUid)) {
1421 * Returns true if there is a submenu with items for the page id, $uid
1422 * Used by the item states "IFSUB", "ACTIFSUB" and "CURIFSUB" to check if there is a submenu
1424 * @param integer Page uid for which to search for a submenu
1425 * @return boolean Returns true if there was a submenu with items found
1428 function isSubMenu($uid) {
1430 // Looking for a mount-pid for this UID since if that exists we should look for a subpages THERE and not in the input $uid;
1431 $mount_info = $this->sys_page
->getMountPointInfo($uid);
1432 if (is_array($mount_info)) {
1433 $uid = $mount_info['mount_pid'];
1436 $recs = $this->sys_page
->getMenu($uid,'uid,pid,doktype,mount_pid,mount_pid_ol,nav_hide,shortcut,shortcut_mode');
1437 foreach($recs as $theRec) {
1438 if (!t3lib_div
::inList($this->doktypeExcludeList
,$theRec['doktype']) && (!$theRec['nav_hide'] ||
$this->conf
['includeNotInMenu'])) { // If a menu item seems to be another type than 'Not in menu', then return true (there were items!)
1445 * Used by procesItemStates() to evaluate if a menu item (identified by $key) is in a certain state.
1447 * @param string The item state to evaluate (SPC, IFSUB, ACT etc... but no xxxRO states of course)
1448 * @param integer Key pointing to menu item from ->menuArr
1449 * @return boolean True (integer!=0) if match, otherwise false (=0, zero)
1451 * @see procesItemStates()
1453 function isItemState($kind,$key) {
1455 if ($this->menuArr
[$key]['ITEM_STATE']) { // If any value is set for ITEM_STATE the normal evaluation is discarded
1456 if (!strcmp($this->menuArr
[$key]['ITEM_STATE'],$kind)) {$natVal=1;}
1460 $natVal = $this->menuArr
[$key]['isSpacer'];
1463 $natVal = $this->isSubMenu($this->menuArr
[$key]['uid']);
1466 $natVal = $this->isActive($this->menuArr
[$key]['uid'], $this->getMPvar($key));
1469 $natVal = $this->isActive($this->menuArr
[$key]['uid'], $this->getMPvar($key)) && $this->isSubMenu($this->menuArr
[$key]['uid']);
1472 $natVal = $this->isCurrent($this->menuArr
[$key]['uid'], $this->getMPvar($key));
1475 $natVal = $this->isCurrent($this->menuArr
[$key]['uid'], $this->getMPvar($key)) && $this->isSubMenu($this->menuArr
[$key]['uid']);
1478 $natVal = $this->menuArr
[$key]['fe_group'];
1487 * Creates an access-key for a TMENU/GMENU menu item based on the menu item titles first letter
1489 * @param string Menu item title.
1490 * @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
1493 function accessKey($title) {
1494 // The global array ACCESSKEY is used to globally control if letters are already used!!
1497 $title = trim(strip_tags($title));
1498 $titleLen = strlen($title);
1499 for ($a=0;$a<$titleLen;$a++
) {
1500 $key = strtoupper(substr($title,$a,1));
1501 if (preg_match('/[A-Z]/', $key) && !isset($GLOBALS['TSFE']->accessKey
[$key])) {
1502 $GLOBALS['TSFE']->accessKey
[$key] = 1;
1503 $result['code'] = ' accesskey="'.$key.'"';
1504 $result['alt'] = ' (ALT+'.$key.')';
1505 $result['key'] = $key;
1513 * Calls a user function for processing of internal data.
1514 * Used for the properties "IProcFunc" and "itemArrayProcFunc"
1516 * @param string Key pointing for the property in the current ->mconf array holding possibly parameters to pass along to the function/method. Currently the keys used are "IProcFunc" and "itemArrayProcFunc".
1517 * @param mixed A variable to pass to the user function and which should be returned again from the user function. The idea is that the user function modifies this variable according to what you want to achieve and then returns it. For "itemArrayProcFunc" this variable is $this->menuArr, for "IProcFunc" it is $this->I
1518 * @return mixed The processed $passVar
1521 function userProcess($mConfKey,$passVar) {
1522 if ($this->mconf
[$mConfKey]) {
1523 $funcConf = $this->mconf
[$mConfKey.'.'];
1524 $funcConf['parentObj'] = $this;
1525 $passVar = $GLOBALS['TSFE']->cObj
->callUserFunction($this->mconf
[$mConfKey], $funcConf, $passVar);
1531 * 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'])
1536 function setATagParts() {
1537 $this->I
['A1'] = '<a '.t3lib_div
::implodeAttributes($this->I
['linkHREF'],1).' '.$this->I
['val']['ATagParams'].$this->I
['accessKey']['code'].'>';
1538 $this->I
['A2'] = '</a>';
1542 * Returns the title for the navigation
1544 * @param string The current page title
1545 * @param string The current value of the navigation title
1546 * @return string Returns the navigation title if it is NOT blank, otherwise the page title.
1549 function getPageTitle($title,$nav_title) {
1550 return strcmp(trim($nav_title),'') ?
$nav_title : $title;
1554 * Return MPvar string for entry $key in ->menuArr
1556 * @param integer Pointer to element in ->menuArr
1557 * @param string Implode token.
1558 * @return string MP vars for element.
1561 function getMPvar($key) {
1562 if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1563 $localMP_array = $this->MP_array
;
1564 if ($this->menuArr
[$key]['_MP_PARAM']) $localMP_array[] = $this->menuArr
[$key]['_MP_PARAM']; // NOTICE: "_MP_PARAM" is allowed to be a commalist of PID pairs!
1565 $MP_params = count($localMP_array) ?
implode(',',$localMP_array) : '';
1571 * Returns where clause part to exclude 'not in menu' pages
1573 * @return string where clause part.
1576 function getDoktypeExcludeWhere() {
1577 return $this->doktypeExcludeList ?
' AND pages.doktype NOT IN ('.$this->doktypeExcludeList
.')' : '';
1581 * Returns an array of banned UIDs (from excludeUidList)
1583 * @return array Array of banned UIDs
1586 function getBannedUids() {
1587 $banUidArray = array();
1589 if (trim($this->conf
['excludeUidList'])) {
1590 $banUidList = str_replace('current', $GLOBALS['TSFE']->page
['uid'], $this->conf
['excludeUidList']);
1591 $banUidArray = t3lib_div
::intExplode(',', $banUidList);
1594 return $banUidArray;
1598 * Calls typolink to create menu item links.
1600 * @param array $page Page record (uid points where to link to)
1601 * @param string $oTarget Target frame/window
1602 * @param boolean $no_cache true if caching should be disabled
1603 * @param string $script Alternative script name
1604 * @param array $overrideArray Array to override values in $page
1605 * @param string $addParams Parameters to add to URL
1606 * @param array $typeOverride "type" value
1607 * @return array See linkData
1609 function menuTypoLink($page, $oTarget, $no_cache, $script, $overrideArray = '', $addParams = '', $typeOverride = '') {
1611 'parameter' => is_array($overrideArray) && $overrideArray['uid'] ?
$overrideArray['uid'] : $page['uid'],
1613 if ($typeOverride && t3lib_div
::testInt($typeOverride)) {
1614 $conf['parameter'] .= ',' . $typeOverride;
1617 $conf['additionalParams'] = $addParams;
1620 $conf['no_cache'] = true;
1623 $conf['target'] = $oTarget;
1625 if ($page['sectionIndex_uid']) {
1626 $conf['section'] = $page['sectionIndex_uid'];
1629 $this->parent_cObj
->typoLink('|', $conf);
1630 $LD = $this->parent_cObj
->lastTypoLinkLD
;
1631 $LD['totalURL'] = $this->parent_cObj
->lastTypoLinkUrl
;
1656 * Extension class creating text based menus
1658 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
1661 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=387&cHash=73a3116ab8
1663 class tslib_tmenu
extends tslib_menu
{
1666 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
1667 * Sets the result for the new "normal state" in $this->result
1670 * @see tslib_menu::procesItemStates()
1672 function generate() {
1673 $splitCount = count($this->menuArr
);
1675 list($NOconf) = $this->procesItemStates($splitCount);
1677 if ($this->mconf
['debugItemConf']) {echo '<h3>$NOconf:</h3>'; debug($NOconf); }
1678 $this->result
= $NOconf;
1682 * Traverses the ->result array of menu items configuration (made by ->generate()) and renders each item.
1683 * 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
1684 * 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.
1686 * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
1688 function writeMenu() {
1689 if (is_array($this->result
) && count($this->result
)) {
1690 $this->WMcObj
= t3lib_div
::makeInstance('tslib_cObj'); // Create new tslib_cObj for our use
1691 $this->WMresult
= '';
1692 $this->INPfixMD5
= substr(md5(microtime().'tmenu'),0,4);
1693 $this->WMmenuItems
= count($this->result
);
1695 $this->WMsubmenuObjSuffixes
= $this->tmpl
->splitConfArray(array('sOSuffix'=>$this->mconf
['submenuObjSuffixes']),$this->WMmenuItems
);
1697 $this->extProc_init();
1698 foreach ($this->result
as $key => $val) {
1699 $GLOBALS['TSFE']->register
['count_HMENU_MENUOBJ']++
;
1700 $GLOBALS['TSFE']->register
['count_MENUOBJ']++
;
1702 $this->WMcObj
->start($this->menuArr
[$key],'pages'); // Initialize the cObj with the page record of the menu item
1705 $this->I
['key'] = $key;
1706 $this->I
['INPfix'] = ($this->imgNameNotRandom ?
'' : '_'.$this->INPfixMD5
).'_'.$key;
1707 $this->I
['val'] = $val;
1708 $this->I
['title'] = $this->WMcObj
->stdWrap($this->getPageTitle($this->menuArr
[$key]['title'],$this->menuArr
[$key]['nav_title']),$this->I
['val']['stdWrap.']);
1709 $this->I
['uid'] = $this->menuArr
[$key]['uid'];
1710 $this->I
['mount_pid'] = $this->menuArr
[$key]['mount_pid'];
1711 $this->I
['pid'] = $this->menuArr
[$key]['pid'];
1712 $this->I
['spacer'] = $this->menuArr
[$key]['isSpacer'];
1715 if ($this->mconf
['accessKey']) {
1716 $this->I
['accessKey'] = $this->accessKey($this->I
['title']);
1718 $this->I
['accessKey'] = Array();
1722 $this->I
['val']['ATagParams'] = $this->WMcObj
->getATagParams($this->I
['val']);
1723 $this->I
['val']['additionalParams'] = $this->WMcObj
->stdWrap($this->I
['val']['additionalParams'],$this->I
['val']['additionalParams.']);
1724 $this->I
['linkHREF'] = $this->link($key,$this->I
['val']['altTarget'],$this->mconf
['forceTypeValue']);
1726 // Title attribute of links:
1727 $titleAttrValue = $this->WMcObj
->stdWrap($this->I
['val']['ATagTitle'],$this->I
['val']['ATagTitle.']).$this->I
['accessKey']['alt'];
1728 if (strlen($titleAttrValue)) {
1729 $this->I
['linkHREF']['title'] = $titleAttrValue;
1732 // Setting "blurlink()" function:
1733 if (!$this->mconf
['noBlur']) {
1734 $this->I
['linkHREF']['onFocus']='blurLink(this);';
1738 if ($this->I
['val']['RO']) {
1739 $this->I
['theName'] = $this->imgNamePrefix
.$this->I
['uid'].$this->I
['INPfix'];
1742 if ($this->I
['val']['beforeROImg']) {
1743 $over.= $this->WMfreezePrefix
."over('".$this->I
['theName']."before');";
1744 $out.= $this->WMfreezePrefix
."out('".$this->I
['theName']."before');";
1746 if ($this->I
['val']['afterROImg']) {
1747 $over.= $this->WMfreezePrefix
."over('".$this->I
['theName']."after');";
1748 $out.= $this->WMfreezePrefix
."out('".$this->I
['theName']."after');";
1750 $this->I
['linkHREF']['onMouseover']=$over;
1751 $this->I
['linkHREF']['onMouseout']=$out;
1752 if ($over ||
$out) $GLOBALS['TSFE']->setJS('mouseOver');
1754 // Change background color:
1755 if ($this->I
['val']['RO_chBgColor']) {
1756 $this->addJScolorShiftFunction();
1757 $chBgP = t3lib_div
::trimExplode('|',$this->I
['val']['RO_chBgColor']);
1758 $this->I
['linkHREF']['onMouseover'].="changeBGcolor('".$chBgP[2].$this->I
['uid']."','".$chBgP[0]."');";
1759 $this->I
['linkHREF']['onMouseout'].="changeBGcolor('".$chBgP[2].$this->I
['uid']."','".$chBgP[1]."');";
1762 $this->extProc_RO($key);
1766 // Calling extra processing function
1767 $this->extProc_beforeLinking($key);
1769 // stdWrap for doNotLinkIt
1770 if (isset($this->I
['val']['doNotLinkIt.'])) {
1771 $this->I
['val']['doNotLinkIt'] = $this->WMcObj
->stdWrap($this->I
['val']['doNotLinkIt'], $this->I
['val']['doNotLinkIt.']);
1775 if (!$this->I
['val']['doNotLinkIt']) {$this->I
['val']['doNotLinkIt']=0;}
1776 if (!$this->I
['spacer'] && $this->I
['val']['doNotLinkIt']!=1) {
1777 $this->setATagParts();
1779 $this->I
['A1'] = '';
1780 $this->I
['A2'] = '';
1783 // ATagBeforeWrap processing:
1784 if ($this->I
['val']['ATagBeforeWrap']) {
1785 $wrapPartsBefore = explode('|',$this->I
['val']['linkWrap']);
1786 $wrapPartsAfter = array('','');
1788 $wrapPartsBefore = array('','');
1789 $wrapPartsAfter = explode('|',$this->I
['val']['linkWrap']);
1791 if ($this->I
['val']['stdWrap2'] ||
isset($this->I
['val']['stdWrap2.'])) {
1792 $wrapPartsStdWrap = explode($this->I
['val']['stdWrap2']?
$this->I
['val']['stdWrap2']:'|',$this->WMcObj
->stdWrap('|',$this->I
['val']['stdWrap2.']));
1793 } else {$wrapPartsStdWrap = array('','');}
1795 // Make before, middle and after parts
1796 $this->I
['parts'] = array();
1797 $this->I
['parts']['before']=$this->getBeforeAfter('before');
1798 $this->I
['parts']['stdWrap2_begin']=$wrapPartsStdWrap[0];
1800 // stdWrap for doNotShowLink
1801 if (isset($this->I
['val']['doNotShowLink.'])) {
1802 $this->I
['val']['doNotShowLink'] = $this->WMcObj
->stdWrap($this->I
['val']['doNotShowLink'], $this->I
['val']['doNotShowLink.']);
1805 if (!$this->I
['val']['doNotShowLink']) {
1806 $this->I
['parts']['notATagBeforeWrap_begin'] = $wrapPartsAfter[0];
1807 $this->I
['parts']['ATag_begin'] = $this->I
['A1'];
1808 $this->I
['parts']['ATagBeforeWrap_begin'] = $wrapPartsBefore[0];
1809 $this->I
['parts']['title'] = $this->I
['title'];
1810 $this->I
['parts']['ATagBeforeWrap_end'] = $wrapPartsBefore[1];
1811 $this->I
['parts']['ATag_end'] = $this->I
['A2'];
1812 $this->I
['parts']['notATagBeforeWrap_end'] = $wrapPartsAfter[1];
1814 $this->I
['parts']['stdWrap2_end']=$wrapPartsStdWrap[1];
1815 $this->I
['parts']['after']=$this->getBeforeAfter('after');
1817 // Passing I to a user function
1818 if ($this->mconf
['IProcFunc']) {
1819 $this->I
= $this->userProcess('IProcFunc',$this->I
);
1822 // Merge parts + beforeAllWrap
1823 $this->I
['theItem']= implode('',$this->I
['parts']);
1824 $this->I
['theItem']= $this->extProc_beforeAllWrap($this->I
['theItem'],$key);
1827 $allWrap = $this->WMcObj
->stdWrap($this->I
['val']['allWrap'],$this->I
['val']['allWrap.']);
1828 $this->I
['theItem'] = $this->tmpl
->wrap($this->I
['theItem'],$allWrap);
1830 if ($this->I
['val']['subst_elementUid']) $this->I
['theItem'] = str_replace('{elementUid}',$this->I
['uid'],$this->I
['theItem']);
1833 if (is_array($this->I
['val']['allStdWrap.'])) {
1834 $this->I
['theItem'] = $this->WMcObj
->stdWrap($this->I
['theItem'],$this->I
['val']['allStdWrap.']);
1837 // Calling extra processing function
1838 $this->extProc_afterLinking($key);
1840 return $this->extProc_finish();
1845 * Generates the before* and after* images for TMENUs
1847 * @param string Can be "before" or "after" and determines which kind of image to create (basically this is the prefix of the TypoScript properties that are read from the ->I['val'] array
1848 * @return string The resulting HTML of the image, if any.
1849 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=388&cHash=a7486044cd
1851 function getBeforeAfter($pref) {
1853 if ($imgInfo = $this->WMcObj
->getImgResource($this->I
['val'][$pref.'Img'],$this->I
['val'][$pref.'Img.'])) {
1854 $imgInfo[3] = t3lib_div
::png_to_gif_by_imagemagick($imgInfo[3]);
1855 if ($this->I
['val']['RO'] && $this->I
['val'][$pref.'ROImg'] && !$this->I
['spacer']) {
1856 $imgROInfo = $this->WMcObj
->getImgResource($this->I
['val'][$pref.'ROImg'],$this->I
['val'][$pref.'ROImg.']);
1857 $imgROInfo[3] = t3lib_div
::png_to_gif_by_imagemagick($imgROInfo[3]);
1859 $theName = $this->imgNamePrefix
.$this->I
['uid'].$this->I
['INPfix'].$pref;
1860 $name = ' '.$this->nameAttribute
.'="'.$theName.'"';
1861 $GLOBALS['TSFE']->JSImgCode
.= chr(10).$theName.'_n=new Image(); '.$theName.'_n.src = "'.$GLOBALS['TSFE']->absRefPrefix
.$imgInfo[3].'"; ';
1862 $GLOBALS['TSFE']->JSImgCode
.= chr(10).$theName.'_h=new Image(); '.$theName.'_h.src = "'.$GLOBALS['TSFE']->absRefPrefix
.$imgROInfo[3].'"; ';
1865 $GLOBALS['TSFE']->imagesOnPage
[]=$imgInfo[3];
1867 ' src="' . $GLOBALS['TSFE']->absRefPrefix
. $imgInfo[3] . '"' .
1868 ' width="' . $imgInfo[0] . '"' .
1869 ' height="' . $imgInfo[1] . '"' .
1871 ($this->I
['val'][$pref.'ImgTagParams'] ?
' ' . $this->I
['val'][$pref.'ImgTagParams'] : '') .
1872 tslib_cObj
::getBorderAttr(' border="0"');
1873 if (!strstr($res,'alt="')) {
1874 $res .= ' alt=""'; // Adding alt attribute if not set.
1877 if ($this->I
['val'][$pref.'ImgLink']) {
1878 $res=$this->I
['A1'].$res.$this->I
['A2'];
1881 return $this->tmpl
->wrap($res.$this->WMcObj
->stdWrap($this->I
['val'][$pref],$this->I
['val'][$pref.'.']), $this->I
['val'][$pref.'Wrap']);
1885 * Adds a JavaScript function to the $GLOBALS['TSFE']->additionalJavaScript array
1891 function addJScolorShiftFunction() {
1892 $GLOBALS['TSFE']->additionalJavaScript
['TMENU:changeBGcolor()']='
1893 function changeBGcolor(id,color) { //
1894 if (document.getElementById && document.getElementById(id)) {
1895 document.getElementById(id).style.background = color;
1897 } else if (document.layers && document.layers[id]) {
1898 document.layers[id].bgColor = color;
1906 * Called right before the traversing of $this->result begins.
1907 * Can be used for various initialization
1911 * @see writeMenu(), tslib_tmenu_layers::extProc_init()
1913 function extProc_init() {
1917 * Called after all processing for RollOver of an element has been done.
1919 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
1922 * @see writeMenu(), tslib_tmenu_layers::extProc_RO()
1924 function extProc_RO($key) {
1928 * Called right before the creation of the link for the menu item
1930 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
1933 * @see writeMenu(), tslib_tmenu_layers::extProc_beforeLinking()
1935 function extProc_beforeLinking($key) {
1939 * 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.
1940 * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
1942 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
1945 * @see writeMenu(), tslib_tmenu_layers::extProc_afterLinking()
1947 function extProc_afterLinking($key) {
1948 // Add part to the accumulated result + fetch submenus
1949 if (!$this->I
['spacer']) {
1950 $this->I
['theItem'].= $this->subMenu($this->I
['uid'], $this->WMsubmenuObjSuffixes
[$key]['sOSuffix']);
1952 $part = $this->WMcObj
->stdWrap($this->I
['val']['wrapItemAndSub'],$this->I
['val']['wrapItemAndSub.']);
1953 $this->WMresult
.= $part ?
$this->tmpl
->wrap($this->I
['theItem'],$part) : $this->I
['theItem'];
1957 * Called before the "allWrap" happens on the menu item.
1959 * @param string The current content of the menu item, $this->I['theItem'], passed along.
1960 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
1961 * @return string The modified version of $item, going back into $this->I['theItem']
1963 * @see writeMenu(), tslib_tmenu_layers::extProc_beforeAllWrap()
1965 function extProc_beforeAllWrap($item,$key) {
1970 * Called before the writeMenu() function returns (only if a menu was generated)
1972 * @return string The total menu content should be returned by this function
1974 * @see writeMenu(), tslib_tmenu_layers::extProc_finish()
1976 function extProc_finish() {
1978 if (is_array($this->mconf
['stdWrap.'])) {
1979 $this->WMresult
= $this->WMcObj
->stdWrap($this->WMresult
,$this->mconf
['stdWrap.']);
1981 return $this->tmpl
->wrap($this->WMresult
,$this->mconf
['wrap']).$this->WMextraScript
;
2009 * Extension class creating graphic based menus (PNG or GIF files)
2011 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
2014 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=384&cHash=93a7644cba
2016 class tslib_gmenu
extends tslib_menu
{
2019 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
2020 * Calls makeGifs() for all "normal" items and if configured for, also the "rollover" items.
2023 * @see tslib_menu::procesItemStates(), makeGifs()
2025 function generate() {
2026 $splitCount = count($this->menuArr
);
2028 list($NOconf,$ROconf) = $this->procesItemStates($splitCount);
2030 //store initial count value
2031 $temp_HMENU_MENUOBJ = $GLOBALS['TSFE']->register
['count_HMENU_MENUOBJ'];
2032 $temp_MENUOBJ = $GLOBALS['TSFE']->register
['count_MENUOBJ'];
2033 // Now we generate the giffiles:
2034 $this->makeGifs($NOconf,'NO');
2035 // store count from NO obj
2036 $tempcnt_HMENU_MENUOBJ = $GLOBALS['TSFE']->register
['count_HMENU_MENUOBJ'];
2037 $tempcnt_MENUOBJ = $GLOBALS['TSFE']->register
['count_MENUOBJ'];
2039 if ($this->mconf
['debugItemConf']) {echo '<h3>$NOconf:</h3>'; debug($NOconf); }
2040 if ($ROconf) { // RollOver
2041 //start recount for rollover with initial values
2042 $GLOBALS['TSFE']->register
['count_HMENU_MENUOBJ']= $temp_HMENU_MENUOBJ;
2043 $GLOBALS['TSFE']->register
['count_MENUOBJ']= $temp_MENUOBJ;
2044 $this->makeGifs($ROconf,'RO');
2045 if ($this->mconf
['debugItemConf']) {echo '<h3>$ROconf:</h3>'; debug($ROconf); }
2047 // use count from NO obj
2048 $GLOBALS['TSFE']->register
['count_HMENU_MENUOBJ'] = $tempcnt_HMENU_MENUOBJ;
2049 $GLOBALS['TSFE']->register
['count_MENUOBJ'] = $tempcnt_MENUOBJ;
2054 * Will traverse input array with configuratoin per-item and create corresponding GIF files for the menu.
2055 * The data of the files are stored in $this->result
2057 * @param array Array with configuration for each item.
2058 * @param string Type of images: normal ("NO") or rollover ("RO"). Valid values are "NO" and "RO"
2063 function makeGifs($conf, $resKey) {
2064 $isGD = $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'];
2066 if (!is_array($conf)) {
2071 $items = count($conf);
2073 // generate the gif-files. the $menuArr is filled with some values like output_w, output_h, output_file
2076 $Hobjs = $this->mconf
['applyTotalH'];
2077 if ($Hobjs) {$Hobjs = t3lib_div
::intExplode(',',$Hobjs);}
2078 $Wobjs = $this->mconf
['applyTotalW'];
2079 if ($Wobjs) {$Wobjs = t3lib_div
::intExplode(',',$Wobjs);}
2080 $minDim = $this->mconf
['min'];
2081 if ($minDim) {$minDim = tslib_cObj
::calcIntExplode(',',$minDim.',');}
2082 $maxDim = $this->mconf
['max'];
2083 if ($maxDim) {$maxDim = tslib_cObj
::calcIntExplode(',',$maxDim.',');}
2086 $conf[$items]=$conf[$items-1];
2087 $this->menuArr
[$items]=Array();
2088 $items = count($conf);
2092 if ($this->mconf
['useLargestItemX'] ||
$this->mconf
['useLargestItemY'] ||
$this->mconf
['distributeX'] ||
$this->mconf
['distributeY']) {
2093 $totalWH = $this->findLargestDims($conf,$items,$Hobjs,$Wobjs,$minDim,$maxDim);
2099 $distributeAccu=array('H'=>0,'W'=>0);
2100 foreach ($conf as $key => $val) {
2101 $GLOBALS['TSFE']->register
['count_HMENU_MENUOBJ']++
;
2102 $GLOBALS['TSFE']->register
['count_MENUOBJ']++
;
2104 if ($items==($c+
1) && $minDim) {
2105 $Lobjs = $this->mconf
['removeObjectsOfDummy'];
2107 $Lobjs = t3lib_div
::intExplode(',',$Lobjs);
2108 foreach ($Lobjs as $remItem) {
2109 unset($val[$remItem]);
2110 unset($val[$remItem.'.']);
2115 $tempXY = explode(',',$val['XY']);
2116 if ($Wcounter<$minDim[0]) {$tempXY[0]=$minDim[0]-$Wcounter; $flag=1;}
2117 if ($Hcounter<$minDim[1]) {$tempXY[1]=$minDim[1]-$Hcounter; $flag=1;}
2118 $val['XY'] = implode(',',$tempXY);
2125 // Pre-working the item
2126 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2127 $gifCreator->init();
2128 $gifCreator->start($val,$this->menuArr
[$key]);
2130 // If useLargestItemH/W is specified
2131 if (count($totalWH) && ($this->mconf
['useLargestItemX'] ||
$this->mconf
['useLargestItemY'])) {
2132 $tempXY = explode(',',$gifCreator->setup
['XY']);
2133 if ($this->mconf
['useLargestItemX']) {$tempXY[0] = max($totalWH['W']);}
2134 if ($this->mconf
['useLargestItemY']) {$tempXY[1] = max($totalWH['H']);}
2135 // regenerate the new values...
2136 $val['XY'] = implode(',',$tempXY);
2137 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2138 $gifCreator->init();
2139 $gifCreator->start($val,$this->menuArr
[$key]);
2142 // If distributeH/W is specified
2143 if (count($totalWH) && ($this->mconf
['distributeX'] ||
$this->mconf
['distributeY'])) {
2144 $tempXY = explode(',',$gifCreator->setup
['XY']);
2146 if ($this->mconf
['distributeX']) {
2147 $diff = $this->mconf
['distributeX']-$totalWH['W_total']-$distributeAccu['W'];
2148 $compensate = round($diff /($items-$c+
1));
2149 $distributeAccu['W']+
=$compensate;
2150 $tempXY[0] = $totalWH['W'][$key]+
$compensate;
2152 if ($this->mconf
['distributeY']) {
2153 $diff = $this->mconf
['distributeY']-$totalWH['H_total']-$distributeAccu['H'];
2154 $compensate = round($diff /($items-$c+
1));
2155 $distributeAccu['H']+
=$compensate;
2156 $tempXY[1] = $totalWH['H'][$key]+
$compensate;
2158 // regenerate the new values...
2159 $val['XY'] = implode(',',$tempXY);
2160 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2161 $gifCreator->init();
2162 $gifCreator->start($val,$this->menuArr
[$key]);
2165 // If max dimensions are specified
2167 $tempXY = explode(',',$val['XY']);
2168 if ($maxDim[0] && $Wcounter+
$gifCreator->XY
[0]>=$maxDim[0]) {$tempXY[0]==$maxDim[0]-$Wcounter; $maxFlag=1;}
2169 if ($maxDim[1] && $Hcounter+
$gifCreator->XY
[1]>=$maxDim[1]) {$tempXY[1]=$maxDim[1]-$Hcounter; $maxFlag=1;}
2171 $val['XY'] = implode(',',$tempXY);
2172 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2173 $gifCreator->init();
2174 $gifCreator->start($val,$this->menuArr
[$key]);
2183 foreach ($Hobjs as $index) {
2184 if ($gifCreator->setup
[$index] && $gifCreator->setup
[$index.'.']) {
2185 $oldOffset = explode(',',$gifCreator->setup
[$index.'.']['offset']);
2186 $gifCreator->setup
[$index.'.']['offset'] = implode(',',$gifCreator->applyOffset($oldOffset,Array(0,-$Hcounter)));
2192 foreach ($Wobjs as $index) {
2193 if ($gifCreator->setup
[$index] && $gifCreator->setup
[$index.'.']) {
2194 $oldOffset = explode(',',$gifCreator->setup
[$index.'.']['offset']);
2195 $gifCreator->setup
[$index.'.']['offset'] = implode(',',$gifCreator->applyOffset($oldOffset,Array(-$Wcounter,0)));
2201 // Finding alternative GIF names if any (by altImgResource)
2203 if ($conf[$key]['altImgResource'] ||
is_array($conf[$key]['altImgResource.'])) {
2204 if (!is_object($cObj)) {$cObj=t3lib_div
::makeInstance('tslib_cObj');}
2205 $cObj->start($this->menuArr
[$key],'pages');
2206 $altImgInfo = $cObj->getImgResource($conf[$key]['altImgResource'],$conf[$key]['altImgResource.']);
2207 $gifFileName=$altImgInfo[3];
2210 // If an alternative name was NOT given, find the GIFBUILDER name.
2211 if (!$gifFileName && $isGD) {
2212 $gifCreator->createTempSubDir('menu/');
2213 $gifFileName = $gifCreator->fileName('menu/');
2216 $this->result
[$resKey][$key] = $conf[$key];
2218 // Generation of image file:
2219 if (file_exists($gifFileName)) { // File exists
2220 $info = @getimagesize
($gifFileName);
2221 $this->result
[$resKey][$key]['output_w']=intval($info[0]);
2222 $this->result
[$resKey][$key]['output_h']=intval($info[1]);
2223 $this->result
[$resKey][$key]['output_file'] = $gifFileName;
2224 } elseif ($isGD) { // file is generated
2225 $gifCreator->make();
2226 $this->result
[$resKey][$key]['output_w']=$gifCreator->w
;
2227 $this->result
[$resKey][$key]['output_h']=$gifCreator->h
;
2228 $this->result
[$resKey][$key]['output_file'] = $gifFileName;
2229 $gifCreator->output($this->result
[$resKey][$key]['output_file']);
2230 $gifCreator->destroy();
2233 $this->result
[$resKey][$key]['output_file'] = t3lib_div
::png_to_gif_by_imagemagick($this->result
[$resKey][$key]['output_file']);
2235 $Hcounter+
=$this->result
[$resKey][$key]['output_h']; // counter is increased
2236 $Wcounter+
=$this->result
[$resKey][$key]['output_w']; // counter is increased
2238 if ($maxFlag) break;
2243 * Function searching for the largest width and height of the menu items to be generated.
2244 * 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.
2245 * Remember to upgrade the code in here if the makeGifs function is updated.
2247 * @param array Same configuration array as passed to makeGifs()
2248 * @param integer The number of menu items
2249 * @param array Array with "applyTotalH" numbers
2250 * @param array Array with "applyTotalW" numbers
2251 * @param array Array with "min" x/y
2252 * @param array Array with "max" x/y
2253 * @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.
2257 function findLargestDims($conf,$items,$Hobjs,$Wobjs,$minDim,$maxDim) {
2269 foreach ($conf as $key => $val) {
2270 // SAME CODE AS makeGifs()! BEGIN
2271 if ($items==($c+
1) && $minDim) {
2272 $Lobjs = $this->mconf
['removeObjectsOfDummy'];
2274 $Lobjs = t3lib_div
::intExplode(',',$Lobjs);
2275 foreach ($Lobjs as $remItem) {
2276 unset($val[$remItem]);
2277 unset($val[$remItem.'.']);
2282 $tempXY = explode(',',$val['XY']);
2283 if ($Wcounter<$minDim[0]) {$tempXY[0]=$minDim[0]-$Wcounter; $flag=1;}
2284 if ($Hcounter<$minDim[1]) {$tempXY[1]=$minDim[1]-$Hcounter; $flag=1;}
2285 $val['XY'] = implode(',',$tempXY);
2290 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2291 $gifCreator->init();
2292 $gifCreator->start($val,$this->menuArr
[$key]);
2294 $tempXY = explode(',',$val['XY']);
2295 if ($maxDim[0] && $Wcounter+
$gifCreator->XY
[0]>=$maxDim[0]) {$tempXY[0]==$maxDim[0]-$Wcounter; $maxFlag=1;}
2296 if ($maxDim[1] && $Hcounter+
$gifCreator->XY
[1]>=$maxDim[1]) {$tempXY[1]=$maxDim[1]-$Hcounter; $maxFlag=1;}
2298 $val['XY'] = implode(',',$tempXY);
2299 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2300 $gifCreator->init();
2301 $gifCreator->start($val,$this->menuArr
[$key]);
2304 // SAME CODE AS makeGifs()! END
2306 // Setting the width/height
2307 $totalWH['W'][$key]=$gifCreator->XY
[0];
2308 $totalWH['H'][$key]=$gifCreator->XY
[1];
2309 $totalWH['W_total']+
=$gifCreator->XY
[0];
2310 $totalWH['H_total']+
=$gifCreator->XY
[1];
2313 $Hcounter+
=$gifCreator->XY
[1]; // counter is increased
2314 $Wcounter+
=$gifCreator->XY
[0]; // counter is increased
2316 if ($maxFlag){break;}
2322 * 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())
2323 * 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
2325 * @return string The HTML for the menu (returns result through $this->extProc_finish(); )
2327 function writeMenu() {
2328 if (is_array($this->menuArr
) && is_array($this->result
) && count($this->result
) && is_array($this->result
['NO'])) {
2329 $this->WMcObj
= t3lib_div
::makeInstance('tslib_cObj'); // Create new tslib_cObj for our use
2330 $this->WMresult
= '';
2331 $this->INPfixMD5
= substr(md5(microtime().$this->GMENU_fixKey
),0,4);
2332 $this->WMmenuItems
= count($this->result
['NO']);
2334 $this->WMsubmenuObjSuffixes
= $this->tmpl
->splitConfArray(array('sOSuffix'=>$this->mconf
['submenuObjSuffixes']),$this->WMmenuItems
);
2336 $this->extProc_init();
2337 for ($key=0;$key<$this->WMmenuItems
;$key++
) {
2338 if ($this->result
['NO'][$key]['output_file']) {
2339 $this->WMcObj
->start($this->menuArr
[$key],'pages'); // Initialize the cObj with the page record of the menu item
2342 $this->I
['key'] = $key;
2343 $this->I
['INPfix']= ($this->imgNameNotRandom ?
'' : '_'.$this->INPfixMD5
).'_'.$key;
2344 $this->I
['val'] = $this->result
['NO'][$key];
2345 $this->I
['title'] = $this->getPageTitle($this->menuArr
[$key]['title'],$this->menuArr
[$key]['nav_title']);
2346 $this->I
['uid'] = $this->menuArr
[$key]['uid'];
2347 $this->I
['mount_pid'] = $this->menuArr
[$key]['mount_pid'];
2348 $this->I
['pid'] = $this->menuArr
[$key]['pid'];
2349 $this->I
['spacer'] = $this->menuArr
[$key]['isSpacer'];
2350 if (!$this->I
['uid'] && !$this->menuArr
[$key]['_OVERRIDE_HREF']) {$this->I
['spacer']=1;}
2351 $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
2352 $this->I
['name'] = '';
2355 if ($this->mconf
['accessKey']) {
2356 $this->I
['accessKey'] = $this->accessKey($this->I
['title']);
2358 $this->I
['accessKey'] = array();
2362 $this->I
['val']['ATagParams'] = $this->WMcObj
->getATagParams($this->I
['val']);
2363 $this->I
['val']['additionalParams'] = $this->WMcObj
->stdWrap($this->I
['val']['additionalParams'],$this->I
['val']['additionalParams.']);
2364 $this->I
['linkHREF'] = $this->link($key,$this->I
['val']['altTarget'],$this->mconf
['forceTypeValue']);
2366 // Title attribute of links:
2367 $titleAttrValue = $this->WMcObj
->stdWrap($this->I
['val']['ATagTitle'],$this->I
['val']['ATagTitle.']).$this->I
['accessKey']['alt'];
2368 if (strlen($titleAttrValue)) {
2369 $this->I
['linkHREF']['title'] = $titleAttrValue;
2371 // Setting "blurlink()" function:
2372 if (!$this->mconf
['noBlur']) {
2373 $this->I
['linkHREF']['onFocus']='blurLink(this);';
2377 if ($this->result
['RO'][$key] && !$this->I
['noLink']) {
2378 $this->I
['theName'] = $this->imgNamePrefix
.$this->I
['uid'].$this->I
['INPfix'];
2379 $this->I
['name'] = ' '.$this->nameAttribute
.'="'.$this->I
["theName"].'"';
2380 $this->I
['linkHREF']['onMouseover']=$this->WMfreezePrefix
.'over(\''.$this->I
['theName'].'\');';
2381 $this->I
['linkHREF']['onMouseout']=$this->WMfreezePrefix
.'out(\''.$this->I
['theName'].'\');';
2382 $GLOBALS['TSFE']->JSImgCode
.= chr(10).$this->I
['theName'].'_n=new Image(); '.$this->I
['theName'].'_n.src = "'.$GLOBALS['TSFE']->absRefPrefix
.$this->I
['val']['output_file'].'"; ';
2383 $GLOBALS['TSFE']->JSImgCode
.= chr(10).$this->I
['theName'].'_h=new Image(); '.$this->I
['theName'].'_h.src = "'.$GLOBALS['TSFE']->absRefPrefix
.$this->result
['RO'][$key]['output_file'].'"; ';
2384 $GLOBALS['TSFE']->imagesOnPage
[]=$this->result
['RO'][$key]['output_file'];
2385 $GLOBALS['TSFE']->setJS('mouseOver');
2386 $this->extProc_RO($key);
2390 $this->I
['altText'] = $this->I
['title'].$this->I
['accessKey']['alt'];
2392 // Calling extra processing function
2393 $this->extProc_beforeLinking($key);
2396 if (!$this->I
['noLink']) {
2397 $this->setATagParts();
2399 $this->I
['A1'] = '';
2400 $this->I
['A2'] = '';
2402 $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']:'').' />';
2404 // Make before, middle and after parts
2405 $this->I
['parts'] = array();
2406 $this->I
['parts']['ATag_begin'] = $this->I
['A1'];
2407 $this->I
['parts']['image'] = $this->I
['IMG'];
2408 $this->I
['parts']['ATag_end'] = $this->I
['A2'];
2410 // Passing I to a user function
2411 if ($this->mconf
['IProcFunc']) {
2412 $this->I
= $this->userProcess('IProcFunc',$this->I
);
2415 // Putting the item together.
2416 // Merge parts + beforeAllWrap
2417 $this->I
['theItem']= implode('',$this->I
['parts']);
2418 $this->I
['theItem']= $this->extProc_beforeAllWrap($this->I
['theItem'],$key);
2421 $this->I
['theItem']= $this->tmpl
->wrap($this->I
['theItem'],$this->I
['val']['wrap']);
2424 $allWrap = $this->WMcObj
->stdWrap($this->I
['val']['allWrap'],$this->I
['val']['allWrap.']);
2425 $this->I
['theItem'] = $this->tmpl
->wrap($this->I
['theItem'],$allWrap);
2427 if ($this->I
['val']['subst_elementUid']) $this->I
['theItem'] = str_replace('{elementUid}',$this->I
['uid'],$this->I
['theItem']);
2430 if (is_array($this->I
['val']['allStdWrap.'])) {
2431 $this->I
['theItem'] = $this->WMcObj
->stdWrap($this->I
['theItem'],$this->I
['val']['allStdWrap.']);
2434 $GLOBALS['TSFE']->imagesOnPage
[]=$this->I
['val']['output_file'];
2436 $this->extProc_afterLinking($key);
2439 return $this->extProc_finish();
2444 * Called right before the traversing of $this->result begins.
2445 * Can be used for various initialization
2449 * @see writeMenu(), tslib_gmenu_layers::extProc_init()
2451 function extProc_init() {
2455 * Called after all processing for RollOver of an element has been done.
2457 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found OR $this->result['RO'][$key] where the configuration for that elements RO version is found!
2460 * @see writeMenu(), tslib_gmenu_layers::extProc_RO()
2462 function extProc_RO($key) {
2466 * Called right before the creation of the link for the menu item
2468 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2471 * @see writeMenu(), tslib_gmenu_layers::extProc_beforeLinking()
2473 function extProc_beforeLinking($key) {
2477 * Called right after the creation of links for the menu item. This is also the last function call before the for-loop traversing menu items goes to the next item.
2478 * This function MUST set $this->WMresult.=[HTML for menu item] to add the generated menu item to the internal accumulation of items.
2479 * Further this calls the subMenu function in the parent class to create any submenu there might be.
2481 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2484 * @see writeMenu(), tslib_gmenu_layers::extProc_afterLinking(), tslib_menu::subMenu()
2486 function extProc_afterLinking($key) {
2487 // Add part to the accumulated result + fetch submenus
2488 if (!$this->I
['spacer']) {
2489 $this->I
['theItem'].= $this->subMenu($this->I
['uid'], $this->WMsubmenuObjSuffixes
[$key]['sOSuffix']);
2491 $part = $this->WMcObj
->stdWrap($this->I
['val']['wrapItemAndSub'],$this->I
['val']['wrapItemAndSub.']);
2492 $this->WMresult
.= $part ?
$this->tmpl
->wrap($this->I
['theItem'],$part) : $this->I
['theItem'];
2497 * Called before the "wrap" happens on the menu item.
2499 * @param string The current content of the menu item, $this->I['theItem'], passed along.
2500 * @param integer Pointer to $this->menuArr[$key] where the current menu element record is found
2501 * @return string The modified version of $item, going back into $this->I['theItem']
2503 * @see writeMenu(), tslib_gmenu_layers::extProc_beforeAllWrap()
2505 function extProc_beforeAllWrap($item,$key) {
2510 * Called before the writeMenu() function returns (only if a menu was generated)
2512 * @return string The total menu content should be returned by this function
2514 * @see writeMenu(), tslib_gmenu_layers::extProc_finish()
2516 function extProc_finish() {
2518 if (is_array($this->mconf
['stdWrap.'])) {
2519 $this->WMresult
= $this->WMcObj
->stdWrap($this->WMresult
,$this->mconf
['stdWrap.']);
2521 return $this->tmpl
->wrap($this->WMresult
,$this->mconf
['wrap']).$this->WMextraScript
;
2547 * ImageMap based menus
2549 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
2552 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=389&cHash=fcf18c5d9f
2554 class tslib_imgmenu
extends tslib_menu
{
2557 * Calls procesItemStates() so that the common configuration for the menu items are resolved into individual configuration per item.
2558 * Calls makeImageMap() to generate the image map image-file
2561 * @see tslib_menu::procesItemStates(), makeImageMap()
2563 function generate() {
2564 $splitCount = count($this->menuArr
);
2566 list($NOconf) = $this->procesItemStates($splitCount);
2568 if ($this->mconf
['debugItemConf']) {echo '<h3>$NOconf:</h3>'; debug($NOconf); }
2569 $this->makeImageMap($NOconf);
2573 * Will traverse input array with configuratoin per-item and create corresponding GIF files for the menu.
2574 * The data of the files are stored in $this->result
2576 * @param array Array with configuration for each item.
2581 function makeImageMap($conf) {
2582 if (!is_array($conf)) {
2585 if (is_array($this->mconf
['main.'])) {
2586 $gifCreator = t3lib_div
::makeInstance('tslib_gifBuilder');
2587 $gifCreator->init();
2590 $conf = $this->mconf
['main.'];
2591 if (is_array($conf)) {
2594 $sKeyArray=t3lib_TStemplate
::sortedKeyList($conf);
2595 $gifObjCount=intval(end($sKeyArray));
2597 $lastOriginal = $gifObjCount;
2599 // Now we add graphical objects to the gifbuilder-setup
2601 foreach ($itemsConf as $key => $val) {
2602 if (is_array($val)) {
2604 $waArr[$key]['free']=$gifObjCount;
2606 $sKeyArray=t3lib_TStemplate
::sortedKeyList($val);
2608 foreach($sKeyArray as $theKey) {
2609 $theValue=$val[$theKey];
2612 if (intval($theKey) && $theValArr=$val[$theKey.'.']) {
2613 $cObjData = $this->menuArr
[$key] ?
$this->menuArr
[$key] : Array();
2616 if ($theValue=='TEXT') {
2617 $waArr[$key]['textNum']=$gifObjCount;
2619 $gifCreator->data
= $cObjData;
2620 $theValArr = $gifCreator->checkTextObj($theValArr);
2621 unset($theValArr['text.']); // if this is not done it seems that imageMaps will be rendered wrong!!