[BUGFIX] Check correctly for allowed localization action
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / SelectImage.php
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea;
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\Tree\View\ElementBrowserFolderTreeView;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Messaging\FlashMessage;
20 use TYPO3\CMS\Core\Resource\File;
21 use TYPO3\CMS\Core\Resource\FileInterface;
22 use TYPO3\CMS\Core\Resource\Folder;
23 use TYPO3\CMS\Core\Resource\ResourceFactory;
24 use TYPO3\CMS\Core\Resource\Service\MagicImageService;
25 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Lang\LanguageService;
28 use TYPO3\CMS\Recordlist\Browser\ElementBrowser;
29
30 /**
31 * Script Class
32 */
33 class SelectImage extends ElementBrowser
34 {
35 /**
36 * These file extensions are allowed in the "plain" image selection mode.
37 *
38 * @const
39 */
40 const PLAIN_MODE_IMAGE_FILE_EXTENSIONS = 'jpg,jpeg,gif,png';
41
42 /**
43 * @var string
44 */
45 public $extKey = 'rtehtmlarea';
46
47 /**
48 * @var string
49 */
50 public $content;
51
52 /**
53 * @var array
54 */
55 public $allowedItems;
56
57 /**
58 * @var array
59 */
60 public $allowedFileTypes = array();
61
62 /**
63 * @var string
64 */
65 protected $defaultClass;
66
67 /**
68 * Relevant for RTE mode "plain": the maximum width an image must have to be selectable.
69 *
70 * @var int
71 */
72 protected $plainMaxWidth;
73
74 /**
75 * Relevant for RTE mode "plain": the maximum height an image must have to be selectable.
76 *
77 * @var int
78 */
79 protected $plainMaxHeight;
80
81 /**
82 * @var string
83 */
84 protected $imgPath;
85
86 /**
87 * @var int
88 */
89 public $editorNo;
90
91 /**
92 * @var int
93 */
94 public $sys_language_content;
95
96 /**
97 * @var array
98 */
99 public $buttonConfig;
100
101 /**
102 * @var bool
103 */
104 public $addModifyTab;
105
106 /**
107 * @var string
108 */
109 protected $hookName = 'ext/rtehtmlarea/mod4/class.tx_rtehtmlarea_select_image.php';
110
111 /**
112 * Initialisation
113 *
114 * @return void
115 */
116 public function init()
117 {
118 $this->initVariables();
119
120 $this->initHookObjects();
121 $this->allowedItems = $this->getAllowedItems('magic,plain,image');
122 // Insert the image and exit
123 $this->insertImage();
124 // or render dialogue
125 $this->initDocumentTemplate();
126 }
127
128 /**
129 * Initialize class variables
130 *
131 * @return void
132 */
133 public function initVariables()
134 {
135 parent::initVariables();
136
137 // Get "act"
138 $this->act = GeneralUtility::_GP('act');
139 if (!$this->act) {
140 $this->act = false;
141 }
142 $this->addModifyTab = (bool)GeneralUtility::_GP('addModifyTab');
143 // Process bparams
144 $pArr = explode('|', $this->bparams);
145 $pRteArr = explode(':', $pArr[1]);
146 $this->editorNo = $pRteArr[0];
147 $this->sys_language_content = $pRteArr[1];
148 $this->RTEtsConfigParams = $pArr[2];
149 if (!$this->editorNo) {
150 $this->editorNo = GeneralUtility::_GP('editorNo');
151 $this->sys_language_content = GeneralUtility::_GP('sys_language_content');
152 $this->RTEtsConfigParams = GeneralUtility::_GP('RTEtsConfigParams');
153 }
154 $pArr[1] = implode(':', array($this->editorNo, $this->sys_language_content));
155 $pArr[2] = $this->RTEtsConfigParams;
156 if ($this->act === 'dragdrop' || $this->act === 'plain') {
157 $this->allowedFileTypes = explode(',', self::PLAIN_MODE_IMAGE_FILE_EXTENSIONS);
158 }
159 $pArr[3] = implode(',', $this->allowedFileTypes);
160 $this->bparams = implode('|', $pArr);
161
162 $this->buttonConfig = $this->getButtonConfig();
163 $this->imgPath = $this->getImgPath();
164 $this->defaultClass = $this->getDefaultClass();
165 $this->setMaximumPlainImageDimensions();
166 }
167
168 /**
169 * Initialize document template object
170 *
171 * @return void
172 */
173 protected function initDocumentTemplate()
174 {
175 parent::initDocumentTemplate();
176
177 $this->doc->bodyTagAdditions = 'onload="SelectImage.initEventListeners();"';
178
179 $pageRenderer = $this->getPageRenderer();
180 $pageRenderer->addCssFile(ExtensionManagementUtility::extRelPath('t3skin') . 'rtehtmlarea/htmlarea.css');
181 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function(Tree) {
182 Tree.ajaxID = "sc_alt_file_navframe_expandtoggle";
183 }');
184 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Rtehtmlarea/Modules/SelectImage', 'function(SelectImage) {
185 SelectImage.editorNo = ' . GeneralUtility::quoteJSvalue($this->editorNo) . ';
186 SelectImage.act = ' . GeneralUtility::quoteJSvalue($this->act ?: reset($this->allowedItems)) . ';
187 SelectImage.sys_language_content = ' . GeneralUtility::quoteJSvalue($this->sys_language_content) . ';
188 SelectImage.RTEtsConfigParams = ' . GeneralUtility::quoteJSvalue(rawurlencode($this->RTEtsConfigParams)) . ';
189 SelectImage.bparams = ' . GeneralUtility::quoteJSvalue($this->bparams) . ';
190 }');
191 }
192
193 /**
194 * Insert the image in the editing area
195 *
196 * @return void
197 */
198 protected function insertImage()
199 {
200 $uidList = (string)GeneralUtility::_GP('uidList');
201 if (!GeneralUtility::_GP('insertImage') || !$uidList) {
202 return;
203 }
204 $uids = explode('|', $uidList);
205 $insertJsStatements = array();
206 foreach ($uids as $uid) {
207 /** @var $fileObject File */
208 $fileObject = ResourceFactory::getInstance()->getFileObject((int)$uid);
209 // Get default values for alt and title attributes from file properties
210 $altText = $fileObject->getProperty('alternative');
211 $titleText = $fileObject->getProperty('title');
212 switch ($this->act) {
213 case 'magic':
214 $insertJsStatements[] = $this->insertMagicImage($fileObject, $altText, $titleText, 'data-htmlarea-file-uid="' . $uid . '"');
215 break;
216 case 'plain':
217 $insertJsStatements[] = $this->insertPlainImage($fileObject, $altText, $titleText, 'data-htmlarea-file-uid="' . $uid . '"');
218 break;
219 default:
220 // Call hook
221 foreach ($this->hookObjects as $hookObject) {
222 if (method_exists($hookObject, 'insertElement')) {
223 $hookObject->insertElement($this->act);
224 }
225 }
226 }
227 }
228 $this->insertImages($insertJsStatements);
229 die;
230 }
231
232 /**
233 * Insert a magic image
234 *
235 * @param File $fileObject: the image file
236 * @param string $altText: text for the alt attribute of the image
237 * @param string $titleText: text for the title attribute of the image
238 * @param string $additionalParams: text representing more HTML attributes to be added on the img tag
239 * @return string the magic image JS insertion statement
240 */
241 public function insertMagicImage(File $fileObject, $altText = '', $titleText = '', $additionalParams = '')
242 {
243 // Create the magic image service
244 /** @var $magicImageService MagicImageService */
245 $magicImageService = GeneralUtility::makeInstance(MagicImageService::class);
246 $magicImageService->setMagicImageMaximumDimensions($this->RTEProperties['default.']);
247 // Create the magic image
248 $imageConfiguration = array(
249 'width' => GeneralUtility::_GP('cWidth'),
250 'height' => GeneralUtility::_GP('cHeight')
251 );
252 $magicImage = $magicImageService->createMagicImage($fileObject, $imageConfiguration);
253 $imageUrl = $magicImage->getPublicUrl();
254 // If file is local, make the url absolute
255 if (substr($imageUrl, 0, 4) !== 'http') {
256 $imageUrl = $this->siteURL . $imageUrl;
257 }
258 // Insert the magic image
259 return $this->imageInsertJsStatement($imageUrl, $magicImage->getProperty('width'), $magicImage->getProperty('height'), $altText, $titleText, $additionalParams);
260 }
261
262 /**
263 * Insert a plain image
264 *
265 * @param \TYPO3\CMS\Core\Resource\File $fileObject: the image file
266 * @param string $altText: text for the alt attribute of the image
267 * @param string $titleText: text for the title attribute of the image
268 * @param string $additionalParams: text representing more HTML attributes to be added on the img tag
269 * @return string the plain image JS insertion statement
270 */
271 public function insertPlainImage(File $fileObject, $altText = '', $titleText = '', $additionalParams = '')
272 {
273 $width = $fileObject->getProperty('width');
274 $height = $fileObject->getProperty('height');
275 if (!$width || !$height) {
276 $filePath = $fileObject->getForLocalProcessing(false);
277 $imageInfo = @getimagesize($filePath);
278 $width = $imageInfo[0];
279 $height = $imageInfo[1];
280 }
281 $imageUrl = $fileObject->getPublicUrl();
282 // If file is local, make the url absolute
283 if (substr($imageUrl, 0, 4) !== 'http') {
284 $imageUrl = $this->siteURL . $imageUrl;
285 }
286 return $this->imageInsertJsStatement($imageUrl, $width, $height, $altText, $titleText, $additionalParams);
287 }
288
289 /**
290 * Assemble the image insertion JS statement
291 *
292 * @param string $url: the url of the image
293 * @param int $width: the width of the image
294 * @param int $height: the height of the image
295 * @param string $altText: text for the alt attribute of the image
296 * @param string $titleText: text for the title attribute of the image
297 * @param string $additionalParams: text representing more html attributes to be added on the img tag
298 * @return string the image insertion JS statement
299 */
300 protected function imageInsertJsStatement($url, $width, $height, $altText = '', $titleText = '', $additionalParams = '')
301 {
302 return 'insertImage(' . GeneralUtility::quoteJSvalue($url) . ',' . $width . ',' . $height . ',' . GeneralUtility::quoteJSvalue($altText)
303 . ',' . GeneralUtility::quoteJSvalue($titleText) . ',' . GeneralUtility::quoteJSvalue($additionalParams) . ');';
304 }
305
306 /**
307 * Echo the HTML page and JS that will insert the images
308 *
309 * @param array $insertJsStatements: array of image insertion JS statements
310 * @return void
311 */
312 protected function insertImages($insertJsStatements)
313 {
314 echo '
315 <!DOCTYPE html>
316 <html>
317 <head>
318 <title>Untitled</title>
319 <script type="text/javascript">
320 var plugin = window.parent.RTEarea[' . GeneralUtility::quoteJSvalue($this->editorNo) . '].editor.getPlugin("TYPO3Image");
321 var imageTags = [];
322 function insertImage(file,width,height,alt,title,additionalParams) {
323 imageTags.push(\'<img src="\'+file+\'" width="\'+parseInt(width)+\'" height="\'+parseInt(height)+\'"\''
324 . ($this->defaultClass ? '+\' class="' . $this->defaultClass . '"\'' : '')
325 . '+ (alt ? \' alt="\' + alt + \'"\' : \'\') + (title ? \' title="\' + title + \'"\' : \'\') + (additionalParams ? \' \' + additionalParams : \'\') +\' />\');
326 }
327 </script>
328 </head>
329 <body>
330 <script type="text/javascript">
331 ' . implode(LF, $insertJsStatements) . '
332 plugin.insertImage(imageTags.join(\' \'));
333 </script>
334 </body>
335 </html>';
336 }
337
338 /**
339 * Generate JS code to be used on the image insert/modify dialogue
340 *
341 * @param string $act: the action to be performed
342 * @param string $editorNo: the number of the RTE instance on the page
343 * @param string $sys_language_content: the language of the content element
344 * @return string the generated JS code
345 */
346 public function getJSCode($act, $editorNo, $sys_language_content)
347 {
348 return '
349 function insertElement(table, uid, type, fileName, filePath, fileExt, fileIcon, action, close) {
350 return SelectImage.jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + "insertImage=1&uidList=" + uid);
351 }
352 function insertMultiple(table, uidList) {
353 var uids = uidList.join("|");
354 return SelectImage.jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + "insertImage=1&uidList=" + uids);
355 }
356 function jumpToUrl(URL,anchor) {
357 SelectImage.jumpToUrl(URL, anchor);
358 };';
359 }
360
361 /**
362 * Session data for this class can be set from outside with this method.
363 * Call after init()
364 *
365 * @param array $data Session data array
366 * @return array Session data and boolean which indicates that data needs to be stored in session because it's changed
367 */
368 public function processSessionData($data)
369 {
370 $store = false;
371 if ($this->act !== 'image') {
372 if ($this->act) {
373 $data['act'] = $this->act;
374 $store = true;
375 } else {
376 $this->act = $data['act'];
377 }
378 }
379 if (isset($this->expandFolder)) {
380 $data['expandFolder'] = $this->expandFolder;
381 $store = true;
382 } else {
383 $this->expandFolder = $data['expandFolder'];
384 }
385 return array($data, $store);
386 }
387
388 /**
389 * Rich Text Editor (RTE) image selector
390 *
391 * @param bool $wiz Not used here, kept for method signature compatibility with parent class
392 * @return string Modified content variable.
393 * @return string
394 */
395 protected function main_rte($wiz = false)
396 {
397 // Starting content:
398 $lang = $this->getLanguageService();
399 $this->content = $this->doc->startPage($lang->getLL('Insert Image', true));
400
401 $this->content .= $this->doc->getTabMenuRaw($this->buildMenuArray($wiz, $this->allowedItems));
402 switch ($this->act) {
403 case 'image':
404 $classesImage = $this->buttonConfig['properties.']['class.']['allowedClasses'] || $this->RTEProperties['default.']['classesImage'] ? 'true' : 'false';
405 $removedProperties = array();
406 if (is_array($this->buttonConfig['properties.'])) {
407 if ($this->buttonConfig['properties.']['removeItems']) {
408 $removedProperties = GeneralUtility::trimExplode(',', $this->buttonConfig['properties.']['removeItems'], true);
409 }
410 }
411 $classesImageJSOptions = '';
412 if ($this->buttonConfig['properties.']['class.']['allowedClasses']) {
413 $classesImageArray = GeneralUtility::trimExplode(',', $this->buttonConfig['properties.']['class.']['allowedClasses'], true);
414 $classesImageJSOptions = '<option value=""></option>';
415 foreach ($classesImageArray as $class) {
416 $classesImageJSOptions .= '<option value="' . $class . '">' . $class . '</option>';
417 }
418 }
419 $lockPlainWidth = 'false';
420 $lockPlainHeight = 'false';
421 if (is_array($this->RTEProperties['default.']['proc.']) && $this->RTEProperties['default.']['proc.']['plainImageMode']) {
422 $plainImageMode = $this->RTEProperties['default.']['proc.']['plainImageMode'];
423 $lockPlainWidth = $plainImageMode == 'lockDimensions' ? 'true' : 'false';
424 $lockPlainHeight = $lockPlainWidth || $plainImageMode == 'lockRatio' || $plainImageMode == 'lockRatioWhenSmaller' ? 'true' : 'false';
425 }
426 $labels = array('notSet','nonFloating','right','left','class','width','height','border','float','padding_top','padding_left','padding_bottom','padding_right','title','alt','update');
427 foreach ($labels as $label) {
428 $localizedLabels[$label] = $lang->getLL($label);
429 }
430 $localizedLabels['image_zoom'] = $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:image_zoom', true);
431 $JScode = '
432 require(["TYPO3/CMS/Rtehtmlarea/Modules/SelectImage"], function(SelectImage) {
433 SelectImage.editorNo = "' . $this->editorNo . '";
434 SelectImage.act = "' . $this->act . '";
435 SelectImage.sys_language_content = "' . $this->sys_language_content . '";
436 SelectImage.RTEtsConfigParams = "' . rawurlencode($this->RTEtsConfigParams) . '";
437 SelectImage.bparams = "' . $this->bparams . '";
438 SelectImage.classesImage = ' . $classesImage . ';
439 SelectImage.labels = ' . json_encode($localizedLabels) . ';
440 SelectImage.Form.build(' . GeneralUtility::quoteJSvalue($classesImageJSOptions) . ', ' . json_encode($removedProperties) . ', ' . $lockPlainWidth . ', ' . $lockPlainHeight . ');
441 SelectImage.Form.insertImageProperties();
442 });';
443 $this->content .= '<br />' . $this->doc->wrapScriptTags($JScode);
444 break;
445 case 'plain':
446 case 'magic':
447 // Create folder tree:
448 $foldertree = GeneralUtility::makeInstance(FolderTree::class);
449 $foldertree->thisScript = $this->thisScript;
450 $tree = $foldertree->getBrowsableTree();
451 // Get currently selected folder
452 if ($this->curUrlInfo['value'] && $this->curUrlInfo['act'] === $this->act) {
453 $cmpPath = $this->curUrlInfo['value'];
454 if (!isset($this->expandFolder)) {
455 $this->expandFolder = $cmpPath;
456 }
457 }
458 // Get the selected folder
459 $selectedFolder = false;
460 if ($this->expandFolder) {
461 $fileOrFolderObject = null;
462 try {
463 $fileOrFolderObject = ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
464 } catch (\Exception $e) {
465 // No path is selected
466 }
467 if ($fileOrFolderObject instanceof Folder) {
468 // it's a folder
469 $selectedFolder = $fileOrFolderObject;
470 } elseif ($fileOrFolderObject instanceof FileInterface) {
471 // it's a file
472 try {
473 $selectedFolder = $fileOrFolderObject->getParentFolder();
474 } catch (\Exception $e) {
475 // Accessing the parent folder failed for some reason. e.g. permissions
476 }
477 }
478 }
479 // If no folder is selected, get the user's default upload folder
480 $backendUser = $this->getBackendUser();
481 if (!$selectedFolder) {
482 try {
483 $selectedFolder = $backendUser->getDefaultUploadFolder();
484 } catch (\Exception $e) {
485 // The configured default user folder does not exist
486 }
487 }
488 // Build the file upload and folder creation form
489 $uploadForm = '';
490 $createFolder = '';
491 if ($selectedFolder) {
492 $uploadForm = $this->uploadForm($selectedFolder);
493 $createFolder = $this->createFolder($selectedFolder);
494 }
495 // Insert the upload form on top, if so configured
496 if ($backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
497 $this->content .= $uploadForm;
498 }
499 // Render the filelist if there is a folder selected
500 $files = '';
501 if ($selectedFolder) {
502 $files = $this->TBE_expandFolder(
503 $selectedFolder,
504 $this->act === 'plain' ? self::PLAIN_MODE_IMAGE_FILE_EXTENSIONS : $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'],
505 $backendUser->getTSConfigVal('options.noThumbsInRTEimageSelect')
506 );
507 }
508 // Setup filelist indexed elements:
509 $this->doc->JScode .= $this->doc->wrapScriptTags('
510 require(["TYPO3/CMS/Recordlist/BrowseFiles"], function(BrowseFiles) {
511 BrowseFiles.addElements(' . json_encode($this->elements) . ');
512 });');
513 // Wrap tree
514 $this->content .= '
515
516 <!--
517 Wrapper table for folder tree / file/folder list:
518 -->
519 <table border="0" cellpadding="0" cellspacing="0" id="typo3-linkFiles">
520 <tr>
521 <td class="c-wCell" valign="top">' . $this->barheader(($lang->getLL('folderTree') . ':')) . $tree . '</td>
522 <td class="c-wCell" valign="top">' . $files . '</td>
523 </tr>
524 </table>
525 ';
526 // Add help message
527 $helpMessage = $this->getHelpMessage($this->act);
528 if ($helpMessage) {
529 $this->content .= GeneralUtility::makeInstance(FlashMessage::class, $helpMessage, '', FlashMessage::INFO)
530 ->render();
531 }
532 // Adding create folder + upload form if applicable
533 if (!$backendUser->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
534 $this->content .= $uploadForm;
535 }
536 $this->content .= $createFolder;
537 $this->content .= '<br />';
538 break;
539 case 'dragdrop':
540 $foldertree = GeneralUtility::makeInstance(ElementBrowserFolderTreeView::class);
541 $foldertree->setLinkParameterProvider($this);
542 $foldertree->thisScript = $this->thisScript;
543 $foldertree->ext_noTempRecyclerDirs = true;
544 $tree = $foldertree->getBrowsableTree();
545 // Get currently selected folder
546 if ($this->curUrlInfo['value'] && $this->curUrlInfo['act'] === $this->act) {
547 $cmpPath = $this->curUrlInfo['value'];
548 if (!isset($this->expandFolder)) {
549 $this->expandFolder = $cmpPath;
550 }
551 }
552 $selectedFolder = false;
553 if ($this->expandFolder) {
554 try {
555 $selectedFolder = ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($this->expandFolder);
556 } catch (\Exception $e) {
557 }
558 }
559 // Render the filelist if there is a folder selected
560 $files = '';
561 if ($selectedFolder) {
562 $files = $this->TBE_dragNDrop($selectedFolder, implode(',', $this->allowedFileTypes));
563 }
564 // Wrap tree
565 $this->content .= '<table border="0" cellpadding="0" cellspacing="0">
566 <tr>
567 <td style="vertical-align: top;">' . $this->barheader(($lang->getLL('folderTree') . ':')) . $tree . '</td>
568 <td>&nbsp;</td>
569 <td style="vertical-align: top;">' . $files . '</td>
570 </tr>
571 </table>';
572 break;
573 default:
574 // Call hook
575 foreach ($this->hookObjects as $hookObject) {
576 $this->content .= $hookObject->getTab($this->act);
577 }
578 }
579 $this->content .= $this->doc->endPage();
580 $this->doc->JScodeArray['rtehtmlarea'] = $this->getJSCode($this->act, $this->editorNo, $this->sys_language_content);
581 $this->content = $this->doc->insertStylesAndJS($this->content);
582 return $this->content;
583 }
584
585 /**
586 * Returns an array definition of the top menu
587 *
588 * @param bool $wiz
589 * @param array $allowedItems
590 * @return array
591 */
592 protected function buildMenuArray($wiz, $allowedItems)
593 {
594 $menuDef = array();
595 $lang = $this->getLanguageService();
596 if (in_array('image', $this->allowedItems) && ($this->act === 'image' || $this->addModifyTab)) {
597 $menuDef['image']['isActive'] = false;
598 $menuDef['image']['label'] = $lang->getLL('currentImage', true);
599 $menuDef['image']['url'] = '#';
600 $menuDef['image']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=image\');return false;"';
601 }
602 if (in_array('magic', $this->allowedItems)) {
603 $menuDef['magic']['isActive'] = false;
604 $menuDef['magic']['label'] = $lang->getLL('magicImage', true);
605 $menuDef['magic']['url'] = '#';
606 $menuDef['magic']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=magic\');return false;"';
607 }
608 if (in_array('plain', $this->allowedItems)) {
609 $menuDef['plain']['isActive'] = false;
610 $menuDef['plain']['label'] = $lang->getLL('plainImage', true);
611 $menuDef['plain']['url'] = '#';
612 $menuDef['plain']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=plain\');return false;"';
613 }
614 if (in_array('dragdrop', $this->allowedItems)) {
615 $menuDef['dragdrop']['isActive'] = false;
616 $menuDef['dragdrop']['label'] = $lang->getLL('dragDropImage', true);
617 $menuDef['dragdrop']['url'] = '#';
618 $menuDef['dragdrop']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=dragdrop\');return false;"';
619 }
620 // Call hook for extra options
621 foreach ($this->hookObjects as $hookObject) {
622 $menuDef = $hookObject->modifyMenuDefinition($menuDef);
623 }
624 // Order the menu items as specified in Page TSconfig
625 $menuDef = $this->orderMenuDefinition($menuDef);
626 // Set active menu item
627 reset($menuDef);
628 if ($this->act === false || !in_array($this->act, $this->allowedItems)) {
629 $this->act = key($menuDef);
630 }
631 $menuDef[$this->act]['isActive'] = true;
632 return $menuDef;
633 }
634
635 /**
636 * Get the path of the image to be inserted or modified
637 *
638 * @return string path to the image
639 */
640 protected function getImgPath()
641 {
642 $RTEtsConfigParts = explode(':', $this->RTEtsConfigParams);
643 return $RTEtsConfigParts[6];
644 }
645
646 /**
647 * Get the configuration of the image button
648 *
649 * @return array the configuration array of the image button
650 */
651 protected function getButtonConfig()
652 {
653 return isset($this->RTEProperties['default.']['buttons.']['image.'])
654 ? $this->RTEProperties['default.']['buttons.']['image.']
655 : array();
656 }
657
658 /**
659 * Get the allowed items or tabs
660 *
661 * @param string $items: initial list of possible items
662 * @return array the allowed items
663 */
664 public function getAllowedItems($items)
665 {
666 $allowedItems = explode(',', $items);
667 $clientInfo = GeneralUtility::clientInfo();
668 if ($clientInfo['BROWSER'] !== 'opera') {
669 $allowedItems[] = 'dragdrop';
670 }
671 // Call hook for extra options
672 foreach ($this->hookObjects as $hookObject) {
673 $allowedItems = $hookObject->addAllowedItems($allowedItems);
674 }
675 // Remove tab "image" if there is no current image
676 if ($this->act !== 'image' && !$this->addModifyTab) {
677 $allowedItems = array_diff($allowedItems, array('image'));
678 }
679 // Remove options according to RTE configuration
680 if (is_array($this->buttonConfig['options.']) && $this->buttonConfig['options.']['removeItems']) {
681 $allowedItems = array_diff($allowedItems, GeneralUtility::trimExplode(',', $this->buttonConfig['options.']['removeItems'], true));
682 }
683
684 reset($allowedItems);
685 if (!in_array($this->act, $allowedItems)) {
686 $this->act = current($allowedItems);
687 }
688 return $allowedItems;
689 }
690
691 /**
692 * Order the definition of menu items according to configured order
693 *
694 * @param array $menuDefinition: definition of menu items
695 * @return array ordered menu definition
696 */
697 public function orderMenuDefinition($menuDefinition)
698 {
699 $orderedMenuDefinition = array();
700 if (is_array($this->buttonConfig['options.']) && $this->buttonConfig['options.']['orderItems']) {
701 $orderItems = GeneralUtility::trimExplode(',', $this->buttonConfig['options.']['orderItems'], true);
702 $orderItems = array_intersect($orderItems, $this->allowedItems);
703 foreach ($orderItems as $item) {
704 $orderedMenuDefinition[$item] = $menuDefinition[$item];
705 }
706 } else {
707 $orderedMenuDefinition = $menuDefinition;
708 }
709 return $orderedMenuDefinition;
710 }
711
712 /**
713 * Get the default image class
714 *
715 * @return string the default class, if any
716 */
717 protected function getDefaultClass()
718 {
719 $defaultClass = '';
720 if (is_array($this->buttonConfig['properties.'])) {
721 if (is_array($this->buttonConfig['properties.']['class.']) && trim($this->buttonConfig['properties.']['class.']['default'])) {
722 $defaultClass = trim($this->buttonConfig['properties.']['class.']['default']);
723 }
724 }
725 return $defaultClass;
726 }
727
728 /**
729 * Set variables for maximum plain image dimensions
730 *
731 * @return void
732 */
733 protected function setMaximumPlainImageDimensions()
734 {
735 if (is_array($this->buttonConfig['options.']) && is_array($this->buttonConfig['options.']['plain.'])) {
736 if ($this->buttonConfig['options.']['plain.']['maxWidth']) {
737 $this->plainMaxWidth = $this->buttonConfig['options.']['plain.']['maxWidth'];
738 }
739 if ($this->buttonConfig['options.']['plain.']['maxHeight']) {
740 $this->plainMaxHeight = $this->buttonConfig['options.']['plain.']['maxHeight'];
741 }
742 }
743 if (!$this->plainMaxWidth) {
744 $this->plainMaxWidth = 640;
745 }
746 if (!$this->plainMaxHeight) {
747 $this->plainMaxHeight = 680;
748 }
749 }
750
751 /**
752 * Get the help message to be displayed on a given tab
753 *
754 * @param string $act: the identifier of the tab
755 * @return string the text of the message
756 */
757 public function getHelpMessage($act)
758 {
759 switch ($act) {
760 case 'plain':
761 return sprintf($this->getLanguageService()->getLL('plainImage_msg'), $this->plainMaxWidth, $this->plainMaxHeight);
762 break;
763 case 'magic':
764 return sprintf($this->getLanguageService()->getLL('magicImage_msg'));
765 break;
766 default:
767 return '';
768 }
769 }
770
771 /**
772 * Checks if the given file is selectable in the filelist.
773 *
774 * In "plain" RTE mode only image files with a maximum width and height are selectable.
775 *
776 * @param FileInterface $file
777 * @param array $imgInfo Image dimensions from \TYPO3\CMS\Core\Imaging\GraphicalFunctions::getImageDimensions()
778 * @return bool TRUE if file is selectable.
779 */
780 protected function fileIsSelectableInFileList(FileInterface $file, array $imgInfo)
781 {
782 return (
783 $this->act !== 'plain'
784 || (
785 GeneralUtility::inList(self::PLAIN_MODE_IMAGE_FILE_EXTENSIONS, strtolower($file->getExtension()))
786 && $imgInfo[0] <= $this->plainMaxWidth
787 && $imgInfo[1] <= $this->plainMaxHeight
788 )
789 );
790 }
791
792 /**
793 * @return LanguageService
794 */
795 protected function getLanguageService()
796 {
797 return $GLOBALS['LANG'];
798 }
799
800 /**
801 * @return BackendUserAuthentication
802 */
803 protected function getBackendUser()
804 {
805 return $GLOBALS['BE_USER'];
806 }
807 }