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