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