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