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' => [