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