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