[BUGFIX] Folder Tree does not respect _temp_ and _recycler_
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Tree / View / FolderTreeView.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 * Generate a folder tree
31 *
32 * Revised for TYPO3 3.6 November/2003 by Kasper Skårhøj
33 *
34 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
35 * @coauthor René Fritz <r.fritz@colorcube.de>
36 */
37 /**
38 * Extension class for the t3lib_treeView class, specially made for browsing folders in the File module
39 *
40 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
41 * @coauthor René Fritz <r.fritz@colorcube.de>
42 * @see class t3lib_treeView
43 */
44 class FolderTreeView extends \TYPO3\CMS\Backend\Tree\View\AbstractTreeView {
45
46 /**
47 * The users' file Storages
48 *
49 * @var \TYPO3\CMS\Core\Resource\ResourceStorage[]
50 */
51 protected $storages = NULL;
52
53 /**
54 * @var array
55 */
56 protected $storageHashNumbers;
57
58 /**
59 * Indicates, whether the AJAX call was successful,
60 * i.e. the requested page has been found
61 *
62 * @var boolean
63 */
64 protected $ajaxStatus = FALSE;
65
66 /**
67 * Constructor function of the class
68 */
69 public function __construct() {
70 parent::init();
71 $this->storages = $GLOBALS['BE_USER']->getFileStorages();
72 $this->treeName = 'folder';
73 // Don't apply any title
74 $this->titleAttrib = '';
75 $this->domIdPrefix = 'folder';
76 }
77
78 /**
79 * Generate the plus/minus icon for the browsable tree.
80 *
81 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject Entry folder object
82 * @param integer $subFolderCounter The current entry number
83 * @param integer $totalSubFolders The total number of entries. If equal to $a, a "bottom" element is returned.
84 * @param integer $nextCount The number of sub-elements to the current element.
85 * @param boolean $isExpanded The element was expanded to render subelements if this flag is set.
86 * @return string Image tag with the plus/minus icon.
87 * @internal
88 * @see t3lib_pageTree::PMicon()
89 */
90 public function PMicon(\TYPO3\CMS\Core\Resource\Folder $folderObject, $subFolderCounter, $totalSubFolders, $nextCount, $isExpanded) {
91 $PM = $nextCount ? ($isExpanded ? 'minus' : 'plus') : 'join';
92 $BTM = $subFolderCounter == $totalSubFolders ? 'bottom' : '';
93 $icon = '<img' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($this->backPath, ('gfx/ol/' . $PM . $BTM . '.gif'), 'width="18" height="16"') . ' alt="" />';
94 if ($nextCount) {
95 $cmd = $this->generateExpandCollapseParameter($this->bank, !$isExpanded, $folderObject);
96 $icon = $this->PMiconATagWrap($icon, $cmd, !$isExpanded);
97 }
98 return $icon;
99 }
100
101 /**
102 * Wrap the plus/minus icon in a link
103 *
104 * @param string $icon HTML string to wrap, probably an image tag.
105 * @param string $cmd Command for 'PM' get var
106 * @param boolean $isExpand Whether to be expanded
107 * @return string Link-wrapped input string
108 * @internal
109 */
110 public function PMiconATagWrap($icon, $cmd, $isExpand = TRUE) {
111 if ($this->thisScript) {
112 // Activates dynamic AJAX based tree
113 $js = htmlspecialchars('Tree.load(\'' . $cmd . '\', ' . intval($isExpand) . ', this);');
114 return '<a class="pm" onclick="' . $js . '">' . $icon . '</a>';
115 } else {
116 return $icon;
117 }
118 }
119
120 /**
121 * Wrapping the folder icon
122 *
123 * @param string $icon The image tag for the icon
124 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject The row for the current element
125 * @return string The processed icon input value.
126 * @internal
127 */
128 public function wrapIcon($icon, \TYPO3\CMS\Core\Resource\Folder $folderObject) {
129 // Add title attribute to input icon tag
130 $theFolderIcon = $this->addTagAttributes($icon, $this->titleAttrib ? $this->titleAttrib . '="' . $this->getTitleAttrib($folderObject) . '"' : '');
131 // Wrap icon in click-menu link.
132 if (!$this->ext_IconMode) {
133 $theFolderIcon = $GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon($theFolderIcon, $folderObject->getCombinedIdentifier(), '', 0);
134 } elseif (!strcmp($this->ext_IconMode, 'titlelink')) {
135 $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($folderObject) . '\',this,\'' . $this->domIdPrefix . $this->getId($folderObject) . '\',' . $this->bank . ');';
136 $theFolderIcon = '<a href="#" onclick="' . htmlspecialchars($aOnClick) . '">' . $theFolderIcon . '</a>';
137 }
138 return $theFolderIcon;
139 }
140
141 /**
142 * Wrapping $title in a-tags.
143 *
144 * @param string $title Title string
145 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject the folder record
146 * @param integer $bank Bank pointer (which mount point number)
147 * @return string
148 * @internal
149 */
150 public function wrapTitle($title, \TYPO3\CMS\Core\Resource\Folder $folderObject, $bank = 0) {
151 $aOnClick = 'return jumpTo(\'' . $this->getJumpToParam($folderObject) . '\', this, \'' . $this->domIdPrefix . $this->getId($folderObject) . '\', ' . $bank . ');';
152 $CSM = ' oncontextmenu="' . htmlspecialchars($GLOBALS['TBE_TEMPLATE']->wrapClickMenuOnIcon('', $folderObject->getCombinedIdentifier(), '', 0, ('&bank=' . $this->bank), '', TRUE)) . '"';
153 return '<a href="#" title="' . htmlspecialchars($title) . '" onclick="' . htmlspecialchars($aOnClick) . '"' . $CSM . '>' . $title . '</a>';
154 }
155
156 /**
157 * Returns the id from the record - for folders, this is an md5 hash.
158 *
159 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject The folder object
160 * @return integer The "uid" field value.
161 */
162 public function getId(\TYPO3\CMS\Core\Resource\Folder $folderObject) {
163 return \TYPO3\CMS\Core\Utility\GeneralUtility::md5Int($folderObject->getCombinedIdentifier());
164 }
165
166 /**
167 * Returns jump-url parameter value.
168 *
169 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject The folder object
170 * @return string The jump-url parameter.
171 */
172 public function getJumpToParam(\TYPO3\CMS\Core\Resource\Folder $folderObject) {
173 return rawurlencode($folderObject->getCombinedIdentifier());
174 }
175
176 /**
177 * Returns the title for the input record. If blank, a "no title" labele (localized) will be returned.
178 * '_title' is used for setting an alternative title for folders.
179 *
180 * @param array $row The input row array (where the key "_title" is used for the title)
181 * @param integer $titleLen Title length (30)
182 * @return string The title
183 */
184 public function getTitleStr($row, $titleLen = 30) {
185 return $row['_title'] ? $row['_title'] : parent::getTitleStr($row, $titleLen);
186 }
187
188 /**
189 * Returns the value for the image "title" attribute
190 *
191 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject The folder to be used
192 * @return string The attribute value (is htmlspecialchared() already)
193 * @todo Define visibility
194 */
195 public function getTitleAttrib(\TYPO3\CMS\Core\Resource\Folder $folderObject) {
196 return htmlspecialchars($folderObject->getName());
197 }
198
199 /**
200 * Will create and return the HTML code for a browsable tree of folders.
201 * Is based on the mounts found in the internal array ->MOUNTS (set in the constructor)
202 *
203 * @return string HTML code for the browsable tree
204 */
205 public function getBrowsableTree() {
206 // Get stored tree structure AND updating it if needed according to incoming PM GET var.
207 $this->initializePositionSaving();
208 // Init done:
209 $treeItems = array();
210 // Traverse mounts:
211 foreach ($this->storages as $storageObject) {
212 $this->getBrowseableTreeForStorage($storageObject);
213 // Add tree:
214 $treeItems = array_merge($treeItems, $this->tree);
215 // if this is an AJAX call, don't run through all mounts, only
216 // show the expansion of the current one, not the rest of the mounts
217 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
218
219 }
220 }
221 return $this->printTree($treeItems);
222 }
223
224 /**
225 * Get a tree for one storage
226 *
227 * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storageObject
228 * @return void
229 */
230 public function getBrowseableTreeForStorage(\TYPO3\CMS\Core\Resource\ResourceStorage $storageObject) {
231 // If there are filemounts, show each, otherwise just the rootlevel folder
232 $fileMounts = $storageObject->getFileMounts();
233 $rootLevelFolders = array();
234 if (count($fileMounts)) {
235 foreach ($fileMounts as $fileMountInfo) {
236 $rootLevelFolders[] = array(
237 'folder' => $fileMountInfo['folder'],
238 'name' => $fileMountInfo['title']
239 );
240 }
241 } else {
242 $rootLevelFolders[] = array(
243 'folder' => $storageObject->getRootLevelFolder(),
244 'name' => $storageObject->getName()
245 );
246 }
247 // Clean the tree
248 $this->reset();
249 // Go through all "root level folders" of this tree (can be the rootlevel folder or any file mount points)
250 foreach ($rootLevelFolders as $rootLevelFolderInfo) {
251 /** @var $rootLevelFolder \TYPO3\CMS\Core\Resource\Folder */
252 $rootLevelFolder = $rootLevelFolderInfo['folder'];
253 $rootLevelFolderName = $rootLevelFolderInfo['name'];
254 $folderHashSpecUID = \TYPO3\CMS\Core\Utility\GeneralUtility::md5int($rootLevelFolder->getCombinedIdentifier());
255 $this->specUIDmap[$folderHashSpecUID] = $rootLevelFolder->getCombinedIdentifier();
256 // Hash key
257 $storageHashNumber = $this->getShortHashNumberForStorage($storageObject, $rootLevelFolder);
258 // Set first:
259 $this->bank = $storageHashNumber;
260 $isOpen = $this->stored[$storageHashNumber][$folderHashSpecUID] || $this->expandFirst;
261 // Set PM icon:
262 $cmd = $this->generateExpandCollapseParameter($this->bank, !$isOpen, $rootLevelFolder);
263 if (!$storageObject->isBrowsable() || $this->getNumberOfSubfolders($storageObject->getRootLevelFolder()) === 0) {
264 $rootIcon = 'blank';
265 } elseif (!$isOpen) {
266 $rootIcon = 'plusonly';
267 } else {
268 $rootIcon = 'minusonly';
269 }
270 $icon = '<img' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($this->backPath, ('gfx/ol/' . $rootIcon . '.gif')) . ' alt="" />';
271 $firstHtml = $this->PM_ATagWrap($icon, $cmd);
272 // @todo: create sprite icons for user/group mounts etc
273 if ($storageObject->isBrowsable() === FALSE) {
274 $icon = 'apps-filetree-folder-locked';
275 } else {
276 $icon = 'apps-filetree-root';
277 }
278 // Mark a storage which is not online, as offline
279 // maybe someday there will be a special icon for this
280 if ($storageObject->isOnline() === FALSE) {
281 $rootLevelFolderName .= ' (' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file.xlf:sys_file_storage.isOffline') . ')';
282 }
283 // Preparing rootRec for the mount
284 $firstHtml .= $this->wrapIcon(\TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon($icon), $rootLevelFolder);
285 $row = array(
286 'uid' => $folderHashSpecUID,
287 'title' => $rootLevelFolderName,
288 'path' => $rootLevelFolder->getCombinedIdentifier(),
289 'folder' => $rootLevelFolder
290 );
291 // Add the storage root to ->tree
292 $this->tree[] = array(
293 'HTML' => $firstHtml,
294 'row' => $row,
295 'bank' => $this->bank,
296 // hasSub is TRUE when the root of the storage is expanded
297 'hasSub' => $isOpen && $storageObject->isBrowsable()
298 );
299 // If the mount is expanded, go down:
300 if ($isOpen && $storageObject->isBrowsable()) {
301 // Set depth:
302 $this->getFolderTree($rootLevelFolder, 999);
303 }
304 }
305 }
306
307 /**
308 * Fetches the data for the tree
309 *
310 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject the folderobject
311 * @param integer $depth Max depth (recursivity limit)
312 * @param string $type HTML-code prefix for recursive calls.
313 * @return integer The count of items on the level
314 * @see getBrowsableTree()
315 */
316 public function getFolderTree(\TYPO3\CMS\Core\Resource\Folder $folderObject, $depth = 999, $type = '') {
317 $depth = intval($depth);
318 // This generates the directory tree
319 $subFolders = $folderObject->getSubfolders();
320 sort($subFolders);
321 $totalSubFolders = count($subFolders);
322 $HTML = '';
323 $subFolderCounter = 0;
324 foreach ($subFolders as $subFolder) {
325 $subFolderCounter++;
326 // Reserve space.
327 $this->tree[] = array();
328 // Get the key for this space
329 end($this->tree);
330 $treeKey = key($this->tree);
331 $specUID = \TYPO3\CMS\Core\Utility\GeneralUtility::md5int($subFolder->getCombinedIdentifier());
332 $this->specUIDmap[$specUID] = $subFolder->getCombinedIdentifier();
333 $row = array(
334 'uid' => $specUID,
335 'path' => $subFolder->getCombinedIdentifier(),
336 'title' => $subFolder->getName(),
337 'folder' => $subFolder
338 );
339 // Make a recursive call to the next level
340 if ($depth > 1 && $this->expandNext($specUID)) {
341 $nextCount = $this->getFolderTree($subFolder, $depth - 1, $type);
342 // Set "did expand" flag
343 $isOpen = 1;
344 } else {
345 $nextCount = $this->getNumberOfSubfolders($subFolder);
346 // Clear "did expand" flag
347 $isOpen = 0;
348 }
349 // Set HTML-icons, if any:
350 if ($this->makeHTML) {
351 $HTML = $this->PMicon($subFolder, $subFolderCounter, $totalSubFolders, $nextCount, $isOpen);
352 if ($subFolder->checkActionPermission('write')) {
353 $type = '';
354 $overlays = array();
355 } else {
356 $type = 'readonly';
357 $overlays = array('status-overlay-locked' => array());
358 }
359 if ($isOpen) {
360 $icon = 'apps-filetree-folder-opened';
361 } else {
362 $icon = 'apps-filetree-folder-default';
363 }
364 if ($subFolder->getName() == '_temp_') {
365 $icon = 'apps-filetree-folder-temp';
366 $row['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:temp', TRUE);
367 $row['_title'] = '<strong>' . $row['title'] . '</strong>';
368 }
369 if ($subFolder->getName() == '_recycler_') {
370 $icon = 'apps-filetree-folder-recycler';
371 $row['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:recycler', TRUE);
372 $row['_title'] = '<strong>' . $row['title'] . '</strong>';
373 }
374 $icon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon($icon, array('title' => $subFolder->getIdentifier()), $overlays);
375 $HTML .= $this->wrapIcon($icon, $subFolder);
376 }
377 // Finally, add the row/HTML content to the ->tree array in the reserved key.
378 $this->tree[$treeKey] = array(
379 'row' => $row,
380 'HTML' => $HTML,
381 'hasSub' => $nextCount && $this->expandNext($specUID),
382 'isFirst' => $subFolderCounter == 1,
383 'isLast' => FALSE,
384 'invertedDepth' => $depth,
385 'bank' => $this->bank
386 );
387 }
388 if ($subFolderCounter > 0) {
389 $this->tree[$treeKey]['isLast'] = TRUE;
390 }
391 return $totalSubFolders;
392 }
393
394 /**
395 * Compiles the HTML code for displaying the structure found inside the ->tree array
396 *
397 * @param array|string $treeItems "tree-array" - if blank string, the internal ->tree array is used.
398 * @return string The HTML code for the tree
399 */
400 public function printTree($treeItems = '') {
401 $doExpand = FALSE;
402 $doCollapse = FALSE;
403 $ajaxOutput = '';
404 $titleLength = intval($this->BE_USER->uc['titleLen']);
405 if (!is_array($treeItems)) {
406 $treeItems = $this->tree;
407 }
408 $out = '
409 <!-- TYPO3 folder tree structure. -->
410 <ul class="tree" id="treeRoot">
411 ';
412 // Evaluate AJAX request
413 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX) {
414 list(, $expandCollapseCommand, $expandedFolderHash, ) = $this->evaluateExpandCollapseParameter();
415 if ($expandCollapseCommand == 1) {
416 // We don't know yet. Will be set later.
417 $invertedDepthOfAjaxRequestedItem = 0;
418 $doExpand = TRUE;
419 } else {
420 $doCollapse = TRUE;
421 }
422 }
423 // We need to count the opened <ul>'s every time we dig into another level,
424 // so we know how many we have to close when all children are done rendering
425 $closeDepth = array();
426 foreach ($treeItems as $treeItem) {
427 /** @var $folderObject \TYPO3\CMS\Core\Resource\Folder */
428 $folderObject = $treeItem['row']['folder'];
429 $classAttr = $treeItem['row']['_CSSCLASS'];
430 $folderIdentifier = $folderObject->getCombinedIdentifier();
431 // this is set if the AJAX request has just opened this folder (via the PM command)
432 $isExpandedFolderIdentifier = $expandedFolderHash == \TYPO3\CMS\Core\Utility\GeneralUtility::md5int($folderIdentifier);
433 $idAttr = htmlspecialchars($this->domIdPrefix . $this->getId($folderObject) . '_' . $treeItem['bank']);
434 $itemHTML = '';
435 // If this item is the start of a new level,
436 // then a new level <ul> is needed, but not in ajax mode
437 if ($treeItem['isFirst'] && !$doCollapse && !($doExpand && $isExpandedFolderIdentifier)) {
438 $itemHTML = '<ul>
439 ';
440 }
441 // Add CSS classes to the list item
442 if ($treeItem['hasSub']) {
443 $classAttr .= ' expanded';
444 }
445 if ($treeItem['isLast']) {
446 $classAttr .= ' last';
447 }
448 $itemHTML .= '
449 <li id="' . $idAttr . '" ' . ($classAttr ? ' class="' . trim($classAttr) . '"' : '') . '><div class="treeLinkItem">' . $treeItem['HTML'] . $this->wrapTitle($this->getTitleStr($treeItem['row'], $titleLength), $folderObject, $treeItem['bank']) . '</div>';
450 if (!$treeItem['hasSub']) {
451 $itemHTML .= '</li>
452 ';
453 }
454 // We have to remember if this is the last one
455 // on level X so the last child on level X+1 closes the <ul>-tag
456 if ($treeItem['isLast'] && !($doExpand && $isExpandedFolderIdentifier)) {
457 $closeDepth[$treeItem['invertedDepth']] = 1;
458 }
459 // If this is the last one and does not have subitems, we need to close
460 // the tree as long as the upper levels have last items too
461 if ($treeItem['isLast'] && !$treeItem['hasSub'] && !$doCollapse && !($doExpand && $isExpandedFolderIdentifier)) {
462 for ($i = $treeItem['invertedDepth']; $closeDepth[$i] == 1; $i++) {
463 $closeDepth[$i] = 0;
464 $itemHTML .= '</ul></li>
465 ';
466 }
467 }
468 // Ajax request: collapse
469 if ($doCollapse && $isExpandedFolderIdentifier) {
470 $this->ajaxStatus = TRUE;
471 return $itemHTML;
472 }
473 // Ajax request: expand
474 if ($doExpand && $isExpandedFolderIdentifier) {
475 $ajaxOutput .= $itemHTML;
476 $invertedDepthOfAjaxRequestedItem = $treeItem['invertedDepth'];
477 } elseif ($invertedDepthOfAjaxRequestedItem) {
478 if ($treeItem['invertedDepth'] < $invertedDepthOfAjaxRequestedItem) {
479 $ajaxOutput .= $itemHTML;
480 } else {
481 $this->ajaxStatus = TRUE;
482 return $ajaxOutput;
483 }
484 }
485 $out .= $itemHTML;
486 }
487 // If this is a AJAX request, output directly
488 if ($ajaxOutput) {
489 $this->ajaxStatus = TRUE;
490 return $ajaxOutput;
491 }
492 // Finally close the first ul
493 $out .= '</ul>
494 ';
495 return $out;
496 }
497
498 /**
499 * Counts the number of directories in a file path.
500 *
501 * @param string $file File path.
502 * @return integer
503 * @deprecated since TYPO3 6.0, as the folder objects do the counting automatically
504 */
505 public function getCount($file) {
506 \TYPO3\CMS\Core\Utility\GeneralUtility::logDeprecatedFunction();
507 // This generates the directory tree
508 $dirs = \TYPO3\CMS\Core\Utility\GeneralUtility::get_dirs($file);
509 $c = 0;
510 if (is_array($dirs)) {
511 $c = count($dirs);
512 }
513 return $c;
514 }
515
516 /**
517 * Counts the number of directories in a file path.
518 *
519 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject File path.
520 * @return integer
521 */
522 public function getNumberOfSubfolders(\TYPO3\CMS\Core\Resource\Folder $folderObject) {
523 $subFolders = $folderObject->getSubfolders();
524 return count($subFolders);
525 }
526
527 /**
528 * Get stored tree structure AND updating it if needed according to incoming PM GET var.
529 *
530 * @return void
531 * @access private
532 * @todo Define visibility
533 */
534 public function initializePositionSaving() {
535 // Get stored tree structure:
536 $this->stored = unserialize($this->BE_USER->uc['browseTrees'][$this->treeName]);
537 $this->getShortHashNumberForStorage();
538 // PM action:
539 // (If an plus/minus icon has been clicked,
540 // the PM GET var is sent and we must update the stored positions in the tree):
541 // 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
542 list($storageHashNumber, $doExpand, $numericFolderHash, $treeName) = $this->evaluateExpandCollapseParameter();
543 if ($treeName && $treeName == $this->treeName) {
544 if (in_array($storageHashNumber, $this->storageHashNumbers)) {
545 if ($doExpand == 1) {
546 // Set
547 $this->stored[$storageHashNumber][$numericFolderHash] = 1;
548 } else {
549 // Clear
550 unset($this->stored[$storageHashNumber][$numericFolderHash]);
551 }
552 $this->savePosition();
553 }
554 }
555 }
556
557 /**
558 * Helper method to map md5-hash to shorter number
559 *
560 * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storageObject
561 * @param \TYPO3\CMS\Core\Resource\Folder $startingPointFolder
562 * @return integer
563 */
564 protected function getShortHashNumberForStorage(\TYPO3\CMS\Core\Resource\ResourceStorage $storageObject = NULL, \TYPO3\CMS\Core\Resource\Folder $startingPointFolder = NULL) {
565 if (!$this->storageHashNumbers) {
566 $this->storageHashNumbers = array();
567 // Mapping md5-hash to shorter number:
568 $hashMap = array();
569 foreach ($this->storages as $storageUid => $storage) {
570 $fileMounts = $storage->getFileMounts();
571 if (count($fileMounts)) {
572 foreach ($fileMounts as $fileMount) {
573 $nkey = hexdec(substr(\TYPO3\CMS\Core\Utility\GeneralUtility::md5int($fileMount['folder']->getCombinedIdentifier()), 0, 4));
574 $this->storageHashNumbers[$storageUid . $fileMount['folder']->getCombinedIdentifier()] = $nkey;
575 }
576 } else {
577 $folder = $storage->getRootLevelFolder();
578 $nkey = hexdec(substr(\TYPO3\CMS\Core\Utility\GeneralUtility::md5int($folder->getCombinedIdentifier()), 0, 4));
579 $this->storageHashNumbers[$storageUid . $folder->getCombinedIdentifier()] = $nkey;
580 }
581 }
582 }
583 if ($storageObject) {
584 if ($startingPointFolder) {
585 return $this->storageHashNumbers[$storageObject->getUid() . $startingPointFolder->getCombinedIdentifier()];
586 } else {
587 return $this->storageHashNumbers[$storageObject->getUid()];
588 }
589 } else {
590 return NULL;
591 }
592 }
593
594 /**
595 * Gets the values from the Expand/Collapse Parameter (&PM)
596 * previously known as "PM" (plus/minus)
597 * PM action:
598 * (If an plus/minus icon has been clicked,
599 * the PM GET var is sent and we must update the stored positions in the tree):
600 * 0: mount key, 1: set/clear boolean, 2: item ID (cannot contain "_"), 3: treeName
601 *
602 * @param string $PM The "plus/minus" command
603 * @return array
604 */
605 protected function evaluateExpandCollapseParameter($PM = NULL) {
606 if ($PM === NULL) {
607 $PM = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('PM');
608 // IE takes anchor as parameter
609 if (($PMpos = strpos($PM, '#')) !== FALSE) {
610 $PM = substr($PM, 0, $PMpos);
611 }
612 }
613 // Take the first three parameters
614 list($mountKey, $doExpand, $folderIdentifier) = explode('_', $PM, 3);
615 // In case the folder identifier contains "_", we just need to get the fourth/last parameter
616 list($folderIdentifier, $treeName) = \TYPO3\CMS\Core\Utility\GeneralUtility::revExplode('_', $folderIdentifier, 2);
617 return array(
618 $mountKey,
619 $doExpand,
620 $folderIdentifier,
621 $treeName
622 );
623 }
624
625 /**
626 * Generates the "PM" string to sent to expand/collapse items
627 *
628 * @param string $mountKey The mount key / storage UID
629 * @param boolean $doExpand Whether to expand/collapse
630 * @param \TYPO3\CMS\Core\Resource\Folder $folderObject The folder object
631 * @param string $treeName The name of the tree
632 * @return string
633 */
634 protected function generateExpandCollapseParameter($mountKey = NULL, $doExpand = FALSE, \TYPO3\CMS\Core\Resource\Folder $folderObject = NULL, $treeName = NULL) {
635 $parts = array(
636 $mountKey !== NULL ? $mountKey : $this->bank,
637 $doExpand == 1 ? 1 : 0,
638 $folderObject !== NULL ? \TYPO3\CMS\Core\Utility\GeneralUtility::md5int($folderObject->getCombinedIdentifier()) : '',
639 $treeName !== NULL ? $treeName : $this->treeName
640 );
641 return implode('_', $parts);
642 }
643
644 /**
645 * Gets the AJAX status.
646 *
647 * @return boolean
648 */
649 public function getAjaxStatus() {
650 return $this->ajaxStatus;
651 }
652
653 }
654
655
656 ?>