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