Documentation TYPO3 par Ameos |
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2005 Kasper Skaarhoj (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 ***************************************************************/ 00101 require_once (PATH_t3lib.'class.t3lib_iconworks.php'); 00102 require_once (PATH_t3lib.'class.t3lib_befunc.php'); 00103 require_once (PATH_t3lib.'class.t3lib_div.php'); 00104 00105 00115 class t3lib_treeView { 00116 00117 // EXTERNAL, static: 00118 var $expandFirst=0; // If set, the first element in the tree is always expanded. 00119 var $expandAll=0; // If set, then ALL items will be expanded, regardless of stored settings. 00120 var $thisScript=''; // Holds the current script to reload to. 00121 var $titleAttrib = 'title'; // Which HTML attribute to use: alt/title. See init(). 00122 var $ext_IconMode = false; // If true, no context menu is rendered on icons. If set to "titlelink" the icon is linked as the title is. 00123 var $addSelfId = 0; // If set, the id of the mounts will be added to the internal ids array 00124 var $title='no title'; // Used if the tree is made of records (not folders for ex.) 00125 00130 var $BE_USER=''; 00131 00137 var $MOUNTS=''; 00138 00139 00140 00145 var $table=''; 00146 00150 var $parentField='pid'; 00151 00157 var $clause=''; 00158 00164 var $orderByFields=''; 00165 00171 var $fieldArray = Array('uid','title'); 00172 00177 var $defaultList = 'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate,cruser_id'; 00178 00179 00187 var $treeName = ''; 00188 00195 var $domIdPrefix = 'row'; 00196 00200 var $backPath; 00201 00205 var $iconPath = ''; 00206 00207 00211 var $iconName = 'default.gif'; 00212 00216 var $makeHTML=1; 00217 00221 var $setRecs = 0; 00222 00227 var $subLevelID = '_SUB_LEVEL'; 00228 00229 00230 00231 00232 // ********* 00233 // Internal 00234 // ********* 00235 // For record trees: 00236 var $ids = Array(); // one-dim array of the uid's selected. 00237 var $ids_hierarchy = array(); // The hierarchy of element uids 00238 var $buffer_idH = array(); // Temporary, internal array 00239 00240 // For FOLDER trees: 00241 var $specUIDmap=array(); // Special UIDs for folders (integer-hashes of paths) 00242 00243 // For arrays: 00244 var $data = false; // Holds the input data array 00245 var $dataLookup = false; // Holds an index with references to the data array. 00246 00247 // For both types 00248 var $tree = Array(); // Tree is accumulated in this variable 00249 var $stored = array(); // Holds (session stored) information about which items in the tree are unfolded and which are not. 00250 var $bank=0; // Points to the current mountpoint key 00251 var $recs = array(); // Accumulates the displayed records. 00252 00253 00254 00255 00256 00257 00258 00267 function init($clause='', $orderByFields='') { 00268 $this->BE_USER = $GLOBALS['BE_USER']; // Setting BE_USER by default 00269 $this->titleAttrib = 'title'; // Setting title attribute to use. 00270 $this->backPath = $GLOBALS['BACK_PATH']; // Setting backpath. 00271 00272 if ($clause) $this->clause = $clause; // Setting clause 00273 if ($orderByFields) $this->orderByFields = $orderByFields; 00274 00275 if (!is_array($this->MOUNTS)) { 00276 $this->MOUNTS = array(0 => 0); // dummy 00277 } 00278 00279 $this->setTreeName(); 00280 00281 if($this->table) { 00282 t3lib_div::loadTCA($this->table); 00283 } 00284 00285 // setting this to false disables the use of array-trees by default 00286 $this->data = false; 00287 $this->dataLookup = false; 00288 } 00289 00290 00298 function setTreeName($treeName='') { 00299 $this->treeName = $treeName ? $treeName : $this->treeName; 00300 $this->treeName = $this->treeName ? $this->treeName : $this->table; 00301 $this->treeName = str_replace('_','',$this->treeName); 00302 } 00303 00304 00312 function addField($field,$noCheck=0) { 00313 global $TCA; 00314 if ($noCheck || is_array($TCA[$this->table]['columns'][$field]) || t3lib_div::inList($this->defaultList,$field)) { 00315 $this->fieldArray[]=$field; 00316 } 00317 } 00318 00319 00320 00326 function reset() { 00327 $this->tree = array(); 00328 $this->recs = array(); 00329 $this->ids = array(); 00330 $this->ids_hierarchy = array(); 00331 } 00332 00333 00334 /******************************************* 00335 * 00336 * output 00337 * 00338 *******************************************/ 00339 00346 function getBrowsableTree() { 00347 00348 // Get stored tree structure AND updating it if needed according to incoming PM GET var. 00349 $this->initializePositionSaving(); 00350 00351 // Init done: 00352 $titleLen=intval($this->BE_USER->uc['titleLen']); 00353 $treeArr=array(); 00354 00355 // Traverse mounts: 00356 foreach($this->MOUNTS as $idx => $uid) { 00357 00358 // Set first: 00359 $this->bank=$idx; 00360 $isOpen = $this->stored[$idx][$uid] || $this->expandFirst; 00361 00362 // Save ids while resetting everything else. 00363 $curIds = $this->ids; 00364 $this->reset(); 00365 $this->ids = $curIds; 00366 00367 // Set PM icon for root of mount: 00368 $cmd=$this->bank.'_'.($isOpen?"0_":"1_").$uid.'_'.$this->treeName; 00369 $icon='<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.($isOpen?'minus':'plus').'only.gif','width="18" height="16"').' alt="" />'; 00370 $firstHtml= $this->PM_ATagWrap($icon,$cmd); 00371 00372 // Preparing rootRec for the mount 00373 if ($uid) { 00374 $rootRec = $this->getRecord($uid); 00375 $firstHtml.=$this->getIcon($rootRec); 00376 } else { 00377 // Artificial record for the tree root, id=0 00378 $rootRec = $this->getRootRecord($uid); 00379 $firstHtml.=$this->getRootIcon($rootRec); 00380 } 00381 00382 if (is_array($rootRec)) { 00383 // Add the root of the mount to ->tree 00384 $this->tree[]=array('HTML'=>$firstHtml,'row'=>$rootRec,'bank'=>$this->bank); 00385 00386 // If the mount is expanded, go down: 00387 if ($isOpen) { 00388 // Set depth: 00389 $depthD='<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/blank.gif','width="18" height="16"').' alt="" />'; 00390 if ($this->addSelfId) $this->ids[] = $uid; 00391 $this->getTree($uid,999,$depthD); 00392 } 00393 00394 // Add tree: 00395 $treeArr=array_merge($treeArr,$this->tree); 00396 } 00397 } 00398 return $this->printTree($treeArr); 00399 } 00400 00407 function printTree($treeArr='') { 00408 $titleLen=intval($this->BE_USER->uc['titleLen']); 00409 if (!is_array($treeArr)) $treeArr=$this->tree; 00410 $out=''; 00411 00412 // put a table around it with IDs to access the rows from JS 00413 // not a problem if you don't need it 00414 // In XHTML there is no "name" attribute of <td> elements - but Mozilla will not be able to highlight rows if the name attribute is NOT there. 00415 $out .= ' 00416 00417 <!-- 00418 TYPO3 tree structure. 00419 --> 00420 <table cellpadding="0" cellspacing="0" border="0" id="typo3-tree">'; 00421 00422 foreach($treeArr as $k => $v) { 00423 $idAttr = htmlspecialchars($this->domIdPrefix.$this->getId($v['row']).'_'.$v['bank']); 00424 $out.=' 00425 <tr> 00426 <td id="'.$idAttr.'">'. 00427 $v['HTML']. 00428 $this->wrapTitle($this->getTitleStr($v['row'],$titleLen),$v['row'],$v['bank']). 00429 '</td> 00430 </tr> 00431 '; 00432 } 00433 $out .= ' 00434 </table>'; 00435 return $out; 00436 } 00437 00438 00439 00440 /******************************************* 00441 * 00442 * rendering parts 00443 * 00444 *******************************************/ 00445 00446 00447 00460 function PMicon($row,$a,$c,$nextCount,$exp) { 00461 $PM = $nextCount ? ($exp?'minus':'plus') : 'join'; 00462 $BTM = ($a==$c)?'bottom':''; 00463 $icon = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$PM.$BTM.'.gif','width="18" height="16"').' alt="" />'; 00464 00465 if ($nextCount) { 00466 $cmd=$this->bank.'_'.($exp?'0_':'1_').$row['uid'].'_'.$this->treeName; 00467 $bMark=($this->bank.'_'.$row['uid']); 00468 $icon = $this->PM_ATagWrap($icon,$cmd,$bMark); 00469 } 00470 return $icon; 00471 } 00472 00482 function PM_ATagWrap($icon,$cmd,$bMark='') { 00483 if ($this->thisScript) { 00484 if ($bMark) { 00485 $anchor = '#'.$bMark; 00486 $name=' name="'.$bMark.'"'; 00487 } 00488 $aUrl = $this->thisScript.'?PM='.$cmd.$anchor; 00489 return '<a href="'.htmlspecialchars($aUrl).'"'.$name.'>'.$icon.'</a>'; 00490 } else { 00491 return $icon; 00492 } 00493 } 00494 00504 function wrapTitle($title,$row,$bank=0) { 00505 $aOnClick = 'return jumpTo(\''.$this->getJumpToParam($row).'\',this,\''.$this->domIdPrefix.$this->getId($row).'_'.$bank.'\');'; 00506 return '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.$title.'</a>'; 00507 } 00508 00517 function wrapIcon($icon,$row) { 00518 return $icon; 00519 } 00520 00528 function addTagAttributes($icon,$attr) { 00529 return ereg_replace(' ?\/?>$','',$icon).' '.$attr.' />'; 00530 } 00531 00540 function wrapStop($str,$row) { 00541 if ($row['php_tree_stop']) { 00542 $str.='<span class="typo3-red">+ </span>'; 00543 } 00544 return $str; 00545 } 00546 00547 00548 00549 00550 00551 00552 /******************************************* 00553 * 00554 * tree handling 00555 * 00556 *******************************************/ 00557 00558 00568 function expandNext($id) { 00569 return ($this->stored[$this->bank][$id] || $this->expandAll)? 1 : 0; 00570 } 00571 00578 function initializePositionSaving() { 00579 // Get stored tree structure: 00580 $this->stored=unserialize($this->BE_USER->uc['browseTrees'][$this->treeName]); 00581 00582 // PM action 00583 // (If an plus/minus icon has been clicked, the PM GET var is sent and we must update the stored positions in the tree): 00584 $PM = explode('_',t3lib_div::_GP('PM')); // 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName 00585 if (count($PM)==4 && $PM[3]==$this->treeName) { 00586 if (isset($this->MOUNTS[$PM[0]])) { 00587 if ($PM[1]) { // set 00588 $this->stored[$PM[0]][$PM[2]]=1; 00589 $this->savePosition(); 00590 } else { // clear 00591 unset($this->stored[$PM[0]][$PM[2]]); 00592 $this->savePosition(); 00593 } 00594 } 00595 } 00596 } 00597 00605 function savePosition() { 00606 $this->BE_USER->uc['browseTrees'][$this->treeName] = serialize($this->stored); 00607 $this->BE_USER->writeUC(); 00608 } 00609 00610 00611 00612 00613 00614 00615 00616 00617 00618 00619 00620 00621 00622 /****************************** 00623 * 00624 * Functions that might be overwritten by extended classes 00625 * 00626 ********************************/ 00627 00634 function getRootIcon($rec) { 00635 return $this->wrapIcon('<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/i/_icon_website.gif','width="18" height="16"').' alt="" />',$rec); 00636 } 00637 00638 00639 00647 function getIcon($row) { 00648 if ($this->iconPath && $this->iconName) { 00649 $icon = '<img'.t3lib_iconWorks::skinImg('',$this->iconPath.$this->iconName,'width="18" height="16"').' alt="" />'; 00650 } else { 00651 $icon = t3lib_iconWorks::getIconImage($this->table,$row,$this->backPath,'align="top" class="c-recIcon"'); 00652 } 00653 00654 return $this->wrapIcon($icon,$row); 00655 } 00656 00657 00666 function getTitleStr($row,$titleLen=30) { 00667 $title = (!strcmp(trim($row['title']),'')) ? '<em>['.$GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.no_title',1).']</em>' : htmlspecialchars(t3lib_div::fixed_lgd_cs($row['title'],$titleLen)); 00668 return $title; 00669 } 00670 00678 function getTitleAttrib($row) { 00679 return htmlspecialchars($row['title']); 00680 } 00681 00688 function getId($row) { 00689 return $row['uid']; 00690 } 00691 00698 function getJumpToParam($row) { 00699 return $this->getId($row); 00700 } 00701 00702 00703 00704 00705 00706 00707 00708 00709 00710 00711 00712 00713 00714 00715 00716 /******************************** 00717 * 00718 * tree data buidling 00719 * 00720 ********************************/ 00721 00731 function getTree($uid, $depth=999, $depthData='',$blankLineCode='') { 00732 00733 // Buffer for id hierarchy is reset: 00734 $this->buffer_idH=array(); 00735 00736 00737 // Init vars 00738 $depth=intval($depth); 00739 $HTML=''; 00740 $a=0; 00741 00742 $res = $this->getDataInit($uid); 00743 $c = $this->getDataCount($res); 00744 $crazyRecursionLimiter = 999; 00745 00746 // Traverse the records: 00747 while ($crazyRecursionLimiter>0 && $row = $this->getDataNext($res)) { 00748 $a++; 00749 $crazyRecursionLimiter--; 00750 00751 $newID =$row['uid']; 00752 $this->tree[]=array(); // Reserve space. 00753 end($this->tree); 00754 $treeKey = key($this->tree); // Get the key for this space 00755 $LN = ($a==$c)?'blank':'line'; 00756 00757 // If records should be accumulated, do so 00758 if ($this->setRecs) { 00759 $this->recs[$row['uid']] = $row; 00760 } 00761 00762 // Accumulate the id of the element in the internal arrays 00763 $this->ids[]=$idH[$row['uid']]['uid']=$row['uid']; 00764 $this->ids_hierarchy[$depth][]=$row['uid']; 00765 00766 // Make a recursive call to the next level 00767 if ($depth>1 && $this->expandNext($newID) && !$row['php_tree_stop']) { 00768 $nextCount=$this->getTree( 00769 $newID, 00770 $depth-1, 00771 $this->makeHTML?$depthData.'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$LN.'.gif','width="18" height="16"').' alt="" />':'', 00772 $blankLineCode.','.$LN 00773 ); 00774 if (count($this->buffer_idH)) $idH[$row['uid']]['subrow']=$this->buffer_idH; 00775 $exp=1; // Set "did expand" flag 00776 } else { 00777 $nextCount=$this->getCount($newID); 00778 $exp=0; // Clear "did expand" flag 00779 } 00780 00781 // Set HTML-icons, if any: 00782 if ($this->makeHTML) { 00783 $HTML = $depthData.$this->PMicon($row,$a,$c,$nextCount,$exp); 00784 $HTML.=$this->wrapStop($this->getIcon($row),$row); 00785 # $HTML.=$this->wrapStop($this->wrapIcon($this->getIcon($row),$row),$row); 00786 } 00787 00788 // Finally, add the row/HTML content to the ->tree array in the reserved key. 00789 $this->tree[$treeKey] = Array( 00790 'row'=>$row, 00791 'HTML'=>$HTML, 00792 'invertedDepth'=>$depth, 00793 'blankLineCode'=>$blankLineCode, 00794 'bank' => $this->bank 00795 ); 00796 } 00797 00798 $this->getDataFree($res); 00799 $this->buffer_idH=$idH; 00800 return $c; 00801 } 00802 00803 00804 00805 00806 00807 00808 00809 00810 00811 00812 00813 00814 /******************************** 00815 * 00816 * Data handling 00817 * Works with records and arrays 00818 * 00819 ********************************/ 00820 00828 function getCount($uid) { 00829 if (is_array($this->data)) { 00830 $res = $this->getDataInit($uid); 00831 return $this->getDataCount($res); 00832 } else { 00833 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00834 'count(*)', 00835 $this->table, 00836 $this->parentField.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($uid, $this->table). 00837 t3lib_BEfunc::deleteClause($this->table). 00838 $this->clause, // whereClauseMightContainGroupOrderBy 00839 '', 00840 '' //$this->orderByFields // sorting is senseless for count(*) !?! 00841 ); 00842 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res); 00843 return $row[0]; 00844 } 00845 } 00846 00847 00848 00855 function getRootRecord($uid) { 00856 return array('title'=>$this->title, 'uid'=>0); 00857 } 00858 00859 00868 function getRecord($uid) { 00869 if (is_array($this->data)) { 00870 return $this->dataLookup[$uid]; 00871 } else { 00872 return t3lib_befunc::getRecord($this->table,$uid); 00873 } 00874 } 00875 00885 function getDataInit($parentId) { 00886 if (is_array($this->data)) { 00887 if (!is_array($this->dataLookup[$parentId][$this->subLevelID])) { 00888 $parentId = -1; 00889 } else { 00890 reset($this->dataLookup[$parentId][$this->subLevelID]); 00891 } 00892 return $parentId; 00893 } else { 00894 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 00895 implode(',',$this->fieldArray), 00896 $this->table, 00897 $this->parentField.'='.$GLOBALS['TYPO3_DB']->fullQuoteStr($parentId, $this->table). 00898 t3lib_BEfunc::deleteClause($this->table). 00899 $this->clause, // whereClauseMightContainGroupOrderBy 00900 '', 00901 $this->orderByFields 00902 ); 00903 return $res; 00904 } 00905 } 00906 00915 function getDataCount(&$res) { 00916 if (is_array($this->data)) { 00917 return count($this->dataLookup[$res][$this->subLevelID]); 00918 } else { 00919 $c = $GLOBALS['TYPO3_DB']->sql_num_rows($res); 00920 return $c; 00921 } 00922 } 00923 00932 function getDataNext(&$res){ 00933 if (is_array($this->data)) { 00934 if ($res<0) { 00935 $row=FALSE; 00936 } else { 00937 list(,$row) = each($this->dataLookup[$res][$this->subLevelID]); 00938 00939 /* 00940 if (!is_array($row)) { 00941 $row=FALSE; 00942 } else { 00943 unset($row['subLevel']); 00944 } 00945 */ 00946 } 00947 return $row; 00948 } else { 00949 return @$GLOBALS['TYPO3_DB']->sql_fetch_assoc($res); 00950 } 00951 } 00952 00960 function getDataFree(&$res){ 00961 if (is_array($this->data)) { 00962 # unset(); 00963 } else { 00964 $GLOBALS['TYPO3_DB']->sql_free_result($res); 00965 } 00966 } 00967 00980 function setDataFromArray(&$dataArr,$traverse=FALSE,$pid=0) { 00981 if (!$traverse) { 00982 $this->data = &$dataArr; 00983 $this->dataLookup=array(); 00984 // add root 00985 $this->dataLookup[0][$this->subLevelID]=&$dataArr; 00986 } 00987 00988 foreach($dataArr as $uid => $val) { 00989 00990 $dataArr[$uid]['uid']=$uid; 00991 $dataArr[$uid]['pid']=$pid; 00992 00993 // gives quick access to id's 00994 $this->dataLookup[$uid] = &$dataArr[$uid]; 00995 00996 if (is_array($val[$this->subLevelID])) { 00997 $this->setDataFromArray($dataArr[$uid][$this->subLevelID],TRUE,$uid); 00998 } 00999 } 01000 } 01001 01009 function setDataFromTreeArray(&$treeArr, &$treeLookupArr) { 01010 $this->data = &$treeArr; 01011 $this->dataLookup=&$treeLookupArr; 01012 } 01013 01014 01015 /* 01016 array( 01017 [id1] => array( 01018 'title'=>'title...', 01019 'id' => 'id1', 01020 'icon' => 'icon ref, relative to typo3/ folder...' 01021 ), 01022 [id2] => array( 01023 'title'=>'title...', 01024 'id' => 'id2', 01025 'icon' => 'icon ref, relative to typo3/ folder...' 01026 ), 01027 [id3] => array( 01028 'title'=>'title...', 01029 'id' => 'id3', 01030 'icon' => 'icon ref, relative to typo3/ folder...' 01031 $this->subLevelID => array( 01032 [id3_asdf#1] => array( 01033 'title'=>'title...', 01034 'id' => 'asdf#1', 01035 'icon' => 'icon ref, relative to typo3/ folder...' 01036 ), 01037 [5] => array( 01038 'title'=>'title...', 01039 'id' => 'id...', 01040 'icon' => 'icon ref, relative to typo3/ folder...' 01041 ), 01042 [6] => array( 01043 'title'=>'title...', 01044 'id' => 'id...', 01045 'icon' => 'icon ref, relative to typo3/ folder...' 01046 ), 01047 ) 01048 ), 01049 ) 01050 */ 01051 } 01052 01053 01054 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_treeview.php']) { 01055 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_treeview.php']); 01056 } 01057 ?>