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