TYPO3 CMS  TYPO3_6-2
PageTreeView.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Backend\View;
3 
19 
27 
32 
36  public $ext_IconMode;
37 
42 
47 
48  // Indicates, whether the ajax call was successful, i.e. the requested page has been found
52  public $ajaxStatus = FALSE;
53 
59  public function __construct() {
60  $this->init();
61  }
62 
71  public function wrapIcon($thePageIcon, &$row) {
72  // If the record is locked, present a warning sign.
73  if ($lockInfo = \TYPO3\CMS\Backend\Utility\BackendUtility::isRecordLocked('pages', $row['uid'])) {
74  $aOnClick = 'alert(' . GeneralUtility::quoteJSvalue($lockInfo['msg']) . ');return false;';
75  $lockIcon = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . IconUtility::getSpriteIcon('status-warning-in-use', array('title' => $lockInfo['msg'])) . '</a>';
76  } else {
77  $lockIcon = '';
78  }
79  // Wrap icon in click-menu link.
80  if (!$this->ext_IconMode) {
81  $thePageIcon = $GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon($thePageIcon, 'pages', $row['uid'], 0, '&bank=' . $this->bank);
82  } elseif ($this->ext_IconMode === 'titlelink') {
83  $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($row) . '\',this,\'' . $this->treeName . '\');';
84  $thePageIcon = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $thePageIcon . '</a>';
85  }
86  // Wrap icon in a drag/drop span.
87  $dragDropIcon = '<span class="dragIcon" id="dragIconID_' . $row['uid'] . '">' . $thePageIcon . '</span>';
88  // Add Page ID:
89  $pageIdStr = '';
90  if ($this->ext_showPageId) {
91  $pageIdStr = '<span class="dragId">[' . $row['uid'] . ']</span> ';
92  }
93  // Call stats information hook
94  $stat = '';
95  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
96  $_params = array('pages', $row['uid']);
97  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) {
98  $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
99  }
100  }
101  return $dragDropIcon . $lockIcon . $pageIdStr . $stat;
102  }
103 
113  public function wrapStop($str, $row) {
114  if ($row['php_tree_stop']) {
115  $str .= '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('setTempDBmount' => $row['uid']))) . '" class="typo3-red">+</a> ';
116  }
117  return $str;
118  }
119 
130  public function wrapTitle($title, $row, $bank = 0) {
131  // Hook for overriding the page title
132  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.webpagetree.php']['pageTitleOverlay'])) {
133  $_params = array('title' => &$title, 'row' => &$row);
134  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.webpagetree.php']['pageTitleOverlay'] as $_funcRef) {
135  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
136  }
137  unset($_params);
138  }
139  $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($row) . '\',this,\'' . $this->domIdPrefix . $this->getId($row) . '\',' . $bank . ');';
140  $CSM = ' oncontextmenu="' . htmlspecialchars($GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon('', 'pages', $row['uid'], 0, ('&bank=' . $this->bank), '', TRUE)) . ';"';
141  $thePageTitle = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '"' . $CSM . '>' . $title . '</a>';
142  // Wrap title in a drag/drop span.
143  return '<span class="dragTitle" id="dragTitleID_' . $row['uid'] . '">' . $thePageTitle . '</span>';
144  }
145 
153  public function printTree($treeArr = '') {
154  $titleLen = (int)$this->BE_USER->uc['titleLen'];
155  if (!is_array($treeArr)) {
156  $treeArr = $this->tree;
157  }
158  $out = '
159  <!-- TYPO3 tree structure. -->
160  <ul class="tree" id="treeRoot">
161  ';
162  // -- evaluate AJAX request
163  // IE takes anchor as parameter
164  $PM = GeneralUtility::_GP('PM');
165  if (($PMpos = strpos($PM, '#')) !== FALSE) {
166  $PM = substr($PM, 0, $PMpos);
167  }
168  $PM = explode('_', $PM);
169  if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX && is_array($PM) && count($PM) == 4 && $PM[2] != 0) {
170  if ($PM[1]) {
171  $expandedPageUid = $PM[2];
172  $ajaxOutput = '';
173  // We don't know yet. Will be set later.
174  $invertedDepthOfAjaxRequestedItem = 0;
175  $doExpand = TRUE;
176  } else {
177  $collapsedPageUid = $PM[2];
178  $doCollapse = TRUE;
179  }
180  }
181  // We need to count the opened <ul>'s every time we dig into another level,
182  // so we know how many we have to close when all children are done rendering
183  $closeDepth = array();
184  foreach ($treeArr as $k => $v) {
185  $classAttr = $v['row']['_CSSCLASS'];
186  $uid = $v['row']['uid'];
187  $idAttr = htmlspecialchars($this->domIdPrefix . $this->getId($v['row']) . '_' . $v['bank']);
188  $itemHTML = '';
189  // If this item is the start of a new level,
190  // then a new level <ul> is needed, but not in ajax mode
191  if ($v['isFirst'] && !$doCollapse && !($doExpand && $expandedPageUid == $uid)) {
192  $itemHTML = '<ul>';
193  }
194  // Add CSS classes to the list item
195  if ($v['hasSub']) {
196  $classAttr .= $classAttr ? ' expanded' : 'expanded';
197  }
198  if ($v['isLast']) {
199  $classAttr .= $classAttr ? ' last' : 'last';
200  }
201  $itemHTML .= '
202  <li id="' . $idAttr . '"' . ($classAttr ? ' class="' . $classAttr . '"' : '') . '><div class="treeLinkItem">' . $v['HTML'] . $this->wrapTitle($this->getTitleStr($v['row'], $titleLen), $v['row'], $v['bank']) . '</div>
203 ';
204  if (!$v['hasSub']) {
205  $itemHTML .= '</li>';
206  }
207  // We have to remember if this is the last one
208  // on level X so the last child on level X+1 closes the <ul>-tag
209  if ($v['isLast'] && !($doExpand && $expandedPageUid == $uid)) {
210  $closeDepth[$v['invertedDepth']] = 1;
211  }
212  // If this is the last one and does not have subitems, we need to close
213  // the tree as long as the upper levels have last items too
214  if ($v['isLast'] && !$v['hasSub'] && !$doCollapse && !($doExpand && $expandedPageUid == $uid)) {
215  for ($i = $v['invertedDepth']; $closeDepth[$i] == 1; $i++) {
216  $closeDepth[$i] = 0;
217  $itemHTML .= '</ul></li>';
218  }
219  }
220  // Ajax request: collapse
221  if ($doCollapse && $collapsedPageUid == $uid) {
222  $this->ajaxStatus = TRUE;
223  return $itemHTML;
224  }
225  // ajax request: expand
226  if ($doExpand && $expandedPageUid == $uid) {
227  $ajaxOutput .= $itemHTML;
228  $invertedDepthOfAjaxRequestedItem = $v['invertedDepth'];
229  } elseif ($invertedDepthOfAjaxRequestedItem) {
230  if ($v['invertedDepth'] < $invertedDepthOfAjaxRequestedItem) {
231  $ajaxOutput .= $itemHTML;
232  } else {
233  $this->ajaxStatus = TRUE;
234  return $ajaxOutput;
235  }
236  }
237  $out .= $itemHTML;
238  }
239  if ($ajaxOutput) {
240  $this->ajaxStatus = TRUE;
241  return $ajaxOutput;
242  }
243  // Finally close the first ul
244  $out .= '</ul>';
245  return $out;
246  }
247 
261  public function PMicon($row, $a, $c, $nextCount, $exp) {
262  $PM = $nextCount ? ($exp ? 'minus' : 'plus') : 'join';
263  $BTM = $a == $c ? 'bottom' : '';
264  $icon = '<img' . IconUtility::skinImg($this->backPath, ('gfx/ol/' . $PM . $BTM . '.gif'), 'width="18" height="16"') . ' alt="" />';
265  if ($nextCount) {
266  $cmd = $this->bank . '_' . ($exp ? '0_' : '1_') . $row['uid'] . '_' . $this->treeName;
267  $icon = $this->PMiconATagWrap($icon, $cmd, !$exp);
268  }
269  return $icon;
270  }
271 
281  public function PMiconATagWrap($icon, $cmd, $isExpand = TRUE) {
282  if ($this->thisScript) {
283  // Activate dynamic ajax-based tree
284  $js = htmlspecialchars('Tree.load(\'' . $cmd . '\', ' . (int)$isExpand . ', this);');
285  return '<a class="pm" onclick="' . $js . '">' . $icon . '</a>';
286  } else {
287  return $icon;
288  }
289  }
290 
298  public function getBrowsableTree() {
299  // Get stored tree structure AND updating it if needed according to incoming PM GET var.
300  $this->initializePositionSaving();
301  // Init done:
302  $titleLen = (int)$this->BE_USER->uc['titleLen'];
303  $treeArr = array();
304  // Traverse mounts:
305  foreach ($this->MOUNTS as $idx => $uid) {
306  // Set first:
307  $this->bank = $idx;
308  $isOpen = $this->stored[$idx][$uid] || $this->expandFirst || $uid === '0';
309  // Save ids while resetting everything else.
310  $curIds = $this->ids;
311  $this->reset();
312  $this->ids = $curIds;
313  // Set PM icon for root of mount:
314  $cmd = $this->bank . '_' . ($isOpen ? '0_' : '1_') . $uid . '_' . $this->treeName;
315  // Only, if not for uid 0
316  if ($uid) {
317  $icon = '<img' . IconUtility::skinImg($this->backPath, ('gfx/ol/' . ($isOpen ? 'minus' : 'plus') . 'only.gif')) . ' alt="" />';
318  $firstHtml = $this->PMiconATagWrap($icon, $cmd, !$isOpen);
319  }
320  // Preparing rootRec for the mount
321  if ($uid) {
322  $rootRec = $this->getRecord($uid);
323  $firstHtml .= $this->getIcon($rootRec);
324  } else {
325  // Artificial record for the tree root, id=0
326  $rootRec = $this->getRootRecord($uid);
327  $firstHtml .= $this->getRootIcon($rootRec);
328  }
329  if (is_array($rootRec)) {
330  // In case it was swapped inside getRecord due to workspaces.
331  $uid = $rootRec['uid'];
332  // Add the root of the mount to ->tree
333  $this->tree[] = array('HTML' => $firstHtml, 'row' => $rootRec, 'bank' => $this->bank, 'hasSub' => TRUE, 'invertedDepth' => 1000);
334  // If the mount is expanded, go down:
335  if ($isOpen) {
336  // Set depth:
337  if ($this->addSelfId) {
338  $this->ids[] = $uid;
339  }
340  $this->getTree($uid, 999, '', $rootRec['_SUBCSSCLASS']);
341  }
342  // Add tree:
343  $treeArr = array_merge($treeArr, $this->tree);
344  }
345  }
346  return $this->printTree($treeArr);
347  }
348 
359  public function getTree($uid, $depth = 999, $blankLineCode = '', $subCSSclass = '') {
360  // Buffer for id hierarchy is reset:
361  $this->buffer_idH = array();
362  // Init vars
363  $depth = (int)$depth;
364  $HTML = '';
365  $a = 0;
366  $res = $this->getDataInit($uid, $subCSSclass);
367  $c = $this->getDataCount($res);
368  $crazyRecursionLimiter = 999;
369  $inMenuPages = array();
370  $outOfMenuPages = array();
371  $outOfMenuPagesTextIndex = array();
372  while ($crazyRecursionLimiter > 0 && ($row = $this->getDataNext($res, $subCSSclass))) {
373  $crazyRecursionLimiter--;
374  // Not in menu:
375  if ($this->ext_separateNotinmenuPages && ($row['doktype'] == \TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_BE_USER_SECTION || $row['doktype'] >= 200 || $row['nav_hide'])) {
376  $outOfMenuPages[] = $row;
377  $outOfMenuPagesTextIndex[] = ($row['doktype'] >= 200 ? 'zzz' . $row['doktype'] . '_' : '') . $row['title'];
378  } else {
379  $inMenuPages[] = $row;
380  }
381  }
382  $label_shownAlphabetically = '';
383  if (count($outOfMenuPages)) {
384  // Sort out-of-menu pages:
385  $outOfMenuPages_alphabetic = array();
386  if ($this->ext_alphasortNotinmenuPages) {
387  asort($outOfMenuPagesTextIndex);
388  $label_shownAlphabetically = ' (alphabetic)';
389  }
390  foreach ($outOfMenuPagesTextIndex as $idx => $txt) {
391  $outOfMenuPages_alphabetic[] = $outOfMenuPages[$idx];
392  }
393  // Merge:
394  $outOfMenuPages_alphabetic[0]['_FIRST_NOT_IN_MENU'] = TRUE;
395  $allRows = array_merge($inMenuPages, $outOfMenuPages_alphabetic);
396  } else {
397  $allRows = $inMenuPages;
398  }
399  // Traverse the records:
400  foreach ($allRows as $row) {
401  $a++;
402  $newID = $row['uid'];
403  // Reserve space.
404  $this->tree[] = array();
405  end($this->tree);
406  // Get the key for this space
407  $treeKey = key($this->tree);
408  $LN = $a == $c ? 'blank' : 'line';
409  // If records should be accumulated, do so
410  if ($this->setRecs) {
411  $this->recs[$row['uid']] = $row;
412  }
413  // Accumulate the id of the element in the internal arrays
414  $this->ids[] = ($idH[$row['uid']]['uid'] = $row['uid']);
415  $this->ids_hierarchy[$depth][] = $row['uid'];
416  // Make a recursive call to the next level
417  if ($depth > 1 && $this->expandNext($newID) && !$row['php_tree_stop']) {
418  $nextCount = $this->getTree($newID, $depth - 1, $blankLineCode . ',' . $LN, $row['_SUBCSSCLASS']);
419  if (count($this->buffer_idH)) {
420  $idH[$row['uid']]['subrow'] = $this->buffer_idH;
421  }
422  // Set "did expand" flag
423  $exp = 1;
424  } else {
425  $nextCount = $this->getCount($newID);
426  // Clear "did expand" flag
427  $exp = 0;
428  }
429  // Set HTML-icons, if any:
430  if ($this->makeHTML) {
431  if ($row['_FIRST_NOT_IN_MENU']) {
432  $HTML = '<img' . IconUtility::skinImg($this->backPath, 'gfx/ol/line.gif') . ' alt="" /><br/><img' . IconUtility::skinImg($this->backPath, 'gfx/ol/line.gif') . ' alt="" /><i>Not shown in menu' . $label_shownAlphabetically . ':</i><br>';
433  } else {
434  $HTML = '';
435  }
436  $HTML .= $this->PMicon($row, $a, $c, $nextCount, $exp);
437  $HTML .= $this->wrapStop($this->getIcon($row), $row);
438  }
439  // Finally, add the row/HTML content to the ->tree array in the reserved key.
440  $this->tree[$treeKey] = array(
441  'row' => $row,
442  'HTML' => $HTML,
443  'hasSub' => $nextCount && $this->expandNext($newID),
444  'isFirst' => $a == 1,
445  'isLast' => FALSE,
446  'invertedDepth' => $depth,
447  'blankLineCode' => $blankLineCode,
448  'bank' => $this->bank
449  );
450  }
451  if ($a) {
452  $this->tree[$treeKey]['isLast'] = TRUE;
453  }
454  $this->getDataFree($res);
455  $this->buffer_idH = $idH;
456  return $c;
457  }
458 
459 }
static skinImg($backPath, $src, $wHattribs='', $outputMode=0)
PMiconATagWrap($icon, $cmd, $isExpand=TRUE)
$uid
Definition: server.php:36
wrapTitle($title, $row, $bank=0)
init($clause='', $orderByFields='')
static getSpriteIcon($iconName, array $options=array(), array $overlays=array())
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
PMicon($row, $a, $c, $nextCount, $exp)