[TASK] Clean up tree code
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / Browser / ElementBrowser.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\Browser;
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\Form\FormEngine;
18 use TYPO3\CMS\Backend\RecordList\ElementBrowserRecordList;
19 use TYPO3\CMS\Backend\Template\DocumentTemplate;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Backend\Utility\IconUtility;
22 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
23 use TYPO3\CMS\Core\Database\DatabaseConnection;
24 use TYPO3\CMS\Core\ElementBrowser\ElementBrowserHookInterface;
25 use TYPO3\CMS\Core\Messaging\FlashMessage;
26 use TYPO3\CMS\Core\Page\PageRenderer;
27 use TYPO3\CMS\Core\Resource\Exception;
28 use TYPO3\CMS\Core\Resource\File;
29 use TYPO3\CMS\Core\Resource\FileInterface;
30 use TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter;
31 use TYPO3\CMS\Core\Resource\Folder;
32 use TYPO3\CMS\Core\Resource\InaccessibleFolder;
33 use TYPO3\CMS\Core\Resource\ProcessedFile;
34 use TYPO3\CMS\Core\Resource\ResourceFactory;
35 use TYPO3\CMS\Core\Utility\File\BasicFileUtility;
36 use TYPO3\CMS\Core\Utility\GeneralUtility;
37 use TYPO3\CMS\Core\Utility\StringUtility;
38 use TYPO3\CMS\Core\Utility\MathUtility;
39 use TYPO3\CMS\Frontend\Service\TypoLinkCodecService;
40 use TYPO3\CMS\Lang\LanguageService;
41
42 /**
43 * class for the Element Browser window.
44 */
45 class ElementBrowser {
46
47 /**
48 * Optional instance of a record list that TBE_expandPage() should
49 * use to render the records in a page
50 *
51 * @var ElementBrowserRecordList
52 */
53 protected $recordList = NULL;
54
55 /**
56 * Current site URL (Frontend)
57 *
58 * @var string
59 * @internal
60 */
61 public $siteURL;
62
63 /**
64 * the script to link to
65 *
66 * @var string
67 */
68 public $thisScript;
69
70 /**
71 * RTE specific TSconfig
72 *
73 * @var array[]
74 */
75 public $thisConfig;
76
77 /**
78 * Target (RTE specific)
79 *
80 * @var string
81 */
82 public $setTarget;
83
84 /**
85 * CSS Class (RTE specific)
86 *
87 * @var string
88 */
89 public $setClass;
90
91 /**
92 * title (RTE specific)
93 *
94 * @var string
95 */
96 public $setTitle;
97
98 /**
99 * @var string
100 */
101 public $setParams;
102
103 /**
104 * Backend template object
105 *
106 * @var DocumentTemplate
107 */
108 public $doc;
109
110 /**
111 * Holds information about files
112 *
113 * @var mixed[][]
114 */
115 public $elements = array();
116
117 /**
118 * The mode determines the main kind of output from the element browser.
119 * There are these options for values: rte, db, file, filedrag, wizard.
120 * "rte" will show the link selector for the Rich Text Editor (see main_rte())
121 * "db" will allow you to browse for pages or records in the page tree (for TCEforms, see main_db())
122 * "file"/"filedrag" will allow you to browse for files or folders in the folder mounts (for TCEforms, main_file())
123 * "wizard" will allow you to browse for links (like "rte") which are passed back to TCEforms (see main_rte(1))
124 *
125 * @see main()
126 * @var string
127 */
128 public $mode;
129
130 /**
131 * Link selector action.
132 * page,file,url,mail are allowed values.
133 * These are only important with the link selector function and in that case they switch
134 * between the various menu options.
135 *
136 * @var string
137 */
138 public $act;
139
140 /**
141 * When you click a page title/expand icon to see the content of a certain page, this
142 * value will contain that value (the ID of the expanded page). If the value is NOT set,
143 * then it will be restored from the module session data (see main(), mode="db")
144 *
145 * @var NULL|int
146 */
147 public $expandPage;
148
149 /**
150 * When you click a folder name/expand icon to see the content of a certain file folder,
151 * this value will contain that value (the path of the expanded file folder). If the
152 * value is NOT set, then it will be restored from the module session data (see main(),
153 * mode="file"/"filedrag"). Example value: "/www/htdocs/typo3/32/3dsplm/fileadmin/css/"
154 *
155 * @var string
156 */
157 public $expandFolder;
158
159 /**
160 * the folder object of a parent folder that was selected
161 *
162 * @var Folder
163 */
164 protected $selectedFolder;
165
166 /**
167 * TYPO3 Element Browser, wizard mode parameters. There is a heap of parameters there,
168 * better debug() them out if you need something... :-)
169 *
170 * @var array[]
171 */
172 public $P;
173
174 /**
175 * Active with TYPO3 Element Browser: Contains the name of the form field for which this window
176 * opens - thus allows us to make references back to the main window in which the form is.
177 * Example value: "data[pages][39][bodytext]|||tt_content|"
178 * or "data[tt_content][NEW3fba56fde763d][image]|||gif,jpg,jpeg,tif,bmp,pcx,tga,png,pdf,ai|"
179 *
180 * Values:
181 * 0: form field name reference, eg. "data[tt_content][123][image]"
182 * 1: htmlArea RTE parameters: editorNo:contentTypo3Language:contentTypo3Charset
183 * 2: RTE config parameters: RTEtsConfigParams
184 * 3: allowed types. Eg. "tt_content" or "gif,jpg,jpeg,tif,bmp,pcx,tga,png,pdf,ai"
185 * 4: IRRE uniqueness: target level object-id to perform actions/checks on, eg. "data[79][tt_address][1][<field>][<foreign_table>]"
186 * 5: IRRE uniqueness: name of function in opener window that checks if element is already used, eg. "inline.checkUniqueElement"
187 * 6: IRRE uniqueness: name of function in opener window that performs some additional(!) action, eg. "inline.setUniqueElement"
188 * 7: IRRE uniqueness: name of function in opener window that performs action instead of using addElement/insertElement, eg. "inline.importElement"
189 *
190 * $pArr = explode('|', $this->bparams);
191 * $formFieldName = $pArr[0];
192 * $allowedTablesOrFileTypes = $pArr[3];
193 *
194 * @var string
195 */
196 public $bparams;
197
198 /**
199 * Used with the Rich Text Editor.
200 * Example value: "tt_content:NEW3fba58c969f5c:bodytext:23:text:23:"
201 *
202 * @var string
203 */
204 public $RTEtsConfigParams;
205
206 /**
207 * Plus/Minus icon value. Used by the tree class to open/close notes on the trees.
208 *
209 * @var string
210 */
211 public $PM;
212
213 /**
214 * Pointer, used when browsing a long list of records etc.
215 *
216 * @var int
217 */
218 public $pointer;
219
220 /**
221 * Used with the link selector: Contains the GET input information about the CURRENT link
222 * in the RTE/TCEform field. This consists of "href", "target" and "title" keys.
223 * This information is passed around in links.
224 *
225 * @var array[]
226 */
227 public $curUrlArray;
228
229 /**
230 * Used with the link selector: Contains a processed version of the input values from curUrlInfo.
231 * This is splitted into pageid, content element id, label value etc.
232 * This is used for the internal processing of that information.
233 *
234 * @var array[]
235 */
236 public $curUrlInfo;
237
238 /**
239 * array which holds hook objects (initialised in init())
240 *
241 * @var ElementBrowserHookInterface[]
242 */
243 protected $hookObjects = array();
244
245 /**
246 * @var BasicFileUtility
247 */
248 public $fileProcessor;
249
250 /**
251 * @var PageRenderer
252 */
253 protected $pageRenderer = NULL;
254
255 /**
256 * Sets the script url depending on being a module or script request
257 */
258 protected function determineScriptUrl() {
259 if ($moduleName = GeneralUtility::_GP('M')) {
260 $this->thisScript = BackendUtility::getModuleUrl($moduleName);
261 } else {
262 $this->thisScript = GeneralUtility::getIndpEnv('SCRIPT_NAME');
263 }
264 }
265
266 /**
267 * Calculate path to this script.
268 * This method is public, to be used in hooks of this class only.
269 *
270 * @return string
271 */
272 public function getThisScript() {
273 return strpos($this->thisScript, '?') === FALSE ? $this->thisScript . '?' : $this->thisScript . '&';
274 }
275
276 /**
277 * Constructor:
278 * Initializes a lot of variables, setting JavaScript functions in header etc.
279 *
280 * @return void
281 * @throws \UnexpectedValueException
282 */
283 public function init() {
284 $this->initVariables();
285
286 $this->RTEtsConfigParams = GeneralUtility::_GP('RTEtsConfigParams');
287 $this->initConfiguration();
288 $this->initDocumentTemplate();
289 // init hook objects:
290 $this->initHookObjects('typo3/class.browse_links.php');
291
292 $this->initCurrentUrl();
293
294 // Determine nature of current url:
295 $this->act = GeneralUtility::_GP('act');
296 if (!$this->act) {
297 $this->act = $this->curUrlInfo['act'];
298 }
299
300 // Initializing the target value (RTE)
301 $this->setTarget = $this->curUrlArray['target'] != '-' ? $this->curUrlArray['target'] : '';
302 if ($this->thisConfig['defaultLinkTarget'] && !isset($this->curUrlArray['target'])) {
303 $this->setTarget = $this->thisConfig['defaultLinkTarget'];
304 }
305 // Initializing the class value (RTE)
306 $this->setClass = $this->curUrlArray['class'] != '-' ? $this->curUrlArray['class'] : '';
307 // Initializing the title value (RTE)
308 $this->setTitle = $this->curUrlArray['title'] != '-' ? $this->curUrlArray['title'] : '';
309 // Initializing the params value
310 $this->setParams = $this->curUrlArray['params'] != '-' ? $this->curUrlArray['params'] : '';
311
312 // Finally, add the accumulated JavaScript to the template object:
313 // also unset the default jumpToUrl() function before
314 unset($this->doc->JScodeArray['jumpToUrl']);
315 $this->doc->JScode .= $this->doc->wrapScriptTags($this->getJSCode());
316 }
317
318 /**
319 * Initialize class variables
320 *
321 * @return void
322 */
323 public function initVariables() {
324 // Main GPvars:
325 $this->pointer = GeneralUtility::_GP('pointer');
326 $this->bparams = GeneralUtility::_GP('bparams');
327 $this->P = GeneralUtility::_GP('P');
328 $this->expandPage = GeneralUtility::_GP('expandPage');
329 $this->expandFolder = GeneralUtility::_GP('expandFolder');
330 $this->PM = GeneralUtility::_GP('PM');
331
332 // Site URL
333 // Current site url
334 $this->siteURL = GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
335 $this->determineScriptUrl();
336
337 // Find "mode"
338 $this->mode = GeneralUtility::_GP('mode');
339 if (!$this->mode) {
340 $this->mode = 'rte';
341 }
342
343 // Init fileProcessor
344 $this->fileProcessor = GeneralUtility::makeInstance(BasicFileUtility::class);
345 $this->fileProcessor->init(array(), $GLOBALS['TYPO3_CONF_VARS']['BE']['fileExtensions']);
346 }
347
348 /**
349 * Initializes the configuration variables
350 *
351 * @return void
352 */
353 public function initConfiguration() {
354 // Rich Text Editor specific configuration:
355 if ((string)$this->mode === 'rte') {
356 $this->thisConfig = $this->getRTEConfig();
357 }
358 }
359
360 /**
361 * Initialize document template object
362 *
363 * @return void
364 */
365 protected function initDocumentTemplate() {
366 // Creating backend template object:
367 $this->doc = GeneralUtility::makeInstance(DocumentTemplate::class);
368 $this->doc->bodyTagId = 'typo3-browse-links-php';
369 $this->doc->backPath = $GLOBALS['BACK_PATH'];
370 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/BrowseLinks');
371 $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree');
372 }
373
374 /**
375 * Initialize hook objects implementing the interface
376 *
377 * @param string $hookKey the hook key
378 * @throws \UnexpectedValueException
379 * @return void
380 */
381 protected function initHookObjects($hookKey) {
382 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookKey]['browseLinksHook'])) {
383 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$hookKey]['browseLinksHook'] as $classData) {
384 $processObject = GeneralUtility::getUserObj($classData);
385 if (!$processObject instanceof ElementBrowserHookInterface) {
386 throw new \UnexpectedValueException('$processObject must implement interface ' . ElementBrowserHookInterface::class, 1195039394);
387 }
388 $parameters = array();
389 $processObject->init($this, $parameters);
390 $this->hookObjects[] = $processObject;
391 }
392 }
393 }
394
395 /**
396 * Initialize $this->curUrlArray and $this->curUrlInfo based on script parameters
397 *
398 * @return void
399 */
400 protected function initCurrentUrl() {
401 // CurrentUrl - the current link url must be passed around if it exists
402 if ($this->mode === 'wizard') {
403 $currentValues = GeneralUtility::trimExplode(LF, trim($this->P['currentValue']));
404 if (!empty($currentValues)) {
405 $currentValue = array_pop($currentValues);
406 } else {
407 $currentValue = '';
408 }
409 $currentLinkParts = GeneralUtility::makeInstance(TypoLinkCodecService::class)->decode($currentValue);
410
411 $initialCurUrlArray = array(
412 'href' => $currentLinkParts['url'],
413 'target' => $currentLinkParts['target'],
414 'class' => $currentLinkParts['class'],
415 'title' => $currentLinkParts['title'],
416 'params' => $currentLinkParts['additionalParams']
417 );
418 $this->curUrlArray = is_array(GeneralUtility::_GP('curUrl'))
419 ? array_merge($initialCurUrlArray, GeneralUtility::_GP('curUrl'))
420 : $initialCurUrlArray;
421 // Additional fields for page links
422 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['extendUrlArray'])
423 && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['extendUrlArray'])
424 ) {
425 $conf = array();
426 $_params = array(
427 'conf' => &$conf,
428 'linkParts' => [
429 // the hook expects old numerical indexes
430 $currentLinkParts['url'],
431 $currentLinkParts['target'],
432 $currentLinkParts['class'],
433 $currentLinkParts['title'],
434 $currentLinkParts['additionalParams']
435 ]
436 );
437 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['extendUrlArray'] as $objRef) {
438 $processor =& GeneralUtility::getUserObj($objRef);
439 $processor->extendUrlArray($_params, $this);
440 }
441 }
442 $this->curUrlInfo = $this->parseCurUrl($this->siteURL . '?id=' . $this->curUrlArray['href'], $this->siteURL);
443 // pageid == 0 means that this is not an internal (page) link
444 if ($this->curUrlInfo['pageid'] == 0 && $this->curUrlArray['href']) {
445 // Check if there is the FAL API
446 if (GeneralUtility::isFirstPartOfStr($this->curUrlArray['href'], 'file:')) {
447 $this->curUrlInfo = $this->parseCurUrl($this->curUrlArray['href'], $this->siteURL);
448 } elseif (file_exists(PATH_site . rawurldecode($this->curUrlArray['href']))) {
449 $this->curUrlInfo = $this->parseCurUrl($this->siteURL . $this->curUrlArray['href'], $this->siteURL);
450 } elseif (strstr($this->curUrlArray['href'], '@')) {
451 $this->curUrlInfo = $this->parseCurUrl('mailto:' . $this->curUrlArray['href'], $this->siteURL);
452 } else {
453 // nothing of the above. this is an external link
454 if (strpos($this->curUrlArray['href'], '://') === FALSE) {
455 $currentLinkParts['url'] = 'http://' . $this->curUrlArray['href'];
456 }
457 $this->curUrlInfo = $this->parseCurUrl($currentLinkParts['url'], $this->siteURL);
458 }
459 } elseif (!$this->curUrlArray['href']) {
460 $this->curUrlInfo = array();
461 $this->act = 'page';
462 } else {
463 $this->curUrlInfo = $this->parseCurUrl($this->siteURL . '?id=' . $this->curUrlArray['href'], $this->siteURL);
464 }
465 } else {
466 $this->curUrlArray = GeneralUtility::_GP('curUrl');
467 if ($this->curUrlArray['all']) {
468 $this->curUrlArray = GeneralUtility::get_tag_attributes($this->curUrlArray['all']);
469 }
470 $this->curUrlInfo = $this->parseCurUrl($this->curUrlArray['href'], $this->siteURL);
471 }
472 }
473
474 /**
475 * Get the RTE configuration from Page TSConfig
476 *
477 * @return array[] RTE configuration array
478 */
479 protected function getRTEConfig() {
480 $RTEtsConfigParts = explode(':', $this->RTEtsConfigParams);
481 $RTEsetup = $this->getBackendUserAuthentication()->getTSConfig('RTE', BackendUtility::getPagesTSconfig($RTEtsConfigParts[5]));
482 return BackendUtility::RTEsetup($RTEsetup['properties'], $RTEtsConfigParts[0], $RTEtsConfigParts[2], $RTEtsConfigParts[4]);
483 }
484
485 /**
486 * Generate JS code to be used on the link insert/modify dialogue
487 *
488 * @return string the generated JS code
489 */
490 public function getJsCode() {
491 // Rich Text Editor specific configuration:
492 $addPassOnParams = '';
493 if ((string)$this->mode == 'rte') {
494 $addPassOnParams .= '&RTEtsConfigParams=' . rawurlencode($this->RTEtsConfigParams);
495 }
496 // BEGIN accumulation of header JavaScript:
497 $JScode = '
498 // This JavaScript is primarily for RTE/Link. jumpToUrl is used in the other cases as well...
499 var add_href=' . GeneralUtility::quoteJSvalue($this->curUrlArray['href'] ? '&curUrl[href]=' . rawurlencode($this->curUrlArray['href']) : '') . ';
500 var add_target=' . GeneralUtility::quoteJSvalue($this->setTarget ? '&curUrl[target]=' . rawurlencode($this->setTarget) : '') . ';
501 var add_class=' . GeneralUtility::quoteJSvalue($this->setClass ? '&curUrl[class]=' . rawurlencode($this->setClass) : '') . ';
502 var add_title=' . GeneralUtility::quoteJSvalue($this->setTitle ? '&curUrl[title]=' . rawurlencode($this->setTitle) : '') . ';
503 var add_params=' . GeneralUtility::quoteJSvalue($this->bparams ? '&bparams=' . rawurlencode($this->bparams) : '') . ';
504
505 var cur_href=' . GeneralUtility::quoteJSvalue($this->curUrlArray['href'] ?: '') . ';
506 var cur_target=' . GeneralUtility::quoteJSvalue($this->setTarget ?: '') . ';
507 var cur_class=' . GeneralUtility::quoteJSvalue($this->setClass ?: '') . ';
508 var cur_title=' . GeneralUtility::quoteJSvalue($this->setTitle ?: '') . ';
509 var cur_params=' . GeneralUtility::quoteJSvalue($this->setParams ?: '') . ';
510
511 function browse_links_setTarget(target) { //
512 cur_target=target;
513 add_target="&curUrl[target]="+escape(target);
514 }
515 function browse_links_setClass(cssClass) { //
516 cur_class = cssClass;
517 add_class = "&curUrl[class]=" + escape(cssClass);
518 }
519 function browse_links_setTitle(title) { //
520 cur_title=title;
521 add_title="&curUrl[title]="+escape(title);
522 }
523 function browse_links_setValue(value) { //
524 cur_href=value;
525 add_href="&curUrl[href]="+value;
526 }
527 function browse_links_setParams(params) { //
528 cur_params=params;
529 add_params="&curUrl[params]="+escape(params);
530 }
531 ' . $this->doc->redirectUrls();
532 // Functions used, if the link selector is in wizard mode (= TCEforms fields)
533 if ($this->mode == 'wizard') {
534 if (!$this->areFieldChangeFunctionsValid() && !$this->areFieldChangeFunctionsValid(TRUE)) {
535 $this->P['fieldChangeFunc'] = array();
536 }
537 unset($this->P['fieldChangeFunc']['alert']);
538 $update = '';
539 foreach ($this->P['fieldChangeFunc'] as $v) {
540 $update .= '
541 window.opener.' . $v;
542 }
543 $P2 = array();
544 $P2['uid'] = $this->P['uid'];
545 $P2['pid'] = $this->P['pid'];
546 $P2['itemName'] = $this->P['itemName'];
547 $P2['formName'] = $this->P['formName'];
548 $P2['fieldChangeFunc'] = $this->P['fieldChangeFunc'];
549 $P2['fieldChangeFuncHash'] = GeneralUtility::hmac(serialize($this->P['fieldChangeFunc']));
550 $P2['params']['allowedExtensions'] = isset($this->P['params']['allowedExtensions']) ? $this->P['params']['allowedExtensions'] : '';
551 $P2['params']['blindLinkOptions'] = isset($this->P['params']['blindLinkOptions']) ? $this->P['params']['blindLinkOptions'] : '';
552 $P2['params']['blindLinkFields'] = isset($this->P['params']['blindLinkFields']) ? $this->P['params']['blindLinkFields']: '';
553 $addPassOnParams .= GeneralUtility::implodeArrayForUrl('P', $P2);
554 $JScode .= '
555 function link_typo3Page(id,anchor) { //
556 updateValueInMainForm(id + (anchor ? anchor : ""));
557 close();
558 return false;
559 }
560 function link_folder(folder) { //
561 updateValueInMainForm(folder);
562 close();
563 return false;
564 }
565 function link_current() { //
566 if (cur_href!="http://" && cur_href!="mailto:") {
567 returnBeforeCleaned = cur_href;
568 if (returnBeforeCleaned.substr(0, 7) == "http://") {
569 returnToMainFormValue = returnBeforeCleaned.substr(7);
570 } else if (returnBeforeCleaned.substr(0, 7) == "mailto:") {
571 if (returnBeforeCleaned.substr(0, 14) == "mailto:mailto:") {
572 returnToMainFormValue = returnBeforeCleaned.substr(14);
573 } else {
574 returnToMainFormValue = returnBeforeCleaned.substr(7);
575 }
576 } else {
577 returnToMainFormValue = returnBeforeCleaned;
578 }
579 updateValueInMainForm(returnToMainFormValue);
580 close();
581 }
582 return false;
583 }
584 function checkReference() { //
585 if (window.opener && window.opener.document && window.opener.document.' . $this->P['formName']
586 . ' && window.opener.document.' . $this->P['formName'] . '["' . $this->P['itemName'] . '"] ) {
587 return window.opener.document.' . $this->P['formName'] . '["' . $this->P['itemName'] . '"];
588 } else {
589 close();
590 }
591 }
592 function updateValueInMainForm(input) { //
593 var field = checkReference();
594 if (field) {
595 if (cur_target == "" && (cur_class != "" || cur_title != "" || cur_params != "")) {
596 cur_target = "-";
597 }
598 if (cur_class == "" && (cur_title != "" || cur_params != "")) {
599 cur_class = "-";
600 }
601 cur_class = cur_class.replace(/[\'\\"]/g, "");
602 if (cur_class.indexOf(" ") != -1) {
603 cur_class = "\\"" + cur_class + "\\"";
604 }
605 if (cur_title == "" && cur_params != "") {
606 cur_title = "-";
607 }
608 // replace each \ with \\
609 cur_title = cur_title.replace(/\\\\/g, "\\\\\\\\");
610 // replace each " with \"
611 cur_title = cur_title.replace(/\\"/g, "\\\\\\"");
612 if (cur_title.indexOf(" ") != -1) {
613 cur_title = "\\"" + cur_title + "\\"";
614 }
615 if (cur_params) {
616 cur_params = cur_params.replace(/\\bid\\=.*?(\\&|$)/, "");
617 }
618 input = input + " " + cur_target + " " + cur_class + " " + cur_title + " " + cur_params;
619 input = input.replace(/^\s+|\s+$/g, "");
620 if(field.value && field.className.search(/textarea/) != -1) {
621 field.value += "\\n" + input;
622 } else {
623 field.value = input;
624 }
625 if (typeof field.onchange === \'function\') {
626 field.onchange();
627 }
628 ' . $update . '
629 }
630 }
631 ';
632 } else {
633 // Functions used, if the link selector is in RTE mode:
634 $JScode .= '
635 function link_typo3Page(id,anchor) { //
636 var theLink = \'' . $this->siteURL . '?id=\'+id+(anchor?anchor:"");
637 self.parent.parent.renderPopup_addLink(theLink, cur_target, cur_class, cur_title);
638 return false;
639 }
640 function link_folder(folder) { //
641 var theLink = \'' . $this->siteURL . '\'+folder;
642 self.parent.parent.renderPopup_addLink(theLink, cur_target, cur_class, cur_title);
643 return false;
644 }
645 function link_current() { //
646 if (cur_href!="http://" && cur_href!="mailto:") {
647 self.parent.parent.renderPopup_addLink(cur_href, cur_target, cur_class, cur_title);
648 }
649 return false;
650 }
651 ';
652 }
653 // General "jumpToUrl" function:
654 $JScode .= '
655 function jumpToUrl(URL,anchor) { //
656 if (URL.charAt(0) === \'?\') {
657 URL = ' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + URL.substring(1);
658 }
659 var add_act = URL.indexOf("act=")==-1 ? "&act=' . $this->act . '" : "";
660 var add_mode = URL.indexOf("mode=")==-1 ? "&mode=' . $this->mode . '" : "";
661 var theLocation = URL + add_act + add_mode + add_href + add_target + add_class + add_title + add_params'
662 . ($addPassOnParams ? '+' . GeneralUtility::quoteJSvalue($addPassOnParams) : '')
663 . '+(typeof(anchor)=="string"?anchor:"");
664 window.location.href = theLocation;
665 return false;
666 }
667 ';
668 /**
669 * Splits parts of $this->bparams
670 *
671 * @see $bparams
672 */
673 $pArr = explode('|', $this->bparams);
674 // This is JavaScript especially for the TBE Element Browser!
675 $formFieldName = 'data[' . $pArr[0] . '][' . $pArr[1] . '][' . $pArr[2] . ']';
676 // insertElement - Call check function (e.g. for uniqueness handling):
677 $JScodeCheck = '';
678 if ($pArr[4] && $pArr[5]) {
679 $JScodeCheck = '
680 // Call a check function in the opener window (e.g. for uniqueness handling):
681 if (parent.window.opener) {
682 var res = parent.window.opener.' . $pArr[5] . '("' . addslashes($pArr[4]) . '",table,uid,type);
683 if (!res.passed) {
684 if (res.message) alert(res.message);
685 performAction = false;
686 }
687 } else {
688 alert("Error - reference to main window is not set properly!");
689 parent.close();
690 }
691 ';
692 }
693 // insertElement - Call helper function:
694 $JScodeHelper = '';
695 if ($pArr[4] && $pArr[6]) {
696 $JScodeHelper = '
697 // Call helper function to manage data in the opener window:
698 if (parent.window.opener) {
699 parent.window.opener.' . $pArr[6] . '("' . addslashes($pArr[4]) . '",table,uid,type,"' . addslashes($pArr[0]) . '");
700 } else {
701 alert("Error - reference to main window is not set properly!");
702 parent.close();
703 }
704 ';
705 }
706 // insertElement - perform action commands:
707 $JScodeActionMultiple = '';
708 if ($pArr[4] && $pArr[7]) {
709 // Call user defined action function:
710 $JScodeAction = '
711 if (parent.window.opener) {
712 parent.window.opener.' . $pArr[7] . '("' . addslashes($pArr[4]) . '",table,uid,type);
713 if (close) { focusOpenerAndClose(close); }
714 } else {
715 alert("Error - reference to main window is not set properly!");
716 if (close) { parent.close(); }
717 }
718 ';
719 $JScodeActionMultiple = '
720 // Call helper function to manage data in the opener window:
721 if (parent.window.opener) {
722 parent.window.opener.' . $pArr[7] . 'Multiple("' . addslashes($pArr[4]) . '",table,uid,type,"'
723 . addslashes($pArr[0]) . '");
724 } else {
725 alert("Error - reference to main window is not set properly!");
726 parent.close();
727 }
728 ';
729 } elseif ($pArr[0] && !$pArr[1] && !$pArr[2]) {
730 $JScodeAction = '
731 addElement(filename,table+"_"+uid,fp,close);
732 ';
733 } else {
734 $JScodeAction = '
735 if (setReferences()) {
736 parent.window.opener.group_change("add","' . $pArr[0] . '","' . $pArr[1] . '","' . $pArr[2]
737 . '",elRef,targetDoc);
738 } else {
739 alert("Error - reference to main window is not set properly!");
740 }
741 focusOpenerAndClose(close);
742 ';
743 }
744 $JScode .= '
745 var elRef="";
746 var targetDoc="";
747
748 function launchView(url) { //
749 var thePreviewWindow="";
750 thePreviewWindow = window.open(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('show_item') . '&table=') . '+url,"ShowItem",'
751 . '"height=300,width=410,status=0,menubar=0,resizable=0,location=0,directories=0,scrollbars=1,toolbar=0");
752 if (thePreviewWindow && thePreviewWindow.focus) {
753 thePreviewWindow.focus();
754 }
755 }
756 function setReferences() { //
757 if (parent.window.opener && parent.window.opener.content && parent.window.opener.content.document.editform'
758 . '&& parent.window.opener.content.document.editform["' . $formFieldName . '"]) {
759 targetDoc = parent.window.opener.content.document;
760 elRef = targetDoc.editform["' . $formFieldName . '"];
761 return true;
762 } else {
763 return false;
764 }
765 }
766 function insertElement(table, uid, type, filename, fp, filetype, imagefile, action, close) { //
767 var performAction = true;
768 ' . $JScodeCheck . '
769 // Call performing function and finish this action:
770 if (performAction) {
771 ' . $JScodeHelper . $JScodeAction . '
772 }
773 return false;
774 }
775 var _hasActionMultipleCode = ' . (!empty($JScodeActionMultiple) ? 'true' : 'false') . ';
776 function insertMultiple(table, uid) {
777 var type = "";
778 ' . $JScodeActionMultiple . '
779 return false;
780 }
781 function addElement(elName, elValue, altElValue, close) { //
782 if (parent.window.opener && parent.window.opener.setFormValueFromBrowseWin) {
783 parent.window.opener.setFormValueFromBrowseWin("' . $pArr[0] . '",altElValue?altElValue:elValue,elName);
784 focusOpenerAndClose(close);
785 } else {
786 alert("Error - reference to main window is not set properly!");
787 parent.close();
788 }
789 }
790 function focusOpenerAndClose(close) { //
791 BrowseLinks.focusOpenerAndClose(close);
792 }
793 ';
794 // extends JavaScript code
795 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['extendJScode'])
796 && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['extendJScode'])
797 ) {
798 $conf = array();
799 $update = '';
800 $_params = array(
801 'conf' => &$conf,
802 'wizardUpdate' => $update,
803 'addPassOnParams' => $addPassOnParams
804 );
805 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['extendJScode'] as $objRef) {
806 $processor =& GeneralUtility::getUserObj($objRef);
807 $JScode .= $processor->extendJScode($_params, $this);
808 }
809 }
810 return $JScode;
811 }
812
813 /**
814 * Session data for this class can be set from outside with this method.
815 * Call after init()
816 *
817 * @param mixed[] $data Session data array
818 * @return array[] Session data and boolean which indicates that data needs to be stored in session because it's changed
819 */
820 public function processSessionData($data) {
821 $store = FALSE;
822 switch ((string)$this->mode) {
823 case 'db':
824 if (isset($this->expandPage)) {
825 $data['expandPage'] = $this->expandPage;
826 $store = TRUE;
827 } else {
828 $this->expandPage = $data['expandPage'];
829 }
830 break;
831 case 'file':
832
833 case 'filedrag':
834
835 case 'folder':
836 if (isset($this->expandFolder)) {
837 $data['expandFolder'] = $this->expandFolder;
838 $store = TRUE;
839 } else {
840 $this->expandFolder = $data['expandFolder'];
841 }
842 break;
843 }
844 return array($data, $store);
845 }
846
847 /******************************************************************
848 *
849 * Main functions
850 *
851 ******************************************************************/
852 /**
853 * Rich Text Editor (RTE) link selector (MAIN function)
854 * Generates the link selector for the Rich Text Editor.
855 * Can also be used to select links for the TCEforms (see $wiz)
856 *
857 * @param bool $wiz If set, the "remove link" is not shown in the menu: Used for the "Select link" wizard which is used by the TCEforms
858 * @return string Modified content variable.
859 */
860 public function main_rte($wiz = FALSE) {
861 // needs to be executed before doc->startPage()
862 if (in_array($this->act, array('file', 'folder'))) {
863 $this->doc->getDragDropCode('folders', 'Tree.ajaxID = "SC_alt_file_navframe::expandCollapse"');
864 } elseif ($this->act === 'page') {
865 $this->doc->getDragDropCode('pages');
866 }
867 // Starting content:
868 $content = $this->doc->startPage('RTE link');
869 // Add the FlashMessages if any
870 $content .= $this->doc->getFlashMessages();
871
872 $allowedItems = $this->getAllowedItems('page,file,folder,url,mail');
873
874 // Removing link fields if configured
875 $blindLinkFields = isset($this->thisConfig['blindLinkFields'])
876 ? GeneralUtility::trimExplode(',', $this->thisConfig['blindLinkFields'], TRUE)
877 : array();
878 $pBlindLinkFields = isset($this->P['params']['blindLinkFields'])
879 ? GeneralUtility::trimExplode(',', $this->P['params']['blindLinkFields'], TRUE)
880 : array();
881 $allowedFields = array_diff(array('target', 'title', 'class', 'params'), $blindLinkFields, $pBlindLinkFields);
882
883 $content .= $this->doc->getTabMenuRaw($this->buildMenuArray($wiz, $allowedItems));
884 // Adding the menu and header to the top of page:
885 $content .= $this->printCurrentUrl($this->curUrlInfo['info']) . '<br />';
886 // Depending on the current action we will create the actual module content for selecting a link:
887 switch ($this->act) {
888 case 'mail':
889 $content .= $this->getEmailSelectorHtml();
890 break;
891 case 'url':
892 $content .= $this->getExternalUrlSelectorHtml();
893 break;
894 case 'file':
895 case 'folder':
896 $content .= $this->getFileSelectorHtml();
897 break;
898 case 'page':
899 $content .= $this->getPageSelectorHtml();
900 break;
901 default:
902 // Call hook
903 foreach ($this->hookObjects as $hookObject) {
904 $content .= $hookObject->getTab($this->act);
905 }
906 }
907 $lang = $this->getLanguageService();
908 if (in_array('params', $allowedFields, TRUE)) {
909 $content .= '
910 <!--
911 Selecting params for link:
912 -->
913 <form action="" name="lparamsform" id="lparamsform">
914 <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkParams">
915 <tr>
916 <td style="width: 96px;">' . $lang->getLL('params', TRUE) . '</td>
917 <td><input type="text" name="lparams" class="typo3-link-input" onchange="'
918 . 'browse_links_setParams(this.value);" value="' . htmlspecialchars($this->setParams)
919 . '" /></td>
920 </tr>
921 </table>
922 </form>
923 ';
924 }
925 if (in_array('class', $allowedFields, TRUE)) {
926 $content .= '
927 <!--
928 Selecting class for link:
929 -->
930 <form action="" name="lclassform" id="lclassform">
931 <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkClass">
932 <tr>
933 <td style="width: 96px;">' . $lang->getLL('class', TRUE) . '</td>
934 <td><input type="text" name="lclass" class="typo3-link-input" onchange="'
935 . 'browse_links_setClass(this.value);" value="' . htmlspecialchars($this->setClass)
936 . '" /></td>
937 </tr>
938 </table>
939 </form>
940 ';
941 }
942 if (in_array('title', $allowedFields, TRUE)) {
943 $content .= '
944 <!--
945 Selecting title for link:
946 -->
947 <form action="" name="ltitleform" id="ltitleform">
948 <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkTitle">
949 <tr>
950 <td style="width: 96px;">' . $lang->getLL('title', TRUE) . '</td>
951 <td><input type="text" name="ltitle" class="typo3-link-input" onchange="'
952 . 'browse_links_setTitle(this.value);" value="' . htmlspecialchars($this->setTitle)
953 . '" /></td>
954 </tr>
955 </table>
956 </form>
957 ';
958 }
959 // additional fields for page links
960 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['addFields_PageLink'])
961 && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['addFields_PageLink'])
962 ) {
963 $conf = array();
964 $_params = array(
965 'conf' => &$conf
966 );
967 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.browse_links.php']['addFields_PageLink'] as $objRef) {
968 $processor =& GeneralUtility::getUserObj($objRef);
969 $content .= $processor->addFields($_params, $this);
970 }
971 }
972 // Target:
973 if ($this->act != 'mail' && in_array('target', $allowedFields, TRUE)) {
974 $ltarget = '
975
976 <!--
977 Selecting target for link:
978 -->
979 <form action="" name="ltargetform" id="ltargetform">
980 <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkTarget">
981 <tr>
982 <td>' . $lang->getLL('target', TRUE) . ':</td>
983 <td><input type="text" name="ltarget" onchange="browse_links_setTarget(this.value);" value="'
984 . htmlspecialchars($this->setTarget) . '"' . $this->doc->formWidth(10) . ' /></td>
985 <td>
986 <select name="ltarget_type" onchange="browse_links_setTarget('
987 . 'this.options[this.selectedIndex].value);document.ltargetform.ltarget.value='
988 . 'this.options[this.selectedIndex].value;this.selectedIndex=0;">
989 <option></option>
990 <option value="_top">' . $lang->getLL('top', TRUE) . '</option>
991 <option value="_blank">' . $lang->getLL('newWindow', TRUE) . '</option>
992 </select>
993 </td>
994 <td>';
995 if (($this->curUrlInfo['act'] == 'page' || $this->curUrlInfo['act'] == 'file' || $this->curUrlInfo['act'] == 'folder')
996 && $this->curUrlArray['href'] && $this->curUrlInfo['act'] == $this->act
997 ) {
998 $ltarget .= '
999 <input class="btn btn-default" type="submit" value="' . $lang->getLL('update', TRUE)
1000 . '" onclick="return link_current();" />';
1001 }
1002 $selectJS = '
1003 if (document.ltargetform.popup_width.options[document.ltargetform.popup_width.selectedIndex].value>0'
1004 . ' && document.ltargetform.popup_height.options[document.ltargetform.popup_height.selectedIndex].value>0) {
1005 document.ltargetform.ltarget.value = document.ltargetform.popup_width.options['
1006 . 'document.ltargetform.popup_width.selectedIndex].value+"x"'
1007 . '+document.ltargetformbrowse_links_setTarget.popup_height.options['
1008 . 'document.ltargetform.popup_height.selectedIndex].value;
1009 browse_links_setTarget(document.ltargetform.ltarget.value);
1010 browse_links_setClass(document.lclassform.lclass.value);
1011 browse_links_setTitle(document.ltitleform.ltitle.value);
1012 browse_links_setParams(document.lparamsform.lparams.value);
1013 document.ltargetform.popup_width.selectedIndex=0;
1014 document.ltargetform.popup_height.selectedIndex=0;
1015 }
1016 ';
1017 $ltarget .= ' </td>
1018 </tr>
1019 <tr>
1020 <td>' . $lang->getLL('target_popUpWindow', TRUE) . ':</td>
1021 <td colspan="3">
1022 <select name="popup_width" onchange="' . htmlspecialchars($selectJS) . '">
1023 <option value="0">' . $lang->getLL('target_popUpWindow_width', TRUE) . '</option>
1024 <option value="300">300</option>
1025 <option value="400">400</option>
1026 <option value="500">500</option>
1027 <option value="600">600</option>
1028 <option value="700">700</option>
1029 <option value="800">800</option>
1030 </select>
1031 x
1032 <select name="popup_height" onchange="' . htmlspecialchars($selectJS) . '">
1033 <option value="0">' . $lang->getLL('target_popUpWindow_height', TRUE) . '</option>
1034 <option value="200">200</option>
1035 <option value="300">300</option>
1036 <option value="400">400</option>
1037 <option value="500">500</option>
1038 <option value="600">600</option>
1039 </select>
1040 </td>
1041 </tr>
1042 </table>
1043 </form>';
1044 // Add "target selector" box to content:
1045 $content .= $ltarget;
1046 // Add some space
1047 $content .= '<br /><br />';
1048 }
1049 // End page, return content:
1050 $content .= $this->doc->endPage();
1051 $content = $this->doc->insertStylesAndJS($content);
1052 return $content;
1053 }
1054
1055 /**
1056 * Get the allowed items or tabs
1057 *
1058 * @param string $items initial list of possible items
1059 * @return array the allowed items
1060 */
1061 public function getAllowedItems($items) {
1062 // Initializing the action value, possibly removing blinded values etc:
1063 $blindLinkOptions = isset($this->thisConfig['blindLinkOptions'])
1064 ? GeneralUtility::trimExplode(',', $this->thisConfig['blindLinkOptions'], TRUE)
1065 : array();
1066 $pBlindLinkOptions = isset($this->P['params']['blindLinkOptions'])
1067 ? GeneralUtility::trimExplode(',', $this->P['params']['blindLinkOptions'])
1068 : array();
1069 $allowedItems = array_diff(explode(',', $items), $blindLinkOptions, $pBlindLinkOptions);
1070
1071 // Call hook for extra options
1072 foreach ($this->hookObjects as $hookObject) {
1073 $allowedItems = $hookObject->addAllowedItems($allowedItems);
1074 }
1075 return $allowedItems;
1076 }
1077
1078 /**
1079 * Returns an array definition of the top menu
1080 *
1081 * @param $wiz
1082 * @param $allowedItems
1083 * @return mixed[][]
1084 */
1085 protected function buildMenuArray($wiz, $allowedItems) {
1086 // Making menu in top:
1087 $menuDef = array();
1088 $lang = $this->getLanguageService();
1089 if (!$wiz) {
1090 $menuDef['removeLink']['isActive'] = $this->act === 'removeLink';
1091 $menuDef['removeLink']['label'] = $lang->getLL('removeLink', TRUE);
1092 $menuDef['removeLink']['url'] = '#';
1093 $menuDef['removeLink']['addParams'] = 'onclick="self.parent.parent.renderPopup_unLink();return false;"';
1094 }
1095 if (in_array('page', $allowedItems)) {
1096 $menuDef['page']['isActive'] = $this->act === 'page';
1097 $menuDef['page']['label'] = $lang->getLL('page', TRUE);
1098 $menuDef['page']['url'] = '#';
1099 $menuDef['page']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=page') . ');return false;"';
1100 }
1101 if (in_array('file', $allowedItems)) {
1102 $menuDef['file']['isActive'] = $this->act === 'file';
1103 $menuDef['file']['label'] = $lang->getLL('file', TRUE);
1104 $menuDef['file']['url'] = '#';
1105 $menuDef['file']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=file') . ');return false;"';
1106 }
1107 if (in_array('folder', $allowedItems)) {
1108 $menuDef['folder']['isActive'] = $this->act === 'folder';
1109 $menuDef['folder']['label'] = $lang->getLL('folder', TRUE);
1110 $menuDef['folder']['url'] = '#';
1111 $menuDef['folder']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=folder') . ');return false;"';
1112 }
1113 if (in_array('url', $allowedItems)) {
1114 $menuDef['url']['isActive'] = $this->act === 'url';
1115 $menuDef['url']['label'] = $lang->getLL('extUrl', TRUE);
1116 $menuDef['url']['url'] = '#';
1117 $menuDef['url']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=url') . ');return false;"';
1118 }
1119 if (in_array('mail', $allowedItems)) {
1120 $menuDef['mail']['isActive'] = $this->act === 'mail';
1121 $menuDef['mail']['label'] = $lang->getLL('email', TRUE);
1122 $menuDef['mail']['url'] = '#';
1123 $menuDef['mail']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=mail') . ');return false;"';
1124 }
1125 // Call hook for extra options
1126 foreach ($this->hookObjects as $hookObject) {
1127 $menuDef = $hookObject->modifyMenuDefinition($menuDef);
1128 }
1129 return $menuDef;
1130 }
1131
1132 /**
1133 * Returns HTML of the email link from
1134 *
1135 * @return string
1136 */
1137 protected function getEmailSelectorHtml() {
1138 $lang = $this->getLanguageService();
1139 $extUrl = '
1140 <!--
1141 Enter mail address:
1142 -->
1143 <form action="" name="lurlform" id="lurlform">
1144 <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkMail">
1145 <tr>
1146 <td style="width: 96px;">
1147 ' . $lang->getLL('emailAddress', TRUE) . ':
1148 </td>
1149 <td>
1150 <input type="text" name="lemail"' . $this->doc->formWidth(20) . ' value="'
1151 . htmlspecialchars(($this->curUrlInfo['act'] === 'mail' ? $this->curUrlInfo['info'] : ''))
1152 . '" />
1153 <input class="btn btn-default" type="submit" value="' . $lang->getLL('setLink', TRUE)
1154 . '" onclick="browse_links_setTarget(\'\');browse_links_setValue(\'mailto:\'+'
1155 . 'document.lurlform.lemail.value); return link_current();" />
1156 </td>
1157 </tr>
1158 </table>
1159 </form>';
1160 return $extUrl;
1161 }
1162
1163 /**
1164 * Returns HTML of the external url link from
1165 *
1166 * @return string
1167 */
1168 protected function getExternalUrlSelectorHtml() {
1169 $extUrl = '
1170
1171 <!--
1172 Enter External URL:
1173 -->
1174 <form action="" name="lurlform" id="lurlform">
1175 <table border="0" cellpadding="2" cellspacing="1" id="typo3-linkURL">
1176 <tr>
1177 <td style="width: 96px;">URL:</td>
1178 <td><input type="text" name="lurl"' . $this->doc->formWidth(30) . ' value="'
1179 . htmlspecialchars(($this->curUrlInfo['act'] === 'url' ? $this->curUrlInfo['info'] : 'http://'))
1180 . '" /> ' . '<input class="btn btn-default" type="submit" value="' . $this->getLanguageService()->getLL('setLink', TRUE)
1181 . '" onclick="browse_links_setValue(document.lurlform.lurl.value); return link_current();" /></td>
1182 </tr>
1183 </table>
1184 </form>';
1185 return $extUrl;
1186 }
1187
1188 /**
1189 * Returns HTML of the file/folder link selector
1190 *
1191 * @param string $treeClassName
1192 * @return string
1193 */
1194 protected function getFileSelectorHtml($treeClassName = \TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView::class) {
1195 $folderTree = GeneralUtility::makeInstance($treeClassName);
1196 $folderTree->thisScript = $this->thisScript;
1197 $tree = $folderTree->getBrowsableTree();
1198 $backendUser = $this->getBackendUserAuthentication();
1199 if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act'] != $this->act) {
1200 $cmpPath = '';
1201 } else {
1202 $cmpPath = $this->curUrlInfo['value'];
1203 if (!isset($this->expandFolder)) {
1204 $this->expandFolder = $cmpPath;
1205 }
1206 }
1207 // Create upload/create folder forms, if a path is given
1208 $selectedFolder = FALSE;
1209 if ($this->expandFolder) {
1210 $fileOrFolderObject = NULL;
1211 try {
1212 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
1213 } catch (\Exception $e) {
1214 // No path is selected
1215 }
1216
1217 if ($fileOrFolderObject instanceof Folder) {
1218 // It's a folder
1219 $selectedFolder = $fileOrFolderObject;
1220 } elseif ($fileOrFolderObject instanceof FileInterface) {
1221 // It's a file
1222 try {
1223 $selectedFolder = $fileOrFolderObject->getParentFolder();
1224 } catch (\Exception $e) {
1225 // Accessing the parent folder failed for some reason. e.g. permissions
1226 }
1227 }
1228 }
1229 // If no folder is selected, get the user's default upload folder
1230 if (!$selectedFolder) {
1231 try {
1232 $selectedFolder = $backendUser->getDefaultUploadFolder();
1233 } catch (\Exception $e) {
1234 // The configured default user folder does not exist
1235 }
1236 }
1237 // Build the file upload and folder creation form
1238 $uploadForm = '';
1239 $createFolder = '';
1240 $content = '';
1241 if ($selectedFolder) {
1242 $uploadForm = ($this->act === 'file') ? $this->uploadForm($selectedFolder) : '';
1243 $createFolder = $this->createFolder($selectedFolder);
1244 }
1245 // Insert the upload form on top, if so configured
1246 if ($backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
1247 $content .= $uploadForm;
1248 }
1249
1250 // Render the filelist if there is a folder selected
1251 $files = '';
1252 if ($selectedFolder) {
1253 $allowedExtensions = isset($this->P['params']['allowedExtensions']) ? $this->P['params']['allowedExtensions'] : '';
1254 $files = $this->expandFolder($selectedFolder, $allowedExtensions);
1255 }
1256 // Create folder tree:
1257 $content .= '
1258 <!--
1259 Wrapper table for folder tree / file/folder list:
1260 -->
1261 <table border="0" cellpadding="0" cellspacing="0" id="typo3-linkFiles">
1262 <tr>
1263 <td class="c-wCell" valign="top">'
1264 . $this->barheader(($this->getLanguageService()->getLL('folderTree') . ':')) . $tree . '</td>
1265 <td class="c-wCell" valign="top">' . $files . '</td>
1266 </tr>
1267 </table>
1268 ';
1269 // Adding create folder + upload form if applicable
1270 if (!$backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
1271 $content .= $uploadForm;
1272 }
1273 $content .= '<br />' . $createFolder . '<br />';
1274 return $content;
1275 }
1276
1277 /**
1278 * Returns HTML of the page link selector
1279 *
1280 * @param string $treeClassName name of the class used for page tree rendering
1281 * @return string
1282 */
1283 protected function getPageSelectorHtml($treeClassName = \TYPO3\CMS\Backend\Tree\View\ElementBrowserPageTreeView::class) {
1284 $backendUser = $this->getBackendUserAuthentication();
1285 $pageTree = GeneralUtility::makeInstance($treeClassName);
1286 $pageTree->thisScript = $this->thisScript;
1287 $pageTree->ext_showPageId = $backendUser->getTSConfigVal('options.pageTree.showPageIdWithTitle');
1288 $pageTree->ext_showNavTitle = $backendUser->getTSConfigVal('options.pageTree.showNavTitle');
1289 $pageTree->addField('nav_title');
1290 $tree = $pageTree->getBrowsableTree();
1291 $cElements = $this->expandPage();
1292 $dbmount = $this->getTemporaryTreeMountCancelNotice();
1293 $content = '
1294
1295 <!--
1296 Wrapper table for page tree / record list:
1297 -->
1298 <table border="0" cellpadding="0" cellspacing="0" id="typo3-linkPages">
1299 <tr>
1300 <td class="c-wCell" valign="top">'
1301 . $this->barheader(($this->getLanguageService()->getLL('pageTree') . ':'))
1302 . $dbmount
1303 . $tree . '</td>
1304 <td class="c-wCell" valign="top">' . $cElements . '</td>
1305 </tr>
1306 </table>
1307 ';
1308 return $content;
1309 }
1310
1311 /**
1312 * TYPO3 Element Browser: Showing a page tree and allows you to browse for records
1313 *
1314 * @return string HTML content for the module
1315 */
1316 public function main_db() {
1317 // Starting content:
1318 $content = $this->doc->startPage('TBE record selector');
1319 // Init variable:
1320 $pArr = explode('|', $this->bparams);
1321 $tables = $pArr[3];
1322 $backendUser = $this->getBackendUserAuthentication();
1323
1324 // Making the browsable pagetree:
1325 /** @var \TYPO3\CMS\Recordlist\Tree\View\ElementBrowserPageTreeView $pageTree */
1326 $pageTree = GeneralUtility::makeInstance(\TYPO3\CMS\Recordlist\Tree\View\ElementBrowserPageTreeView::class);
1327 $pageTree->thisScript = $this->thisScript;
1328 $pageTree->ext_pArrPages = $tables === 'pages' ? 1 : 0;
1329 $pageTree->ext_showNavTitle = $backendUser->getTSConfigVal('options.pageTree.showNavTitle');
1330 $pageTree->ext_showPageId = $backendUser->getTSConfigVal('options.pageTree.showPageIdWithTitle');
1331 $pageTree->addField('nav_title');
1332
1333 $withTree = TRUE;
1334 if (($tables !== '') && ($tables !== '*')) {
1335 $tablesArr = GeneralUtility::trimExplode(',', $tables, TRUE);
1336 $onlyRootLevel = TRUE;
1337 foreach ($tablesArr as $currentTable) {
1338 $tableTca = $GLOBALS['TCA'][$currentTable];
1339 if (isset($tableTca)) {
1340 if (!isset($tableTca['ctrl']['rootLevel']) || ((int)$tableTca['ctrl']['rootLevel']) != 1) {
1341 $onlyRootLevel = FALSE;
1342 }
1343 }
1344 }
1345 if ($onlyRootLevel) {
1346 $withTree = FALSE;
1347 // page to work on will be root
1348 $this->expandPage = 0;
1349 }
1350 }
1351
1352 $tree = $pageTree->getBrowsableTree();
1353 // Making the list of elements, if applicable:
1354 $cElements = $this->TBE_expandPage($tables);
1355 // Putting the things together, side by side:
1356 $content .= '
1357
1358 <!--
1359 Wrapper table for page tree / record list:
1360 -->
1361 <table border="0" cellpadding="0" cellspacing="0" id="typo3-EBrecords">
1362 <tr>';
1363 if ($withTree) {
1364 $content .= '<td class="c-wCell" valign="top">'
1365 . $this->barheader(($this->getLanguageService()->getLL('pageTree') . ':'))
1366 . $this->getTemporaryTreeMountCancelNotice()
1367 . $tree . '</td>';
1368 }
1369 $content .= '<td class="c-wCell" valign="top">' . $cElements . '</td>
1370 </tr>
1371 </table>
1372 ';
1373 // Add some space
1374 $content .= '<br /><br />';
1375 // End page, return content:
1376 $content .= $this->doc->endPage();
1377 $content = $this->doc->insertStylesAndJS($content);
1378 return $content;
1379 }
1380
1381 /**
1382 * TYPO3 Element Browser: Showing a folder tree, allowing you to browse for files.
1383 *
1384 * @return string HTML content for the module
1385 */
1386 public function main_file() {
1387 // include JS files and set prefs for foldertree
1388 $this->doc->getDragDropCode('folders', 'Tree.ajaxID = "SC_alt_file_navframe::expandCollapse"');
1389 // Starting content:
1390 $content = $this->doc->startPage('TBE file selector');
1391 // Add the FlashMessages if any
1392 $content .= $this->doc->getFlashMessages();
1393 // Init variable:
1394 $pArr = explode('|', $this->bparams);
1395 // The key number 3 of the pArr contains the "allowed" string. Disallowed is not passed to
1396 // the element browser at all but only filtered out in TCEMain afterwards
1397 $allowed = $pArr[3];
1398 if ($allowed !== 'sys_file' && $allowed !== '*' && !empty($allowed)) {
1399 $allowedFileExtensions = $allowed;
1400 }
1401 $backendUser = $this->getBackendUserAuthentication();
1402
1403 if (isset($allowedFileExtensions)) {
1404 // Create new filter object
1405 $filterObject = GeneralUtility::makeInstance(FileExtensionFilter::class);
1406 $filterObject->setAllowedFileExtensions($allowedFileExtensions);
1407 // Set file extension filters on all storages
1408 $storages = $backendUser->getFileStorages();
1409 /** @var $storage \TYPO3\CMS\Core\Resource\ResourceStorage */
1410 foreach ($storages as $storage) {
1411 $storage->addFileAndFolderNameFilter(array($filterObject, 'filterFileList'));
1412 }
1413 }
1414 // Create upload/create folder forms, if a path is given
1415 $this->selectedFolder = FALSE;
1416 if ($this->expandFolder) {
1417 $fileOrFolderObject = NULL;
1418
1419 // Try to fetch the folder the user had open the last time he browsed files
1420 // Fallback to the default folder in case the last used folder is not existing
1421 try {
1422 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
1423 } catch (Exception $accessException) {
1424 // We're just catching the exception here, nothing to be done if folder does not exist or is not accessible.
1425 }
1426
1427 if ($fileOrFolderObject instanceof Folder) {
1428 // It's a folder
1429 $this->selectedFolder = $fileOrFolderObject;
1430 } elseif ($fileOrFolderObject instanceof FileInterface) {
1431 // It's a file
1432 $this->selectedFolder = $fileOrFolderObject->getParentFolder();
1433 }
1434 }
1435 // Or get the user's default upload folder
1436 if (!$this->selectedFolder) {
1437 try {
1438 $this->selectedFolder = $backendUser->getDefaultUploadFolder();
1439 } catch (\Exception $e) {
1440 // The configured default user folder does not exist
1441 }
1442 }
1443 // Build the file upload and folder creation form
1444 $uploadForm = '';
1445 $createFolder = '';
1446 if ($this->selectedFolder) {
1447 $uploadForm = $this->uploadForm($this->selectedFolder);
1448 $createFolder = $this->createFolder($this->selectedFolder);
1449 }
1450 // Insert the upload form on top, if so configured
1451 if ($backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
1452 $content .= $uploadForm;
1453 }
1454 // Getting flag for showing/not showing thumbnails:
1455 $noThumbs = $backendUser->getTSConfigVal('options.noThumbsInEB');
1456 $_MOD_SETTINGS = array();
1457 if (!$noThumbs) {
1458 // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
1459 $_MOD_MENU = array('displayThumbs' => '');
1460 $_MCONF['name'] = 'file_list';
1461 $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
1462 }
1463 $noThumbs = $noThumbs ?: !$_MOD_SETTINGS['displayThumbs'];
1464 // Create folder tree:
1465 /** @var \TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView $folderTree */
1466 $folderTree = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView::class);
1467 $folderTree->thisScript = $this->thisScript;
1468 $folderTree->ext_noTempRecyclerDirs = $this->mode == 'filedrag';
1469 $tree = $folderTree->getBrowsableTree();
1470 if ($this->selectedFolder) {
1471 if ($this->mode == 'filedrag') {
1472 $files = $this->TBE_dragNDrop($this->selectedFolder, $pArr[3]);
1473 } else {
1474 $files = $this->TBE_expandFolder($this->selectedFolder, $pArr[3], $noThumbs);
1475 }
1476 } else {
1477 $files = '';
1478 }
1479
1480 // Putting the parts together, side by side:
1481 $content .= '
1482
1483 <!--
1484 Wrapper table for folder tree / file list:
1485 -->
1486 <table border="0" cellpadding="0" cellspacing="0" id="typo3-EBfiles">
1487 <tr>
1488 <td class="c-wCell" valign="top">' . $this->barheader(($this->getLanguageService()->getLL('folderTree') . ':'))
1489 . $tree . '</td>
1490 <td class="c-wCell" valign="top">' . $files . '</td>
1491 </tr>
1492 </table>
1493 ';
1494 // Adding create folder + upload forms if applicable:
1495 if (!$backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
1496 $content .= $uploadForm;
1497 }
1498 $content .= $createFolder;
1499 // Add some space
1500 $content .= '<br /><br />';
1501 // Setup indexed elements:
1502 $this->doc->JScode .= $this->doc->wrapScriptTags('
1503 require(["TYPO3/CMS/Backend/BrowseLinks"], function(BrowseLinks) {
1504 BrowseLinks.addElements(' . json_encode($this->elements) . ');
1505 });');
1506 // Ending page, returning content:
1507 $content .= $this->doc->endPage();
1508 $content = $this->doc->insertStylesAndJS($content);
1509 return $content;
1510 }
1511
1512 /**
1513 * TYPO3 Element Browser: Showing a folder tree, allowing you to browse for folders.
1514 *
1515 * @return string HTML content for the module
1516 */
1517 public function main_folder() {
1518 // include JS files
1519 // Setting prefs for foldertree
1520 $this->doc->getDragDropCode('folders', 'Tree.ajaxID = "SC_alt_file_navframe::expandCollapse";');
1521 // Starting content:
1522 $content = $this->doc->startPage('TBE folder selector');
1523 // Add the FlashMessages if any
1524 $content .= $this->doc->getFlashMessages();
1525 // Init variable:
1526 $parameters = explode('|', $this->bparams);
1527 if ($this->expandFolder) {
1528 $this->selectedFolder = ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($this->expandFolder);
1529 }
1530 if ($this->selectedFolder) {
1531 $createFolder = $this->createFolder($this->selectedFolder);
1532 } else {
1533 $createFolder = '';
1534 }
1535 // Create folder tree:
1536 /** @var \TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView $folderTree */
1537 $folderTree = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView::class);
1538 $folderTree->thisScript = $this->thisScript;
1539 $folderTree->ext_noTempRecyclerDirs = $this->mode == 'filedrag';
1540 $tree = $folderTree->getBrowsableTree(FALSE);
1541 $folders = '';
1542 if ($this->selectedFolder) {
1543 if ($this->mode == 'filedrag') {
1544 $folders = $this->TBE_dragNDrop($this->selectedFolder, $parameters[3]);
1545 } else {
1546 $folders = $this->TBE_expandSubFolders($this->selectedFolder);
1547 }
1548 }
1549 // Putting the parts together, side by side:
1550 $content .= '
1551
1552 <!--
1553 Wrapper table for folder tree / folder list:
1554 -->
1555 <table border="0" cellpadding="0" cellspacing="0" id="typo3-EBfiles">
1556 <tr>
1557 <td class="c-wCell" valign="top">' . $this->barheader(($this->getLanguageService()->getLL('folderTree') . ':'))
1558 . $tree . '</td>
1559 <td class="c-wCell" valign="top">' . $folders . '</td>
1560 </tr>
1561 </table>
1562 ';
1563 // Adding create folder if applicable:
1564 $content .= $createFolder;
1565 // Add some space
1566 $content .= '<br /><br />';
1567 // Ending page, returning content:
1568 $content .= $this->doc->endPage();
1569 $content = $this->doc->insertStylesAndJS($content);
1570 return $content;
1571 }
1572
1573 /******************************************************************
1574 *
1575 * Record listing
1576 *
1577 ******************************************************************/
1578 /**
1579 * For RTE: This displays all content elements on a page and lets you create a link to the element.
1580 *
1581 * @return string HTML output. Returns content only if the ->expandPage value is set (pointing to a page uid to show tt_content records from ...)
1582 */
1583 public function expandPage() {
1584 $out = '';
1585 // Set page id (if any) to expand
1586 $expPageId = $this->expandPage;
1587 // If there is an anchor value (content element reference) in the element reference, then force an ID to expand:
1588 if (!$this->expandPage && $this->curUrlInfo['cElement']) {
1589 // Set to the current link page id.
1590 $expPageId = $this->curUrlInfo['pageid'];
1591 }
1592 // Draw the record list IF there is a page id to expand:
1593 if ($expPageId
1594 && MathUtility::canBeInterpretedAsInteger($expPageId)
1595 && $this->getBackendUserAuthentication()->isInWebMount($expPageId)
1596 ) {
1597 // Set header:
1598 $out .= $this->barheader($this->getLanguageService()->getLL('contentElements') . ':');
1599 // Create header for listing, showing the page title/icon:
1600 $mainPageRec = BackendUtility::getRecordWSOL('pages', $expPageId);
1601 $db = $this->getDatabaseConnection();
1602 $picon = IconUtility::getSpriteIconForRecord('pages', $mainPageRec);
1603 $picon .= BackendUtility::getRecordTitle('pages', $mainPageRec, TRUE);
1604 $out .= $picon . '<ul class="list-tree flat-tree-root">';
1605 // Look up tt_content elements from the expanded page:
1606 $res = $db->exec_SELECTquery(
1607 'uid,header,hidden,starttime,endtime,fe_group,CType,colPos,bodytext',
1608 'tt_content',
1609 'pid=' . (int)$expPageId . BackendUtility::deleteClause('tt_content')
1610 . BackendUtility::versioningPlaceholderClause('tt_content'),
1611 '',
1612 'colPos,sorting'
1613 );
1614 $cc = $db->sql_num_rows($res);
1615 // Traverse list of records:
1616 $c = 0;
1617 while ($row = $db->sql_fetch_assoc($res)) {
1618 $c++;
1619 $icon = IconUtility::getSpriteIconForRecord('tt_content', $row);
1620 $selected = '';
1621 if ($this->curUrlInfo['act'] == 'page' && $this->curUrlInfo['cElement'] == $row['uid']) {
1622 $selected = ' class="bg-success"';
1623 }
1624 // Putting list element HTML together:
1625 $out .= '<li>'
1626 . '<a href="#"' . $selected . ' onclick="return link_typo3Page(\'' . $expPageId . '\',\'#' . $row['uid'] . '\');">'
1627 . $icon . BackendUtility::getRecordTitle('tt_content', $row, TRUE) . '</a></li>';
1628 }
1629 $out .= '</ul>';
1630 }
1631 return $out;
1632 }
1633
1634 /**
1635 * For TYPO3 Element Browser: This lists all content elements from the given list of tables
1636 *
1637 * @param string $tables Comma separated list of tables. Set to "*" if you want all tables.
1638 * @return string HTML output.
1639 */
1640 public function TBE_expandPage($tables) {
1641 $backendUser = $this->getBackendUserAuthentication();
1642 if (!MathUtility::canBeInterpretedAsInteger($this->expandPage)
1643 || $this->expandPage < 0
1644 || !$backendUser->isInWebMount($this->expandPage)
1645 ) {
1646 return '';
1647 }
1648 // Set array with table names to list:
1649 if (trim($tables) === '*') {
1650 $tablesArr = array_keys($GLOBALS['TCA']);
1651 } else {
1652 $tablesArr = GeneralUtility::trimExplode(',', $tables, TRUE);
1653 }
1654 reset($tablesArr);
1655 // Headline for selecting records:
1656 $out = $this->barheader($this->getLanguageService()->getLL('selectRecords') . ':');
1657 // Create the header, showing the current page for which the listing is.
1658 // Includes link to the page itself, if pages are amount allowed tables.
1659 $titleLen = (int)$backendUser->uc['titleLen'];
1660 $mainPageRec = BackendUtility::getRecordWSOL('pages', $this->expandPage);
1661 $ATag = '';
1662 $ATag_e = '';
1663 $ATag2 = '';
1664 $picon = '';
1665 if (is_array($mainPageRec)) {
1666 $picon = IconUtility::getSpriteIconForRecord('pages', $mainPageRec);
1667 if (in_array('pages', $tablesArr)) {
1668 $ATag = '<a href="#" onclick="return insertElement(\'pages\', \'' . $mainPageRec['uid'] . '\', \'db\', '
1669 . GeneralUtility::quoteJSvalue($mainPageRec['title']) . ', \'\', \'\', \'\',\'\',1);">';
1670 $ATag2 = '<a href="#" onclick="return insertElement(\'pages\', \'' . $mainPageRec['uid'] . '\', \'db\', '
1671 . GeneralUtility::quoteJSvalue($mainPageRec['title']) . ', \'\', \'\', \'\',\'\',0);">';
1672 $ATag_e = '</a>';
1673 }
1674 }
1675 $pBicon = $ATag2 ? IconUtility::getSpriteIcon('actions-edit-add') : '';
1676 $pText = htmlspecialchars(GeneralUtility::fixed_lgd_cs($mainPageRec['title'], $titleLen));
1677 $out .= $picon . $ATag2 . $pBicon . $ATag_e . $ATag . $pText . $ATag_e . '<br />';
1678 // Initialize the record listing:
1679 $id = $this->expandPage;
1680 $pointer = MathUtility::forceIntegerInRange($this->pointer, 0, 100000);
1681 $perms_clause = $backendUser->getPagePermsClause(1);
1682 $pageInfo = BackendUtility::readPageAccess($id, $perms_clause);
1683 // Generate the record list:
1684 /** @var $dbList ElementBrowserRecordList */
1685 if (is_object($this->recordList)) {
1686 $dbList = $this->recordList;
1687 } else {
1688 $dbList = GeneralUtility::makeInstance(ElementBrowserRecordList::class);
1689 }
1690 $dbList->thisScript = $this->thisScript;
1691 $dbList->backPath = $GLOBALS['BACK_PATH'];
1692 $dbList->thumbs = 0;
1693 $dbList->calcPerms = $backendUser->calcPerms($pageInfo);
1694 $dbList->noControlPanels = 1;
1695 $dbList->clickMenuEnabled = 0;
1696 $dbList->tableList = implode(',', $tablesArr);
1697 $pArr = explode('|', $this->bparams);
1698 // a string like "data[pages][79][storage_pid]"
1699 $fieldPointerString = $pArr[0];
1700 // parts like: data, pages], 79], storage_pid]
1701 $fieldPointerParts = explode('[', $fieldPointerString);
1702 $relatingTableName = substr($fieldPointerParts[1], 0, -1);
1703 $relatingFieldName = substr($fieldPointerParts[3], 0, -1);
1704 if ($relatingTableName && $relatingFieldName) {
1705 $dbList->setRelatingTableAndField($relatingTableName, $relatingFieldName);
1706 }
1707 $dbList->start($id, GeneralUtility::_GP('table'), $pointer, GeneralUtility::_GP('search_field'),
1708 GeneralUtility::_GP('search_levels'), GeneralUtility::_GP('showLimit')
1709 );
1710 $dbList->setDispFields();
1711 $dbList->generateList();
1712 $out .= $dbList->getSearchBox();
1713 $out .= "<script>document.getElementById('db_list-searchbox-toolbar').style.display = 'block';document.getElementById('db_list-searchbox-toolbar').style.position = 'relative';</script>";
1714
1715 // Add the HTML for the record list to output variable:
1716 $out .= $dbList->HTMLcode;
1717 // Add support for fieldselectbox in singleTableMode
1718 if ($dbList->table) {
1719 $out .= $dbList->fieldSelectBox($dbList->table);
1720 }
1721
1722 // Return accumulated content:
1723 return $out;
1724 }
1725
1726 /**
1727 * Render list of folders inside a folder.
1728 *
1729 * @param Folder $folder Folder
1730 * @return string HTML output
1731 */
1732 public function TBE_expandSubFolders(Folder $folder) {
1733 $content = '';
1734 if ($folder->checkActionPermission('read')) {
1735 $content .= $this->folderList($folder);
1736 }
1737 // Return accumulated content for folderlisting:
1738 return $content;
1739 }
1740
1741 /******************************************************************
1742 *
1743 * File listing
1744 *
1745 ******************************************************************/
1746 /**
1747 * For RTE: This displays all files from folder. No thumbnails shown
1748 *
1749 * @param Folder $folder The folder path to expand
1750 * @param string $extensionList List of file extensions to show
1751 * @return string HTML output
1752 */
1753 public function expandFolder(Folder $folder, $extensionList = '') {
1754 if (!$folder->checkActionPermission('read')) {
1755 return '';
1756 }
1757 $lang = $this->getLanguageService();
1758 $renderFolders = $this->act === 'folder';
1759 // Create header for file/folder listing:
1760 if ($renderFolders) {
1761 $out = $this->barheader($lang->getLL('folders') . ':');
1762 } else {
1763 $out = $this->barheader($lang->getLL('files') . ':');
1764 }
1765 // Prepare current path value for comparison (showing red arrow)
1766 $currentIdentifier = '';
1767 if ($this->curUrlInfo['value']) {
1768 $currentIdentifier = $this->curUrlInfo['info'];
1769 }
1770 // Create header element; The folder from which files are listed.
1771 $titleLen = (int)$this->getBackendUserAuthentication()->uc['titleLen'];
1772 $folderIcon = IconUtility::getSpriteIconForResource($folder);
1773 $folderIcon .= htmlspecialchars(GeneralUtility::fixed_lgd_cs($folder->getIdentifier(), $titleLen));
1774 $selected = '';
1775 if ($this->curUrlInfo['act'] == 'folder' && $currentIdentifier == $folder->getCombinedIdentifier()) {
1776 $selected = ' class="bg-success"';
1777 }
1778 $out .= '<a href="#"' . $selected . ' title="' . htmlspecialchars($folder->getIdentifier()) . '" onclick="return link_folder(\'file:' . $folder->getCombinedIdentifier() . '\');">'
1779 . $folderIcon . '</a><br />';
1780 // Get files from the folder:
1781 if ($renderFolders) {
1782 $items = $folder->getSubfolders();
1783 } else {
1784 $items = $this->getFilesInFolder($folder, $extensionList);
1785 }
1786 $c = 0;
1787
1788 if (!empty($items)) {
1789 $out .= '<ul class="list-tree flat-tree-root">';
1790 foreach ($items as $fileOrFolderObject) {
1791 $c++;
1792 if ($renderFolders) {
1793 $fileIdentifier = $fileOrFolderObject->getCombinedIdentifier();
1794 $overlays = array();
1795 if ($fileOrFolderObject instanceof InaccessibleFolder) {
1796 $overlays = array('status-overlay-locked' => array());
1797 }
1798 $icon = IconUtility::getSpriteIcon(
1799 IconUtility::mapFileExtensionToSpriteIconName('folder'),
1800 array('title' => $fileOrFolderObject->getName()),
1801 $overlays);
1802 $itemUid = 'file:' . $fileIdentifier;
1803 } else {
1804 $fileIdentifier = $fileOrFolderObject->getUid();
1805 // Get size and icon:
1806 $size = ' (' . GeneralUtility::formatSize($fileOrFolderObject->getSize()) . 'bytes)';
1807 $icon = IconUtility::getSpriteIconForResource($fileOrFolderObject, array('title' => $fileOrFolderObject->getName() . $size));
1808 $itemUid = 'file:' . $fileIdentifier;
1809 }
1810 $selected = '';
1811 if (($this->curUrlInfo['act'] == 'file' || $this->curUrlInfo['act'] == 'folder')
1812 && $currentIdentifier == $fileIdentifier
1813 ) {
1814 $selected = ' class="bg-success"';
1815 }
1816 // Put it all together for the file element:
1817 $out .=
1818 '<li><a href="#"' . $selected . ' title="' . htmlspecialchars($fileOrFolderObject->getName()) . '" onclick="return link_folder(\'' . $itemUid . '\');">' .
1819 $icon .
1820 htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileOrFolderObject->getName(), $titleLen)) .
1821 '</a></li>';
1822 }
1823 $out .= '</ul>';
1824 }
1825 return $out;
1826 }
1827
1828 /**
1829 * For TYPO3 Element Browser: Expand folder of files.
1830 *
1831 * @param Folder $folder The folder path to expand
1832 * @param string $extensionList List of fileextensions to show
1833 * @param bool $noThumbs Whether to show thumbnails or not. If set, no thumbnails are shown.
1834 * @return string HTML output
1835 */
1836 public function TBE_expandFolder(Folder $folder, $extensionList = '', $noThumbs = FALSE) {
1837 if (!$folder->checkActionPermission('read')) {
1838 return '';
1839 }
1840 $extensionList = $extensionList == '*' ? '' : $extensionList;
1841 $files = $this->getFilesInFolder($folder, $extensionList);
1842 return $this->fileList($files, $folder, $noThumbs);
1843 }
1844
1845 /**
1846 * Render list of files.
1847 *
1848 * @param File[] $files List of files
1849 * @param Folder $folder If set a header with a folder icon and folder name are shown
1850 * @param bool $noThumbs Whether to show thumbnails or not. If set, no thumbnails are shown.
1851 * @return string HTML output
1852 */
1853 protected function fileList(array $files, Folder $folder = NULL, $noThumbs = FALSE) {
1854 $out = '';
1855
1856 $lang = $this->getLanguageService();
1857 $lines = array();
1858 // Create headline (showing number of files):
1859 $filesCount = count($files);
1860 $out .= $this->barheader(sprintf($lang->getLL('files') . ' (%s):', $filesCount));
1861 $out .= '<div id="filelist">';
1862 $out .= $this->getBulkSelector($filesCount);
1863 $titleLen = (int)$this->getBackendUserAuthentication()->uc['titleLen'];
1864 // Create the header of current folder:
1865 if ($folder) {
1866 $folderIcon = IconUtility::getSpriteIconForResource($folder);
1867 $lines[] = '<tr class="t3-row-header">
1868 <td colspan="4">' . $folderIcon
1869 . htmlspecialchars(GeneralUtility::fixed_lgd_cs($folder->getIdentifier(), $titleLen)) . '</td>
1870 </tr>';
1871 }
1872 if ($filesCount == 0) {
1873 $lines[] = '
1874 <tr class="file_list_normal">
1875 <td colspan="4">No files found.</td>
1876 </tr>';
1877 }
1878 // Traverse the file list:
1879 /** @var $fileObject \TYPO3\CMS\Core\Resource\File */
1880 foreach ($files as $fileObject) {
1881 $fileExtension = $fileObject->getExtension();
1882 // Thumbnail/size generation:
1883 $imgInfo = array();
1884 if (GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']), strtolower($fileExtension)) && !$noThumbs) {
1885 $processedFile = $fileObject->process(
1886 ProcessedFile::CONTEXT_IMAGEPREVIEW,
1887 array('width' => 64, 'height' => 64)
1888 );
1889 $imageUrl = $processedFile->getPublicUrl(TRUE);
1890 $imgInfo = array(
1891 $fileObject->getProperty('width'),
1892 $fileObject->getProperty('height')
1893 );
1894 $pDim = $imgInfo[0] . 'x' . $imgInfo[1] . ' pixels';
1895 $clickIcon = '<img src="' . $imageUrl . '" ' .
1896 'width="' . $processedFile->getProperty('width') . '" ' .
1897 'height="' . $processedFile->getProperty('height') . '" ' .
1898 'hspace="5" vspace="5" border="1" />';
1899 } else {
1900 $clickIcon = '';
1901 $pDim = '';
1902 }
1903 // Create file icon:
1904 $size = ' (' . GeneralUtility::formatSize($fileObject->getSize()) . 'bytes' . ($pDim ? ', ' . $pDim : '') . ')';
1905 $icon = IconUtility::getSpriteIconForResource($fileObject, array('title' => $fileObject->getName() . $size));
1906 // Create links for adding the file:
1907 $filesIndex = count($this->elements);
1908 $this->elements['file_' . $filesIndex] = array(
1909 'type' => 'file',
1910 'table' => 'sys_file',
1911 'uid' => $fileObject->getUid(),
1912 'fileName' => $fileObject->getName(),
1913 'filePath' => $fileObject->getUid(),
1914 'fileExt' => $fileExtension,
1915 'fileIcon' => $icon
1916 );
1917 if ($this->fileIsSelectableInFileList($fileObject, $imgInfo)) {
1918 $ATag = '<a href="#" title="' . htmlspecialchars($fileObject->getName()) . '" onclick="return BrowseLinks.File.insertElement(\'file_' . $filesIndex . '\');">';
1919 $ATag_alt = substr($ATag, 0, -4) . ',1);">';
1920 $bulkCheckBox = '<input type="checkbox" class="typo3-bulk-item" name="file_' . $filesIndex . '" value="0" /> ';
1921 $ATag_e = '</a>';
1922 } else {
1923 $ATag = '';
1924 $ATag_alt = '';
1925 $ATag_e = '';
1926 $bulkCheckBox = '';
1927 }
1928 // Create link to showing details about the file in a window:
1929 $Ahref = $GLOBALS['BACK_PATH'] . 'show_item.php?type=file&table=_FILE&uid='
1930 . rawurlencode($fileObject->getCombinedIdentifier())
1931 . '&returnUrl=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI'));
1932 $ATag2 = '<a href="' . htmlspecialchars($Ahref) . '">';
1933 $ATag2_e = '</a>';
1934 // Combine the stuff:
1935 $filenameAndIcon = $bulkCheckBox . $ATag_alt . $icon
1936 . htmlspecialchars(GeneralUtility::fixed_lgd_cs($fileObject->getName(), $titleLen)) . $ATag_e;
1937 // Show element:
1938 if ($pDim) {
1939 // Image...
1940 $lines[] = '
1941 <tr class="file_list_normal">
1942 <td nowrap="nowrap">' . $filenameAndIcon . '&nbsp;</td>
1943 <td>' . $ATag . IconUtility::getSpriteIcon('actions-edit-add', array('title' => $lang->getLL('addToList', TRUE))) . $ATag_e . '</td>
1944 <td nowrap="nowrap">' . $ATag2 . IconUtility::getSpriteIcon('actions-document-info', array('title' => $lang->getLL('info', TRUE))) . $lang->getLL('info', TRUE) . $ATag2_e . '</td>
1945 <td nowrap="nowrap">&nbsp;' . $pDim . '</td>
1946 </tr>';
1947 $lines[] = '
1948 <tr>
1949 <td class="filelistThumbnail" colspan="4">' . $ATag_alt . $clickIcon . $ATag_e . '</td>
1950 </tr>';
1951 } else {
1952 $lines[] = '
1953 <tr class="file_list_normal">
1954 <td nowrap="nowrap">' . $filenameAndIcon . '&nbsp;</td>
1955 <td>' . $ATag . IconUtility::getSpriteIcon('actions-edit-add', array('title' => $lang->getLL('addToList', TRUE))) . $ATag_e . '</td>
1956 <td nowrap="nowrap">' . $ATag2 . IconUtility::getSpriteIcon('actions-document-info', array('title' => $lang->getLL('info', TRUE))) . $lang->getLL('info', TRUE) . $ATag2_e . '</td>
1957 <td>&nbsp;</td>
1958 </tr>';
1959 }
1960 }
1961 // Wrap all the rows in table tags:
1962 $out .= '
1963
1964 <!--
1965 File listing
1966 -->
1967 <table cellpadding="0" cellspacing="0" id="typo3-filelist">
1968 ' . implode('', $lines) . '
1969 </table>';
1970 // Return accumulated content for file listing:
1971 $out .= '</div>';
1972 return $out;
1973 }
1974
1975 /**
1976 * Checks if the given file is selectable in the file list.
1977 *
1978 * By default all files are selectable. This method may be overwritten in child classes.
1979 *
1980 * @param FileInterface $file
1981 * @param mixed[] $imgInfo Image dimensions from \TYPO3\CMS\Core\Imaging\GraphicalFunctions::getImageDimensions()
1982 * @return bool TRUE if file is selectable.
1983 */
1984 protected function fileIsSelectableInFileList(FileInterface $file, array $imgInfo) {
1985 return TRUE;
1986 }
1987
1988 /**
1989 * Render list of folders.
1990 *
1991 * @param Folder $baseFolder
1992 * @return string HTML output
1993 */
1994 public function folderList(Folder $baseFolder) {
1995 $content = '';
1996 $lang = $this->getLanguageService();
1997 $folders = $baseFolder->getSubfolders();
1998 $folderIdentifier = $baseFolder->getCombinedIdentifier();
1999 // Create headline (showing number of folders):
2000 $content .= $this->barheader(sprintf($lang->getLL('folders') . ' (%s):', count($folders)));
2001 $titleLength = (int)$this->getBackendUserAuthentication()->uc['titleLen'];
2002 // Create the header of current folder:
2003 $aTag = '<a href="#" onclick="return insertElement(\'\',' . GeneralUtility::quoteJSvalue($folderIdentifier)
2004 . ', \'folder\', ' . GeneralUtility::quoteJSvalue($folderIdentifier) . ', ' . GeneralUtility::quoteJSvalue($folderIdentifier)
2005 . ', \'\', \'\',\'\',1);">';
2006 // Add the foder icon
2007 $folderIcon = $aTag;
2008 $folderIcon .= IconUtility::getSpriteIcon('apps-filetree-folder-default');
2009 $folderIcon .= htmlspecialchars(GeneralUtility::fixed_lgd_cs($baseFolder->getName(), $titleLength));
2010 $folderIcon .= '</a>';
2011 $content .= $folderIcon . '<br />';
2012
2013 $lines = array();
2014 // Traverse the folder list:
2015 foreach ($folders as $subFolder) {
2016 $subFolderIdentifier = $subFolder->getCombinedIdentifier();
2017 // Create folder icon:
2018 $icon = '<img src="clear.gif" width="16" height="16" alt="" />';
2019 $icon .= IconUtility::getSpriteIcon('apps-filetree-folder-default', array('title' => htmlspecialchars($subFolder->getName())));
2020 // Create links for adding the folder:
2021 if ($this->P['itemName'] != '' && $this->P['formName'] != '') {
2022 $aTag = '<a href="#" onclick="return set_folderpath(' . GeneralUtility::quoteJSvalue($subFolderIdentifier)
2023 . ');">';
2024 } else {
2025 $aTag = '<a href="#" onclick="return insertElement(\'\',' . GeneralUtility::quoteJSvalue($subFolderIdentifier)
2026 . ', \'folder\', ' . GeneralUtility::quoteJSvalue($subFolderIdentifier) . ', '
2027 . GeneralUtility::quoteJSvalue($subFolderIdentifier) . ', \'\', \'\');">';
2028 }
2029 if (strstr($subFolderIdentifier, ',') || strstr($subFolderIdentifier, '|')) {
2030 // In case an invalid character is in the filepath, display error message:
2031 $errorMessage = GeneralUtility::quoteJSvalue(sprintf($lang->getLL('invalidChar'), ', |'));
2032 $aTag = ($aTag_alt = '<a href="#" onclick="alert(' . $errorMessage . ');return false;">');
2033 } else {
2034 // If foldername is OK, just add it:
2035 $aTag_alt = substr($aTag, 0, -4) . ',\'\',1);">';
2036 }
2037 $aTag_e = '</a>';
2038 // Combine icon and folderpath:
2039 $foldernameAndIcon = $aTag_alt . $icon
2040 . htmlspecialchars(GeneralUtility::fixed_lgd_cs($subFolder->getName(), $titleLength)) . $aTag_e;
2041 if ($this->P['itemName'] != '') {
2042 $lines[] = '
2043 <tr class="bgColor4">
2044 <td nowrap="nowrap">' . $foldernameAndIcon . '&nbsp;</td>
2045 <td>&nbsp;</td>
2046 </tr>';
2047 } else {
2048 $lines[] = '
2049 <tr class="bgColor4">
2050 <td nowrap="nowrap">' . $foldernameAndIcon . '&nbsp;</td>
2051 <td>' . $aTag . IconUtility::getSpriteIcon('actions-edit-add', array('title' => $lang->getLL('addToList', TRUE))) . $aTag_e . ' </td>
2052 <td>&nbsp;</td>
2053 </tr>';
2054 }
2055 $lines[] = '
2056 <tr>
2057 <td colspan="3"><img src="clear.gif" width="1" height="3" alt="" /></td>
2058 </tr>';
2059 }
2060 // Wrap all the rows in table tags:
2061 $content .= '
2062
2063 <!--
2064 Folder listing
2065 -->
2066 <table border="0" cellpadding="0" cellspacing="1" id="typo3-folderList">
2067 ' . implode('', $lines) . '
2068 </table>';
2069 // Return accumulated content for folderlisting:
2070 return $content;
2071 }
2072
2073 /**
2074 * For RTE: This displays all IMAGES (gif,png,jpg) (from extensionList) from folder. Thumbnails are shown for images.
2075 * This listing is of images located in the web-accessible paths ONLY - the listing is for drag-n-drop use in the RTE
2076 *
2077 * @param Folder $folder The folder path to expand
2078 * @param string $extensionList List of file extensions to show
2079 * @return string HTML output
2080 */
2081 public function TBE_dragNDrop(Folder $folder, $extensionList = '') {
2082 if (!$folder) {
2083 return '';
2084 }
2085 $lang = $this->getLanguageService();
2086 if (!$folder->getStorage()->isPublic()) {
2087 // Print this warning if the folder is NOT a web folder
2088 return $this->barheader($lang->getLL('files'))
2089 . $this->getMsgBox($lang->getLL('noWebFolder'), 'status-dialog-warning');
2090 }
2091 $out = '';
2092
2093 // Read files from directory:
2094 $extensionList = $extensionList == '*' ? '' : $extensionList;
2095 $files = $this->getFilesInFolder($folder, $extensionList);
2096
2097 $out .= $this->barheader(sprintf($lang->getLL('files') . ' (%s):', count($files)));
2098 $titleLen = (int)$this->getBackendUserAuthentication()->uc['titleLen'];
2099 $picon = IconUtility::getSpriteIcon('apps-filetree-folder-default');
2100 $picon .= htmlspecialchars(GeneralUtility::fixed_lgd_cs(basename($folder->getName()), $titleLen));
2101 $out .= $picon . '<br />';
2102 // Init row-array:
2103 $lines = array();
2104 // Add "drag-n-drop" message:
2105 $lines[] = '
2106 <tr>
2107 <td colspan="2">' . $this->getMsgBox($lang->getLL('findDragDrop')) . '</td>
2108 </tr>';
2109 // Traverse files:
2110 foreach ($files as $fileObject) {
2111 // URL of image:
2112 $iUrl = GeneralUtility::rawurlencodeFP($fileObject->getPublicUrl(TRUE));
2113 // Show only web-images
2114 $fileExtension = strtolower($fileObject->getExtension());
2115 if (GeneralUtility::inList('gif,jpeg,jpg,png', $fileExtension)) {
2116 $imgInfo = array(
2117 $fileObject->getProperty('width'),
2118 $fileObject->getProperty('height')
2119 );
2120 $pDim = $imgInfo[0] . 'x' . $imgInfo[1] . ' pixels';
2121 $size = ' (' . GeneralUtility::formatSize($fileObject->getSize()) . 'bytes' . ($pDim ? ', ' . $pDim : '') . ')';
2122 $filenameAndIcon = IconUtility::getSpriteIconForResource($fileObject, array('title' => $fileObject->getName() . $size));
2123 if (GeneralUtility::_GP('noLimit')) {
2124 $maxW = 10000;
2125 $maxH = 10000;
2126 } else {
2127 $maxW = 380;
2128 $maxH = 500;
2129 }
2130 $IW = $imgInfo[0];
2131 $IH = $imgInfo[1];
2132 if ($IW > $maxW) {
2133 $IH = ceil($IH / $IW * $maxW);
2134 $IW = $maxW;
2135 }
2136 if ($IH > $maxH) {
2137 $IW = ceil($IW / $IH * $maxH);
2138 $IH = $maxH;
2139 }
2140 // Make row:
2141 $lines[] = '
2142 <tr class="bgColor4">
2143 <td nowrap="nowrap">' . $filenameAndIcon . '&nbsp;</td>
2144 <td nowrap="nowrap">' . ($imgInfo[0] != $IW
2145 ? '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('noLimit' => '1')))
2146 . '">' . IconUtility::getSpriteIcon('status-dialog-warning', array('title' => $lang->getLL('clickToRedrawFullSize', TRUE)))
2147 . '</a>'
2148 : '')
2149 . $pDim . '&nbsp;</td>
2150 </tr>';
2151 $lines[] = '
2152 <tr>
2153 <td colspan="2"><img src="' . htmlspecialchars($iUrl) . '" data-htmlarea-file-uid="' . $fileObject->getUid()
2154 . '" width="' . htmlspecialchars($IW) . '" height="' . htmlspecialchars($IH) . '" border="1" alt="" /></td>
2155 </tr>';
2156 $lines[] = '
2157 <tr>
2158 <td colspan="2"><img src="clear.gif" width="1" height="3" alt="" /></td>
2159 </tr>';
2160 }
2161 }
2162 // Finally, wrap all rows in a table tag:
2163 $out .= '
2164
2165
2166 <!--
2167 File listing / Drag-n-drop
2168 -->
2169 <table border="0" cellpadding="0" cellspacing="1" id="typo3-dragBox">
2170 ' . implode('', $lines) . '
2171 </table>';
2172
2173 return $out;
2174 }
2175
2176 /******************************************************************
2177 *
2178 * Miscellaneous functions
2179 *
2180 ******************************************************************/
2181
2182 /**
2183 * Prints a 'header' where string is in a tablecell
2184 *
2185 * @param string $str The string to print in the header. The value is htmlspecialchars()'ed before output.
2186 * @return string The header HTML (wrapped in a table)
2187 */
2188 public function barheader($str) {
2189 return '
2190 <!-- Bar header: -->
2191 <h3>' . htmlspecialchars($str) . '</h3>
2192 ';
2193 }
2194
2195 /**
2196 * Displays a message box with the input message
2197 *
2198 * @param string $inputMessage Input message to show (will be htmlspecialchars()'ed inside of this function)
2199 * @param string $icon Sprite sprite name. Default is 'actions-document-info'.
2200 * @return string HTML for the message (wrapped in a table).
2201 */
2202 public function getMsgBox($inputMessage, $icon = 'actions-document-info') {
2203 return '
2204 <!-- Message box -->
2205 <table cellspacing="0" class="bgColor4" id="typo3-msgBox">
2206 <tr>
2207 <td>' . IconUtility::getSpriteIcon($icon) . htmlspecialchars($inputMessage) . '</td>
2208 </tr>
2209 </table>
2210 ';
2211 }
2212
2213 /**
2214 * For RTE/link: This prints the 'currentUrl'
2215 *
2216 * @param string $str URL value. The value is htmlspecialchars()'ed before output.
2217 * @return string HTML content, wrapped in a table.
2218 */
2219 public function printCurrentUrl($str) {
2220 // Output the folder or file identifier, when working with files
2221 if (isset($str) && MathUtility::canBeInterpretedAsInteger($str)) {
2222 try {
2223 $fileObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($str);
2224 } catch (Exception\FileDoesNotExistException $e) {
2225 $fileObject = NULL;
2226 }
2227 $str = is_object($fileObject) ? $fileObject->getIdentifier() : '';
2228 }
2229 if ($str !== '') {
2230 return '
2231 <!-- Print current URL -->
2232 <table border="0" cellpadding="0" cellspacing="0" id="typo3-curUrl">
2233 <tr>
2234 <td>' . $this->getLanguageService()->getLL('currentLink', TRUE) . ': '
2235 . htmlspecialchars(rawurldecode($str)) . '</td>
2236 </tr>
2237 </table>';
2238 } else {
2239 return '';
2240 }
2241 }
2242
2243 /**
2244 * For RTE/link: Parses the incoming URL and determines if it's a page, file, external or mail address.
2245 *
2246 * @param string $href HREF value tp analyse
2247 * @param string $siteUrl The URL of the current website (frontend)
2248 * @return array[] Array with URL information stored in assoc. keys: value, act (page, file, mail), pageid, cElement, info
2249 */
2250 public function parseCurUrl($href, $siteUrl) {
2251 $href = trim($href);
2252 $lang = $this->getLanguageService();
2253 if ($href) {
2254 $info = array();
2255 // Default is "url":
2256 $info['value'] = $href;
2257 $info['act'] = 'url';
2258 if (!StringUtility::beginsWith($href, 'file://') && strpos($href, 'file:') !== FALSE) {
2259 $rel = substr($href, strpos($href, 'file:') + 5);
2260 $rel = rawurldecode($rel);
2261 // resolve FAL-api "file:UID-of-sys_file-record" and "file:combined-identifier"
2262 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($rel);
2263 if ($fileOrFolderObject instanceof Folder) {
2264 $info['act'] = 'folder';
2265 $info['value'] = $fileOrFolderObject->getCombinedIdentifier();
2266 } elseif ($fileOrFolderObject instanceof File) {
2267 $info['act'] = 'file';
2268 $info['value'] = $fileOrFolderObject->getUid();
2269 } else {
2270 $info['value'] = $rel;
2271 }
2272 } elseif (StringUtility::beginsWith($href, $siteUrl)) {
2273 // If URL is on the current frontend website:
2274 // URL is a file, which exists:
2275 if (file_exists(PATH_site . rawurldecode($href))) {
2276 $info['value'] = rawurldecode($href);
2277 if (@is_dir((PATH_site . $info['value']))) {
2278 $info['act'] = 'folder';
2279 } else {
2280 $info['act'] = 'file';
2281 }
2282 } else {
2283 // URL is a page (id parameter)
2284 $uP = parse_url($href);
2285
2286 $pp = preg_split('/^id=/', $uP['query']);
2287 $pp[1] = preg_replace('/&id=[^&]*/', '', $pp[1]);
2288 $parameters = explode('&', $pp[1]);
2289 $id = array_shift($parameters);
2290 if ($id) {
2291 // Checking if the id-parameter is an alias.
2292 if (!MathUtility::canBeInterpretedAsInteger($id)) {
2293 list($idPartR) = BackendUtility::getRecordsByField('pages', 'alias', $id);
2294 $id = (int)$idPartR['uid'];
2295 }
2296 $pageRow = BackendUtility::getRecordWSOL('pages', $id);
2297 $titleLen = (int)$this->getBackendUserAuthentication()->uc['titleLen'];
2298 $info['value'] = ((((($lang->getLL('page', TRUE) . ' \'')
2299 . htmlspecialchars(GeneralUtility::fixed_lgd_cs($pageRow['title'], $titleLen)))
2300 . '\' (ID:') . $id) . ($uP['fragment'] ? ', #' . $uP['fragment'] : '')) . ')';
2301 $info['pageid'] = $id;
2302 $info['cElement'] = $uP['fragment'];
2303 $info['act'] = 'page';
2304 $info['query'] = $parameters[0] ? '&' . implode('&', $parameters) : '';
2305 }
2306 }
2307 } else {
2308 // Email link:
2309 if (strtolower(substr($href, 0, 7)) === 'mailto:') {
2310 $info['value'] = trim(substr($href, 7));
2311 $info['act'] = 'mail';
2312 }
2313 }
2314 $info['info'] = $info['value'];
2315 } else {
2316 // NO value input:
2317 $info = array();
2318 $info['info'] = $lang->getLL('none');
2319 $info['value'] = '';
2320 $info['act'] = 'page';
2321 }
2322 // let the hook have a look
2323 foreach ($this->hookObjects as $hookObject) {
2324 $info = $hookObject->parseCurrentUrl($href, $siteUrl, $info);
2325 }
2326 return $info;
2327 }
2328
2329 /**
2330 * Setter for the class that should be used by TBE_expandPage() to generate the record list.
2331 * This method is intended to be used by Extensions that implement their own browsing functionality.
2332 *
2333 * @param ElementBrowserRecordList $recordList
2334 * @throws \InvalidArgumentException
2335 * @return void
2336 * @api
2337 */
2338 public function setRecordList($recordList) {
2339 if (!$recordList instanceof ElementBrowserRecordList) {
2340 throw new \InvalidArgumentException('$recordList needs to be an instance of ' . ElementBrowserRecordList::class, 1370878522);
2341 }
2342 $this->recordList = $recordList;
2343 }
2344
2345 /**
2346 * For TBE: Makes an upload form for uploading files to the filemount the user is browsing.
2347 * The files are uploaded to the tce_file.php script in the core which will handle the upload.
2348 *
2349 * @param Folder $folderObject Absolute filepath on server to which to upload.
2350 * @return string HTML for an upload form.
2351 */
2352 public function uploadForm(Folder $folderObject) {
2353 if (!$folderObject->checkActionPermission('write')) {
2354 return '';
2355 }
2356 // Read configuration of upload field count
2357 $userSetting = $this->getBackendUserAuthentication()->getTSConfigVal('options.folderTree.uploadFieldsInLinkBrowser');
2358 $count = isset($userSetting) ? $userSetting : 1;
2359 if ($count === '0') {
2360 return '';
2361 }
2362 $count = (int)$count === 0 ? 1 : (int)$count;
2363 // Create header, showing upload path:
2364 $header = $folderObject->getIdentifier();
2365 $lang = $this->getLanguageService();
2366 $code = '
2367 <br />
2368 <!--
2369 Form, for uploading files:
2370 -->
2371 <form action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_file')) . '" method="post" name="editform"'
2372 . ' id="typo3-uplFilesForm" enctype="multipart/form-data">
2373 <table border="0" cellpadding="0" cellspacing="0" id="typo3-uplFiles">
2374 <tr>
2375 <td>' . $this->barheader($lang->sL(
2376 'LLL:EXT:lang/locallang_core.xlf:file_upload.php.pagetitle', TRUE) . ':') . '</td>
2377 </tr>
2378 <tr>
2379 <td class="c-wCell c-hCell"><strong>' . $lang->getLL('path', TRUE) . ':</strong> '
2380 . htmlspecialchars($header) . '</td>
2381 </tr>
2382 <tr>
2383 <td class="c-wCell c-hCell">';
2384 // Traverse the number of upload fields (default is 3):
2385 for ($a = 1; $a <= $count; $a++) {
2386 $code .= '<input type="file" multiple="multiple" name="upload_' . $a . '[]"' . $this->doc->formWidth(35)
2387 . ' size="50" />
2388 <input type="hidden" name="file[upload][' . $a . '][target]" value="'
2389 . htmlspecialchars($folderObject->getCombinedIdentifier()) . '" />
2390 <input type="hidden" name="file[upload][' . $a . '][data]" value="' . $a . '" /><br />';
2391 }
2392 // Make footer of upload form, including the submit button:
2393 $redirectValue = $this->getThisScript() . 'act=' . $this->act . '&mode=' . $this->mode
2394 . '&expandFolder=' . rawurlencode($folderObject->getCombinedIdentifier())
2395 . '&bparams=' . rawurlencode($this->bparams)
2396 . (is_array($this->P) ? GeneralUtility::implodeArrayForUrl('P', $this->P) : '');
2397 $code .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($redirectValue) . '" />';
2398 $code .= FormEngine::getHiddenTokenField('tceAction');
2399 $code .= '
2400 <div id="c-override">
2401 <label>
2402 <input type="checkbox" name="overwriteExistingFiles" id="overwriteExistingFiles" value="1" /> '
2403 . $lang->sL('LLL:EXT:lang/locallang_misc.xlf:overwriteExistingFiles', TRUE) . '
2404 </label>
2405 </div>
2406 <input class="btn btn-default" type="submit" name="submit" value="'
2407 . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_upload.php.submit', TRUE) . '" />
2408 ';
2409 $code .= '</td>
2410 </tr>
2411 </table>
2412 </form><br />';
2413 return $code;
2414 }
2415
2416 /**
2417 * For TBE: Makes a form for creating new folders in the filemount the user is browsing.
2418 * The folder creation request is sent to the tce_file.php script in the core which will handle the creation.
2419 *
2420 * @param Folder $folderObject Absolute filepath on server in which to create the new folder.
2421 * @return string HTML for the create folder form.
2422 */
2423 public function createFolder(Folder $folderObject) {
2424 if (!$folderObject->checkActionPermission('write')) {
2425 return '';
2426 }
2427 $backendUser = $this->getBackendUserAuthentication();
2428 if (!($backendUser->isAdmin() || $backendUser->getTSConfigVal('options.createFoldersInEB'))) {
2429 return '';
2430 }
2431 // Don't show Folder-create form if it's denied
2432 if ($backendUser->getTSConfigVal('options.folderTree.hideCreateFolder')) {
2433 return '';
2434 }
2435 $lang = $this->getLanguageService();
2436 // Create header, showing upload path:
2437 $header = $folderObject->getIdentifier();
2438 $code = '
2439
2440 <!--
2441 Form, for creating new folders:
2442 -->
2443 <form action="' . htmlspecialchars(BackendUtility::getModuleUrl('tce_file')) . '" method="post" name="editform2" id="typo3-crFolderForm">
2444 <table border="0" cellpadding="0" cellspacing="0" id="typo3-crFolder">
2445 <tr>
2446 <td>' . $this->barheader($lang->sL(
2447 'LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.pagetitle') . ':') . '</td>
2448 </tr>
2449 <tr>
2450 <td class="c-wCell c-hCell"><strong>'
2451 . $lang->getLL('path', TRUE) . ':</strong> ' . htmlspecialchars($header) . '</td>
2452 </tr>
2453 <tr>
2454 <td class="c-wCell c-hCell">';
2455 // Create the new-folder name field:
2456 $a = 1;
2457 $code .= '<input' . $this->doc->formWidth(20) . ' type="text" name="file[newfolder][' . $a . '][data]" />'
2458 . '<input type="hidden" name="file[newfolder][' . $a . '][target]" value="'
2459 . htmlspecialchars($folderObject->getCombinedIdentifier()) . '" />';
2460 // Make footer of upload form, including the submit button:
2461 $redirectValue = $this->getThisScript() . 'act=' . $this->act . '&mode=' . $this->mode
2462 . '&expandFolder=' . rawurlencode($folderObject->getCombinedIdentifier())
2463 . '&bparams=' . rawurlencode($this->bparams)
2464 . (is_array($this->P) ? GeneralUtility::implodeArrayForUrl('P', $this->P) : '');
2465 $code .= '<input type="hidden" name="redirect" value="' . htmlspecialchars($redirectValue) . '" />'
2466 . FormEngine::getHiddenTokenField('tceAction')
2467 . '<input class="btn btn-default" type="submit" name="submit" value="'
2468 . $lang->sL('LLL:EXT:lang/locallang_core.xlf:file_newfolder.php.submit', TRUE) . '" />';
2469 $code .= '</td>
2470 </tr>
2471 </table>
2472 </form>';
2473 return $code;
2474 }
2475
2476 /**
2477 * Get the HTML data required for a bulk selection of files of the TYPO3 Element Browser.
2478 *
2479 * @param int $filesCount Number of files currently displayed
2480 * @return string HTML data required for a bulk selection of files - if $filesCount is 0, nothing is returned
2481 */
2482 public function getBulkSelector($filesCount) {
2483 if (!$filesCount) {
2484 return '';
2485 }
2486
2487 $lang = $this->getLanguageService();
2488 $labelToggleSelection = $lang->sL('LLL:EXT:lang/locallang_browse_links.xlf:toggleSelection', TRUE);
2489 $labelImportSelection = $lang->sL('LLL:EXT:lang/locallang_browse_links.xlf:importSelection', TRUE);
2490 // Getting flag for showing/not showing thumbnails:
2491 $noThumbsInEB = $this->getBackendUserAuthentication()->getTSConfigVal('options.noThumbsInEB');
2492 $out = $this->doc->spacer(10) . '<div>' . '<a href="#" onclick="BrowseLinks.Selector.handle()">'
2493 . IconUtility::getSpriteIcon('actions-document-import-t3d', array('title' => $labelImportSelection))
2494 . $labelImportSelection . '</a>&nbsp;&nbsp;&nbsp;'
2495 . '<a href="#" onclick="BrowseLinks.Selector.toggle()">'
2496 . IconUtility::getSpriteIcon('actions-document-select', array('title' => $labelToggleSelection))
2497 . $labelToggleSelection . '</a>' . '</div>';
2498 if (!$noThumbsInEB && $this->selectedFolder) {
2499 // MENU-ITEMS, fetching the setting for thumbnails from File>List module:
2500 $_MOD_MENU = array('displayThumbs' => '');
2501 $_MCONF['name'] = 'file_list';
2502 $_MOD_SETTINGS = BackendUtility::getModuleData($_MOD_MENU, GeneralUtility::_GP('SET'), $_MCONF['name']);
2503 $addParams = '&act=' . $this->act . '&mode=' . $this->mode
2504 . '&expandFolder=' . rawurlencode($this->selectedFolder->getCombinedIdentifier())
2505 . '&bparams=' . rawurlencode($this->bparams);
2506 $thumbNailCheck = BackendUtility::getFuncCheck('', 'SET[displayThumbs]', $_MOD_SETTINGS['displayThumbs'],
2507 GeneralUtility::_GP('M') ? '' : $this->thisScript, $addParams, 'id="checkDisplayThumbs"')
2508 . ' <label for="checkDisplayThumbs">'
2509 . $lang->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:displayThumbs', TRUE) . '</label>';
2510 $out .= $this->doc->spacer(5) . $thumbNailCheck . $this->doc->spacer(15);
2511 } else {
2512 $out .= $this->doc->spacer(15);
2513 }
2514 return $out;
2515 }
2516
2517 /**
2518 * Determines whether submitted field change functions are valid
2519 * and are coming from the system and not from an external abuse.
2520 *
2521 * @param bool $handleFlexformSections Whether to handle flexform sections differently
2522 * @return bool Whether the submitted field change functions are valid
2523 */
2524 protected function areFieldChangeFunctionsValid($handleFlexformSections = FALSE) {
2525 $result = FALSE;
2526 if (isset($this->P['fieldChangeFunc']) && is_array($this->P['fieldChangeFunc']) && isset($this->P['fieldChangeFuncHash'])) {
2527 $matches = array();
2528 $pattern = '#\\[el\\]\\[(([^]-]+-[^]-]+-)(idx\\d+-)([^]]+))\\]#i';
2529 $fieldChangeFunctions = $this->P['fieldChangeFunc'];
2530 // Special handling of flexform sections:
2531 // Field change functions are modified in JavaScript, thus the hash is always invalid
2532 if ($handleFlexformSections && preg_match($pattern, $this->P['itemName'], $matches)) {
2533 $originalName = $matches[1];
2534 $cleanedName = $matches[2] . $matches[4];
2535 foreach ($fieldChangeFunctions as &$value) {
2536 $value = str_replace($originalName, $cleanedName, $value);
2537 }
2538 unset($value);
2539 }
2540 $result = $this->P['fieldChangeFuncHash'] === GeneralUtility::hmac(serialize($fieldChangeFunctions));
2541 }
2542 return $result;
2543 }
2544
2545 /**
2546 * Check if a temporary tree mount is set and return a cancel button
2547 *
2548 * @return string
2549 */
2550 protected function getTemporaryTreeMountCancelNotice() {
2551 if ((int)$this->getBackendUserAuthentication()->getSessionData('pageTree_temporaryMountPoint') === 0) {
2552 return '';
2553 }
2554 $link = '<a href="' . htmlspecialchars(GeneralUtility::linkThisScript(array('setTempDBmount' => 0))) . '">'
2555 . $this->getLanguageService()->sl('LLL:EXT:lang/locallang_core.xlf:labels.temporaryDBmount', TRUE) . '</a>';
2556 /** @var FlashMessage $flashMessage */
2557 $flashMessage = GeneralUtility::makeInstance(
2558 FlashMessage::class,
2559 $link,
2560 '',
2561 FlashMessage::INFO
2562 );
2563 return $flashMessage->render();
2564 }
2565
2566 /**
2567 * Get a list of Files in a folder filtered by extension
2568 *
2569 * @param Folder $folder
2570 * @param string $extensionList
2571 * @return \TYPO3\CMS\Core\Resource\File[]
2572 */
2573 protected function getFilesInFolder(Folder $folder, $extensionList) {
2574 if ($extensionList !== '') {
2575 /** @var FileExtensionFilter $filter */
2576 $filter = GeneralUtility::makeInstance(FileExtensionFilter::class);
2577 $filter->setAllowedFileExtensions($extensionList);
2578 $folder->setFileAndFolderNameFilters(array(array($filter, 'filterFileList')));
2579 }
2580 return $folder->getFiles();
2581 }
2582
2583 /**
2584 * @return LanguageService
2585 */
2586 protected function getLanguageService() {
2587 return $GLOBALS['LANG'];
2588 }
2589
2590 /**
2591 * @return BackendUserAuthentication
2592 */
2593 protected function getBackendUserAuthentication() {
2594 return $GLOBALS['BE_USER'];
2595 }
2596
2597 /**
2598 * @return DatabaseConnection
2599 */
2600 protected function getDatabaseConnection() {
2601 return $GLOBALS['TYPO3_DB'];
2602 }
2603
2604 /**
2605 * @return PageRenderer
2606 */
2607 protected function getPageRenderer() {
2608 if ($this->pageRenderer === NULL) {
2609 $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
2610 }
2611
2612 return $this->pageRenderer;
2613 }
2614
2615 }