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