[FOLLOWUP][TASK] Add linkbrowser to CKEditor 12/50912/6
authorFrans Saris <franssaris@gmail.com>
Fri, 9 Dec 2016 08:25:56 +0000 (09:25 +0100)
committerBenni Mack <benni@typo3.org>
Fri, 9 Dec 2016 12:35:25 +0000 (13:35 +0100)
Streamlined added config and moved plugin out of the Contrib folder
and pass correct contents language to editor.

Releases: master
Resolves: #78917
Change-Id: Iccd66e2bea7f1503e2c4b3ae68096da70e9822ef
Reviewed-on: https://review.typo3.org/50912
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Daniel Gorges <daniel.gorges@b13.de>
Tested-by: Daniel Gorges <daniel.gorges@b13.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/rte_ckeditor/Classes/Controller/BrowseLinksController.php
typo3/sysext/rte_ckeditor/Classes/Form/Element/RichTextElement.php
typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/Contrib/plugins/typo3link/plugin.js [deleted file]
typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/Plugins/typo3link.js [new file with mode: 0644]
typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/defaultconfig.js

index f6bbe76..b475499 100644 (file)
@@ -38,7 +38,7 @@ class BrowseLinksController extends AbstractLinkBrowserController
      *
      * @var int
      */
-    protected $contentTypo3Language;
+    protected $contentsLanguage;
 
     /**
      * Language service object for localization to the content language
@@ -136,10 +136,10 @@ class BrowseLinksController extends AbstractLinkBrowserController
         $currentLinkParts = isset($queryParameters['curUrl']) ? $queryParameters['curUrl'] : [];
         $this->currentLinkParts = $currentLinkParts;
         $this->editorId = GeneralUtility::_GP('editorId');
-        $this->contentTypo3Language = GeneralUtility::_GP('contentTypo3Language');
+        $this->contentsLanguage = GeneralUtility::_GP('contentsLanguage');
         $this->RTEtsConfigParams = GeneralUtility::_GP('RTEtsConfigParams');
 
-        $this->contentLanguageService->init($this->contentTypo3Language);
+        $this->contentLanguageService->init($this->contentsLanguage);
 
         $RTEtsConfigParts = explode(':', $this->RTEtsConfigParams);
         $RTEsetup = $this->getBackendUser()->getTSConfig('RTE', BackendUtility::getPagesTSconfig($RTEtsConfigParts[5]));
@@ -276,8 +276,8 @@ class BrowseLinksController extends AbstractLinkBrowserController
 
         // todo: find new name for this option
         // Initializing additional attributes
-        if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes']) {
-            $addAttributes = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes'], true);
+        if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rte_ckeditor']['plugins']['TYPO3Link']['additionalAttributes']) {
+            $addAttributes = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rte_ckeditor']['plugins']['TYPO3Link']['additionalAttributes'], true);
             foreach ($addAttributes as $attribute) {
                 $this->additionalAttributes[$attribute] = $this->linkAttributeValues[$attribute] ?? '';
             }
@@ -565,7 +565,7 @@ class BrowseLinksController extends AbstractLinkBrowserController
         return [
             'act' => isset($overrides['act']) ? $overrides['act'] : $this->displayedLinkHandlerId,
             'editorId' => $this->editorId,
-            'contentTypo3Language' => $this->contentTypo3Language,
+            'contentsLanguage' => $this->contentsLanguage,
             'RTEtsConfigParams' => $this->RTEtsConfigParams,
         ];
     }
index aade0bc..5813a16 100644 (file)
@@ -16,8 +16,11 @@ namespace TYPO3\CMS\RteCKEditor\Form\Element;
  */
 
 use TYPO3\CMS\Backend\Form\Element\AbstractFormElement;
