TYPO3 CMS  TYPO3_8-7
PageTreeView.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\View;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
22 
27 {
31  public $ext_showPageId = false;
32 
38  public $ajaxStatus = false;
39 
43  public function __construct()
44  {
45  parent::__construct();
46  $this->init();
47  }
48 
56  public function wrapIcon($thePageIcon, $row)
57  {
59  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
60  // If the record is locked, present a warning sign.
61  if ($lockInfo = BackendUtility::isRecordLocked('pages', $row['uid'])) {
62  $aOnClick = 'alert(' . GeneralUtility::quoteJSvalue($lockInfo['msg']) . ');return false;';
63  $lockIcon = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">'
64  . '<span title="' . htmlspecialchars($lockInfo['msg']) . '">' . $iconFactory->getIcon('status-warning-in-use', Icon::SIZE_SMALL)->render() . '</span></a>';
65  } else {
66  $lockIcon = '';
67  }
68  // Wrap icon in click-menu link.
69  if (!$this->ext_IconMode) {
70  $thePageIcon = BackendUtility::wrapClickMenuOnIcon($thePageIcon, 'pages', $row['uid'], 'tree');
71  } elseif ($this->ext_IconMode === 'titlelink') {
72  $aOnClick = 'return jumpTo(' . GeneralUtility::quoteJSvalue($this->getJumpToParam($row)) . ',this,' . GeneralUtility::quoteJSvalue($this->treeName) . ');';
73  $thePageIcon = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $thePageIcon . '</a>';
74  }
75  // Wrap icon in a drag/drop span.
76  $dragDropIcon = '<span class="list-tree-icon dragIcon" id="dragIconID_' . $row['uid'] . '">' . $thePageIcon . '</span> ';
77  // Add Page ID:
78  $pageIdStr = '';
79  if ($this->ext_showPageId) {
80  $pageIdStr = '<span class="dragId">[' . $row['uid'] . ']</span> ';
81  }
82  // Call stats information hook
83  $stat = '';
84  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
85  $_params = ['pages', $row['uid']];
86  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) {
87  $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
88  }
89  }
90  return $dragDropIcon . $lockIcon . $pageIdStr . $stat;
91  }
92 
102  public function wrapTitle($title, $row, $bank = 0)
103  {
104  // Hook for overriding the page title
105  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.webpagetree.php']['pageTitleOverlay'])) {
106  $_params = ['title' => &$title, 'row' => &$row];
107  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.webpagetree.php']['pageTitleOverlay'] as $_funcRef) {
108  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
109  }
110  unset($_params);
111  }
112  $aOnClick = 'return jumpTo(' . GeneralUtility::quoteJSvalue($this->getJumpToParam($row)) . ',this,' . GeneralUtility::quoteJSvalue($this->domIdPrefix . $this->getId($row)) . ',' . $bank . ');';
113  $clickMenuParts = BackendUtility::wrapClickMenuOnIcon('', 'pages', $row['uid'], 'tree', '', '', true);
114 
115  $thePageTitle = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '"' . GeneralUtility::implodeAttributes($clickMenuParts) . '>' . $title . '</a>';
116  // Wrap title in a drag/drop span.
117  return '<span class="list-tree-title dragTitle" id="dragTitleID_' . $row['uid'] . '">' . $thePageTitle . '</span>';
118  }
119 
126  public function printTree($treeArr = '')
127  {
128  $titleLen = (int)$this->BE_USER->uc['titleLen'];
129  if (!is_array($treeArr)) {
130  $treeArr = $this->tree;
131  }
132  $out = '<ul class="list-tree list-tree-root">';
133  // -- evaluate AJAX request
134  // IE takes anchor as parameter
135  $PM = GeneralUtility::_GP('PM');
136  if (($PMpos = strpos($PM, '#')) !== false) {
137  $PM = substr($PM, 0, $PMpos);
138  }
139  $PM = explode('_', $PM);
140 
141  $doCollapse = false;
142  $doExpand = false;
143  $expandedPageUid = null;
144  $collapsedPageUid = null;
145  if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX && is_array($PM) && count($PM) === 4 && $PM[2] != 0) {
146  if ($PM[1]) {
147  $expandedPageUid = $PM[2];
148  $doExpand = true;
149  } else {
150  $collapsedPageUid = $PM[2];
151  $doCollapse = true;
152  }
153  }
154  // We need to count the opened <ul>'s every time we dig into another level,
155  // so we know how many we have to close when all children are done rendering
156  $closeDepth = [];
157  $ajaxOutput = '';
158  $invertedDepthOfAjaxRequestedItem = 0;
159  foreach ($treeArr as $k => $treeItem) {
160  $classAttr = $treeItem['row']['_CSSCLASS'];
161  $uid = $treeItem['row']['uid'];
162  $idAttr = htmlspecialchars($this->domIdPrefix . $this->getId($treeItem['row']) . '_' . $treeItem['bank']);
163  $itemHTML = '';
164  // If this item is the start of a new level,
165  // then a new level <ul> is needed, but not in ajax mode
166  if ($treeItem['isFirst'] && !$doCollapse && (!$doExpand || (int)$expandedPageUid !== (int)$uid)) {
167  $itemHTML = '<ul class="list-tree">';
168  }
169 
170  // Add CSS classes to the list item
171  if ($treeItem['hasSub']) {
172  $classAttr .= ' list-tree-control-open';
173  }
174  $itemHTML .= '<li id="' . $idAttr . '" ' . ($classAttr ? ' class="' . trim($classAttr) . '"' : '')
175  . '><span class="list-tree-group">' . $treeItem['HTML']
176  . $this->wrapTitle($this->getTitleStr($treeItem['row'], $titleLen), $treeItem['row'], $treeItem['bank']) . '</span>';
177  if (!$treeItem['hasSub']) {
178  $itemHTML .= '</li>';
179  }
180 
181  // We have to remember if this is the last one
182  // on level X so the last child on level X+1 closes the <ul>-tag
183  if ($treeItem['isLast'] && !($doExpand && $expandedPageUid == $uid)) {
184  $closeDepth[$treeItem['invertedDepth']] = 1;
185  }
186  // If this is the last one and does not have subitems, we need to close
187  // the tree as long as the upper levels have last items too
188  if ($treeItem['isLast'] && !$treeItem['hasSub'] && !$doCollapse && !($doExpand && $expandedPageUid == $uid)) {
189  for ($i = $treeItem['invertedDepth']; $closeDepth[$i] == 1; $i++) {
190  $closeDepth[$i] = 0;
191  $itemHTML .= '</ul></li>';
192  }
193  }
194  // Ajax request: collapse
195  if ($doCollapse && (int)$collapsedPageUid === (int)$uid) {
196  $this->ajaxStatus = true;
197  return $itemHTML;
198  }
199  // ajax request: expand
200  if ($doExpand && (int)$expandedPageUid === (int)$uid) {
201  $ajaxOutput .= $itemHTML;
202  $invertedDepthOfAjaxRequestedItem = $treeItem['invertedDepth'];
203  } elseif ($invertedDepthOfAjaxRequestedItem) {
204  if ($treeItem['invertedDepth'] < $invertedDepthOfAjaxRequestedItem) {
205  $ajaxOutput .= $itemHTML;
206  } else {
207  $this->ajaxStatus = true;
208  return $ajaxOutput;
209  }
210  }
211  $out .= $itemHTML;
212  }
213  if ($ajaxOutput) {
214  $this->ajaxStatus = true;
215  return $ajaxOutput;
216  }
217  // Finally close the first ul
218  $out .= '</ul>';
219  return $out;
220  }
221 
234  public function PMicon($row, $a, $c, $nextCount, $exp)
235  {
236  $icon = '';
237  if ($nextCount) {
238  $cmd = $this->bank . '_' . ($exp ? '0_' : '1_') . $row['uid'] . '_' . $this->treeName;
239  $icon = $this->PMiconATagWrap($icon, $cmd, !$exp);
240  }
241  return $icon;
242  }
243 
253  public function PMiconATagWrap($icon, $cmd, $isExpand = true)
254  {
255  if ($this->thisScript) {
256  // Activate dynamic ajax-based tree
257  $js = htmlspecialchars('Tree.load(' . GeneralUtility::quoteJSvalue($cmd) . ', ' . (int)$isExpand . ', this);');
258  return '<a class="list-tree-control' . (!$isExpand ? ' list-tree-control-open' : ' list-tree-control-closed') . '" onclick="' . $js . '"><i class="fa"></i></a>';
259  }
260  return $icon;
261  }
262 
269  public function getBrowsableTree()
270  {
271  // Get stored tree structure AND updating it if needed according to incoming PM GET var.
272  $this->initializePositionSaving();
273  // Init done:
274  $treeArr = [];
275  // Traverse mounts:
276  $firstHtml = '';
277  foreach ($this->MOUNTS as $idx => $uid) {
278  // Set first:
279  $this->bank = $idx;
280  $isOpen = $this->stored[$idx][$uid] || $this->expandFirst || $uid === '0';
281  // Save ids while resetting everything else.
282  $curIds = $this->ids;
283  $this->reset();
284  $this->ids = $curIds;
285  // Only, if not for uid 0
286  if ($uid) {
287  // Set PM icon for root of mount:
288  $cmd = $this->bank . '_' . ($isOpen ? '0_' : '1_') . $uid . '_' . $this->treeName;
289  $firstHtml = '<a class="list-tree-control list-tree-control-' . ($isOpen ? 'open' : 'closed')
290  . '" href="' . htmlspecialchars($this->getThisScript() . 'PM=' . $cmd) . '"><i class="fa"></i></a>';
291  }
292  // Preparing rootRec for the mount
293  if ($uid) {
294  $rootRec = $this->getRecord($uid);
295  $firstHtml .= $this->getIcon($rootRec);
296  } else {
297  // Artificial record for the tree root, id=0
298  $rootRec = $this->getRootRecord();
299  $firstHtml .= $this->getRootIcon($rootRec);
300  }
301  if (is_array($rootRec)) {
302  // In case it was swapped inside getRecord due to workspaces.
303  $uid = $rootRec['uid'];
304  // Add the root of the mount to ->tree
305  $this->tree[] = ['HTML' => $firstHtml, 'row' => $rootRec, 'bank' => $this->bank, 'hasSub' => true, 'invertedDepth' => 1000];
306  // If the mount is expanded, go down:
307  if ($isOpen) {
308  // Set depth:
309  if ($this->addSelfId) {
310  $this->ids[] = $uid;
311  }
312  $this->getTree($uid);
313  }
314  // Add tree:
315  $treeArr = array_merge($treeArr, $this->tree);
316  }
317  }
318  return $this->printTree($treeArr);
319  }
320 }
static implodeAttributes(array $arr, $xhtmlSafe=false, $dontOmitBlankAttribs=false)
static wrapClickMenuOnIcon( $content, $table, $uid=0, $context='', $_addParams='', $_enDisItems='', $returnTagParameters=false)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
wrapTitle($title, $row, $bank=0)
init($clause='', $orderByFields='')
static makeInstance($className,... $constructorArguments)
getTree($uid, $depth=999, $depthData='')
PMiconATagWrap($icon, $cmd, $isExpand=true)
PMicon($row, $a, $c, $nextCount, $exp)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']