From 4baad7650fa4c44dbf4c2c0fcc6c18bf717775c6 Mon Sep 17 00:00:00 2001
From: Benjamin Kott <benjamin.kott@outlook.com>
Date: Wed, 4 Jan 2023 15:22:48 +0100
Subject: [PATCH] [BUGFIX] Restore visibility for soft hyphens and non-breaking
 spaces
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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: core-ci <typo3@b13.com>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Frank Nägler <frank.naegler@typo3.com>
Tested-by: Frank Nägler <frank.naegler@typo3.com>
---
 .../rte_ckeditor/plugin/soft-hyphen.ts        |  27 +----
 .../rte_ckeditor/plugin/whitespace.ts         | 102 ++++++++++++++++++
 .../Configuration/CKEditor5Migrator.php       |   3 +-
 ...lityForSoftHyphensAndNonBreakingSpaces.rst |  64 +++++++++++
 .../Configuration/RTE/Default.yaml            |   2 +-
 .../Configuration/RTE/Editor/Plugins.yaml     |   4 +-
 .../rte_ckeditor/Configuration/RTE/Full.yaml  |   6 +-
 .../Resources/Public/Css/editor.css           |  22 ++++
 .../Public/JavaScript/plugin/soft-hyphen.js   |   2 +-
 .../Public/JavaScript/plugin/whitespace.js    |  13 +++
 10 files changed, 214 insertions(+), 31 deletions(-)
 create mode 100644 Build/Sources/TypeScript/rte_ckeditor/plugin/whitespace.ts
 create mode 100644 typo3/sysext/core/Documentation/Changelog/12.2/Deprecation-99454-RestoreVisibilityForSoftHyphensAndNonBreakingSpaces.rst
 create mode 100644 typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/whitespace.js

diff --git a/Build/Sources/TypeScript/rte_ckeditor/plugin/soft-hyphen.ts b/Build/Sources/TypeScript/rte_ckeditor/plugin/soft-hyphen.ts
index 4a10126e6b1a..9b8a09ced468 100644
--- a/Build/Sources/TypeScript/rte_ckeditor/plugin/soft-hyphen.ts
+++ b/Build/Sources/TypeScript/rte_ckeditor/plugin/soft-hyphen.ts
@@ -1,30 +1,11 @@
-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.');
   }
 }
diff --git a/Build/Sources/TypeScript/rte_ckeditor/plugin/whitespace.ts b/Build/Sources/TypeScript/rte_ckeditor/plugin/whitespace.ts
new file mode 100644
index 000000000000..91d8154a6f30
--- /dev/null
+++ b/Build/Sources/TypeScript/rte_ckeditor/plugin/whitespace.ts
@@ -0,0 +1,102 @@
+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);
+    });
+  }
+}
diff --git a/typo3/sysext/core/Classes/Configuration/CKEditor5Migrator.php b/typo3/sysext/core/Classes/Configuration/CKEditor5Migrator.php
index f0a809215b9d..35344adf0cce 100644
--- a/typo3/sysext/core/Classes/Configuration/CKEditor5Migrator.php
+++ b/typo3/sysext/core/Classes/Configuration/CKEditor5Migrator.php
@@ -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'],
     ];
diff --git a/typo3/sysext/core/Documentation/Changelog/12.2/Deprecation-99454-RestoreVisibilityForSoftHyphensAndNonBreakingSpaces.rst b/typo3/sysext/core/Documentation/Changelog/12.2/Deprecation-99454-RestoreVisibilityForSoftHyphensAndNonBreakingSpaces.rst
new file mode 100644
index 000000000000..c63e24c9a62a
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/12.2/Deprecation-99454-RestoreVisibilityForSoftHyphensAndNonBreakingSpaces.rst
@@ -0,0 +1,64 @@
+.. 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
diff --git a/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml b/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml
index 7678c4814200..d45a1eaf63a7 100644
--- a/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml
+++ b/typo3/sysext/rte_ckeditor/Configuration/RTE/Default.yaml
@@ -18,6 +18,7 @@ editor:
         - italic
         - subscript
         - superscript
+        - softhyphen
         - '|'
         - bulletedList
         - numberedList
@@ -26,7 +27,6 @@ editor:
         - '|'
         - findAndReplace
         - link
-        - SoftHyphen
         - '|'
         - removeFormat
         - undo
diff --git a/typo3/sysext/rte_ckeditor/Configuration/RTE/Editor/Plugins.yaml b/typo3/sysext/rte_ckeditor/Configuration/RTE/Editor/Plugins.yaml
index 3da71263fd5d..93a507d22967 100644
--- a/typo3/sysext/rte_ckeditor/Configuration/RTE/Editor/Plugins.yaml
+++ b/typo3/sysext/rte_ckeditor/Configuration/RTE/Editor/Plugins.yaml
@@ -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
diff --git a/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml b/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml
index 18cc80f2637f..f69918a6beda 100644
--- a/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml
+++ b/typo3/sysext/rte_ckeditor/Configuration/RTE/Full.yaml
@@ -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
         - '-'
diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/Css/editor.css b/typo3/sysext/rte_ckeditor/Resources/Public/Css/editor.css
index 96571bf96a66..c7453fd57de6 100644
--- a/typo3/sysext/rte_ckeditor/Resources/Public/Css/editor.css
+++ b/typo3/sysext/rte_ckeditor/Resources/Public/Css/editor.css
@@ -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: ' ';
+}
diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/soft-hyphen.js b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/soft-hyphen.js
index 42715fc9e8f1..d1909b46737a 100644
--- a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/soft-hyphen.js
+++ b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/soft-hyphen.js
@@ -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
diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/whitespace.js b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/whitespace.js
new file mode 100644
index 000000000000..17ca53db262e
--- /dev/null
+++ b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/plugin/whitespace.js
@@ -0,0 +1,13 @@
+/*
+ * 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
-- 
GitLab