"subLevel" is now "--subLevel--"
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_treeview.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2002 Kasper Skaarhoj (kasper@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains base class for creating a browsable array/page/folder tree in HTML
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 November/2003 by Kasper Skaarhoj
32 *
33 * @author Kasper Skaarhoj <kasper@typo3.com>
34 * @coauthor René Fritz <r.fritz@colorcube.de>
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 104: class t3lib_treeView
42 * 239: function init($clause='')
43 * 256: function reset()
44 * 269: function getBrowsableTree()
45 * 328: function printTree($treeArr='')
46 * 370: function PMicon($row,$a,$c,$nextCount,$exp)
47 * 392: function PM_ATagWrap($icon,$cmd,$bMark='')
48 * 409: function wrapTitle($title,$row)
49 * 422: function wrapIcon($icon,$row)
50 * 443: function addTagAttributes($icon,$attr)
51 * 455: function wrapStop($str,$row)
52 * 469: function getCount($uid)
53 * 491: function addField($field,$noCheck=0)
54 * 507: function expandNext($id)
55 * 517: function initializePositionSaving()
56 * 544: function savePosition()
57 *
58 * SECTION: Functions that might be overwritten by extended classes
59 * 573: function getRootRecord($uid)
60 * 583: function getRootIcon($rec)
61 * 595: function getRecord($uid)
62 * 609: function getId($row)
63 * 619: function getJumpToParm($row)
64 * 630: function getIcon($row)
65 * 648: function getTitleStr($row,$titleLen=30)
66 * 660: function getTitleAttrib($row)
67 *
68 * SECTION: Data handling
69 * 693: function getTree($uid, $depth=999, $depthData='',$blankLineCode='')
70 * 771: function getDataInit($parentId)
71 * 800: function getDataCount($res)
72 * 817: function getDataNext($res)
73 * 842: function getDataFree($res)
74 * 862: function setDataFromArray(&$dataArr,$traverse=FALSE,$pid=0)
75 *
76 * TOTAL FUNCTIONS: 29
77 * (This index is automatically created/updated by the extension "extdeveval")
78 *
79 */
80
81
82
83
84
85
86
87
88
89
90
91 require_once (PATH_t3lib.'class.t3lib_iconworks.php');
92 require_once (PATH_t3lib.'class.t3lib_befunc.php');
93 require_once (PATH_t3lib.'class.t3lib_div.php');
94
95 /**
96 * Base class for creating a browsable array/page/folder tree in HTML
97 *
98 * @author Kasper Skaarhoj <kasper@typo3.com>
99 * @coauthor René Fritz <r.fritz@colorcube.de>
100 * @package TYPO3
101 * @subpackage t3lib
102 * @see t3lib_browsetree, t3lib_pagetree, t3lib_foldertree
103 */
104 class t3lib_treeView {
105
106 // EXTERNAL, static:
107 var $expandFirst=0; // If set, the first element in the tree is always expanded.
108 var $expandAll=0; // If set, then ALL items will be expanded, regardless of stored settings.
109 var $thisScript=''; // Holds the current script to reload to.
110 var $titleAttrib = 'title'; // Which HTML attribute to use: alt/title. See init().
111 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.
112 var $addSelfId = 0; // If set, the id of the mounts will be added to the internal ids array
113 var $title='no title'; // Used if the tree is made of records (not folders for ex.)
114
115 /**
116 * Needs to be initialized with $GLOBALS['BE_USER']
117 * Done by default in init()
118 */
119 var $BE_USER='';
120
121 /**
122 * Needs to be initialized with e.g. $GLOBALS['WEBMOUNTS']
123 * Default setting in init() is 0 => 0
124 * The keys are mount-ids (can be anything basically) and the values are the ID of the root element (COULD be zero or anything else. For pages that would be the uid of the page, zero for the pagetree root.)
125 */
126 var $MOUNTS='';
127
128
129
130 /**
131 * Database table to get the tree data from.
132 * Leave blank if data comes from an array.
133 */
134 var $table='';
135
136 /**
137 * Defines the field of $table which is the parent id field (like pid for table pages).
138 */
139 var $parentField='pid';
140
141 /**
142 * WHERE clause used for selecting records for the tree. Is set by function init.
143 * Only makes sense when $this->table is set.
144 * @see init()
145 */
146 var $clause=' AND NOT deleted';
147
148 /**
149 * Default set of fields selected from the tree table.
150 * Make SURE that these fields names listed herein are actually possible to select from $this->table (if that variable is set to a TCA table name)
151 * @see addField()
152 */
153 var $fieldArray = Array('uid','title');
154
155 /**
156 * List of other fields which are ALLOWED to set (here, based on the "pages" table!)
157 * @see addField()
158 */
159 var $defaultList = 'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate,cruser_id';
160
161
162 /**
163 * Unique name for the tree.
164 * Used as key for storing the tree into the BE users settings.
165 * Used as key to pass parameters in links.
166 * MUST NOT contain underscore chars.
167 * etc.
168 */
169 var $treeName = '';
170 /**
171 * A prefix for table cell id's which will be wrapped around an item.
172 * Can be used for highlighting by JavaScript.
173 * Needs to be unique if multiple trees are on one HTML page.
174 * @see printTree()
175 */
176 var $domIdPrefix = 'row';
177
178 /**
179 * Back path for icons
180 */
181 var $backPath;
182
183 /**
184 * Icon file path.
185 */
186 var $iconPath = '';
187
188
189 /**
190 * Icon file name for item icons.
191 */
192 var $iconName = 'default.gif';
193
194 /**
195 * If true, HTML code is also accumulated in ->tree array during rendering of the tree.
196 */
197 var $makeHTML=1;
198
199 /**
200 * If true, records as selected will be stored internally in the ->recs array
201 */
202 var $setRecs = 0;
203
204
205
206
207
208 // *********
209 // Internal
210 // *********
211 // For record trees:
212 var $ids = Array(); // one-dim array of the uid's selected.
213 var $ids_hierarchy = array(); // The hierarchy of element uids
214 var $buffer_idH = array(); // Temporary, internal array
215
216 // For FOLDER trees:
217 var $specUIDmap=array(); // Special UIDs for folders (integer-hashes of paths)
218
219 // For arrays:
220 var $data = false; // Holds the input data array
221 var $dataLookup = false; // Holds an index with references to the data array.
222
223 // For both types
224 var $tree = Array(); // Tree is accumulated in this variable
225 var $stored = array(); // Holds (session stored) information about which items in the tree are unfolded and which are not.
226 var $bank=0; // Points to the current mountpoint key
227 var $recs = array(); // Accumulates the displayed records.
228
229
230
231
232
233
234
235 /**
236 * Initialize the tree class. Needs to be overwritten
237 * Will set ->fieldsArray, ->backPath and ->clause
238 *
239 * @param string record select clause
240 * @return void
241 */
242 function init($clause='') {
243 $this->BE_USER = $GLOBALS['BE_USER']; // Setting BE_USER by default
244 $this->titleAttrib = 'title'; // Setting title attribute to use.
245 $this->backPath = $GLOBALS['BACK_PATH']; // Setting backpath.
246
247 $this->clause = $clause ? $clause : $this->clause; // Setting clause
248
249 if (!is_array($this->MOUNTS)) {
250 $this->MOUNTS = array(0 => 0); // dummy
251 }
252
253 $this->setTreeName();
254
255 if($this->table) {
256 t3lib_div::loadTCA($this->table);
257 }
258 }
259
260
261 /**
262 * Sets the tree name which is used to identify the tree
263 * Used for JavaScript and other things
264 *
265 * @param string Default is the table name. Underscores are stripped.
266 * @return void
267 */
268 function setTreeName($treeName='') {
269 $this->treeName = $treeName ? $treeName : $this->treeName;
270 $this->treeName = $this->treeName ? $this->treeName : $this->table;
271 $this->treeName = str_replace('_','',$this->treeName);
272 }
273
274
275 /**
276 * Adds a fieldname to the internal array ->fieldArray
277 *
278 * @param string Field name to
279 * @param boolean If set, the fieldname will be set no matter what. Otherwise the field name must either be found as key in $TCA[$table]['columns'] or in the list ->defaultList
280 * @return void
281 */
282 function addField($field,$noCheck=0) {
283 global $TCA;
284 if ($noCheck || is_array($TCA[$this->table]['columns'][$field]) || t3lib_div::inList($this->defaultList,$field)) {
285 $this->fieldArray[]=$field;
286 }
287 }
288
289
290
291 /**
292 * Resets the tree, recs, ids, and ids_hierarchy internal variables. Use it if you need it.
293 *
294 * @return void
295 */
296 function reset() {
297 $this->tree = array();
298 $this->recs = array();
299 $this->ids = array();
300 $this->ids_hierarchy = array();
301
302 $This->data = false;
303 $this->dataLookup = false;
304 }
305
306
307 /*******************************************
308 *
309 * output
310 *
311 *******************************************/
312
313 /**
314 * Will create and return the HTML code for a browsable tree
315 * Is based on the mounts found in the internal array ->MOUNTS (set in the constructor)
316 *
317 * @return string HTML code for the browsable tree
318 */
319 function getBrowsableTree() {
320
321 // Get stored tree structure AND updating it if needed according to incoming PM GET var.
322 $this->initializePositionSaving();
323
324 // Init done:
325 $titleLen=intval($this->BE_USER->uc['titleLen']);
326 $treeArr=array();
327
328 // Traverse mounts:
329 foreach($this->MOUNTS as $idx => $uid) {
330
331 // Set first:
332 $this->bank=$idx;
333 $isOpen = $this->stored[$idx][$uid] || $this->expandFirst;
334
335 // Save ids while resetting everything else.
336 $curIds = $this->ids;
337 $this->reset();
338 $this->ids = $curIds;
339
340 // Set PM icon for root of mount:
341 $cmd=$this->bank.'_'.($isOpen?"0_":"1_").$uid.'_'.$this->treeName;
342 $icon='<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.($isOpen?'minus':'plus').'only.gif','width="18" height="16"').' alt="" />';
343 $firstHtml= $this->PM_ATagWrap($icon,$cmd);
344
345 // Preparing rootRec for the mount
346 if ($uid) {
347 $rootRec=$this->getRecord($uid);
348 $firstHtml.=$this->getIcon($rootRec);
349 } else {
350 // Artificial record for the tree root, id=0
351 $rootRec=$this->getRootRecord($uid);
352 $firstHtml.=$this->getRootIcon($rootRec);
353 }
354
355 // Add the root of the mount to ->tree
356 $this->tree[]=array('HTML'=>$firstHtml,'row'=>$rootRec,'bank'=>$this->bank);
357
358 // If the mount is expanded, go down:
359 if ($isOpen) {
360 // Set depth:
361 $depthD='<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/blank.gif','width="18" height="16"').' alt="" />';
362 if ($this->addSelfId) $this->ids[] = $uid;
363 $this->getTree($uid,999,$depthD);
364 }
365
366 // Add tree:
367 $treeArr=array_merge($treeArr,$this->tree);
368 }
369 return $this->printTree($treeArr);
370 }
371
372 /**
373 * Compiles the HTML code for displaying the structure found inside the ->tree array
374 *
375 * @param array "tree-array" - if blank string, the internal ->tree array is used.
376 * @return string The HTML code for the tree
377 */
378 function printTree($treeArr='') {
379 $titleLen=intval($this->BE_USER->uc['titleLen']);
380 if (!is_array($treeArr)) $treeArr=$this->tree;
381 $out='';
382
383 // put a table around it with IDs to access the rows from JS
384 // not a problem if you don't need it
385 // 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.
386 $out .= '
387
388 <!--
389 TYPO3 tree structure.
390 -->
391 <table cellpadding="0" cellspacing="0" border="0" id="typo3-tree">';
392
393 foreach($treeArr as $k => $v) {
394 $idAttr = htmlspecialchars($this->domIdPrefix.$this->getId($v['row']).'_'.$v['bank']);
395 $out.='
396 <tr>
397 <td id="'.$idAttr.'">'.
398 $v['HTML'].
399 $this->wrapTitle($this->getTitleStr($v['row'],$titleLen),$v['row'],$v['bank']).
400 '</td>
401 </tr>
402 ';
403 }
404 $out .= '
405 </table>';
406 return $out;
407 }
408
409
410
411 /*******************************************
412 *
413 * rendering parts
414 *
415 *******************************************/
416
417
418
419 /**
420 * Generate the plus/minus icon for the browsable tree.
421 *
422 * @param array record for the entry
423 * @param integer The current entry number
424 * @param integer The total number of entries. If equal to $a, a "bottom" element is returned.
425 * @param integer The number of sub-elements to the current element.
426 * @param boolean The element was expanded to render subelements if this flag is set.
427 * @return string Image tag with the plus/minus icon.
428 * @access private
429 * @see t3lib_pageTree::PMicon()
430 */
431 function PMicon($row,$a,$c,$nextCount,$exp) {
432 $PM = $nextCount ? ($exp?'minus':'plus') : 'join';
433 $BTM = ($a==$c)?'bottom':'';
434 $icon = '<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$PM.$BTM.'.gif','width="18" height="16"').' alt="" />';
435
436 if ($nextCount) {
437 $cmd=$this->bank.'_'.($exp?'0_':'1_').$row['uid'].'_'.$this->treeName;
438 $bMark=($this->bank.'_'.$row['uid']);
439 $icon = $this->PM_ATagWrap($icon,$cmd,$bMark);
440 }
441 return $icon;
442 }
443
444 /**
445 * Wrap the plus/minus icon in a link
446 *
447 * @param string HTML string to wrap, probably an image tag.
448 * @param string Command for 'PM' get var
449 * @param boolean If set, the link will have a anchor point (=$bMark) and a name attribute (=$bMark)
450 * @return string Link-wrapped input string
451 * @access private
452 */
453 function PM_ATagWrap($icon,$cmd,$bMark='') {
454 if ($this->thisScript) {
455 if ($bMark) {
456 $anchor = '#'.$bMark;
457 $name=' name="'.$bMark.'"';
458 }
459 $aUrl = $this->thisScript.'?PM='.$cmd.$anchor;
460 return '<a href="'.htmlspecialchars($aUrl).'"'.$name.'>'.$icon.'</a>';
461 } else {
462 return $icon;
463 }
464 }
465
466 /**
467 * Wrapping $title in a-tags.
468 *
469 * @param string Title string
470 * @param string Item record
471 * @return string
472 * @access private
473 */
474 function wrapTitle($title,$row,$bank=0) {
475 $aOnClick = 'return jumpTo('.$this->getJumpToParm($row).',this,\''.$this->domIdPrefix.$this->getId($row).'_'.$bank.'\');';
476 return '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.$title.'</a>';
477 }
478
479 /**
480 * Wrapping the image tag, $icon, for the row, $row (except for mount points)
481 *
482 * @param string The image tag for the icon
483 * @param array The row for the current element
484 * @return string The processed icon input value.
485 * @access private
486 */
487 function wrapIcon($icon,$row) {
488 return $icon;
489 }
490
491 /**
492 * Adds attributes to image tag.
493 *
494 * @param string Icon image tag
495 * @param string Attributes to add, eg. ' border="0"'
496 * @return string Image tag, modified with $attr attributes added.
497 */
498 function addTagAttributes($icon,$attr) {
499 return ereg_replace(' ?\/?>$','',$icon).' '.$attr.' />';
500 }
501
502 /**
503 * Adds a red "+" to the input string, $str, if the field "php_tree_stop" in the $row (pages) is set
504 *
505 * @param string Input string, like a page title for the tree
506 * @param array record row with "php_tree_stop" field
507 * @return string Modified string
508 * @access private
509 */
510 function wrapStop($str,$row) {
511 if ($row['php_tree_stop']) {
512 $str.='<span class="typo3-red">+ </span>';
513 }
514 return $str;
515 }
516
517
518
519
520
521
522 /*******************************************
523 *
524 * tree handling
525 *
526 *******************************************/
527
528
529 /**
530 * Returns true/false if the next level for $id should be expanded - based on data in $this->stored[][] and ->expandAll flag.
531 * Extending parent function
532 *
533 * @param integer record id/key
534 * @return boolean
535 * @access private
536 * @see t3lib_pageTree::expandNext()
537 */
538 function expandNext($id) {
539 return ($this->stored[$this->bank][$id] || $this->expandAll)? 1 : 0;
540 }
541
542 /**
543 * Get stored tree structure AND updating it if needed according to incoming PM GET var.
544 *
545 * @return void
546 * @access private
547 */
548 function initializePositionSaving() {
549 // Get stored tree structure:
550 $this->stored=unserialize($this->BE_USER->uc['browseTrees'][$this->treeName]);
551
552 // PM action
553 // (If an plus/minus icon has been clicked, the PM GET var is sent and we must update the stored positions in the tree):
554 $PM = explode('_',t3lib_div::GPvar('PM')); // 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
555 if (count($PM)==4 && $PM[3]==$this->treeName) {
556 if (isset($this->MOUNTS[$PM[0]])) {
557 if ($PM[1]) { // set
558 $this->stored[$PM[0]][$PM[2]]=1;
559 $this->savePosition();
560 } else { // clear
561 unset($this->stored[$PM[0]][$PM[2]]);
562 $this->savePosition();
563 }
564 }
565 }
566 }
567
568 /**
569 * Saves the content of ->stored (keeps track of expanded positions in the tree)
570 * $this->treeName will be used as key for BE_USER->uc[] to store it in
571 *
572 * @return void
573 * @access private
574 */
575 function savePosition() {
576 $this->BE_USER->uc['browseTrees'][$this->treeName] = serialize($this->stored);
577 $this->BE_USER->writeUC();
578 }
579
580
581
582
583
584
585
586
587
588
589
590
591
592 /******************************
593 *
594 * Functions that might be overwritten by extended classes
595 *
596 ********************************/
597
598 /**
599 * Returns the root icon for a tree/mountpoint (defaults to the globe)
600 *
601 * @param array Record for root.
602 * @return string Icon image tag.
603 */
604 function getRootIcon($rec) {
605 return $this->wrapIcon('<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/i/_icon_website.gif','width="18" height="16"').' alt="" />',$rec);
606 }
607
608
609
610 /**
611 * Get icon for the row.
612 * If $this->iconPath and $this->iconName is set, try to get icon based on those values.
613 *
614 * @param array Item row.
615 * @return string Image tag.
616 */
617 function getIcon($row) {
618 if ($this->iconPath && $this->iconName) {
619 $icon = '<img'.t3lib_iconWorks::skinImg('',$this->iconPath.$this->iconName,'width="18" height="16"').' alt="" />';
620 } else {
621 $icon = t3lib_iconWorks::getIconImage($this->table,$row,$this->backPath,'align="top" class="c-recIcon"');
622 }
623
624 return $this->wrapIcon($icon,$row);
625 }
626
627
628 /**
629 * Returns the title for the input record. If blank, a "no title" labele (localized) will be returned.
630 * Do NOT htmlspecialchar the string from this function - has already been done.
631 *
632 * @param array The input row array (where the key "title" is used for the title)
633 * @param integer Title length (30)
634 * @return string The title.
635 */
636 function getTitleStr($row,$titleLen=30) {
637 $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($row['title'],$titleLen));
638 return $title;
639 }
640
641 /**
642 * Returns the value for the image "title" attribute
643 *
644 * @param array The input row array (where the key "title" is used for the title)
645 * @return string The attribute value (is htmlspecialchared() already)
646 * @see wrapIcon()
647 */
648 function getTitleAttrib($row) {
649 return htmlspecialchars($row['title']);
650 }
651
652 /**
653 * Returns the id from the record (typ. uid)
654 *
655 * @param array Record array
656 * @return integer The "uid" field value.
657 */
658 function getId($row) {
659 return $row['uid'];
660 }
661
662 /**
663 * Returns jump-url parameter value.
664 *
665 * @param array The record array.
666 * @return string The jump-url parameter.
667 */
668 function getJumpToParm($row) {
669 return "'".$this->getId($row)."'";
670 }
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686 /********************************
687 *
688 * tree data buidling
689 *
690 ********************************/
691
692 /**
693 * Fetches the data for the tree
694 *
695 * @param integer item id for which to select subitems (parent id)
696 * @param integer Max depth (recursivity limit)
697 * @param string HTML-code prefix for recursive calls.
698 * @param string ? (internal)
699 * @return integer The count of items on the level
700 */
701 function getTree($uid, $depth=999, $depthData='',$blankLineCode='') {
702 // Buffer for id hierarchy is reset:
703 $this->buffer_idH=array();
704
705
706 // Init vars
707 $depth=intval($depth);
708 $HTML='';
709 $a=0;
710
711 $res = $this->getDataInit($uid);
712 $c = $this->getDataCount($res);
713 $crazyRecursionLimiter = 999;
714
715 // Traverse the records:
716 while ($crazyRecursionLimiter>0 && $row = $this->getDataNext($res)) {
717 $a++;
718 $crazyRecursionLimiter--;
719
720 $newID =$row['uid'];
721 $this->tree[]=array(); // Reserve space.
722 end($this->tree);
723 $treeKey = key($this->tree); // Get the key for this space
724 $LN = ($a==$c)?'blank':'line';
725
726 // If records should be accumulated, do so
727 if ($this->setRecs) {
728 $this->recs[$row['uid']] = $row;
729 }
730
731 // Accumulate the id of the element in the internal arrays
732 $this->ids[]=$idH[$row['uid']]['uid']=$row['uid'];
733 $this->ids_hierarchy[$depth][]=$row['uid'];
734
735 // Make a recursive call to the next level
736 if ($depth>1 && $this->expandNext($newID) && !$row['php_tree_stop']) {
737 $nextCount=$this->getTree(
738 $newID,
739 $depth-1,
740 $this->makeHTML?$depthData.'<img'.t3lib_iconWorks::skinImg($this->backPath,'gfx/ol/'.$LN.'.gif','width="18" height="16"').' alt="" />':'',
741 $blankLineCode.','.$LN
742 );
743 if (count($this->buffer_idH)) $idH[$row['uid']]['subrow']=$this->buffer_idH;
744 $exp=1; // Set "did expand" flag
745 } else {
746 $nextCount=$this->getCount($newID);
747 $exp=0; // Clear "did expand" flag
748 }
749
750 // Set HTML-icons, if any:
751 if ($this->makeHTML) {
752 $HTML = $depthData.$this->PMicon($row,$a,$c,$nextCount,$exp);
753 $HTML.=$this->wrapStop($this->getIcon($row),$row);
754 # $HTML.=$this->wrapStop($this->wrapIcon($this->getIcon($row),$row),$row);
755 }
756
757 // Finally, add the row/HTML content to the ->tree array in the reserved key.
758 $this->tree[$treeKey] = Array(
759 'row'=>$row,
760 'HTML'=>$HTML,
761 'invertedDepth'=>$depth,
762 'blankLineCode'=>$blankLineCode,
763 'bank' => $this->bank
764 );
765 }
766
767 $this->getDataFree($res);
768 $this->buffer_idH=$idH;
769 return $c;
770 }
771
772
773
774 /********************************
775 *
776 * Data handling
777 * Works with records and arrays
778 *
779 ********************************/
780
781
782
783 /**
784 * Returns the number of records having the parent id, $uid
785 *
786 * @param integer id to count subitems for
787 * @return integer
788 * @access private
789 */
790 function getCount($uid) {
791 if (is_array($this->data)) {
792 $res = $this->getDataInit($uid);
793 return $this->getDataCount($res);
794 } else {
795 $query = 'SELECT count(*) FROM '.$this->table.
796 ' WHERE '.$this->parentField.'="'.addslashes($uid).'"'.
797 $this->clause;
798 $res = mysql(TYPO3_db, $query);
799 $row=mysql_fetch_row($res);
800 return $row[0];
801 }
802 }
803
804
805
806 /**
807 * Returns root record for uid (<=0)
808 *
809 * @param integer uid, <= 0 (normally, this does not matter)
810 * @return array Array with title/uid keys with values of $this->title/0 (zero)
811 */
812 function getRootRecord($uid) {
813 return array('title'=>$this->title, 'uid'=>0);
814 }
815
816
817 /**
818 * Returns the record for a uid.
819 * For tables: Looks up the record in the database.
820 * For arrays: Returns the fake record for uid id.
821 *
822 * @param integer UID to look up
823 * @return array The record
824 */
825 function getRecord($uid) {
826 if (is_array($this->data)) {
827 return $this->dataLookup[$uid];
828 } else {
829 return t3lib_befunc::getRecord($this->table,$uid);
830 }
831 }
832
833 /**
834 * Getting the tree data: Selecting/Initializing data pointer to items for a certain parent id.
835 * For tables: This will make a database query to select all children to "parent"
836 * For arrays: This will return key to the ->dataLookup array
837 *
838 * @param integer parent item id
839 * @return mixed data handle (Tables: An sql-resource, arrays: A parentId integer. -1 is returned if there were NO subLevel.)
840 * @access private
841 */
842 function getDataInit($parentId) {
843 if (is_array($this->data)) {
844 if (!is_array($this->dataLookup[$parentId]['--subLevel--'])) {
845 $parentId = -1;
846 } else {
847 reset($this->dataLookup[$parentId]['--subLevel--']);
848 }
849 return $parentId;
850 } else {
851 $query = 'SELECT '.implode($this->fieldArray,',').' FROM '.$this->table.
852 ' WHERE '.$this->parentField.'="'.addslashes($parentId).'"'.
853 $this->clause;
854 $res = mysql(TYPO3_db, $query);
855 if (mysql_error()) {
856 echo mysql_error();
857 debug($query);
858 }
859 return $res;
860 }
861 }
862
863 /**
864 * Getting the tree data: Counting elements in resource
865 *
866 * @param mixed data handle
867 * @return integer number of items
868 * @access private
869 * @see getDataInit()
870 */
871 function getDataCount($res) {
872 if (is_array($this->data)) {
873 return count($this->dataLookup[$res]['--subLevel--']);
874 } else {
875 $c=mysql_num_rows($res);
876 return $c;
877 }
878 }
879
880 /**
881 * Getting the tree data: next entry
882 *
883 * @param mixed data handle
884 * @return array item data array OR FALSE if end of elements.
885 * @access private
886 * @see getDataInit()
887 */
888 function getDataNext($res){
889 if (is_array($this->data)) {
890 if ($res<0) {
891 $row=FALSE;
892 } else {
893 list(,$row) = each($this->dataLookup[$res]['--subLevel--']);
894 }
895 return $row;
896 } else {
897 return @mysql_fetch_assoc($res);
898 }
899 }
900
901 /**
902 * Getting the tree data: frees data handle
903 *
904 * @param mixed data handle
905 * @return void
906 * @access private
907 */
908 function getDataFree($res){
909 if (is_array($this->data)) {
910 # unset();
911 } else {
912 mysql_free_result($res);
913 }
914 }
915
916 /**
917 * Used to initialize class with an array to browse.
918 * The array inputted will be traversed and an internal index for lookup is created.
919 * The keys of the input array are perceived as "uid"s of records which means that keys GLOBALLY must be unique like uids are.
920 * "uid" and "pid" "fakefields" are also set in each record.
921 * All other fields are optional.
922 *
923 * @param array The input array, see examples below in this script.
924 * @param boolean Internal, for recursion.
925 * @param integer Internal, for recursion.
926 * @return void
927 */
928 function setDataFromArray(&$dataArr,$traverse=FALSE,$pid=0) {
929 if (!$traverse) {
930 $this->data = &$dataArr;
931 $this->dataLookup=array();
932 // add root
933 $this->dataLookup[0]['subLevel']=&$dataArr;
934 $this->dataLookup[0]['--subLevel--']=&$dataArr;
935 }
936
937 foreach($dataArr as $uid => $val) {
938
939 $dataArr[$uid]['uid']=$uid;
940 $dataArr[$uid]['pid']=$pid;
941
942 // gives quick access to id's
943 $this->dataLookup[$uid] = &$dataArr[$uid];
944
945 if (is_array($val['--subLevel--'])) {
946 $this->setDataFromArray($dataArr[$uid]['--subLevel--'],TRUE,$uid);
947 unset($dataArr[$uid]['--subLevel--']);
948 }
949 }
950 if (!$traverse) {
951 $this->data = &$dataArr;
952
953 }
954
955 }
956
957 function setDataFromTreeArray(&$treeArr, &$treeLookupArr) {
958 $this->data = &$treeArr;
959 $this->dataLookup=&$treeLookupArr;
960 }
961
962
963 /*
964 array(
965 [id1] => array(
966 'title'=>'title...',
967 'id' => 'id1',
968 'icon' => 'icon ref, relative to typo3/ folder...'
969 ),
970 [id2] => array(
971 'title'=>'title...',
972 'id' => 'id2',
973 'icon' => 'icon ref, relative to typo3/ folder...'
974 ),
975 [id3] => array(
976 'title'=>'title...',
977 'id' => 'id3',
978 'icon' => 'icon ref, relative to typo3/ folder...'
979 '--subLevel--' => array(
980 [id3_asdf#1] => array(
981 'title'=>'title...',
982 'id' => 'asdf#1',
983 'icon' => 'icon ref, relative to typo3/ folder...'
984 ),
985 [5] => array(
986 'title'=>'title...',
987 'id' => 'id...',
988 'icon' => 'icon ref, relative to typo3/ folder...'
989 ),
990 [6] => array(
991 'title'=>'title...',
992 'id' => 'id...',
993 'icon' => 'icon ref, relative to typo3/ folder...'
994 ),
995 )
996 ),
997 )
998 */
999 }
1000
1001
1002
1003
1004 class t3lib_TCEforms_SelectTreeView extends t3lib_treeview {
1005
1006 function wrapTitle($title,$v) {
1007 if($v['uid']>0) {
1008 $aOnClick = 'setFormValueFromBrowseWin(\''.$this->TCEforms_itemFormElName.'\','.$v['uid'].',\''.$title.'\'); return false;';
1009 return '<a href="#" onclick="'.htmlspecialchars($aOnClick).'">'.$title.'</a>';
1010 } else {
1011 return $title;
1012 }
1013 }
1014 }
1015
1016
1017
1018
1019 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_treeview.php']) {
1020 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_treeview.php']);
1021 }
1022 ?>