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