Main Page | Directories | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages | Examples

class.t3lib_treeview.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 1999-2004 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']->quoteStr($uid, $this->table).'"'.
00837                      t3lib_BEfunc::deleteClause($this->table).
00838                      $this->clause, // whereClauseMightContainGroupOrderBy
00839                   '',
00840                   $this->orderByFields
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']->quoteStr($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 ?>

Generated on Sun Oct 3 01:05:51 2004 for TYPO3core 3.7.0 dev by  doxygen 1.3.8-20040913