42939bf90207f1779c58b4283f80c51791273bef
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / BrowseLinks.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\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * Script class for the Element Browser window.
22 *
23 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
24 */
25 class BrowseLinks extends \TYPO3\CMS\Recordlist\Browser\ElementBrowser {
26
27 public $editorNo;
28 /**
29 * TYPO3 language code of the content language
30 */
31 public $contentTypo3Language;
32
33 public $contentTypo3Charset = 'utf-8';
34 /**
35 * Language service object for localization to the content language
36 */
37 protected $contentLanguageService;
38
39 public $additionalAttributes = array();
40
41 public $buttonConfig = array();
42
43 public $RTEProperties = array();
44
45 public $anchorTypes = array('page', 'url', 'file', 'mail', 'spec');
46
47 public $classesAnchorDefault = array();
48
49 public $classesAnchorDefaultTitle = array();
50
51 public $classesAnchorClassTitle = array();
52
53 public $classesAnchorDefaultTarget = array();
54
55 public $classesAnchorJSOptions = array();
56
57 protected $defaultLinkTarget;
58
59 public $allowedItems;
60
61 /**
62 * Constructor:
63 * Initializes a lot of variables, setting JavaScript functions in header etc.
64 *
65 * @return void
66 */
67 public function init() {
68 $this->initVariables();
69 // Create content language service
70 $this->contentLanguageService = GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
71 $this->contentLanguageService->init($this->contentTypo3Language);
72 $this->initConfiguration();
73
74 $this->initDocumentTemplate();
75
76 // Initializing hooking browsers
77 $this->initHookObjects('ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php');
78 $this->allowedItems = $this->getAllowedItems('page,file,folder,url,mail,spec');
79 $this->initCurrentUrl();
80 // Determine nature of current url:
81 $this->act = GeneralUtility::_GP('act');
82 if (!$this->act) {
83 $this->act = $this->curUrlInfo['act'];
84 }
85 // Setting initial values for link attributes
86 $this->initLinkAttributes();
87
88 // Adding RTE JS code
89 // also unset the default jumpToUrl() function before
90 unset($this->doc->JScodeArray['jumpToUrl']);
91 $this->doc->JScodeArray['rtehtmlarea'] = $this->getJSCode();
92 }
93
94 /**
95 * Initialize class variables
96 *
97 * @return void
98 */
99 public function initVariables() {
100 parent::initVariables();
101
102 // Process bparams
103 $pArr = explode('|', $this->bparams);
104 $pRteArr = explode(':', $pArr[1]);
105 $this->editorNo = $pRteArr[0];
106 $this->contentTypo3Language = $pRteArr[1];
107 $this->RTEtsConfigParams = $pArr[2];
108 if (!$this->editorNo) {
109 $this->editorNo = GeneralUtility::_GP('editorNo');
110 $this->contentTypo3Language = GeneralUtility::_GP('contentTypo3Language');
111 $this->RTEtsConfigParams = GeneralUtility::_GP('RTEtsConfigParams');
112 }
113 $pArr[1] = implode(':', array($this->editorNo, $this->contentTypo3Language, $this->contentTypo3Charset));
114 $pArr[2] = $this->RTEtsConfigParams;
115 $this->bparams = implode('|', $pArr);
116 }
117
118 /**
119 * Initializes the configuration variables
120 *
121 * @return void
122 */
123 public function initConfiguration() {
124 $this->thisConfig = $this->getRTEConfig();
125 $this->buttonConfig = $this->getButtonConfig('link');
126 }
127
128 /**
129 * Initialize document template object
130 *
131 * @return void
132 */
133 protected function initDocumentTemplate() {
134 parent::initDocumentTemplate();
135 $this->doc->getContextMenuCode();
136 // Apply the same styles as those of the base script
137 $this->doc->bodyTagId = 'typo3-browse-links-php';
138 $this->doc->getPageRenderer()->addCssFile($this->doc->backPath . \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extRelPath('t3skin') . 'rtehtmlarea/htmlarea.css');
139 // Add attributes to body tag. Note: getBodyTagAdditions will invoke the hooks
140 $this->doc->bodyTagAdditions = $this->getBodyTagAdditions();
141 $this->doc->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Backend/LegacyTree', 'function(Tree) {
142 Tree.ajaxID = "SC_alt_file_navframe::expandCollapse";
143 }');
144 }
145
146 /**
147 * Initialize $this->curUrlArray and $this->curUrlInfo based on script parameters
148 *
149 * @return void
150 */
151 protected function initCurrentUrl() {
152 // CurrentUrl - the current link url must be passed around if it exists
153 $this->curUrlArray = GeneralUtility::_GP('curUrl');
154 if ($this->curUrlArray['all']) {
155 $this->curUrlArray = GeneralUtility::get_tag_attributes($this->curUrlArray['all']);
156 $this->curUrlArray['href'] = htmlspecialchars_decode($this->curUrlArray['href']);
157 }
158 // Note: parseCurUrl will invoke the hooks
159 $this->curUrlInfo = $this->parseCurUrl($this->curUrlArray['href'], $this->siteURL);
160 if (isset($this->curUrlArray['data-htmlarea-external']) && $this->curUrlArray['data-htmlarea-external'] === '1' && $this->curUrlInfo['act'] != 'mail') {
161 $this->curUrlInfo['act'] = 'url';
162 $this->curUrlInfo['info'] = $this->curUrlArray['href'];
163 }
164 }
165
166 /**
167 * Get the RTE configuration from Page TSConfig
168 *
169 * @return array RTE configuration array
170 */
171 protected function getRTEConfig() {
172 $RTEtsConfigParts = explode(':', $this->RTEtsConfigParams);
173 $RTEsetup = $GLOBALS['BE_USER']->getTSConfig('RTE', BackendUtility::getPagesTSconfig($RTEtsConfigParts[5]));
174 $this->RTEProperties = $RTEsetup['properties'];
175 return BackendUtility::RTEsetup($this->RTEProperties, $RTEtsConfigParts[0], $RTEtsConfigParts[2], $RTEtsConfigParts[4]);
176 }
177
178 /**
179 * Get the configuration of the button
180 *
181 * @param string $buttonName: the name of the button
182 * @return array the configuration array of the image button
183 */
184 protected function getButtonConfig($buttonName) {
185 return is_array($this->thisConfig['buttons.']) && is_array($this->thisConfig['buttons.'][$buttonName . '.'])
186 ? $this->thisConfig['buttons.'][$buttonName . '.']
187 : array();
188 }
189
190 /**
191 * Initialize the current or default values of the link attributes
192 *
193 * @return void
194 */
195 protected function initLinkAttributes() {
196 // Initializing the class value
197 $this->setClass = isset($this->curUrlArray['class']) ? $this->curUrlArray['class'] : '';
198 // Processing the classes configuration
199 $classSelected = array();
200 if ($this->buttonConfig['properties.']['class.']['allowedClasses']) {
201 $classesAnchorArray = GeneralUtility::trimExplode(',', $this->buttonConfig['properties.']['class.']['allowedClasses'], TRUE);
202 // Collecting allowed classes and configured default values
203 $classesAnchor = array();
204 $classesAnchor['all'] = array();
205 $titleReadOnly = $this->buttonConfig['properties.']['title.']['readOnly']
206 || $this->buttonConfig[$this->act . '.']['properties.']['title.']['readOnly'];
207 if (is_array($this->RTEProperties['classesAnchor.'])) {
208 foreach ($this->RTEProperties['classesAnchor.'] as $label => $conf) {
209 if (in_array($conf['class'], $classesAnchorArray)) {
210 $classesAnchor['all'][] = $conf['class'];
211 if (in_array($conf['type'], $this->anchorTypes)) {
212 $classesAnchor[$conf['type']][] = $conf['class'];
213 if ($this->buttonConfig[$conf['type'] . '.']['properties.']['class.']['default'] == $conf['class']) {
214 $this->classesAnchorDefault[$conf['type']] = $conf['class'];
215 if ($conf['titleText']) {
216 $this->classesAnchorDefaultTitle[$conf['type']] = $this->getLLContent(trim($conf['titleText']));
217 }
218 if (isset($conf['target'])) {
219 $this->classesAnchorDefaultTarget[$conf['type']] = trim($conf['target']);
220 }
221 }
222 }
223 if ($titleReadOnly && $conf['titleText']) {
224 $this->classesAnchorClassTitle[$conf['class']] = ($this->classesAnchorDefaultTitle[$conf['type']] = $this->getLLContent(trim($conf['titleText'])));
225 }
226 }
227 }
228 }
229 // Constructing the class selector options
230 foreach ($this->anchorTypes as $anchorType) {
231 $currentClass = $this->curUrlInfo['act'] === $anchorType ? $this->curUrlArray['class'] : '';
232 foreach ($classesAnchorArray as $class) {
233 if (!in_array($class, $classesAnchor['all']) || in_array($class, $classesAnchor['all']) && is_array($classesAnchor[$anchorType]) && in_array($class, $classesAnchor[$anchorType])) {
234 $selected = '';
235 if ($currentClass == $class || !$currentClass && $this->classesAnchorDefault[$anchorType] == $class) {
236 $selected = 'selected="selected"';
237 $classSelected[$anchorType] = TRUE;
238 }
239 $classLabel = is_array($this->RTEProperties['classes.']) && is_array($this->RTEProperties['classes.'][$class . '.']) && $this->RTEProperties['classes.'][$class . '.']['name'] ? $this->getPageConfigLabel($this->RTEProperties['classes.'][$class . '.']['name'], 0) : $class;
240 $classStyle = is_array($this->RTEProperties['classes.']) && is_array($this->RTEProperties['classes.'][$class . '.']) && $this->RTEProperties['classes.'][$class . '.']['value'] ? $this->RTEProperties['classes.'][$class . '.']['value'] : '';
241 $this->classesAnchorJSOptions[$anchorType] .= '<option ' . $selected . ' value="' . $class . '"' . ($classStyle ? ' style="' . $classStyle . '"' : '') . '>' . $classLabel . '</option>';
242 }
243 }
244 if ($this->classesAnchorJSOptions[$anchorType] && !($this->buttonConfig['properties.']['class.']['required'] || $this->buttonConfig[$this->act . '.']['properties.']['class.']['required'])) {
245 $selected = '';
246 if (!$this->setClass && !$this->classesAnchorDefault[$anchorType]) {
247 $selected = 'selected="selected"';
248 }
249 $this->classesAnchorJSOptions[$anchorType] = '<option ' . $selected . ' value=""></option>' . $this->classesAnchorJSOptions[$anchorType];
250 }
251 }
252 }
253 // Initializing the title value
254 $this->setTitle = isset($this->curUrlArray['title']) ? $this->curUrlArray['title'] : '';
255 // Initializing the target value
256 $this->setTarget = isset($this->curUrlArray['target']) ? $this->curUrlArray['target'] : '';
257 // Default target
258 $this->defaultLinkTarget = $this->classesAnchorDefault[$this->act] && $this->classesAnchorDefaultTarget[$this->act]
259 ? $this->classesAnchorDefaultTarget[$this->act]
260 : (isset($this->buttonConfig[$this->act . '.']['properties.']['target.']['default'])
261 ? $this->buttonConfig[$this->act . '.']['properties.']['target.']['default']
262 : (isset($this->buttonConfig['properties.']['target.']['default'])
263 ? $this->buttonConfig['properties.']['target.']['default']
264 : ''));
265 // Initializing additional attributes
266 if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes']) {
267 $addAttributes = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes'], TRUE);
268 foreach ($addAttributes as $attribute) {
269 $this->additionalAttributes[$attribute] = isset($this->curUrlArray[$attribute]) ? $this->curUrlArray[$attribute] : '';
270 }
271 }
272 }
273
274 /**
275 * Provide the additional parameters to be included in the template body tag
276 *
277 * @return string the body tag additions
278 */
279 public function getBodyTagAdditions() {
280 $bodyTagAdditions = array();
281 // call hook for extra additions
282 foreach ($this->hookObjects as $hookObject) {
283 if (method_exists($hookObject, 'addBodyTagAdditions')) {
284 $bodyTagAdditions = $hookObject->addBodyTagAdditions($bodyTagAdditions);
285 }
286 }
287 return GeneralUtility::implodeAttributes($bodyTagAdditions, TRUE);
288 }
289
290 /**
291 * Generate JS code to be used on the link insert/modify dialogue
292 *
293 * @return string the generated JS code
294 */
295 public function getJSCode() {
296 // BEGIN accumulation of header JavaScript:
297 $JScode = '';
298 $JScode .= '
299 var plugin = window.parent.RTEarea["' . $this->editorNo . '"].editor.getPlugin("TYPO3Link");
300 var HTMLArea = window.parent.HTMLArea;
301 var add_href=' . GeneralUtility::quoteJSvalue($this->curUrlArray['href'] ? '&curUrl[href]=' . rawurlencode($this->curUrlArray['href']) : '') . ';
302 var add_target=' . GeneralUtility::quoteJSvalue($this->setTarget ? '&curUrl[target]=' . rawurlencode($this->setTarget) : '') . ';
303 var add_class=' . GeneralUtility::quoteJSvalue($this->setClass ? '&curUrl[class]=' . rawurlencode($this->setClass) : '') . ';
304 var add_title=' . GeneralUtility::quoteJSvalue($this->setTitle ? '&curUrl[title]=' . rawurlencode($this->setTitle) : '') . ';
305 var add_params=' . GeneralUtility::quoteJSvalue($this->bparams ? '&bparams=' . rawurlencode($this->bparams) : '') . ';
306 var additionalValues = ' . (count($this->additionalAttributes) ? json_encode($this->additionalAttributes, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) : '{}') . ';';
307 // Attributes setting functions
308 $JScode .= '
309 var cur_href=' . GeneralUtility::quoteJSvalue($this->curUrlArray['href'] ? ($this->curUrlInfo['query'] ? substr($this->curUrlArray['href'], 0, -strlen($this->curUrlInfo['query'])) : $this->curUrlArray['href']) : '') . ';
310 var cur_target=' . GeneralUtility::quoteJSvalue($this->setTarget ?: '') . ';
311 var cur_class=' . GeneralUtility::quoteJSvalue($this->setClass ?: '') . ';
312 var cur_title=' . GeneralUtility::quoteJSvalue($this->setTitle ?: '') . ';
313
314 function browse_links_setTarget(value) {
315 cur_target=value;
316 add_target="&curUrl[target]="+encodeURIComponent(value);
317 }
318 function browse_links_setClass(value) {
319 cur_class=value;
320 add_class="&curUrl[class]="+encodeURIComponent(value);
321 }
322 function browse_links_setTitle(value) {
323 cur_title=value;
324 add_title="&curUrl[title]="+encodeURIComponent(value);
325 }
326 function browse_links_setHref(value) {
327 cur_href=value;
328 add_href="&curUrl[href]="+value;
329 }
330 function browse_links_setAdditionalValue(name, value) {
331 additionalValues[name] = value;
332 }
333 ';
334 // Link setting functions
335 $JScode .= '
336 function link_typo3Page(id,anchor) {
337 var parameters = (document.ltargetform.query_parameters && document.ltargetform.query_parameters.value) ? (document.ltargetform.query_parameters.value.charAt(0) == "&" ? "" : "&") + document.ltargetform.query_parameters.value : "";
338 var theLink = \'' . $this->siteURL . '?id=\' + id + parameters + (anchor ? anchor : "");
339 if (document.ltargetform.anchor_title) browse_links_setTitle(document.ltargetform.anchor_title.value);
340 if (document.ltargetform.anchor_class) browse_links_setClass(document.ltargetform.anchor_class.value);
341 if (document.ltargetform.ltarget) browse_links_setTarget(document.ltargetform.ltarget.value);
342 if (document.ltargetform.lrel) browse_links_setAdditionalValue("rel", document.ltargetform.lrel.value);
343 browse_links_setAdditionalValue("data-htmlarea-external", "");
344 plugin.createLink(theLink,cur_target,cur_class,cur_title,additionalValues);
345 return false;
346 }
347 function link_folder(folder) {
348 if (folder && folder.substr(0, 5) == "file:") {
349 var theLink = \'' . $this->siteURL . '?file:\' + encodeURIComponent(folder.substr(5));
350 } else {
351 var theLink = \'' . $this->siteURL . '?\' + folder;
352 }
353 if (document.ltargetform.anchor_title) browse_links_setTitle(document.ltargetform.anchor_title.value);
354 if (document.ltargetform.anchor_class) browse_links_setClass(document.ltargetform.anchor_class.value);
355 if (document.ltargetform.ltarget) browse_links_setTarget(document.ltargetform.ltarget.value);
356 if (document.ltargetform.lrel) browse_links_setAdditionalValue("rel", document.ltargetform.lrel.value);
357 browse_links_setAdditionalValue("data-htmlarea-external", "");
358 plugin.createLink(theLink,cur_target,cur_class,cur_title,additionalValues);
359 return false;
360 }
361 function link_spec(theLink) {
362 if (document.ltargetform.anchor_title) browse_links_setTitle(document.ltargetform.anchor_title.value);
363 if (document.ltargetform.anchor_class) browse_links_setClass(document.ltargetform.anchor_class.value);
364 if (document.ltargetform.ltarget) browse_links_setTarget(document.ltargetform.ltarget.value);
365 browse_links_setAdditionalValue("data-htmlarea-external", "");
366 plugin.createLink(theLink,cur_target,cur_class,cur_title,additionalValues);
367 return false;
368 }
369 function link_current() {
370 var parameters = (document.ltargetform.query_parameters && document.ltargetform.query_parameters.value) ? (document.ltargetform.query_parameters.value.charAt(0) == "&" ? "" : "&") + document.ltargetform.query_parameters.value : "";
371 if (document.ltargetform.anchor_title) browse_links_setTitle(document.ltargetform.anchor_title.value);
372 if (document.ltargetform.anchor_class) browse_links_setClass(document.ltargetform.anchor_class.value);
373 if (document.ltargetform.ltarget) browse_links_setTarget(document.ltargetform.ltarget.value);
374 if (document.ltargetform.lrel) browse_links_setAdditionalValue("rel", document.ltargetform.lrel.value);
375 if (cur_href!="http://" && cur_href!="mailto:") {
376 plugin.createLink(cur_href + parameters,cur_target,cur_class,cur_title,additionalValues);
377 }
378 return false;
379 }
380 ';
381 // General "jumpToUrl" and launchView functions:
382 $JScode .= '
383 function jumpToUrl(URL,anchor) {
384 if (URL.charAt(0) === \'?\') {
385 URL = ' . GeneralUtility::quoteJSvalue($this->getThisScript()) . ' + URL.substring(1);
386 }
387 var add_editorNo = URL.indexOf("editorNo=")==-1 ? "&editorNo=' . $this->editorNo . '" : "";
388 var add_contentTypo3Language = URL.indexOf("contentTypo3Language=")==-1 ? "&contentTypo3Language=' . $this->contentTypo3Language . '" : "";
389 var add_act = URL.indexOf("act=")==-1 ? "&act=' . $this->act . '" : "";
390 var add_mode = URL.indexOf("mode=")==-1 ? "&mode=' . $this->mode . '" : "";
391 var add_additionalValues = "";
392 if (plugin.pageTSConfiguration && plugin.pageTSConfiguration.additionalAttributes) {
393 var additionalAttributes = plugin.pageTSConfiguration.additionalAttributes.split(",");
394 for (var i = additionalAttributes.length; --i >= 0;) {
395 if (additionalValues[additionalAttributes[i]] != "") {
396 add_additionalValues += "&curUrl[" + additionalAttributes[i] + "]=" + encodeURIComponent(additionalValues[additionalAttributes[i]]);
397 }
398 }
399 }
400 var theLocation = URL+add_act+add_editorNo+add_contentTypo3Language+add_mode+add_href+add_target+add_class+add_title+add_additionalValues+add_params+(anchor?anchor:"");
401 window.location.href = theLocation;
402 return false;
403 }
404 function launchView(url) {
405 var thePreviewWindow="";
406 thePreviewWindow = window.open(' . GeneralUtility::quoteJSvalue(BackendUtility::getModuleUrl('show_item') . '&table=') . '+url,"ShowItem","height=300,width=410,status=0,menubar=0,resizable=0,location=0,directories=0,scrollbars=1,toolbar=0");
407 if (thePreviewWindow && thePreviewWindow.focus) {
408 thePreviewWindow.focus();
409 }
410 }
411 ';
412 // Hook to overwrite or extend javascript functions
413 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php']['extendJScode']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php']['extendJScode'])) {
414 $conf = array();
415 $_params = array(
416 'conf' => &$conf
417 );
418 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php']['extendJScode'] as $objRef) {
419 $processor =& GeneralUtility::getUserObj($objRef);
420 $JScode .= $processor->extendJScode($_params, $this);
421 }
422 }
423 return $JScode;
424 }
425
426 /******************************************************************
427 *
428 * Main functions
429 *
430 ******************************************************************/
431 /**
432 * Rich Text Editor (RTE) link selector (MAIN function)
433 * Generates the link selector for the Rich Text Editor.
434 * Can also be used to select links for the TCEforms (see $wiz)
435 *
436 * @param bool $wiz If set, the "remove link" is not shown in the menu: Used for the "Select link" wizard which is used by the TCEforms
437 * @return string Modified content variable.
438 */
439 public function main_rte($wiz = FALSE) {
440 // Starting content:
441 $content = $this->doc->startPage($GLOBALS['LANG']->getLL('Insert/Modify Link', TRUE));
442 // Making menu in top:
443 $content .= $this->doc->getTabMenuRaw($this->buildMenuArray($wiz, $this->allowedItems));
444 // Adding the menu and header to the top of page:
445 $content .= $this->printCurrentUrl($this->curUrlInfo['info']) . '<br />';
446 // Depending on the current action we will create the actual module content for selecting a link:
447 switch ($this->act) {
448 case 'mail':
449 $extUrl = $this->getEmailSelectorHtml();
450 $content .= $this->addAttributesForm($extUrl);
451 break;
452 case 'url':
453 $extUrl = $this->getExternalUrlSelectorHtml();
454 $content .= $this->addAttributesForm($extUrl);
455 break;
456 case 'file':
457 case 'folder':
458 $content .= $this->addAttributesForm();
459 $content .= $this->getFileSelectorHtml(\TYPO3\CMS\Rtehtmlarea\FolderTree::class);
460 break;
461 case 'spec':
462 $content .= $this->getUserLinkSelectorHtml();
463 break;
464 case 'page':
465 $content .= $this->addAttributesForm();
466 $content .= $this->getPageSelectorHtml(\TYPO3\CMS\Rtehtmlarea\PageTree::class);
467 break;
468 default:
469 // call hook
470 foreach ($this->hookObjects as $hookObject) {
471 $content .= $hookObject->getTab($this->act);
472 }
473 }
474 // End page, return content:
475 $content .= $this->doc->endPage();
476 $content = $this->doc->insertStylesAndJS($content);
477 return $content;
478 }
479
480 /**
481 * Returns an array definition of the top menu
482 *
483 * @param $wiz
484 * @param $allowedItems
485 * @return array
486 */
487 protected function buildMenuArray($wiz, $allowedItems) {
488 $menuDef = array();
489 if (!$wiz && $this->curUrlArray['href']) {
490 $menuDef['removeLink']['isActive'] = $this->act == 'removeLink';
491 $menuDef['removeLink']['label'] = $GLOBALS['LANG']->getLL('removeLink', TRUE);
492 $menuDef['removeLink']['url'] = '#';
493 $menuDef['removeLink']['addParams'] = 'onclick="plugin.unLink();return false;"';
494 }
495 if (in_array('page', $this->allowedItems)) {
496 $menuDef['page']['isActive'] = $this->act == 'page';
497 $menuDef['page']['label'] = $GLOBALS['LANG']->getLL('page', TRUE);
498 $menuDef['page']['url'] = '#';
499 $menuDef['page']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=page&mode=' . $this->mode . '&bparams=' . $this->bparams) . ');return false;"';
500 }
501 if (in_array('file', $this->allowedItems)) {
502 $menuDef['file']['isActive'] = $this->act == 'file';
503 $menuDef['file']['label'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_browse_links.xlf:file', TRUE);
504 $menuDef['file']['url'] = '#';
505 $menuDef['file']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=file&mode=' . $this->mode . '&bparams=' . $this->bparams) . ');return false;"';
506 }
507 if (in_array('folder', $this->allowedItems)) {
508 $menuDef['folder']['isActive'] = $this->act == 'folder';
509 $menuDef['folder']['label'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_browse_links.xlf:folder', TRUE);
510 $menuDef['folder']['url'] = '#';
511 $menuDef['folder']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=folder&mode=' . $this->mode . '&bparams=' . $this->bparams) . ');return false;"';
512 }
513 if (in_array('url', $this->allowedItems)) {
514 $menuDef['url']['isActive'] = $this->act == 'url';
515 $menuDef['url']['label'] = $GLOBALS['LANG']->getLL('extUrl', TRUE);
516 $menuDef['url']['url'] = '#';
517 $menuDef['url']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=url&mode=' . $this->mode . '&bparams=' . $this->bparams) . ');return false;"';
518 }
519 if (in_array('mail', $this->allowedItems)) {
520 $menuDef['mail']['isActive'] = $this->act == 'mail';
521 $menuDef['mail']['label'] = $GLOBALS['LANG']->getLL('email', TRUE);
522 $menuDef['mail']['url'] = '#';
523 $menuDef['mail']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=mail&mode=' . $this->mode . '&bparams=' . $this->bparams) . ');return false;"';
524 }
525 if (is_array($this->thisConfig['userLinks.']) && in_array('spec', $this->allowedItems)) {
526 $menuDef['spec']['isActive'] = $this->act == 'spec';
527 $menuDef['spec']['label'] = $GLOBALS['LANG']->getLL('special', TRUE);
528 $menuDef['spec']['url'] = '#';
529 $menuDef['spec']['addParams'] = 'onclick="jumpToUrl(' . GeneralUtility::quoteJSvalue('?act=spec&mode=' . $this->mode . '&bparams=' . $this->bparams) . ');return false;"';
530 }
531 // call hook for extra options
532 foreach ($this->hookObjects as $hookObject) {
533 $menuDef = $hookObject->modifyMenuDefinition($menuDef);
534 }
535 return $menuDef;
536 }
537
538 /**
539 * Returns HTML of the email link from
540 *
541 * @return string
542 */
543 protected function getEmailSelectorHtml() {
544 $extUrl = '
545 <!--
546 Enter mail address:
547 -->
548 <tr>
549 <td>
550 <label>
551 ' . $GLOBALS['LANG']->getLL('emailAddress', TRUE) . ':
552 </label>
553 </td>
554 <td>
555 <input type="text" name="lemail"' . $this->doc->formWidth(20)
556 . ' value="' . htmlspecialchars(($this->curUrlInfo['act'] == 'mail' ? $this->curUrlInfo['info'] : '')) . '" />
557 <input class="btn btn-default" type="submit" value="' . $GLOBALS['LANG']->getLL('setLink', TRUE)
558 . '" onclick="browse_links_setTarget(\'\');browse_links_setHref(\'mailto:\'+document.ltargetform.lemail.value);'
559 . 'browse_links_setAdditionalValue(\'data-htmlarea-external\', \'\');return link_current();" />
560 </td>
561 </tr>';
562 return $extUrl;
563 }
564
565 /**
566 * Returns HTML of the external url link from
567 *
568 * @return string
569 */
570 protected function getExternalUrlSelectorHtml() {
571 $extUrl = '
572 <!--
573 Enter External URL:
574 -->
575 <tr>
576 <td>
577 <label>
578 URL:
579 </label>
580 </td>
581 <td colspan="3">
582 <input type="text" name="lurl"' . $this->doc->formWidth(20)
583 . ' value="' . htmlspecialchars(($this->curUrlInfo['act'] == 'url' ? $this->curUrlInfo['info'] : 'http://'))
584 . '" />
585 <input class="btn btn-default" type="submit" value="' . $GLOBALS['LANG']->getLL('setLink', TRUE)
586 . '" onclick="if (/^[A-Za-z0-9_+]{1,8}:/.test(document.ltargetform.lurl.value)) { '
587 . ' browse_links_setHref(document.ltargetform.lurl.value); } else { browse_links_setHref(\'http://\''
588 . '+document.ltargetform.lurl.value); }; browse_links_setAdditionalValue(\'data-htmlarea-external\', \'1\');'
589 . 'return link_current();" />
590 </td>
591 </tr>';
592 return $extUrl;
593 }
594
595 /**
596 * Returns HTML of the user defined link selector
597 *
598 * @return string
599 */
600 protected function getUserLinkSelectorHtml() {
601 if (!is_array($this->thisConfig['userLinks.'])) {
602 return '';
603 }
604 $subcats = array();
605 $v = $this->thisConfig['userLinks.'];
606 foreach ($v as $k2 => $dummyValue) {
607 $k2i = (int)$k2;
608 if (substr($k2, -1) == '.' && is_array($v[$k2i . '.'])) {
609 // Title:
610 $title = trim($v[$k2i]);
611 if (!$title) {
612 $title = $v[$k2i . '.']['url'];
613 } else {
614 $title = $GLOBALS['LANG']->sL($title);
615 }
616 // Description:
617 $description = $v[$k2i . '.']['description'] ? $GLOBALS['LANG']->sL($v[($k2i . '.')]['description'], TRUE) . '<br />' : '';
618 // URL + onclick event:
619 $onClickEvent = '';
620 if (isset($v[$k2i . '.']['target'])) {
621 $onClickEvent .= 'browse_links_setTarget(\'' . $v[($k2i . '.')]['target'] . '\');';
622 }
623 $v[$k2i . '.']['url'] = str_replace('###_URL###', $this->siteURL, $v[$k2i . '.']['url']);
624 if (substr($v[$k2i . '.']['url'], 0, 7) == 'http://' || substr($v[$k2i . '.']['url'], 0, 7) == 'mailto:') {
625 $onClickEvent .= 'cur_href=' . GeneralUtility::quoteJSvalue($v[($k2i . '.')]['url']) . ';link_current();';
626 } else {
627 $onClickEvent .= 'link_spec(' . GeneralUtility::quoteJSvalue($this->siteURL . $v[($k2i . '.')]['url']) . ');';
628 }
629 // Link:
630 $A = array('<a href="#" onclick="' . htmlspecialchars($onClickEvent) . 'return false;">', '</a>');
631 // Adding link to menu of user defined links:
632 $icon = $this->curUrlInfo['info'] == $v[$k2i . '.']['url']
633 ? '<img' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($GLOBALS['BACK_PATH'], 'gfx/blinkarrow_right.gif', 'width="5" height="9"') . ' class="c-blinkArrowR" alt="" />'
634 : '';
635 $subcats[$k2i] = '
636 <tr>
637 <td class="bgColor4">' . $A[0]
638 . '<strong>' . htmlspecialchars($title) . $icon . '</strong><br />' . $description . $A[1] . '</td>
639 </tr>';
640 }
641 }
642 // Sort by keys:
643 ksort($subcats);
644 // Add menu to content:
645 $content = '
646 <!--
647 Special userdefined menu:
648 -->
649 <table border="0" cellpadding="1" cellspacing="1" id="typo3-linkSpecial">
650 <tr>
651 <td class="bgColor5" class="c-wCell" valign="top"><strong>' . $GLOBALS['LANG']->getLL('special', TRUE) . '</strong></td>
652 </tr>
653 ' . implode('', $subcats) . '
654 </table>
655 ';
656 return $content;
657 }
658
659 /**
660 * Get the allowed items or tabs
661 *
662 * @param string $items: initial list of possible items
663 * @return array the allowed items
664 */
665 public function getAllowedItems($items) {
666 $allowedItems = explode(',', $items);
667 // Calling hook for extra options
668 foreach ($this->hookObjects as $hookObject) {
669 $allowedItems = $hookObject->addAllowedItems($allowedItems);
670 }
671 // Removing items as per configuration
672 if (is_array($this->buttonConfig['options.']) && $this->buttonConfig['options.']['removeItems']) {
673 $allowedItems = array_diff($allowedItems, GeneralUtility::trimExplode(',', $this->buttonConfig['options.']['removeItems'], TRUE));
674 }
675 reset($allowedItems);
676 if (!in_array($this->act, $allowedItems)) {
677 $this->act = current($allowedItems);
678 }
679 return $allowedItems;
680 }
681
682 /**
683 * Creates a form for link attributes
684 *
685 * @param string $rows: html code for some initial rows of the table to be wrapped in form
686 * @return string The HTML code of the form
687 */
688 public function addAttributesForm($rows = '') {
689 $ltargetForm = '';
690 $additionalAttributeFields = '';
691 // Add page id, target, class selector box, title and parameters fields:
692 $lpageId = $this->addPageIdSelector();
693 $queryParameters = $this->addQueryParametersSelector();
694 $ltarget = $this->addTargetSelector();
695 $lclass = $this->addClassSelector();
696 $ltitle = $this->addTitleSelector();
697 $rel = $this->addRelField();
698 // additional fields for links
699 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php']['addAttributeFields'])
700 && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php']['addAttributeFields'])
701 ) {
702 $conf = array();
703 $_params = array(
704 'conf' => &$conf
705 );
706 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['ext/rtehtmlarea/mod3/class.tx_rtehtmlarea_browse_links.php']['addAttributeFields'] as $objRef) {
707 $processor =& GeneralUtility::getUserObj($objRef);
708 $additionalAttributeFields .= $processor->getAttributefields($_params, $this);
709 }
710 }
711 if ($rows || $lpageId || $queryParameters || $lclass || $ltitle || $ltarget || $rel) {
712 $ltargetForm = $this->wrapInForm($rows . $lpageId . $queryParameters . $lclass . $ltitle . $ltarget . $rel . $additionalAttributeFields);
713 }
714 return $ltargetForm;
715 }
716
717 /**
718 * Wrap in form
719 *
720 * @param string $string
721 * @return string
722 */
723 public function wrapInForm($string) {
724 $form = '
725 <!--
726 Selecting target for link:
727 -->
728 <form action="" name="ltargetform" id="ltargetform">
729 <table id="typo3-linkTarget" class="htmlarea-window-table">' . $string;
730 if ($this->act == $this->curUrlInfo['act'] && $this->act != 'mail' && $this->curUrlArray['href']) {
731 $form .= '
732 <tr>
733 <td>
734 </td>
735 <td colspan="3">
736 <input class="btn btn-default" type="submit" value="' . $GLOBALS['LANG']->getLL('update', TRUE) . '" onclick="'
737 . ($this->act == 'url' ? 'browse_links_setAdditionalValue(\'data-htmlarea-external\', \'1\'); ' : '')
738 . 'return link_current();" />
739 </td>
740 </tr>';
741 }
742 $form .= '
743 </table>
744 </form>';
745 return $form;
746 }
747
748 /**
749 * Add page id selector
750 *
751 * @return string
752 */
753 public function addPageIdSelector() {
754 if ($this->act == 'page' && isset($this->buttonConfig['pageIdSelector.']['enabled'])
755 && $this->buttonConfig['pageIdSelector.']['enabled']
756 ) {
757 return '
758 <tr>
759 <td>
760 <label>
761 ' . $GLOBALS['LANG']->getLL('page_id', TRUE) . ':
762 </label>
763 </td>
764 <td colspan="3">
765 <input type="text" size="6" name="luid" /> <input class="btn btn-default" type="submit" value="'
766 . $GLOBALS['LANG']->getLL('setLink', TRUE) . '" onclick="return link_typo3Page(document.ltargetform.luid.value);" />
767 </td>
768 </tr>';
769 }
770 return '';
771 }
772
773 /**
774 * Add rel field
775 *
776 * @return string
777 */
778 public function addRelField() {
779 // Unset rel attribute if we changed tab
780 $currentRel = $this->curUrlInfo['act'] === $this->act && isset($this->curUrlArray['rel']) ? $this->curUrlArray['rel'] : '';
781 if (($this->act == 'page' || $this->act == 'url' || $this->act == 'file')
782 && isset($this->buttonConfig['relAttribute.']['enabled']) && $this->buttonConfig['relAttribute.']['enabled']
783 ) {
784 return '
785 <tr>
786 <td><label>' . $GLOBALS['LANG']->getLL('linkRelationship', TRUE) . ':</label></td>
787 <td colspan="3">
788 <input type="text" name="lrel" value="' . $currentRel . '" '
789 . $this->doc->formWidth(30) . ' />
790 </td>
791 </tr>';
792 }
793 return '';
794 }
795
796 /**
797 * Add query parameter selector
798 *
799 * @return string
800 */
801 public function addQueryParametersSelector() {
802 if ($this->act == 'page' && isset($this->buttonConfig['queryParametersSelector.']['enabled'])
803 && $this->buttonConfig['queryParametersSelector.']['enabled']
804 ) {
805 return '
806 <tr>
807 <td><label>' . $GLOBALS['LANG']->getLL('query_parameters', TRUE) . ':</label></td>
808 <td colspan="3">
809 <input type="text" name="query_parameters" value="' . ($this->curUrlInfo['query'] ?: '')
810 . '" ' . $this->doc->formWidth(30) . ' />
811 </td>
812 </tr>';
813 }
814 return '';
815 }
816
817 /**
818 * Add target selector
819 *
820 * @return string
821 */
822 public function addTargetSelector() {
823 if ($this->act === 'mail') {
824 return '';
825 }
826 $targetSelectorConfig = array();
827 $popupSelectorConfig = array();
828 if (is_array($this->buttonConfig['targetSelector.'])) {
829 $targetSelectorConfig = $this->buttonConfig['targetSelector.'];
830 }
831 if (is_array($this->buttonConfig['popupSelector.'])) {
832 $popupSelectorConfig = $this->buttonConfig['popupSelector.'];
833 }
834 // Reset the target to default if we changed tab
835 $currentTarget = $this->curUrlInfo['act'] === $this->act && isset($this->curUrlArray['target']) ? $this->curUrlArray['target'] : '';
836 $target = $currentTarget ?: $this->defaultLinkTarget;
837 $ltarget = '
838 <tr id="ltargetrow"' . ($targetSelectorConfig['disabled'] && $popupSelectorConfig['disabled'] ? ' style="display: none;"' : '') . '>
839 <td><label>' . $GLOBALS['LANG']->getLL('target', TRUE) . ':</label></td>
840 <td><input type="text" name="ltarget" onchange="browse_links_setTarget(this.value);" value="'
841 . htmlspecialchars($target) . '"' . $this->doc->formWidth(10) . ' /></td>';
842 $ltarget .= '
843 <td colspan="2">';
844 if (!$targetSelectorConfig['disabled']) {
845 $ltarget .= '
846 <select name="ltarget_type" onchange="browse_links_setTarget(this.options[this.selectedIndex].value);document.ltargetform.ltarget.value=this.options[this.selectedIndex].value;this.selectedIndex=0;">
847 <option></option>
848 <option value="_top">' . $GLOBALS['LANG']->getLL('top', TRUE) . '</option>
849 <option value="_blank">' . $GLOBALS['LANG']->getLL('newWindow', TRUE) . '</option>
850 </select>';
851 }
852 $ltarget .= '
853 </td>
854 </tr>';
855 if (!$popupSelectorConfig['disabled']) {
856 $selectJS = 'if (document.ltargetform.popup_width.options[document.ltargetform.popup_width.selectedIndex].value>0 && document.ltargetform.popup_height.options[document.ltargetform.popup_height.selectedIndex].value>0) {
857 document.ltargetform.ltarget.value = document.ltargetform.popup_width.options[document.ltargetform.popup_width.selectedIndex].value+\'x\'+document.ltargetform.popup_height.options[document.ltargetform.popup_height.selectedIndex].value;
858 browse_links_setTarget(document.ltargetform.ltarget.value);
859 document.ltargetform.popup_width.selectedIndex=0;
860 document.ltargetform.popup_height.selectedIndex=0;
861 }';
862 $ltarget .= '
863 <tr>
864 <td><label>' . $GLOBALS['LANG']->getLL('target_popUpWindow', TRUE) . ':</label></td>
865 <td colspan="3">
866 <select name="popup_width" onchange="' . $selectJS . '">
867 <option value="0">' . $GLOBALS['LANG']->getLL('target_popUpWindow_width', TRUE) . '</option>
868 <option value="300">300</option>
869 <option value="400">400</option>
870 <option value="500">500</option>
871 <option value="600">600</option>
872 <option value="700">700</option>
873 <option value="800">800</option>
874 </select>
875 x
876 <select name="popup_height" onchange="' . $selectJS . '">
877 <option value="0">' . $GLOBALS['LANG']->getLL('target_popUpWindow_height', TRUE) . '</option>
878 <option value="200">200</option>
879 <option value="300">300</option>
880 <option value="400">400</option>
881 <option value="500">500</option>
882 <option value="600">600</option>
883 </select>
884 </td>
885 </tr>';
886 }
887 return $ltarget;
888 }
889
890 /**
891 * Return html code for the class selector
892 *
893 * @return string the html code to be added to the form
894 */
895 public function addClassSelector() {
896 $selectClass = '';
897 if ($this->classesAnchorJSOptions[$this->act]) {
898 $selectClass = '
899 <tr>
900 <td><label>' . $GLOBALS['LANG']->getLL('anchor_class', TRUE) . ':</label></td>
901 <td colspan="3">
902 <select name="anchor_class" onchange="' . $this->getClassOnChangeJS() . '">
903 ' . $this->classesAnchorJSOptions[$this->act] . '
904 </select>
905 </td>
906 </tr>';
907 }
908 return $selectClass;
909 }
910
911 /**
912 * Return JS code for the class selector onChange event
913 *
914 * @return string class selector onChange JS code
915 */
916 public function getClassOnChangeJS() {
917 return '
918 if (document.ltargetform.anchor_class) {
919 document.ltargetform.anchor_class.value = document.ltargetform.anchor_class.options[document.ltargetform.anchor_class.selectedIndex].value;
920 if (document.ltargetform.anchor_class.value && HTMLArea.classesAnchorSetup) {
921 for (var i = HTMLArea.classesAnchorSetup.length; --i >= 0;) {
922 var anchorClass = HTMLArea.classesAnchorSetup[i];
923 if (anchorClass[\'name\'] == document.ltargetform.anchor_class.value) {
924 if (anchorClass[\'titleText\'] && document.ltargetform.anchor_title) {
925 document.ltargetform.anchor_title.value = anchorClass[\'titleText\'];
926 document.getElementById(\'rtehtmlarea-browse-links-title-readonly\').innerHTML = anchorClass[\'titleText\'];
927 browse_links_setTitle(anchorClass[\'titleText\']);
928 }
929 if (typeof anchorClass[\'target\'] !== \'undefined\') {
930 if (document.ltargetform.ltarget) {
931 document.ltargetform.ltarget.value = anchorClass[\'target\'];
932 }
933 browse_links_setTarget(anchorClass[\'target\']);
934 } else if (document.ltargetform.ltarget && document.getElementById(\'ltargetrow\').style.display == \'none\') {
935 // Reset target to default if field is not displayed and class has no configured target
936 document.ltargetform.ltarget.value = \'' . ($this->defaultLinkTarget ?: '') . '\';
937 browse_links_setTarget(document.ltargetform.ltarget.value);
938 }
939 break;
940 }
941 }
942 }
943 browse_links_setClass(document.ltargetform.anchor_class.value);
944 }
945 ';
946 }
947
948 /**
949 * Add title selector
950 *
951 * @return string
952 */
953 public function addTitleSelector() {
954 // Reset the title to default if we changed tab
955 $currentTitle = $this->curUrlInfo['act'] === $this->act && isset($this->curUrlArray['title']) ? $this->curUrlArray['title'] : '';
956 $title = $currentTitle ?: (!$this->classesAnchorDefault[$this->act] ? '' : $this->classesAnchorDefaultTitle[$this->act]);
957 $readOnly = isset($this->buttonConfig[$this->act . '.']['properties.']['title.']['readOnly'])
958 ? $this->buttonConfig[$this->act . '.']['properties.']['title.']['readOnly']
959 : (isset($this->buttonConfig['properties.']['title.']['readOnly'])
960 ? $this->buttonConfig['properties.']['title.']['readOnly']
961 : FALSE);
962 if ($readOnly) {
963 $currentClass = $this->curUrlInfo['act'] === $this->act ? $this->curUrlArray['class'] : '';
964 if (!$currentClass) {
965 $currentClass = !$this->classesAnchorDefault[$this->act] ? '' : $this->classesAnchorDefault[$this->act];
966 }
967 $title = $currentClass
968 ? $this->classesAnchorClassTitle[$currentClass]
969 : $this->classesAnchorDefaultTitle[$this->act];
970 }
971 return '
972 <tr>
973 <td><label for="rtehtmlarea-browse-links-anchor_title" id="rtehtmlarea-browse-links-title-label">' . $GLOBALS['LANG']->getLL('anchor_title', TRUE) . ':</label></td>
974 <td colspan="3">
975 <span id="rtehtmlarea-browse-links-title-input" style="display: ' . ($readOnly ? 'none' : 'inline') . ';">
976 <input type="text" id="rtehtmlarea-browse-links-anchor_title" name="anchor_title" value="' . htmlspecialchars($title) . '" ' . $this->doc->formWidth(30) . ' />
977 </span>
978 <span id="rtehtmlarea-browse-links-title-readonly" style="display: ' . ($readOnly ? 'inline' : 'none') . ';">' . htmlspecialchars($title) . '</span>
979 </td>
980 </tr>';
981 }
982
983 /**
984 * Localize a string using the language of the content element rather than the language of the BE interface
985 *
986 * @param string string: the label to be localized
987 * @return string Localized string.
988 */
989 public function getLLContent($string) {
990 return $this->contentLanguageService->sL($string);
991 }
992
993 /**
994 * Localize a label obtained from Page TSConfig
995 *
996 * @param string $string The label to be localized
997 * @param bool $JScharCode If needs to be converted to a array of char numbers
998 * @return string Localized string
999 */
1000 public function getPageConfigLabel($string, $JScharCode = TRUE) {
1001 if (substr($string, 0, 4) !== 'LLL:') {
1002 $label = $string;
1003 } else {
1004 $label = $GLOBALS['LANG']->sL(trim($string));
1005 }
1006 $label = str_replace('"', '\\"', str_replace('\\\'', '\'', $label));
1007 return $JScharCode ? GeneralUtility::quoteJSvalue($label) : $label;
1008 }
1009
1010 }