From c542acb7ff1d0112022e71cca9f3fc87d61d8764 Mon Sep 17 00:00:00 2001 From: Benjamin-K Date: Tue, 23 Feb 2021 13:36:55 +0100 Subject: [PATCH] FEATURE: Add keyboard shortcut option (#37) --- Configuration/Settings.yaml | 9 ++ README.md | 28 +++--- .../HyphensEditor/src/manifest.config.js | 4 +- .../Scripts/HyphensEditor/src/manifest.js | 5 +- .../HyphensEditor/src/plugins/hyphens.js | 93 ++++++++++--------- 5 files changed, 79 insertions(+), 60 deletions(-) diff --git a/Configuration/Settings.yaml b/Configuration/Settings.yaml index 4728bf8..2a34b7a 100644 --- a/Configuration/Settings.yaml +++ b/Configuration/Settings.yaml @@ -9,6 +9,15 @@ Neos: Shel.Neos:HyphensEditor: resource: resource://Shel.Neos.Hyphens/Public/HyphensEditor/Plugin.js + frontendConfiguration: + 'Shel.Neos:HyphensEditor': + # `shortcut` can be used to create a keyboard shortcut to insert soft hyphen + # Use any falsy value like `null` or `false` to disable it + shortcut: + - 'Ctrl' + - 'Shift' + - 189 # This is the minus sign + fusion: autoInclude: Shel.Neos.Hyphens: true diff --git a/README.md b/README.md index d0b0a1d..6121be0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Hyphens CKEditor5 plugin for Neos CMS +# Hyphens CKEditor5 plugin for Neos CMS [![Latest Stable Version](https://poser.pugx.org/shel/neos-hyphens/v/stable)](https://packagist.org/packages/shel/neos-hyphens) [![Total Downloads](https://poser.pugx.org/shel/neos-hyphens/downloads)](https://packagist.org/packages/shel/neos-hyphens) @@ -8,20 +8,20 @@ This package provides a button to insert soft hyphens for the inline editor in Neos CMS. -Many browser support some kind of hyphenation via CSS but it doesnt work reliably on all systems +Many browser support some kind of hyphenation via CSS but it doesnt work reliably on all systems and not with all languages. See the [CanIuse](https://caniuse.com/#feat=css-hyphens) table for details. -Therefore this package provides a manual way to insert them. You should be careful with using the +Therefore this package provides a manual way to insert them. You should be careful with using the CSS based hyphenation in combination with the manual hyphens as the result can be unexpected. It's compatible with Neos CMS 3.3 and 4.x with the Neos.Ui 2+. -## Example +## Example In the backend this plugin will add the option to add soft hyphens. They will look like this while editing: -![Visible hyphens while editing](Documentation/neos-backend-hyphens.jpg) - +![Visible hyphens while editing](Documentation/neos-backend-hyphens.jpg) + And in the frontend will convert this: ![Unwanted hyphenation without soft hyphens](Documentation/neos-frontend-before.jpg) @@ -32,8 +32,8 @@ Into this: And in action: -![Expected hyphenation](Documentation/example.gif) - +![Expected hyphenation](Documentation/example.gif) + ## Advantages * Your editors gain control over word breaks. @@ -50,7 +50,7 @@ See [enhancement issue list](https://github.com/Sebobo/Shel.Neos.Hyphens/issues? Run this in your site package composer require --no-update shel/neos-hyphens - + Then run `composer update` in your project directory. ## How to use @@ -64,7 +64,9 @@ Enable it for a node with editable text like this: inline: editorOptions: hyphens: true - + +This will add a new button to insert a soft hyphen. As an alternative, you can use the shortcut `Ctrl + Shift + -` to add a new soft hyphen. To change the keys of the shortcut, have a look at the [Settings.yaml](Configuration/Settings.yaml#L12) file. + ## Customization ### Hyphen styling in the backend @@ -73,13 +75,13 @@ You can provide your own styling by referencing your own stylesheet. See the file `Override.Page.fusion` on how the default styling is included. You can either override the configuration from your own package and just use your stylesheet -or you can add yours and use both. +or you can add yours and use both. ## Contributions -Contributions are very welcome! +Contributions are very welcome! -Please create detailed issues and PRs. +Please create detailed issues and PRs. **If you use this package and want to support or speed up it's development, [get in touch with me](mailto:hyphens@helzle.it).** diff --git a/Resources/Private/Scripts/HyphensEditor/src/manifest.config.js b/Resources/Private/Scripts/HyphensEditor/src/manifest.config.js index 329da07..ec52264 100644 --- a/Resources/Private/Scripts/HyphensEditor/src/manifest.config.js +++ b/Resources/Private/Scripts/HyphensEditor/src/manifest.config.js @@ -10,10 +10,10 @@ const addPlugin = (Plugin, isEnabled) => (ckEditorConfiguration, options) => { return ckEditorConfiguration; }; -export default ckEditorRegistry => { +export default (ckEditorRegistry, editorConfig) => { const config = ckEditorRegistry.get('config'); - config.set('hyphens', addPlugin(Hyphens, $get('hyphens'))); + config.set('hyphens', addPlugin(Hyphens(editorConfig), $get('hyphens'))); return config; }; diff --git a/Resources/Private/Scripts/HyphensEditor/src/manifest.js b/Resources/Private/Scripts/HyphensEditor/src/manifest.js index 4e0d9f7..a4bcf6c 100644 --- a/Resources/Private/Scripts/HyphensEditor/src/manifest.js +++ b/Resources/Private/Scripts/HyphensEditor/src/manifest.js @@ -2,9 +2,10 @@ import manifest from '@neos-project/neos-ui-extensibility'; import initializeRichtextToolbarRegistry from './manifest.richtextToolbar'; import initializeConfigRegistry from './manifest.config'; -manifest('Shel.Neos:HyphenEditor', {}, globalRegistry => { +manifest('Shel.Neos:HyphenEditor', {}, (globalRegistry, {frontendConfiguration}) => { const ckEditorRegistry = globalRegistry.get('ckEditor5'); + const editorConfig = frontendConfiguration['Shel.Neos:HyphensEditor']; initializeRichtextToolbarRegistry(ckEditorRegistry); - initializeConfigRegistry(ckEditorRegistry); + initializeConfigRegistry(ckEditorRegistry, editorConfig); }); diff --git a/Resources/Private/Scripts/HyphensEditor/src/plugins/hyphens.js b/Resources/Private/Scripts/HyphensEditor/src/plugins/hyphens.js index 2959a4c..03a33a5 100644 --- a/Resources/Private/Scripts/HyphensEditor/src/plugins/hyphens.js +++ b/Resources/Private/Scripts/HyphensEditor/src/plugins/hyphens.js @@ -1,63 +1,70 @@ import {Plugin, ViewRange} from 'ckeditor5-exports'; import ShyCommand from '../commands/shy'; -import styles from './hyphens.vanilla-css'; +import './hyphens.vanilla-css'; const softHyphenCharacter = '\u00AD'; -export default class Hyphens extends Plugin { - static get pluginName() { - return 'Hyphens'; - } +function HyphensFactory(config) { + return class Hyphens extends Plugin { + static get pluginName() { + return 'Hyphens'; + } - init() { - const {editor} = this; + init() { + const {editor} = this; - editor.commands.add('insertShyEntity', new ShyCommand(this.editor)); + editor.commands.add('insertShyEntity', new ShyCommand(this.editor)); + if (config.shortcut) { + editor.keystrokes.set(config.shortcut, 'insertShyEntity'); + } - editor.conversion.for('editingDowncast').add(dispatcher => { - dispatcher.on('insert:$text', (evt, data, conversionApi) => { - // Here should be an `if` that would check whether the feature's command is enabled. - if (!conversionApi.consumable.consume(data.item, 'insert')) { - return; - } + editor.conversion.for('editingDowncast').add(dispatcher => { + dispatcher.on('insert:$text', (evt, data, conversionApi) => { + // Here should be an `if` that would check whether the feature's command is enabled. + if (!conversionApi.consumable.consume(data.item, 'insert')) { + return; + } - const viewWriter = conversionApi.writer; + const viewWriter = conversionApi.writer; - let modelPosition = data.range.start; - let viewPosition = conversionApi.mapper.toViewPosition(modelPosition); + let modelPosition = data.range.start; + let viewPosition = conversionApi.mapper.toViewPosition(modelPosition); - const dataChunks = data.item.data.split(softHyphenCharacter); - for (let i = 0; i < dataChunks.length; i++) { - const chunk = dataChunks[i]; + const dataChunks = data.item.data.split(softHyphenCharacter); + for (let i = 0; i < dataChunks.length; i++) { + const chunk = dataChunks[i]; - if (chunk !== '') { - viewWriter.insert(viewPosition, viewWriter.createText(chunk)); + if (chunk !== '') { + viewWriter.insert(viewPosition, viewWriter.createText(chunk)); - // Need to recalculate `viewPosition` after every inserted item. - modelPosition = modelPosition.getShiftedBy(chunk.length); - viewPosition = conversionApi.mapper.toViewPosition(modelPosition); - } + // Need to recalculate `viewPosition` after every inserted item. + modelPosition = modelPosition.getShiftedBy(chunk.length); + viewPosition = conversionApi.mapper.toViewPosition(modelPosition); + } - // Do not insert anything after the last chunk - if (i === dataChunks.length - 1) { - break; - } + // Do not insert anything after the last chunk + if (i === dataChunks.length - 1) { + break; + } - // Insert utf8 dash character as representation - // We will wrap in in a span in following lines. - viewWriter.insert(viewPosition, viewWriter.createText(softHyphenCharacter)); + // Insert utf8 dash character as representation + // We will wrap in in a span in following lines. + viewWriter.insert(viewPosition, viewWriter.createText(softHyphenCharacter)); - const viewSpaceSpan = viewWriter.createAttributeElement('span', {class: 'shy'}); - const modelWrapRange = new ViewRange(modelPosition, modelPosition.getShiftedBy(1)); - const viewWrapRange = conversionApi.mapper.toViewRange(modelWrapRange); + const viewSpaceSpan = viewWriter.createAttributeElement('span', {class: 'shy'}); + const modelWrapRange = new ViewRange(modelPosition, modelPosition.getShiftedBy(1)); + const viewWrapRange = conversionApi.mapper.toViewRange(modelWrapRange); - viewWriter.wrap(viewWrapRange, viewSpaceSpan); + viewWriter.wrap(viewWrapRange, viewSpaceSpan); - // Need to recalculate `viewPosition` after every inserted item. - modelPosition = modelPosition.getShiftedBy(1); - viewPosition = conversionApi.mapper.toViewPosition(modelPosition); - } - }, {priority: 'high'}); - }); + // Need to recalculate `viewPosition` after every inserted item. + modelPosition = modelPosition.getShiftedBy(1); + viewPosition = conversionApi.mapper.toViewPosition(modelPosition); + } + }, {priority: 'high'}); + }); + } } } + +export default HyphensFactory;