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