|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 /** 00028 * Page navigation tree for the Web module 00029 * 00030 * Revised for TYPO3 3.6 2/2003 by Kasper Skårhøj 00031 * XHTML compliant 00032 * 00033 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00034 * @author Benjamin Mack <bmack@xnos.org> 00035 * 00036 * 00037 * [CLASS/FUNCTION INDEX of SCRIPT] 00038 * 00039 * 00040 * 00041 * 71: class webPageTree extends t3lib_browseTree 00042 * 81: function webPageTree() 00043 * 92: function wrapIcon($icon,&$row) 00044 * 130: function wrapStop($str,$row) 00045 * 146: function wrapTitle($title,$row,$bank=0) 00046 * 165: function printTree($treeArr = '') 00047 * 271: function PMicon($row,$a,$c,$nextCount,$exp) 00048 * 292: function PMiconATagWrap($icon, $cmd, $isExpand = true) 00049 * 309: function getBrowsableTree() 00050 * 377: function getTree($uid, $depth=999, $depthData='',$blankLineCode='',$subCSSclass='') 00051 * 00052 * 00053 * TOTAL FUNCTIONS: 9 00054 * (This index is automatically created/updated by the extension "extdeveval") 00055 * 00056 */ 00057 00058 00059 /** 00060 * Extension class for the t3lib_browsetree class, specially made 00061 * for browsing pages in the Web module 00062 * 00063 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00064 * @author Benjamin Mack <bmack@xnos.org> 00065 * @package TYPO3 00066 * @subpackage core 00067 * @see class t3lib_browseTree 00068 */ 00069 class webPageTree extends t3lib_browseTree { 00070 00071 var $ext_showPageId; 00072 var $ext_IconMode; 00073 var $ext_separateNotinmenuPages; 00074 var $ext_alphasortNotinmenuPages; 00075 var $ajaxStatus = false; // Indicates, whether the ajax call was successful, i.e. the requested page has been found 00076 00077 /** 00078 * Calls init functions 00079 * 00080 * @return void 00081 */ 00082 function webPageTree() { 00083 $this->init(); 00084 } 00085 00086 /** 00087 * Wrapping icon in browse tree 00088 * 00089 * @param string Icon IMG code 00090 * @param array Data row for element. 00091 * @return string Page icon 00092 */ 00093 function wrapIcon($thePageIcon, &$row) { 00094 // If the record is locked, present a warning sign. 00095 if ($lockInfo=t3lib_BEfunc::isRecordLocked('pages',$row['uid'])) { 00096 $aOnClick = 'alert('.$GLOBALS['LANG']->JScharCode($lockInfo['msg']).');return false;'; 00097 $lockIcon='<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'. 00098 t3lib_iconWorks::getSpriteIcon('status-warning-in-use',array('title'=>htmlspecialchars($lockInfo['msg']))). 00099 '</a>'; 00100 } else $lockIcon = ''; 00101 00102 // Wrap icon in click-menu link. 00103 if (!$this->ext_IconMode) { 00104 $thePageIcon = $GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon($thePageIcon,'pages',$row['uid'],0,'&bank='.$this->bank); 00105 } elseif (!strcmp($this->ext_IconMode,'titlelink')) { 00106 $aOnClick = 'return jumpTo(\''.$this->getJumpToParam($row).'\',this,\''.$this->treeName.'\');'; 00107 $thePageIcon='<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.$thePageIcon.'</a>'; 00108 } 00109 00110 // Wrap icon in a drag/drop span. 00111 $dragDropIcon = '<span class="dragIcon" id="dragIconID_'.$row['uid'].'">'.$thePageIcon.'</span>'; 00112 00113 // Add Page ID: 00114 $pageIdStr = ''; 00115 if ($this->ext_showPageId) { 00116 $pageIdStr = '<span class="dragId">[' . $row['uid'] . ']</span> '; 00117 } 00118 00119 // Call stats information hook 00120 $stat = ''; 00121 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) { 00122 $_params = array('pages',$row['uid']); 00123 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) { 00124 $stat.=t3lib_div::callUserFunction($_funcRef,$_params,$this); 00125 } 00126 } 00127 00128 return $dragDropIcon.$lockIcon.$pageIdStr.$stat; 00129 } 00130 00131 /** 00132 * Adds a red "+" to the input string, $str, if the field "php_tree_stop" in the $row (pages) is set 00133 * 00134 * @param string Input string, like a page title for the tree 00135 * @param array record row with "php_tree_stop" field 00136 * @return string Modified string 00137 * @access private 00138 */ 00139 function wrapStop($str,$row) { 00140 if ($row['php_tree_stop']) { 00141 $str.='<a href="'.htmlspecialchars(t3lib_div::linkThisScript(array('setTempDBmount' => $row['uid']))).'" class="typo3-red">+</a> '; 00142 } 00143 return $str; 00144 } 00145 00146 /** 00147 * Wrapping $title in a-tags. 00148 * 00149 * @param string Title string 00150 * @param string Item record 00151 * @param integer Bank pointer (which mount point number) 00152 * @return string 00153 * @access private 00154 */ 00155 function wrapTitle($title,$row,$bank=0) { 00156 // Hook for overriding the page title 00157 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.webpagetree.php']['pageTitleOverlay'])) { 00158 $_params = array('title' => &$title, 'row' => &$row); 00159 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.webpagetree.php']['pageTitleOverlay'] as $_funcRef) { 00160 t3lib_div::callUserFunction($_funcRef, $_params, $this); 00161 } 00162 unset($_params); 00163 } 00164 00165 $aOnClick = 'return jumpTo(\''.$this->getJumpToParam($row).'\',this,\''.$this->domIdPrefix.$this->getId($row).'\','.$bank.');'; 00166 $CSM = ''; 00167 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['useOnContextMenuHandler']) { 00168 $CSM = ' oncontextmenu="'.htmlspecialchars($GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon('','pages',$row['uid'],0,'&bank='.$this->bank,'',TRUE)).';"'; 00169 } 00170 $thePageTitle='<a href="#" onclick="'.htmlspecialchars($aOnClick).'"'.$CSM.'>'.$title.'</a>'; 00171 00172 // Wrap title in a drag/drop span. 00173 return '<span class="dragTitle" id="dragTitleID_'.$row['uid'].'">'.$thePageTitle.'</span>'; 00174 } 00175 00176 00177 /** 00178 * Compiles the HTML code for displaying the structure found inside the ->tree array 00179 * 00180 * @param array "tree-array" - if blank string, the internal ->tree array is used. 00181 * @return string The HTML code for the tree 00182 */ 00183 function printTree($treeArr = '') { 00184 $titleLen = intval($this->BE_USER->uc['titleLen']); 00185 if (!is_array($treeArr)) { 00186 $treeArr = $this->tree; 00187 } 00188 00189 $out = ' 00190 <!-- TYPO3 tree structure. --> 00191 <ul class="tree" id="treeRoot"> 00192 '; 00193 00194 // -- evaluate AJAX request 00195 // IE takes anchor as parameter 00196 $PM = t3lib_div::_GP('PM'); 00197 if(($PMpos = strpos($PM, '#')) !== false) { $PM = substr($PM, 0, $PMpos); } 00198 $PM = explode('_', $PM); 00199 if ((TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) && is_array($PM) && count($PM) == 4 && $PM[2] != 0) { 00200 if($PM[1]) { 00201 $expandedPageUid = $PM[2]; 00202 $ajaxOutput = ''; 00203 $invertedDepthOfAjaxRequestedItem = 0; // We don't know yet. Will be set later. 00204 $doExpand = true; 00205 } else { 00206 $collapsedPageUid = $PM[2]; 00207 $doCollapse = true; 00208 } 00209 } 00210 00211 // we need to count the opened <ul>'s every time we dig into another level, 00212 // so we know how many we have to close when all children are done rendering 00213 $closeDepth = array(); 00214 00215 foreach($treeArr as $k => $v) { 00216 $classAttr = $v['row']['_CSSCLASS']; 00217 $uid = $v['row']['uid']; 00218 $idAttr = htmlspecialchars($this->domIdPrefix.$this->getId($v['row']).'_'.$v['bank']); 00219 $itemHTML = ''; 00220 00221 // if this item is the start of a new level, 00222 // then a new level <ul> is needed, but not in ajax mode 00223 if($v['isFirst'] && !($doCollapse) && !($doExpand && $expandedPageUid == $uid)) { 00224 $itemHTML = '<ul>'; 00225 } 00226 00227 // add CSS classes to the list item 00228 if($v['hasSub']) { $classAttr .= ($classAttr) ? ' expanded': 'expanded'; } 00229 if($v['isLast']) { $classAttr .= ($classAttr) ? ' last' : 'last'; } 00230 00231 $itemHTML .=' 00232 <li id="'.$idAttr.'"'.($classAttr ? ' class="'.$classAttr.'"' : '').'><div class="treeLinkItem">'. 00233 $v['HTML']. 00234 $this->wrapTitle($this->getTitleStr($v['row'],$titleLen),$v['row'],$v['bank'])."</div>\n"; 00235 00236 00237 if(!$v['hasSub']) { $itemHTML .= '</li>'; } 00238 00239 // we have to remember if this is the last one 00240 // on level X so the last child on level X+1 closes the <ul>-tag 00241 if($v['isLast'] && !($doExpand && $expandedPageUid == $uid)) { $closeDepth[$v['invertedDepth']] = 1; } 00242 00243 00244 // if this is the last one and does not have subitems, we need to close 00245 // the tree as long as the upper levels have last items too 00246 if($v['isLast'] && !$v['hasSub'] && !$doCollapse && !($doExpand && $expandedPageUid == $uid)) { 00247 for ($i = $v['invertedDepth']; $closeDepth[$i] == 1; $i++) { 00248 $closeDepth[$i] = 0; 00249 $itemHTML .= '</ul></li>'; 00250 } 00251 } 00252 00253 // ajax request: collapse 00254 if($doCollapse && $collapsedPageUid == $uid) { 00255 $this->ajaxStatus = true; 00256 return $itemHTML; 00257 } 00258 00259 // ajax request: expand 00260 if($doExpand && $expandedPageUid == $uid) { 00261 $ajaxOutput .= $itemHTML; 00262 $invertedDepthOfAjaxRequestedItem = $v['invertedDepth']; 00263 } elseif($invertedDepthOfAjaxRequestedItem) { 00264 if($v['invertedDepth'] < $invertedDepthOfAjaxRequestedItem) { 00265 $ajaxOutput .= $itemHTML; 00266 } else { 00267 $this->ajaxStatus = true; 00268 return $ajaxOutput; 00269 } 00270 } 00271 00272 $out .= $itemHTML; 00273 } 00274 00275 if($ajaxOutput) { 00276 $this->ajaxStatus = true; 00277 return $ajaxOutput; 00278 } 00279 00280 // finally close the first ul 00281 $out .= '</ul>'; 00282 return $out; 00283 } 00284 00285 00286 /** 00287 * Generate the plus/minus icon for the browsable tree. 00288 * 00289 * @param array record for the entry 00290 * @param integer The current entry number 00291 * @param integer The total number of entries. If equal to $a, a "bottom" element is returned. 00292 * @param integer The number of sub-elements to the current element. 00293 * @param boolean The element was expanded to render subelements if this flag is set. 00294 * @return string Image tag with the plus/minus icon. 00295 * @access private 00296 * @see t3lib_pageTree::PMicon() 00297 */ 00298 function PMicon($row,$a,$c,$nextCount,$exp) { 00299 $PM = $nextCount ? ($exp ? 'minus' : 'plus') : 'join'; 00300 $BTM = ($a == $c) ? 'bottom' : ''; 00301 $icon = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$PM.$BTM.'.gif','width="18" height="16"').' alt="" />'; 00302 00303 if ($nextCount) { 00304 $cmd = $this->bank.'_'.($exp?'0_':'1_').$row['uid'].'_'.$this->treeName; 00305 $icon = $this->PMiconATagWrap($icon,$cmd,!$exp); 00306 } 00307 return $icon; 00308 } 00309 00310 00311 /** 00312 * Wrap the plus/minus icon in a link 00313 * 00314 * @param string HTML string to wrap, probably an image tag. 00315 * @param string Command for 'PM' get var 00316 * @return string Link-wrapped input string 00317 * @access private 00318 */ 00319 function PMiconATagWrap($icon, $cmd, $isExpand = true) { 00320 if ($this->thisScript) { 00321 // activate dynamic ajax-based tree 00322 $js = htmlspecialchars('Tree.load(\''.$cmd.'\', '.intval($isExpand).', this);'); 00323 return '<a class="pm" onclick="'.$js.'">'.$icon.'</a>'; 00324 } else { 00325 return $icon; 00326 } 00327 } 00328 00329 00330 /** 00331 * Will create and return the HTML code for a browsable tree 00332 * Is based on the mounts found in the internal array ->MOUNTS (set in the constructor) 00333 * 00334 * @return string HTML code for the browsable tree 00335 */ 00336 function getBrowsableTree() { 00337 00338 // Get stored tree structure AND updating it if needed according to incoming PM GET var. 00339 $this->initializePositionSaving(); 00340 00341 // Init done: 00342 $titleLen = intval($this->BE_USER->uc['titleLen']); 00343 $treeArr = array(); 00344 00345 // Traverse mounts: 00346 foreach($this->MOUNTS as $idx => $uid) { 00347 00348 // Set first: 00349 $this->bank = $idx; 00350 $isOpen = $this->stored[$idx][$uid] || $this->expandFirst || $uid === '0'; 00351 00352 // Save ids while resetting everything else. 00353 $curIds = $this->ids; 00354 $this->reset(); 00355 $this->ids = $curIds; 00356 00357 // Set PM icon for root of mount: 00358 $cmd = $this->bank.'_'.($isOpen? "0_" : "1_").$uid.'_'.$this->treeName; 00359 // only, if not for uid 0 00360 if ($uid) { 00361 $icon = '<img' . t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/' . ($isOpen ? 'minus' :'plus' ) . 'only.gif') . ' alt="" />'; 00362 $firstHtml = $this->PMiconATagWrap($icon, $cmd, !$isOpen); 00363 } 00364 00365 // Preparing rootRec for the mount 00366 if ($uid) { 00367 $rootRec = $this->getRecord($uid); 00368 $firstHtml.=$this->getIcon($rootRec); 00369 } else { 00370 // Artificial record for the tree root, id=0 00371 $rootRec = $this->getRootRecord($uid); 00372 $firstHtml.=$this->getRootIcon($rootRec); 00373 } 00374 00375 if (is_array($rootRec)) { 00376 // In case it was swapped inside getRecord due to workspaces. 00377 $uid = $rootRec['uid']; 00378 00379 // Add the root of the mount to ->tree 00380 $this->tree[] = array('HTML'=>$firstHtml, 'row'=>$rootRec, 'bank'=>$this->bank, 'hasSub'=>true, 'invertedDepth'=>1000); 00381 00382 // If the mount is expanded, go down: 00383 if ($isOpen) { 00384 // Set depth: 00385 if ($this->addSelfId) { $this->ids[] = $uid; } 00386 $this->getTree($uid, 999, '', $rootRec['_SUBCSSCLASS']); 00387 } 00388 // Add tree: 00389 $treeArr=array_merge($treeArr,$this->tree); 00390 } 00391 } 00392 return $this->printTree($treeArr); 00393 } 00394 00395 00396 /** 00397 * Fetches the data for the tree 00398 * 00399 * @param integer item id for which to select subitems (parent id) 00400 * @param integer Max depth (recursivity limit) 00401 * @param string ? (internal) 00402 * @return integer The count of items on the level 00403 */ 00404 function getTree($uid, $depth=999, $blankLineCode='', $subCSSclass='') { 00405 00406 // Buffer for id hierarchy is reset: 00407 $this->buffer_idH = array(); 00408 00409 // Init vars 00410 $depth = intval($depth); 00411 $HTML = ''; 00412 $a = 0; 00413 00414 $res = $this->getDataInit($uid, $subCSSclass); 00415 $c = $this->getDataCount($res); 00416 $crazyRecursionLimiter = 999; 00417 00418 $inMenuPages = array(); 00419 $outOfMenuPages = array(); 00420 $outOfMenuPagesTextIndex = array(); 00421 while ($crazyRecursionLimiter > 0 && $row = $this->getDataNext($res,$subCSSclass)) { 00422 $crazyRecursionLimiter--; 00423 00424 // Not in menu: 00425 // @TODO: RFC #7370: doktype 2&5 are deprecated since TYPO3 4.2-beta1 00426 if ($this->ext_separateNotinmenuPages && 00427 ($row['doktype'] == t3lib_pageSelect::DOKTYPE_HIDE_IN_MENU || $row['doktype'] == t3lib_pageSelect::DOKTYPE_BE_USER_SECTION || 00428 $row['doktype'] >= 200 || $row['nav_hide'])) { 00429 $outOfMenuPages[] = $row; 00430 $outOfMenuPagesTextIndex[] = ($row['doktype']>=200 ? 'zzz'.$row['doktype'].'_' : '').$row['title']; 00431 } else { 00432 $inMenuPages[] = $row; 00433 } 00434 } 00435 00436 $label_shownAlphabetically = ""; 00437 if (count($outOfMenuPages)) { 00438 // Sort out-of-menu pages: 00439 $outOfMenuPages_alphabetic = array(); 00440 if ($this->ext_alphasortNotinmenuPages) { 00441 asort($outOfMenuPagesTextIndex); 00442 $label_shownAlphabetically = " (alphabetic)"; 00443 } 00444 foreach($outOfMenuPagesTextIndex as $idx => $txt) { 00445 $outOfMenuPages_alphabetic[] = $outOfMenuPages[$idx]; 00446 } 00447 00448 // Merge: 00449 $outOfMenuPages_alphabetic[0]['_FIRST_NOT_IN_MENU']=TRUE; 00450 $allRows = array_merge($inMenuPages,$outOfMenuPages_alphabetic); 00451 } else { 00452 $allRows = $inMenuPages; 00453 } 00454 00455 // Traverse the records: 00456 foreach ($allRows as $row) { 00457 $a++; 00458 00459 $newID = $row['uid']; 00460 $this->tree[]=array(); // Reserve space. 00461 end($this->tree); 00462 $treeKey = key($this->tree); // Get the key for this space 00463 $LN = ($a==$c) ? 'blank' : 'line'; 00464 00465 // If records should be accumulated, do so 00466 if ($this->setRecs) { $this->recs[$row['uid']] = $row; } 00467 00468 // Accumulate the id of the element in the internal arrays 00469 $this->ids[]=$idH[$row['uid']]['uid'] = $row['uid']; 00470 $this->ids_hierarchy[$depth][] = $row['uid']; 00471 00472 // Make a recursive call to the next level 00473 if ($depth > 1 && $this->expandNext($newID) && !$row['php_tree_stop']) { 00474 $nextCount=$this->getTree( 00475 $newID, 00476 $depth-1, 00477 $blankLineCode.','.$LN, 00478 $row['_SUBCSSCLASS'] 00479 ); 00480 if (count($this->buffer_idH)) { $idH[$row['uid']]['subrow']=$this->buffer_idH; } 00481 $exp = 1; // Set "did expand" flag 00482 } else { 00483 $nextCount = $this->getCount($newID); 00484 $exp = 0; // Clear "did expand" flag 00485 } 00486 00487 // Set HTML-icons, if any: 00488 if ($this->makeHTML) { 00489 if ($row['_FIRST_NOT_IN_MENU']) { 00490 $HTML = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/line.gif').' alt="" /><br/><img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/line.gif').' alt="" /><i>Not shown in menu'.$label_shownAlphabetically.':</i><br>'; 00491 } else { 00492 $HTML = ''; 00493 } 00494 00495 $HTML.= $this->PMicon($row,$a,$c,$nextCount,$exp); 00496 $HTML.= $this->wrapStop($this->getIcon($row),$row); 00497 } 00498 00499 // Finally, add the row/HTML content to the ->tree array in the reserved key. 00500 $this->tree[$treeKey] = array( 00501 'row' => $row, 00502 'HTML' => $HTML, 00503 'hasSub' => $nextCount&&$this->expandNext($newID), 00504 'isFirst'=> $a==1, 00505 'isLast' => false, 00506 'invertedDepth'=> $depth, 00507 'blankLineCode'=> $blankLineCode, 00508 'bank' => $this->bank 00509 ); 00510 } 00511 00512 if($a) { $this->tree[$treeKey]['isLast'] = true; } 00513 00514 $this->getDataFree($res); 00515 $this->buffer_idH = $idH; 00516 return $c; 00517 } 00518 } 00519 00520 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/class.webpagetree.php'])) { 00521 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['typo3/class.webpagetree.php']); 00522 } 00523 00524 ?>
1.8.0