+use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
@@ -100,7 +103,63 @@ class RichTextElement extends AbstractFormElement
     }
 
     /**
-     * Gets the JavaScript code for ckeditor module
+     * Determine the contents language iso code
+     *
+     * @return string
+     */
+    protected function getContentsLanguage()
+    {
+        $language = $this->getLanguageService()->lang;
+        if ($language === 'default' || !$language) {
+            $language = 'en';
+        }
+        $currentLanguageUid = $this->data['databaseRow']['sys_language_uid'];
+        if (is_array($currentLanguageUid)) {
+            $currentLanguageUid = $currentLanguageUid[0];
+        }
+        $contentLanguageUid = (int)max($currentLanguageUid, 0);
+        if ($contentLanguageUid) {
+            $contentISOLanguage = $language;
+            if (ExtensionManagementUtility::isLoaded('static_info_tables')) {
+                $tableA = 'sys_language';
+                $tableB = 'static_languages';
+
+                $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+                    ->getQueryBuilderForTable($tableA);
+
+                $result = $queryBuilder
+                    ->select('a.uid', 'b.lg_iso_2', 'b.lg_country_iso_2')
+                    ->from($tableA, 'a')
+                    ->where('a.uid', (int)$contentLanguageUid)
+                    ->leftJoin(
+                        'a',
+                        $tableB,
+                        'b',
+                        $queryBuilder->expr()->eq('a.static_lang_isocode', $queryBuilder->quoteIdentifier('b.uid'))
+                    )
+                    ->execute();
+
+                while ($languageRow = $result->fetch()) {
+                    $contentISOLanguage = strtolower(trim($languageRow['lg_iso_2']) . (trim($languageRow['lg_country_iso_2']) ? '_' . trim($languageRow['lg_country_iso_2']) : ''));
+                }
+            }
+        } else {
+            $contentISOLanguage = trim($this->rteConfiguration['defaultContentLanguage'] ?? '') ?: 'en';
+            $languageCodeParts = explode('_', $contentISOLanguage);
+            $contentISOLanguage = strtolower($languageCodeParts[0]) . ($languageCodeParts[1] ? '_' . strtoupper($languageCodeParts[1]) : '');
+            // Find the configured language in the list of localization locales
+            /** @var $locales Locales */
+            $locales = GeneralUtility::makeInstance(Locales::class);
+            // If not found, default to 'en'
+            if (!in_array($contentISOLanguage, $locales->getLocales(), true)) {
+                $contentISOLanguage = 'en';
+            }
+        }
+        return $contentISOLanguage;
+    }
+
+    /**
+     * Gets the JavaScript code for CKEditor module
      *
      * @param string $resourcesPath
      * @param string $fieldId
@@ -108,32 +167,33 @@ class RichTextElement extends AbstractFormElement
      */
     protected function getCkEditorRequireJsModuleCode(string $resourcesPath, string $fieldId) : string
     {
-        // todo: find new name for this option (do we still need this?)
-        // Initializing additional attributes
-        $additionalAttributes = [];
-        if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes']) {
-            $additionalAttributes = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rtehtmlarea']['plugins']['TYPO3Link']['additionalAttributes'], true);
-        }
-
         $customConfig = [
             'contentsCss' => $resourcesPath . 'Css/contents.css',
             'customConfig' => $resourcesPath . 'JavaScript/defaultconfig.js',
             'toolbar' => 'Basic',
             'uiColor' => '#F8F8F8',
             'stylesSet' => 'default',
+            'extraPlugins' => '',
             'RTEtsConfigParams' => $this->getRTEtsConfigParams(),
-            'elementbrowser' => [
-                'link' => [
-                    'moduleUrl' => BackendUtility::getModuleUrl('rteckeditor_wizard_browse_links'),
-                    'additionalAttributes' => $additionalAttributes
-                ]
-            ]
+            'contentsLanguage' => $this->getContentsLanguage(),
         ];
 
+        $externalPlugins = '';
+        foreach ($this->getExternalPlugins() as $pluginName => $config) {
+            $customConfig[$pluginName] = $config['config'];
+            $customConfig['extraPlugins'] .= ',' . $pluginName;
+
+            $externalPlugins .= 'CKEDITOR.plugins.addExternal(';
+            $externalPlugins .= GeneralUtility::quoteJSvalue($pluginName) . ',';
+            $externalPlugins .= GeneralUtility::quoteJSvalue($config['path']) . ',';
+            $externalPlugins .= '\'\');';
+        }
+
         return 'function(CKEDITOR) {
                 CKEDITOR.config.height = 400;
                 CKEDITOR.contentsCss = "' . $resourcesPath . 'Css/contents.css";
                 CKEDITOR.config.width = "auto";
