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