diff --git a/Classes/EventListener/RteConfigEnhancer.php b/Classes/EventListener/RteConfigEnhancer.php new file mode 100644 index 0000000..79a13f9 --- /dev/null +++ b/Classes/EventListener/RteConfigEnhancer.php @@ -0,0 +1,32 @@ +getConfiguration(); + $configuration['syntax_code'] = [ + 'resource' => 'EXT:syntax/Resources/Public/CKEditor/Plugins/Code/plugin.js' + ]; + $event->setConfiguration($configuration); + } + + public function beforePrepareConfiguration(BeforePrepareConfigurationForEditorEvent $event): void + { + $configuration = $event->getConfiguration(); + $configuration['extraPlugins'][] = 'syntax_code'; + $event->setConfiguration($configuration); + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 0000000..8e25db8 --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,11 @@ +services: + BK2K\Syntax\EventListener\RteConfigEnhancer: + tags: + - name: event.listener + identifier: 'ext-syntax/rteConfigEnhancer' + method: 'beforeGetExternalPlugins' + event: TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforeGetExternalPluginsEvent + - name: event.listener + identifier: 'ext-syntax/rteConfigEnhancer' + method: 'beforePrepareConfiguration' + event: TYPO3\CMS\RteCKEditor\Form\Element\Event\BeforePrepareConfigurationForEditorEvent diff --git a/Resources/Public/CKEditor/Plugins/Code/dialogs/code.js b/Resources/Public/CKEditor/Plugins/Code/dialogs/code.js new file mode 100644 index 0000000..bd2de45 --- /dev/null +++ b/Resources/Public/CKEditor/Plugins/Code/dialogs/code.js @@ -0,0 +1,88 @@ +CKEDITOR.dialog.add('code', function () { + + var clientHeight = document.documentElement.clientHeight; + var size = CKEDITOR.document.getWindow().getViewPaneSize(); + var width = Math.min(size.width - 70, 800); + var height = size.height / 2; + + if (clientHeight < 650) { + height = clientHeight - 220; + } + + return { + title: 'Code', + minWidth: 200, + minHeight: 100, + contents: [ + { + id: 'info', + elements: [ + { + id: 'lang', + type: 'select', + label: 'Language', + items: [ + ['None', 'language-none'], + ['Apache Configuration', 'language-apacheconf'], + ['C-like', 'language-clike'], + ['CSS', 'language-css'], + ['Git', 'language-git'], + ['HTML', 'language-html'], + ['JavaScript', 'language-javascript'], + ['JSON', 'language-json'], + ['Markup ', 'language-markup'], + ['Less', 'language-less'], + ['Markdown', 'language-markdown'], + ['MathML', 'language-mathml'], + ['nginx', 'language-nginx'], + ['PHP', 'language-php'], + ['Sass', 'language-sass'], + ['Scss', 'language-scss'], + ['SVG', 'language-svg'], + ['TypoScript', 'language-typoscript'], + ['XML', 'language-xml'], + ['YAML', 'language-yaml'], + ], + setup: function (widget) { + this.setValue(widget.data.lang); + }, + commit: function (widget) { + widget.setData('lang', this.getValue()); + } + }, + { + id: 'linenumbers', + type: 'checkbox', + label: 'Linenumbers', + default: true, + setup: function (widget) { + this.setValue(widget.data.linenumbers); + }, + commit: function (widget) { + widget.setData('linenumbers', this.getValue()); + } + }, + { + id: 'code', + type: 'textarea', + label: 'Code', + setup: function (widget) { + this.setValue(widget.data.code); + }, + commit: function (widget) { + widget.setData('code', this.getValue()); + }, + required: true, + validate: CKEDITOR.dialog.validate.notEmpty('Code cannot be empty.'), + inputStyle: 'cursor:auto;' + + 'tab-size:4;' + + 'width:' + width + 'px;' + + 'height:' + height + 'px;' + + 'padding: 1em;' + + 'text-align:left;', + } + ] + } + ] + }; +}); diff --git a/Resources/Public/CKEditor/Plugins/Code/icons/code.png b/Resources/Public/CKEditor/Plugins/Code/icons/code.png new file mode 100644 index 0000000..f5caa14 Binary files /dev/null and b/Resources/Public/CKEditor/Plugins/Code/icons/code.png differ diff --git a/Resources/Public/CKEditor/Plugins/Code/icons/hidpi/code.png b/Resources/Public/CKEditor/Plugins/Code/icons/hidpi/code.png new file mode 100644 index 0000000..245c5ad Binary files /dev/null and b/Resources/Public/CKEditor/Plugins/Code/icons/hidpi/code.png differ diff --git a/Resources/Public/CKEditor/Plugins/Code/lang/de.js b/Resources/Public/CKEditor/Plugins/Code/lang/de.js new file mode 100644 index 0000000..345f73e --- /dev/null +++ b/Resources/Public/CKEditor/Plugins/Code/lang/de.js @@ -0,0 +1,3 @@ +CKEDITOR.plugins.setLang('syntax_code', 'de', { + toolbar: 'Code einfügen' +}); diff --git a/Resources/Public/CKEditor/Plugins/Code/lang/en.js b/Resources/Public/CKEditor/Plugins/Code/lang/en.js new file mode 100644 index 0000000..ff6b6ed --- /dev/null +++ b/Resources/Public/CKEditor/Plugins/Code/lang/en.js @@ -0,0 +1,3 @@ +CKEDITOR.plugins.setLang('syntax_code', 'en', { + toolbar: 'Insert Code' +}); diff --git a/Resources/Public/CKEditor/Plugins/Code/plugin.js b/Resources/Public/CKEditor/Plugins/Code/plugin.js new file mode 100644 index 0000000..7825c62 --- /dev/null +++ b/Resources/Public/CKEditor/Plugins/Code/plugin.js @@ -0,0 +1,72 @@ +'use strict'; + +(function () { + + CKEDITOR.plugins.add('syntax_code', { + lang: 'en,de', + requires: 'widget,dialog', + icons: 'code', + hidpi: true, + onLoad: function () { + CKEDITOR.dialog.add('code', this.path + 'dialogs/code.js'); + }, + init: function (editor) { + editor.addContentsCss(this.path + 'styles/code.css'); + editor.widgets.add('code', { + button: 'Insert Code Block', + template: '
', + parts: { + pre: 'pre', + code: 'code' + }, + allowedContent: 'pre(line-numbers); code(language-*)', + requiredContent: 'pre', + styleableElements: 'pre', + dialog: 'code', + mask: true, + upcast: function (element) { + if (element.name != 'pre') { + return; + } + var children = element.children.filter( + child => child.type != CKEDITOR.NODE_TEXT + ); + if (children.length != 1 || children[0].name != 'code') { + return; + } + var code = children[0]; + if (code.children.length != 1 || code.children[0].type != CKEDITOR.NODE_TEXT) { + return; + } + return element; + }, + downcast: function (element) { + var code = element.getFirst('code'); + code.children.length = 0; + code.add(new CKEDITOR.htmlParser.text(CKEDITOR.tools.htmlEncode(this.data.code))); + return element; + }, + init: function () { + this.data.code = CKEDITOR.tools.htmlDecode(this.parts.code.getHtml()); + this.data.lang = this.parts.code.getAttribute('class') ?? 'language-none'; + this.data.linenumbers = this.parts.pre.hasClass('line-numbers'); + }, + data: function () { + if (this.data.lang) { + this.parts.code.removeAttribute(['class']) + this.parts.code.addClass(this.data.lang); + } + if (this.data.linenumbers) { + this.parts.pre.addClass('line-numbers'); + } else { + this.parts.pre.removeClass('line-numbers'); + } + if (this.data.code) { + this.parts.code.setHtml(CKEDITOR.tools.htmlEncode(this.data.code)); + } + } + }); + } + }); + +})(); diff --git a/Resources/Public/CKEditor/Plugins/Code/styles/code.css b/Resources/Public/CKEditor/Plugins/Code/styles/code.css new file mode 100644 index 0000000..3b363d3 --- /dev/null +++ b/Resources/Public/CKEditor/Plugins/Code/styles/code.css @@ -0,0 +1,6 @@ +.cke_widget_code pre { + padding: 1rem; + background-color: #f2f2f2; + border: 1px solid #cacaca; + border-radius: 3px; +} diff --git a/composer.json b/composer.json index 363d221..1a92bb2 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ "php": ">=7.0.0", "typo3/cms-backend": "^8.7 || ^9.5 || ^10.0 || 10.*@dev", "typo3/cms-core": "^8.7 || ^9.5 || ^10.0 || 10.*@dev", - "typo3/cms-frontend": "^8.7 || ^9.5 || ^10.0 || 10.*@dev" + "typo3/cms-frontend": "^8.7 || ^9.5 || ^10.0 || 10.*@dev", + "typo3/cms-rte-ckeditor": "^8.7 || ^9.5 || ^10.0 || 10.*@dev" }, "require-dev": { "friendsofphp/php-cs-fixer": "^2.3.1", diff --git a/ext_emconf.php b/ext_emconf.php index 7df7fb7..47806ad 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -13,8 +13,8 @@ 'category' => 'templates', 'constraints' => [ 'depends' => [ - 'typo3' => '8.7.0-10.0.99', - 'rte_ckeditor' => '8.7.0-10.0.99' + 'typo3' => '8.7.0-10.4.99', + 'rte_ckeditor' => '8.7.0-10.4.99' ] ], 'autoload' => [