+                ' . $externalPlugins . '
                 CKEDITOR.replace("' . $fieldId . '", ' . json_encode($customConfig) . ');
         }';
     }
@@ -149,7 +209,7 @@ class RichTextElement extends AbstractFormElement
         $itemFormElementName = $this->data['parameterArray']['itemFormElName'];
         $value = $this->data['parameterArray']['itemFormElValue'] ?? '';
 
-        return '<textarea ' . $this->getValidationDataAsDataAttribute($this->data['parameterArray']['fieldConf']['config']) . ' id="' . $fieldId . '" name="' . htmlspecialchars($itemFormElementName) . '">' . htmlspecialchars($value) . '</textarea>';
+        return '<textarea style="display:none" ' . $this->getValidationDataAsDataAttribute($this->data['parameterArray']['fieldConf']['config']) . ' id="' . $fieldId . '" name="' . htmlspecialchars($itemFormElementName) . '">' . htmlspecialchars($value) . '</textarea>';
     }
 
     /**
@@ -171,6 +231,38 @@ class RichTextElement extends AbstractFormElement
     }
 
     /**
+     * Get configuration of external/additional plugins
+     *
+     * @return array
+     */
+    protected function getExternalPlugins() : array
+    {
+        // todo: find new name for this option (do we still need this?)
+        // Initializing additional attributes
+        $additionalAttributes = [];
+        if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rte_ckeditor']['plugins']['TYPO3Link']['additionalAttributes']) {
+            $additionalAttributes = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['rte_ckeditor']['plugins']['TYPO3Link']['additionalAttributes'], true);
+        }
+
+        $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
+        // todo: add api for this https://forge.typo3.org/issues/78929
+        $pluginPath = PathUtility::getAbsoluteWebPath(
+            ExtensionManagementUtility::extPath('rte_ckeditor', 'Resources/Public/JavaScript/Plugins/typo3link.js')
+        );
+        $externalPlugins = [
+            'typo3link' => [
+                'path' => $pluginPath,
+                'config' => [
+                    'routeUrl' => (string)$uriBuilder->buildUriFromRoute('rteckeditor_wizard_browse_links'),
+                    'additionalAttributes' => $additionalAttributes
+                ]
+            ]
+        ];
+
+        return $externalPlugins;
+    }
+
+    /**
      * @return LanguageService
      */
     protected function getLanguageService() : LanguageService
diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/Contrib/plugins/typo3link/plugin.js b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/Contrib/plugins/typo3link/plugin.js
deleted file mode 100644 (file)
index ae48c57..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-'use strict';
-
-(function () {
-
-       CKEDITOR.plugins.add('typo3link', {
-               elementBrowser: null,
-               init: function (editor) {
-                       var allowed = 'a[!href,title,class,target,rel]',
-                               required = 'a[href]';
-
-                       if (editor.config.elementbrowser.link.additionalAttributes && editor.config.elementbrowser.link.additionalAttributes.length) {
-                               allowed = allowed.replace( ']', ',' + editor.config.elementbrowser.link.additionalAttributes.join(',') + ']');
-                       }
-
-                       // Override link command
-                       editor.addCommand('link', {
-                               exec: openLinkBrowser,
-                               allowedContent: allowed,
-                               requiredContent: required
-                       });
-
-                       // Override doubleclick opening default link dialog
-                       editor.on('doubleclick', function (evt) {
-                               var element = CKEDITOR.plugins.link.getSelectedLink(editor) || evt.data.element;
-                               if (!element.isReadOnly() && element.is('a') && element.getAttribute('href')) {
-                                       evt.stop();
-                                       openLinkBrowser(editor, element);
-                               }
-                       }, null, null, 30);
-
-               }
-       });
-
-       /**
-        * Open link browser
-        *
-        * @param {Object} editor CKEditor object
-        * @param {Object} element Selected link element
-        */
-       function openLinkBrowser(editor, element) {
-               var additionalParameters = '';
-
-               if (!element) {
-                       element = CKEDITOR.plugins.link.getSelectedLink(editor);
-               }
-               if (element) {
-                       additionalParameters = '&curUrl[url]=' + encodeURIComponent(element.getAttribute('href'));
-                       var i = 0,
-                               attributeNames = ["target", "class", "title", "rel"];
-                       for (i = 0; i < attributeNames.length; ++i) {
-                               if (element.getAttribute(attributeNames[i])) {
-                                       additionalParameters += '&curUrl[' + attributeNames[i] + ']=';
-                                       additionalParameters += encodeURIComponent(element.getAttribute(attributeNames[i]));
-                               }
-                       }
-
-                       var additionalAttributes = editor.config.elementbrowser.link.additionalAttributes;
-                       for (i = additionalAttributes.length; --i >= 0;) {
-                               if (element.hasAttribute(additionalAttributes[i])) {
-                                       additionalParameters += '&curUrl[' + additionalAttributes[i] + ']=';
-                                       additionalParameters += encodeURIComponent(element.getAttribute(additionalAttributes[i]));
-                               }
-                       }
-               }
-
-               openElementBrowser(
-                       editor,
-                       editor.lang.link.toolbar,
-                       TYPO3.settings.Textarea.RTEPopupWindow.height - 20,
-                       makeUrlFromModulePath(
-                               editor,
-                               editor.config.elementbrowser.link.moduleUrl,
-                               additionalParameters
-                       ));
-       }
-
-       /**
-        * Make url from module path
-        *
-        * @param {Object} editor CKEditor object
-        * @param {String} modulePath Module path
-        * @param {String} parameters Additional parameters
-        *
-        * @return {String} The url
-        */
-       function makeUrlFromModulePath(editor, modulePath, parameters) {
-
-               // todo: check if we need `+ '&contentTypo3Language=' + this.editorConfiguration.typo3ContentLanguage `
-               return modulePath
-                       + (modulePath.indexOf("?") === -1 ? "?" : "&")
-                       + 'RTEtsConfigParams=' + editor.config.RTEtsConfigParams
-                       + '&editorId=' + editor.id
-                       + (parameters ? parameters : '');
-       }
-
-       /**
-        * Open a window with container iframe
-        *
-        * @param {Object} editor The CKEditor instance
-        * @param {String} title The window title (will be localized here)
-        * @param {Integer} height The height of the containing iframe
-        * @param {String} url The url to load ino the iframe
-        */
-       function openElementBrowser(editor, title, height, url) {
-               require([
-                       'jquery',
-                       'TYPO3/CMS/Backend/Modal',
-                       'TYPO3/CMS/Backend/Severity'
-                       ], function ($, Modal, Severity) {
-
-                       var $iframe = $('<iframe />', {
-                                       src: url,
-                                       'class': 'content-iframe',
-                                       style: 'border: 0; width: 100%; height: ' + height * 1 + 'px;'
-                               }),
-                               $content = $('<div />', {'class': 'rte-ckeditor-window', id: editor.id}).append($iframe);
-
-                       var elementBrowser = Modal.show(title, $content, Severity.notice);
-
-                       // TODO: add this to less/css (.rte-ckeditor-window .modal-body)
-                       //               further, make modal wider and maybe resize-able
-                       elementBrowser.find('.modal-body').css('padding', 0);
-
-               });
-       }
-
-})();
diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/Plugins/typo3link.js b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/Plugins/typo3link.js
new file mode 100644 (file)
index 0000000..eec31a4
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+'use strict';
+
+(function () {
+
+       CKEDITOR.plugins.add('typo3link', {
+               elementBrowser: null,
+               init: function (editor) {
+                       var allowed = 'a[!href,title,class,target,rel]',
+                               required = 'a[href]';
+
+                       if (editor.config.typo3link.additionalAttributes && editor.config.typo3link.additionalAttributes.length) {
+                               allowed = allowed.replace( ']', ',' + editor.config.typo3link.additionalAttributes.join(',') + ']');
+                       }
+
+                       // Override link command
+                       editor.addCommand('link', {
+                               exec: openLinkBrowser,
+                               allowedContent: allowed,
+                               requiredContent: required
+                       });
+
+                       // Override doubleclick opening default link dialog
+                       editor.on('doubleclick', function (evt) {
+                               var element = CKEDITOR.plugins.link.getSelectedLink(editor) || evt.data.element;
+                               if (!element.isReadOnly() && element.is('a') && element.getAttribute('href')) {
+                                       evt.stop();
+                                       openLinkBrowser(editor, element);
+                               }
+                       }, null, null, 30);
+
+               }
+       });
+
+       /**
+        * Open link browser
+        *
+        * @param {Object} editor CKEditor object
+        * @param {Object} element Selected link element
+        */
+       function openLinkBrowser(editor, element) {
+               var additionalParameters = '';
+
+               if (!element) {
+                       element = CKEDITOR.plugins.link.getSelectedLink(editor);
+               }
+               if (element) {
+                       additionalParameters = '&curUrl[url]=' + encodeURIComponent(element.getAttribute('href'));
+                       var i = 0,
+                               attributeNames = ["target", "class", "title", "rel"];
+                       for (i = 0; i < attributeNames.length; ++i) {
+                               if (element.getAttribute(attributeNames[i])) {
+                                       additionalParameters += '&curUrl[' + attributeNames[i] + ']=';
+                                       additionalParameters += encodeURIComponent(element.getAttribute(attributeNames[i]));
+                               }
+                       }
+
+                       var additionalAttributes = editor.config.typo3link.additionalAttributes;
+                       for (i = additionalAttributes.length; --i >= 0;) {
+                               if (element.hasAttribute(additionalAttributes[i])) {
+                                       additionalParameters += '&curUrl[' + additionalAttributes[i] + ']=';
+                                       additionalParameters += encodeURIComponent(element.getAttribute(additionalAttributes[i]));
+                               }
+                       }
+               }
+
+               openElementBrowser(
+                       editor,
+                       editor.lang.link.toolbar,
+                       TYPO3.settings.Textarea.RTEPopupWindow.height - 20,
+                       makeUrlFromModulePath(
+                               editor,
+                               editor.config.typo3link.routeUrl,
+                               additionalParameters
+                       ));
+       }
+
+       /**
+        * Make url from url
+        *
+        * @param {Object} editor CKEditor object
+        * @param {String} routeUrl URL
+        * @param {String} parameters Additional parameters
+        *
+        * @return {String} The url
+        */
+       function makeUrlFromModulePath(editor, routeUrl, parameters) {
+
+               return routeUrl
+                       + (routeUrl.indexOf('?') === -1 ? '?' : '&')
+                       + 'RTEtsConfigParams=' + editor.config.RTEtsConfigParams
+                       + '&contentsLanguage=' + editor.config.contentsLanguage
+                       + '&editorId=' + editor.id
+                       + (parameters ? parameters : '');
+       }
+
+       /**
+        * Open a window with container iframe
+        *
+        * @param {Object} editor The CKEditor instance
+        * @param {String} title The window title (will be localized here)
+        * @param {Integer} height The height of the containing iframe
+        * @param {String} url The url to load ino the iframe
+        */
+       function openElementBrowser(editor, title, height, url) {
+               require([
+                       'jquery',
+                       'TYPO3/CMS/Backend/Modal',
+                       'TYPO3/CMS/Backend/Severity'
+                       ], function ($, Modal, Severity) {
+
+                       var $iframe = $('<iframe />', {
+                                       src: url,
+                                       'class': 'content-iframe',
+                                       style: 'border: 0; width: 100%; height: ' + height * 1 + 'px;'
+                               }),
+                               $content = $('<div />', {'class': 'rte-ckeditor-window', id: editor.id}).append($iframe);
+
+                       var elementBrowser = Modal.show(title, $content, Severity.notice);
+
+                       // TODO: add this to less/css (.rte-ckeditor-window .modal-body)
+                       //               further, make modal wider and maybe resize-able
+                       elementBrowser.find('.modal-body').css('padding', 0);
+
+               });
+       }
+
+})();
index 857a58f..09cd584 100644 (file)
@@ -41,7 +41,6 @@ CKEDITOR.editorConfig = function( config ) {
        // Simplify the dialog windows.
        config.removeDialogTabs = 'image:advanced;link:advanced';
 
-       config.extraPlugins = 'typo3link';
 };
 
 CKEDITOR.stylesSet.add('default', [