[TASK] RTE: Extract JavaScript from select image php controller
[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 = "' . $this->editorNo . '";
140 SelectImage.act = "' . ($this->act ?: 'plain') . '";
141 SelectImage.sys_language_content = "' . $this->sys_language_content . '";
142 SelectImage.RTEtsConfigParams = "' . rawurlencode($this->RTEtsConfigParams) . '";
143 SelectImage.bparams = "' . $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["' . $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 if ($this->buttonConfig['properties.']['class.']['allowedClasses']) {
366 $classesImageArray = GeneralUtility::trimExplode(',', $this->buttonConfig['properties.']['class.']['allowedClasses'], TRUE);
367 $classesImageJSOptions = '<option value=""></option>';
368 foreach ($classesImageArray as $class) {
369 $classesImageJSOptions .= '<option value="' . $class . '">' . $class . '</option>';
370 }
371 }
372 $lockPlainWidth = 'false';
373 $lockPlainHeight = 'false';
374 if (is_array($this->thisConfig['proc.']) && $this->thisConfig['proc.']['plainImageMode']) {
375 $plainImageMode = $this->thisConfig['proc.']['plainImageMode'];
376 $lockPlainWidth = $plainImageMode == 'lockDimensions' ? 'true' : 'false';
377 $lockPlainHeight = $lockPlainWidth || $plainImageMode == 'lockRatio' || $plainImageMode == 'lockRatioWhenSmaller' ? 'true' : 'false';
378 }
379 $labels = array('notSet','nonFloating','right','left','class','width','height','border','float','padding_top','padding_left','padding_bottom','padding_right','title','alt','update');
380 foreach ($labels as $label) {
381 $localizedLabels[$label] = $GLOBALS['LANG']->getLL($label);
382 }
383 $localizedLabels['image_zoom'] = $GLOBALS['LANG']->sL('LLL:EXT:cms/locallang_ttc.xlf:image_zoom', TRUE);
384 $JScode = '
385 require(["TYPO3/CMS/Rtehtmlarea/Modules/SelectImage"], function(SelectImage) {
386 SelectImage.editorNo = "' . $this->editorNo . '";
387 SelectImage.act = "' . $this->act . '";
388 SelectImage.sys_language_content = "' . $this->sys_language_content . '";
389 SelectImage.RTEtsConfigParams = "' . rawurlencode($this->RTEtsConfigParams) . '";
390 SelectImage.bparams = "' . $this->bparams . '";
391 SelectImage.classesImage = ' . $classesImage . ';
392 SelectImage.labels = ' . json_encode($localizedLabels) . '
393 SelectImage.Form.build("' . $classesImageJSOptions . '", ' . json_encode($removedProperties) . ', ' . $lockPlainWidth . ', ' . $lockPlainHeight . ');
394 SelectImage.Form.insertImageProperties();
395 });';
396 $this->content .= '<br />' . $this->doc->wrapScriptTags($JScode);
397 break;
398 case 'plain':
399 case 'magic':
400 // Create folder tree:
401 $foldertree = GeneralUtility::makeInstance(\TYPO3\CMS\Rtehtmlarea\FolderTree::class);
402 $foldertree->thisScript = $this->thisScript;
403 $tree = $foldertree->getBrowsableTree();
404 // Get currently selected folder
405 if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act'] != $this->act) {
406 $cmpPath = '';
407 } else {
408 $cmpPath = $this->curUrlInfo['value'];
409 if (!isset($this->expandFolder)) {
410 $this->expandFolder = $cmpPath;
411 }
412 }
413 // Get the selected folder
414 $selectedFolder = FALSE;
415 if ($this->expandFolder) {
416 $fileOrFolderObject = NULL;
417 try {
418 $fileOrFolderObject = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->retrieveFileOrFolderObject($this->expandFolder);
419 } catch (\Exception $e) {
420 // No path is selected
421 }
422 if ($fileOrFolderObject instanceof \TYPO3\CMS\Core\Resource\Folder) {
423 // it's a folder
424 $selectedFolder = $fileOrFolderObject;
425 } elseif ($fileOrFolderObject instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
426 // it's a file
427 try {
428 $selectedFolder = $fileOrFolderObject->getParentFolder();
429 } catch (\Exception $e) {
430 // Accessing the parent folder failed for some reason. e.g. permissions
431 }
432 }
433 }
434 // If no folder is selected, get the user's default upload folder
435 if (!$selectedFolder) {
436 try {
437 $selectedFolder = $GLOBALS['BE_USER']->getDefaultUploadFolder();
438 } catch (\Exception $e) {
439 // The configured default user folder does not exist
440 }
441 }
442 // Build the file upload and folder creation form
443 $uploadForm = '';
444 $createFolder = '';
445 if ($selectedFolder) {
446 $uploadForm = $this->uploadForm($selectedFolder);
447 $createFolder = $this->createFolder($selectedFolder);
448 }
449 // Insert the upload form on top, if so configured
450 if ($GLOBALS['BE_USER']->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
451 $this->content .= $uploadForm;
452 }
453 // Render the filelist if there is a folder selected
454 $files = '';
455 if ($selectedFolder) {
456 $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'));
457 }
458 // Setup filelist indexed elements:
459 $this->doc->JScode .= $this->doc->wrapScriptTags('
460 require(["TYPO3/CMS/Backend/BrowseLinks"], function(BrowseLinks) {
461 BrowseLinks.addElements(' . json_encode($this->elements) . ');
462 });');
463 // Wrap tree
464 $this->content .= '
465
466 <!--
467 Wrapper table for folder tree / file/folder list:
468 -->
469 <table border="0" cellpadding="0" cellspacing="0" id="typo3-linkFiles">
470 <tr>
471 <td class="c-wCell" valign="top">' . $this->barheader(($GLOBALS['LANG']->getLL('folderTree') . ':')) . $tree . '</td>
472 <td class="c-wCell" valign="top">' . $files . '</td>
473 </tr>
474 </table>
475 ';
476 // Add help message
477 $helpMessage = $this->getHelpMessage($this->act);
478 if ($helpMessage) {
479 $this->content .= $this->getMsgBox($helpMessage);
480 }
481 // Adding create folder + upload form if applicable
482 if (!$GLOBALS['BE_USER']->getTSConfigVal('options.uploadFieldsInTopOfEB')) {
483 $this->content .= $uploadForm;
484 }
485 $this->content .= $createFolder;
486 $this->content .= '<br />';
487 break;
488 case 'dragdrop':
489 $foldertree = GeneralUtility::makeInstance(\TYPO3\CMS\Recordlist\Tree\View\ElementBrowserFolderTreeView::class);
490 $foldertree->thisScript = $this->thisScript;
491 $foldertree->ext_noTempRecyclerDirs = TRUE;
492 $tree = $foldertree->getBrowsableTree();
493 // Get currently selected folder
494 if (!$this->curUrlInfo['value'] || $this->curUrlInfo['act'] != $this->act) {
495 $cmpPath = '';
496 } else {
497 $cmpPath = $this->curUrlInfo['value'];
498 if (!isset($this->expandFolder)) {
499 $this->expandFolder = $cmpPath;
500 }
501 }
502 $selectedFolder = FALSE;
503 if ($this->expandFolder) {
504 try {
505 $selectedFolder = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($this->expandFolder);
506 } catch (\Exception $e) {
507 }
508 }
509 // Render the filelist if there is a folder selected
510 $files = '';
511 if ($selectedFolder) {
512 $files = $this->TBE_dragNDrop($selectedFolder, implode(',', $this->allowedFileTypes));
513 }
514 // Wrap tree
515 $this->content .= '<table border="0" cellpadding="0" cellspacing="0">
516 <tr>
517 <td style="vertical-align: top;">' . $this->barheader(($GLOBALS['LANG']->getLL('folderTree') . ':')) . $tree . '</td>
518 <td>&nbsp;</td>
519 <td style="vertical-align: top;">' . $files . '</td>
520 </tr>
521 </table>';
522 break;
523 default:
524 // Call hook
525 foreach ($this->hookObjects as $hookObject) {
526 $this->content .= $hookObject->getTab($this->act);
527 }
528 }
529 $this->content .= $this->doc->endPage();
530 $this->doc->JScodeArray['rtehtmlarea'] = $this->getJSCode($this->act, $this->editorNo, $this->sys_language_content);
531 $this->content = $this->doc->insertStylesAndJS($this->content);
532 return $this->content;
533 }
534
535 /**
536 * Returns an array definition of the top menu
537 *
538 * @param $wiz
539 * @param $allowedItems
540 * @return array
541 */
542 protected function buildMenuArray($wiz, $allowedItems) {
543 $menuDef = array();
544 if (in_array('image', $this->allowedItems) && ($this->act === 'image' || $this->addModifyTab)) {
545 $menuDef['image']['isActive'] = FALSE;
546 $menuDef['image']['label'] = $GLOBALS['LANG']->getLL('currentImage', TRUE);
547 $menuDef['image']['url'] = '#';
548 $menuDef['image']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=image\');return false;"';
549 }
550 if (in_array('magic', $this->allowedItems)) {
551 $menuDef['magic']['isActive'] = FALSE;
552 $menuDef['magic']['label'] = $GLOBALS['LANG']->getLL('magicImage', TRUE);
553 $menuDef['magic']['url'] = '#';
554 $menuDef['magic']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=magic\');return false;"';
555 }
556 if (in_array('plain', $this->allowedItems)) {
557 $menuDef['plain']['isActive'] = FALSE;
558 $menuDef['plain']['label'] = $GLOBALS['LANG']->getLL('plainImage', TRUE);
559 $menuDef['plain']['url'] = '#';
560 $menuDef['plain']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=plain\');return false;"';
561 }
562 if (in_array('dragdrop', $this->allowedItems)) {
563 $menuDef['dragdrop']['isActive'] = FALSE;
564 $menuDef['dragdrop']['label'] = $GLOBALS['LANG']->getLL('dragDropImage', TRUE);
565 $menuDef['dragdrop']['url'] = '#';
566 $menuDef['dragdrop']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + \'act=dragdrop\');return false;"';
567 }
568 // Call hook for extra options
569 foreach ($this->hookObjects as $hookObject) {
570 $menuDef = $hookObject->modifyMenuDefinition($menuDef);
571 }
572 // Order the menu items as specified in Page TSconfig
573 $menuDef = $this->orderMenuDefinition($menuDef);
574 // Set active menu item
575 reset($menuDef);
576 if ($this->act === FALSE || !in_array($this->act, $this->allowedItems)) {
577 $this->act = key($menuDef);
578 }
579 $menuDef[$this->act]['isActive'] = TRUE;
580 return $menuDef;
581 }
582
583 /**
584 * Initializes the configuration variables
585 *
586 * @return void
587 */
588 public function initConfiguration() {
589 $this->thisConfig = $this->getRTEConfig();
590 $this->buttonConfig = $this->getButtonConfig();
591 $this->imgPath = $this->getImgPath();
592 $this->defaultClass = $this->getDefaultClass();
593 $this->setMaximumPlainImageDimensions();
594 }
595
596 /**
597 * Get the path of the image to be inserted or modified
598 *
599 * @return string path to the image
600 */
601 protected function getImgPath() {
602 $RTEtsConfigParts = explode(':', $this->RTEtsConfigParams);
603 return $RTEtsConfigParts[6];
604 }
605
606 /**
607 * Get the configuration of the image button
608 *
609 * @return array the configuration array of the image button
610 */
611 protected function getButtonConfig() {
612 return is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.']['image.']) ? $this->thisConfig['buttons.']['image.'] : array();
613 }
614
615 /**
616 * Get the allowed items or tabs
617 *
618 * @param string $items: initial list of possible items
619 * @return array the allowed items
620 */
621 public function getAllowedItems($items) {
622 $allowedItems = explode(',', $items);
623 $clientInfo = GeneralUtility::clientInfo();
624 if ($clientInfo['BROWSER'] !== 'opera') {
625 $allowedItems[] = 'dragdrop';
626 }
627 // Call hook for extra options
628 foreach ($this->hookObjects as $hookObject) {
629 $allowedItems = $hookObject->addAllowedItems($allowedItems);
630 }
631 // Remove tab "image" if there is no current image
632 if ($this->act !== 'image' && !$this->addModifyTab) {
633 $allowedItems = array_diff($allowedItems, array('image'));
634 }
635 // Remove options according to RTE configuration
636 if (is_array($this->buttonConfig['options.']) && $this->buttonConfig['options.']['removeItems']) {
637 $allowedItems = array_diff($allowedItems, GeneralUtility::trimExplode(',', $this->buttonConfig['options.']['removeItems'], TRUE));
638 }
639 return $allowedItems;
640 }
641
642 /**
643 * Order the definition of menu items according to configured order
644 *
645 * @param array $menuDefinition: definition of menu items
646 * @return array ordered menu definition
647 */
648 public function orderMenuDefinition($menuDefinition) {
649 $orderedMenuDefinition = array();
650 if (is_array($this->buttonConfig['options.']) && $this->buttonConfig['options.']['orderItems']) {
651 $orderItems = GeneralUtility::trimExplode(',', $this->buttonConfig['options.']['orderItems'], TRUE);
652 $orderItems = array_intersect($orderItems, $this->allowedItems);
653 foreach ($orderItems as $item) {
654 $orderedMenuDefinition[$item] = $menuDefinition[$item];
655 }
656 } else {
657 $orderedMenuDefinition = $menuDefinition;
658 }
659 return $orderedMenuDefinition;
660 }
661
662 /**
663 * Get the default image class
664 *
665 * @return string the default class, if any
666 */
667 protected function getDefaultClass() {
668 $defaultClass = '';
669 if (is_array($this->buttonConfig['properties.'])) {
670 if (is_array($this->buttonConfig['properties.']['class.']) && trim($this->buttonConfig['properties.']['class.']['default'])) {
671 $defaultClass = trim($this->buttonConfig['properties.']['class.']['default']);
672 }
673 }
674 return $defaultClass;
675 }
676
677 /**
678 * Set variables for maximum plain image dimensions
679 *
680 * @return void
681 */
682 protected function setMaximumPlainImageDimensions() {
683 if (is_array($this->buttonConfig['options.']) && is_array($this->buttonConfig['options.']['plain.'])) {
684 if ($this->buttonConfig['options.']['plain.']['maxWidth']) {
685 $this->plainMaxWidth = $this->buttonConfig['options.']['plain.']['maxWidth'];
686 }
687 if ($this->buttonConfig['options.']['plain.']['maxHeight']) {
688 $this->plainMaxHeight = $this->buttonConfig['options.']['plain.']['maxHeight'];
689 }
690 }
691 if (!$this->plainMaxWidth) {
692 $this->plainMaxWidth = 640;
693 }
694 if (!$this->plainMaxHeight) {
695 $this->plainMaxHeight = 680;
696 }
697 }
698
699 /**
700 * Get the help message to be displayed on a given tab
701 *
702 * @param string $act: the identifier of the tab
703 * @return string the text of the message
704 */
705 public function getHelpMessage($act) {
706 switch ($act) {
707 case 'plain':
708 return sprintf($GLOBALS['LANG']->getLL('plainImage_msg'), $this->plainMaxWidth, $this->plainMaxHeight);
709 break;
710 case 'magic':
711 return sprintf($GLOBALS['LANG']->getLL('magicImage_msg'));
712 break;
713 default:
714 return '';
715 }
716 }
717
718 /**
719 * Checks if the given file is selectable in the file list.
720 *
721 * In "plain" RTE mode only image files with a maximum width and height are selectable.
722 *
723 * @param \TYPO3\CMS\Core\Resource\FileInterface $file
724 * @param array $imgInfo Image dimensions from \TYPO3\CMS\Core\Imaging\GraphicalFunctions::getImageDimensions()
725 * @return bool TRUE if file is selectable.
726 */
727 protected function fileIsSelectableInFileList(\TYPO3\CMS\Core\Resource\FileInterface $file, array $imgInfo) {
728 return (
729 $this->act !== 'plain'
730 || (
731 GeneralUtility::inList(self::PLAIN_MODE_IMAGE_FILE_EXTENSIONS, strtolower($file->getExtension()))
732 && $imgInfo[0] <= $this->plainMaxWidth
733 && $imgInfo[1] <= $this->plainMaxHeight
734 )
735 );
736 }
737
738 }