Skip to content
Snippets Groups Projects
Commit 4baad765 authored by Benjamin Kott's avatar Benjamin Kott Committed by Benni Mack
Browse files

[BUGFIX] Restore visibility for soft hyphens and non-breaking spaces

Non-breaking spaces and soft hyphens are now visible in
the editor to help the editor to identify them visually.

Keyboard shortcuts are now working for non-breaking spaces
and soft hyphens and use more common defaults:
- ctrl+shift+space for non-breaking space
- ctrl+shift+dash for soft hyphen

Please note that MacOS use different shortcuts:
- alt+shift+space for non-breaking space
- alt+shift+dash for soft hyphen

The SoftHyphen plugin for CKEditor is now deprecated and
replaced with a new Whitespace Plugin that handles
non-breaking spaces and soft hyphens. Loading the
SoftHyphen will trigger a console warning.

Resolves: #99454
Releases: main
Change-Id: I2a1c5edfd7e95f85c060746795231fda56b56f8c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/77255


Tested-by: default avatarcore-ci <typo3@b13.com>
Tested-by: default avatarBenni Mack <benni@typo3.org>
Reviewed-by: default avatarBenni Mack <benni@typo3.org>
Reviewed-by: default avatarFrank Nägler <frank.naegler@typo3.com>
Tested-by: default avatarFrank Nägler <frank.naegler@typo3.com>
parent 435954a4
Branches
Tags
No related merge requests found
Showing
with 214 additions and 31 deletions
import {UI, Core} from '@typo3/ckeditor5-bundle';
import type {EditorWithUI} from '@ckeditor/ckeditor5-core/src/editor/editorwithui';
import { Core } from '@typo3/ckeditor5-bundle';
import Whitespace from '@typo3/rte-ckeditor/plugin/whitespace';
export default class SoftHyphen extends Core.Plugin {
static readonly pluginName = 'SoftHyphen';
static readonly requires = [Whitespace];
public init(): void {
const editor = this.editor as EditorWithUI;
editor.ui.componentFactory.add(SoftHyphen.pluginName, locale => {
const button = new UI.ButtonView(locale);
button.label = 'Soft-Hyphen';
// @todo introduce SVG loader
button.icon = '<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><defs><style>.cls-1{fill:none;}.cls-2{fill:#464646;}.cls-3{fill:url(#Unbenannter_Verlauf_19);}</style><linearGradient id="Unbenannter_Verlauf_19" x1="3" y1="8" x2="13" y2="8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset="0.1" stop-color="#464646"/><stop offset="0.9" stop-color="#464646"/><stop offset="1" stop-opacity="0"/></linearGradient></defs><title>typo3_softhyphen</title><rect class="cls-1" width="16" height="16"/><path class="cls-2" d="M1,8a8.51,8.51,0,0,1,.4-2.7A6.12,6.12,0,0,1,2.79,3H4a9.55,9.55,0,0,0-.78,1.13A7,7,0,0,0,2.67,5.3a5.91,5.91,0,0,0-.32,1.27,9.35,9.35,0,0,0,0,2.86,5.91,5.91,0,0,0,.32,1.27,7,7,0,0,0,.55,1.17A9.55,9.55,0,0,0,4,13H2.79A6.12,6.12,0,0,1,1.4,10.7,8.51,8.51,0,0,1,1,8Z"/><path class="cls-2" d="M15,8a8.51,8.51,0,0,1-.4,2.7A6.12,6.12,0,0,1,13.21,13H12a9.55,9.55,0,0,0,.78-1.13,7,7,0,0,0,.55-1.17,5.91,5.91,0,0,0,.32-1.27,9.35,9.35,0,0,0,0-2.86,5.91,5.91,0,0,0-.32-1.27,7,7,0,0,0-.55-1.17A9.55,9.55,0,0,0,12,3h1.21A6.12,6.12,0,0,1,14.6,5.3,8.51,8.51,0,0,1,15,8Z"/><rect class="cls-3" x="3" y="7" width="10" height="2"/></svg>';
button.keystroke = 'Ctrl!+-';
button.on( 'execute', () => this.addSoftHyphen());
return button;
});
}
private addSoftHyphen(): void {
const editor = this.editor as EditorWithUI;
editor.model.change( writer => {
editor.model.insertContent(
writer.createText('\u00AD')
);
});
console.warn('The TYPO3 CKEditor5 SoftHyphen plugin is deprecated and will be removed with v13. Please use the Whitespace plugin instead.');
}
}
import { Core, UI, Utils } from '@typo3/ckeditor5-bundle';
import type { EditorWithUI } from '@ckeditor/ckeditor5-core/src/editor/editorwithui';
/**
* CKEditor5 Whitespace Plugin
*
* Add support for non breaking spaces
* - Make non breaking spaces visible
* - Shortcut for adding non breaking space:
* - alt+shift+space on MacOS
* - ctrl+shift+space on all other Systems
*
* Add support for soft hyphen
* - Make soft hyphens visible
* - Register button for editor ui: softhyphen
* - Shortcut for adding non breaking space:
* - alt+shift+dash on MacOS
* - ctrl+shift+dash on all other Systems
*/
export default class Whitespace extends Core.Plugin {
static readonly pluginName = 'Whitespace';
public init(): void {
const editor = this.editor as EditorWithUI;
editor.ui.componentFactory.add('softhyphen', locale => {
const button = new UI.ButtonView(locale);
button.label = 'Soft-Hyphen';
button.icon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xml:space="preserve"><path d="M4.25 3C3.082 4.683 2 6.917 2 10.026 2 13.083 3.114 15.282 4.25 17H3c-1.008-1.425-2-3.624-2-6.974.016-3.384.992-5.583 2-7.026h1.25zM17 3c1.008 1.443 1.984 3.642 2 7.026 0 3.35-.992 5.549-2 6.974h-1.25c1.136-1.718 2.25-3.917 2.25-6.974 0-3.11-1.082-5.343-2.25-7.026H17zM6 9h8v2H6z"/></svg>';
button.on('execute', () => this.insertSoftHyphen());
return button;
});
// CKEditor should map Ctrl to Cmd on MacOs, but for
// some reason the shortcut is blocked and cannot be
// overwritten.
//
// For this reason we are using "Alt" as controlKey on MacOS.
// All other System use "Ctrl" as controlKey.
const controlKey = Utils.env.isMac ? 'Alt' : 'Ctrl';
editor.keystrokes.set([controlKey, 'Shift', 189], (data, cancel) => {
this.insertSoftHyphen();
cancel();
});
editor.keystrokes.set([controlKey, 'Shift', 'Space'], (data, cancel) => {
this.insertNonBreakingSpace();
cancel();
});
editor.conversion.for('editingDowncast').add(downcastDispatcher => {
downcastDispatcher.on('insert:$text', (evt, data, conversionApi) => {
if (!conversionApi.consumable.consume(data.item, evt.name)) {
return;
}
const viewWriter = conversionApi.writer;
const chunks = data.item.data
.split(/([\u00AD,\u00A0])/)
.filter((value: String) => value !== '');
let currentPosition = data.range.start;
chunks.forEach((chunk) => {
viewWriter.insert(
conversionApi.mapper.toViewPosition(currentPosition),
viewWriter.createText(chunk)
);
if (chunk === '\u00AD' || chunk === '\u00A0') {
const className = chunk === '\u00AD' ? 'softhyphen' : 'nbsp';
const wrapper = viewWriter.createAttributeElement('span', { class: 'ck ck-' + className });
const wrapperRange = viewWriter.createRange(
conversionApi.mapper.toViewPosition(currentPosition),
conversionApi.mapper.toViewPosition(currentPosition.getShiftedBy(chunk.length))
);
viewWriter.wrap(wrapperRange, wrapper);
}
currentPosition = currentPosition.getShiftedBy(chunk.length);
});
}, { priority: 'high' });
});
}
private insertNonBreakingSpace(): void {
const editor = this.editor as EditorWithUI;
editor.model.change(writer => {
const insertPosition = editor.model.document.selection.getFirstPosition();
writer.insertText('\u00A0', insertPosition);
});
}
private insertSoftHyphen(): void {
const editor = this.editor as EditorWithUI;
editor.model.change(writer => {
const insertPosition = editor.model.document.selection.getFirstPosition();
writer.insertText('\u00AD', insertPosition);
});
}
}
......@@ -23,7 +23,7 @@ namespace TYPO3\CMS\Core\Configuration;
class CKEditor5Migrator
{
private const TOOLBAR_GROUPS_MAP = [
'basicstyles' => ['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript'],
'basicstyles' => ['bold', 'italic', 'underline', 'strikethrough', 'subscript', 'superscript', 'softhyphen'],
'format' => ['heading'],
'styles' => ['style'],
'list' => ['numberedList', 'bulletedList'],
......@@ -58,6 +58,7 @@ class CKEditor5Migrator
'Format' => ['heading'],
'BasicStyle' => ['heading'],
'Table' => ['insertTable'],
'SoftHyphen' => ['softhyphen'],
'specialcharacters' => ['specialCharacters'],
'specialchar' => ['specialCharacters'],
];
......
.. include:: /Includes.rst.txt
.. _deprecation-99454-1672842347:
=================================================================================
Deprecation: #99454 - Restore visibility for soft hyphens and non-breaking spaces
=================================================================================
See :issue:`99454`
Description
===========
Non-breaking spaces and soft hyphens are now visible in
the editor to help the editor to identify them visually.
Keyboard shortcuts are now working for non-breaking spaces
and soft hyphens and use more common defaults:
- ctrl+shift+space for non-breaking space
- ctrl+shift+dash for soft hyphen
The SoftHyphen plugin for CKEditor is now deprecated and
replaced with a new Whitespace Plugin that handles
non-breaking spaces and soft hyphens. Loading the
SoftHyphen will trigger a console warning.
Impact
======
Including the SoftHyphen will trigger a deprecation warning.
Affected installations
======================
All installations that include the Plugin manually.
Migration
=========
Replace the module to resolve the deprecation.
Before
~~~~~~
.. code-block:: yaml
editor:
config:
importModules:
- '@typo3/rte-ckeditor/plugin/soft-hyphen.js'
After
~~~~~
.. code-block:: yaml
editor:
config:
importModules:
- '@typo3/rte-ckeditor/plugin/whitespace.js'
.. index:: Backend, JavaScript, RTE, NotScanned, ext:rte_ckeditor
......@@ -18,6 +18,7 @@ editor:
- italic
- subscript
- superscript
- softhyphen
- '|'
- bulletedList
- numberedList
......@@ -26,7 +27,6 @@ editor:
- '|'
- findAndReplace
- link
- SoftHyphen
- '|'
- removeFormat
- undo
......
......@@ -7,8 +7,8 @@ editor:
# load modules for plugins when CKEditor is initialized
# see CKEditor plugin API for details
importModules:
# softhyphen plugin for adding ctrl+dash support to insert a conditional word break
- '@typo3/rte-ckeditor/plugin/soft-hyphen.js'
# Plugin for whitespace control like soft hypens and non breaking spaces
- '@typo3/rte-ckeditor/plugin/whitespace.js'
- '@typo3/rte-ckeditor/plugin/typo3-link.js'
# Configure global wordCount plugin defaults
......
......@@ -32,6 +32,7 @@ editor:
toolbar:
items:
- clipboard
- removeFormat
- undo
- redo
# grouping separator
......@@ -40,7 +41,6 @@ editor:
- selectAll
- '|'
- link
- SoftHyphen
- insertTable
- tableColumn
- tableRow
......@@ -56,14 +56,14 @@ editor:
- strikethrough
- subscript
- superscript
- alignment
- removeFormat
- softhyphen
- '|'
- bulletedList
- numberedList
- blockQuote
- indent
- outdent
- alignment
- '|'
- specialCharacters
- '-'
......
......@@ -12,3 +12,25 @@
.ck.ck-word-count {
margin-top: .5rem;
}
.ck.ck-softhyphen {
border-radius: .15em;
color: #0078e6;
background-color: rgba(0,120,230,.1);
}
.ck.ck-softhyphen:before {
content: '–';
margin-left: .1em;
margin-right: .1em;
}
.ck.ck-nbsp {
border-radius: .15em;
color: #c83c3c;
background-color: rgba(200,60,60,.1);
}
.ck.ck-nbsp:before {
content: ' ';
}
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
import{UI,Core}from"@typo3/ckeditor5-bundle.js";export default class SoftHyphen extends Core.Plugin{init(){this.editor.ui.componentFactory.add(SoftHyphen.pluginName,(t=>{const e=new UI.ButtonView(t);return e.label="Soft-Hyphen",e.icon='<svg id="Ebene_1" data-name="Ebene 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16"><defs><style>.cls-1{fill:none;}.cls-2{fill:#464646;}.cls-3{fill:url(#Unbenannter_Verlauf_19);}</style><linearGradient id="Unbenannter_Verlauf_19" x1="3" y1="8" x2="13" y2="8" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset="0.1" stop-color="#464646"/><stop offset="0.9" stop-color="#464646"/><stop offset="1" stop-opacity="0"/></linearGradient></defs><title>typo3_softhyphen</title><rect class="cls-1" width="16" height="16"/><path class="cls-2" d="M1,8a8.51,8.51,0,0,1,.4-2.7A6.12,6.12,0,0,1,2.79,3H4a9.55,9.55,0,0,0-.78,1.13A7,7,0,0,0,2.67,5.3a5.91,5.91,0,0,0-.32,1.27,9.35,9.35,0,0,0,0,2.86,5.91,5.91,0,0,0,.32,1.27,7,7,0,0,0,.55,1.17A9.55,9.55,0,0,0,4,13H2.79A6.12,6.12,0,0,1,1.4,10.7,8.51,8.51,0,0,1,1,8Z"/><path class="cls-2" d="M15,8a8.51,8.51,0,0,1-.4,2.7A6.12,6.12,0,0,1,13.21,13H12a9.55,9.55,0,0,0,.78-1.13,7,7,0,0,0,.55-1.17,5.91,5.91,0,0,0,.32-1.27,9.35,9.35,0,0,0,0-2.86,5.91,5.91,0,0,0-.32-1.27,7,7,0,0,0-.55-1.17A9.55,9.55,0,0,0,12,3h1.21A6.12,6.12,0,0,1,14.6,5.3,8.51,8.51,0,0,1,15,8Z"/><rect class="cls-3" x="3" y="7" width="10" height="2"/></svg>',e.keystroke="Ctrl!+-",e.on("execute",(()=>this.addSoftHyphen())),e}))}addSoftHyphen(){const t=this.editor;t.model.change((e=>{t.model.insertContent(e.createText("­"))}))}}SoftHyphen.pluginName="SoftHyphen";
\ No newline at end of file
import{Core}from"@typo3/ckeditor5-bundle.js";import Whitespace from"@typo3/rte-ckeditor/plugin/whitespace.js";export default class SoftHyphen extends Core.Plugin{init(){console.warn("The TYPO3 CKEditor5 SoftHyphen plugin is deprecated and will be removed with v13. Please use the Whitespace plugin instead.")}}SoftHyphen.pluginName="SoftHyphen",SoftHyphen.requires=[Whitespace];
\ No newline at end of file
/*
* 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!
*/
import{Core,UI,Utils}from"@typo3/ckeditor5-bundle.js";export default class Whitespace extends Core.Plugin{init(){const e=this.editor;e.ui.componentFactory.add("softhyphen",(e=>{const t=new UI.ButtonView(e);return t.label="Soft-Hyphen",t.icon='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" xml:space="preserve"><path d="M4.25 3C3.082 4.683 2 6.917 2 10.026 2 13.083 3.114 15.282 4.25 17H3c-1.008-1.425-2-3.624-2-6.974.016-3.384.992-5.583 2-7.026h1.25zM17 3c1.008 1.443 1.984 3.642 2 7.026 0 3.35-.992 5.549-2 6.974h-1.25c1.136-1.718 2.25-3.917 2.25-6.974 0-3.11-1.082-5.343-2.25-7.026H17zM6 9h8v2H6z"/></svg>',t.on("execute",(()=>this.insertSoftHyphen())),t}));const t=Utils.env.isMac?"Alt":"Ctrl";e.keystrokes.set([t,"Shift",189],((e,t)=>{this.insertSoftHyphen(),t()})),e.keystrokes.set([t,"Shift","Space"],((e,t)=>{this.insertNonBreakingSpace(),t()})),e.conversion.for("editingDowncast").add((e=>{e.on("insert:$text",((e,t,i)=>{if(!i.consumable.consume(t.item,e.name))return;const n=i.writer,o=t.item.data.split(/([\u00AD,\u00A0])/).filter((e=>""!==e));let s=t.range.start;o.forEach((e=>{if(n.insert(i.mapper.toViewPosition(s),n.createText(e)),"­"===e||" "===e){const t="­"===e?"softhyphen":"nbsp",o=n.createAttributeElement("span",{class:"ck ck-"+t}),r=n.createRange(i.mapper.toViewPosition(s),i.mapper.toViewPosition(s.getShiftedBy(e.length)));n.wrap(r,o)}s=s.getShiftedBy(e.length)}))}),{priority:"high"})}))}insertNonBreakingSpace(){const e=this.editor;e.model.change((t=>{const i=e.model.document.selection.getFirstPosition();t.insertText(" ",i)}))}insertSoftHyphen(){const e=this.editor;e.model.change((t=>{const i=e.model.document.selection.getFirstPosition();t.insertText("­",i)}))}}Whitespace.pluginName="Whitespace";
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment