From 672b8fa1c5078d8c7dc2020d3e7a6091d612ee6b Mon Sep 17 00:00:00 2001
From: Andreas Fernandez <a.fernandez@scripting-base.de>
Date: Sun, 5 Apr 2020 08:11:28 +0200
Subject: [PATCH] [BUGFIX] Preserve selection ranges in RteLinkBrowser

When the RteLinkBrowser is opened, any active ranges are now backed up
and reused later when an element gets linked. This fixes clashes with
the browser's internal search feature that overrides the `Selection`
object.

Resolves: #90952
Releases: master, 9.5
Change-Id: I155157e808370cd5ff05076a6c82f09da3b0cb3c
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64078
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Josef Glatz <josefglatz@gmail.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Josef Glatz <josefglatz@gmail.com>
---
 .../Resources/Public/TypeScript/RteLinkBrowser.ts           | 6 ++++++
 .../Resources/Public/JavaScript/RteLinkBrowser.js           | 2 +-
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/Build/Sources/TypeScript/rte_ckeditor/Resources/Public/TypeScript/RteLinkBrowser.ts b/Build/Sources/TypeScript/rte_ckeditor/Resources/Public/TypeScript/RteLinkBrowser.ts
index 7b0a6c86b127..9781e99b6409 100644
--- a/Build/Sources/TypeScript/rte_ckeditor/Resources/Public/TypeScript/RteLinkBrowser.ts
+++ b/Build/Sources/TypeScript/rte_ckeditor/Resources/Public/TypeScript/RteLinkBrowser.ts
@@ -23,6 +23,7 @@ import Modal = require('TYPO3/CMS/Backend/Modal');
 class RteLinkBrowser {
   protected plugin: any = null;
   protected CKEditor: CKEDITOR.editor = null;
+  protected ranges: CKEDITOR.dom.range[] = null;
   protected siteUrl: string = '';
 
   /**
@@ -47,6 +48,9 @@ class RteLinkBrowser {
       });
     }
 
+    // Backup all ranges that are active when the Link Browser is requested
+    this.ranges = this.CKEditor.getSelection().getRanges();
+
     // siteUrl etc are added as data attributes to the body tag
     $.extend(RteLinkBrowser, $('body').data());
 
@@ -111,6 +115,7 @@ class RteLinkBrowser {
     linkElement.setAttribute('href', link);
 
     const selection = this.CKEditor.getSelection();
+    selection.selectRanges(this.ranges);
     if (selection && selection.getSelectedText() === '') {
       selection.selectElement(selection.getStartElement());
     }
@@ -119,6 +124,7 @@ class RteLinkBrowser {
     } else {
       linkElement.setText(linkElement.getAttribute('href'));
     }
+
     this.CKEditor.insertElement(linkElement);
 
     Modal.dismiss();
diff --git a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/RteLinkBrowser.js b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/RteLinkBrowser.js
index e813f2cf1d2d..f99d12b48a2e 100644
--- a/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/RteLinkBrowser.js
+++ b/typo3/sysext/rte_ckeditor/Resources/Public/JavaScript/RteLinkBrowser.js
@@ -10,4 +10,4 @@
  *
  * The TYPO3 project - inspiring people to share!
  */
-define(["require","exports","jquery","TYPO3/CMS/Recordlist/LinkBrowser","TYPO3/CMS/Backend/Modal","ckeditor"],(function(t,e,i,n,s){"use strict";class l{constructor(){this.plugin=null,this.CKEditor=null,this.siteUrl=""}initialize(t){let e=s.currentModal.data("ckeditor");if(void 0!==e)this.CKEditor=e;else{let e;e=void 0!==top.TYPO3.Backend&&void 0!==top.TYPO3.Backend.ContentContainer.get()?top.TYPO3.Backend.ContentContainer.get():window.parent,i.each(e.CKEDITOR.instances,(e,i)=>{i.id===t&&(this.CKEditor=i)})}i.extend(l,i("body").data()),i(".t3js-class-selector").on("change",()=>{i("option:selected",this).data("linkTitle")&&i(".t3js-linkTitle").val(i("option:selected",this).data("linkTitle"))}),i(".t3js-removeCurrentLink").on("click",t=>{t.preventDefault(),this.CKEditor.execCommand("unlink"),s.dismiss()})}finalizeFunction(t){const e=this.CKEditor.document.createElement("a"),l=n.getLinkAttributeValues();let r=l.params?l.params:"";l.target&&e.setAttribute("target",l.target),l.class&&e.setAttribute("class",l.class),l.title&&e.setAttribute("title",l.title),delete l.title,delete l.class,delete l.target,delete l.params,i.each(l,(t,i)=>{e.setAttribute(t,i)});const a=t.match(/^([a-z0-9]+:\/\/[^:\/?#]+(?:\/?[^?#]*)?)(\??[^#]*)(#?.*)$/);if(a&&a.length>0){t=a[1]+a[2];const e=a[2].length>0?"&":"?";r.length>0&&("&"===r[0]&&(r=r.substr(1)),r.length>0&&(t+=e+r)),t+=a[3]}e.setAttribute("href",t);const o=this.CKEditor.getSelection();o&&""===o.getSelectedText()&&o.selectElement(o.getStartElement()),o&&o.getSelectedText()?e.setText(o.getSelectedText()):e.setText(e.getAttribute("href")),this.CKEditor.insertElement(e),s.dismiss()}}let r=new l;return n.finalizeFunction=t=>{r.finalizeFunction(t)},r}));
\ No newline at end of file
+define(["require","exports","jquery","TYPO3/CMS/Recordlist/LinkBrowser","TYPO3/CMS/Backend/Modal","ckeditor"],(function(t,e,i,n,s){"use strict";class l{constructor(){this.plugin=null,this.CKEditor=null,this.ranges=null,this.siteUrl=""}initialize(t){let e=s.currentModal.data("ckeditor");if(void 0!==e)this.CKEditor=e;else{let e;e=void 0!==top.TYPO3.Backend&&void 0!==top.TYPO3.Backend.ContentContainer.get()?top.TYPO3.Backend.ContentContainer.get():window.parent,i.each(e.CKEDITOR.instances,(e,i)=>{i.id===t&&(this.CKEditor=i)})}this.ranges=this.CKEditor.getSelection().getRanges(),i.extend(l,i("body").data()),i(".t3js-class-selector").on("change",()=>{i("option:selected",this).data("linkTitle")&&i(".t3js-linkTitle").val(i("option:selected",this).data("linkTitle"))}),i(".t3js-removeCurrentLink").on("click",t=>{t.preventDefault(),this.CKEditor.execCommand("unlink"),s.dismiss()})}finalizeFunction(t){const e=this.CKEditor.document.createElement("a"),l=n.getLinkAttributeValues();let r=l.params?l.params:"";l.target&&e.setAttribute("target",l.target),l.class&&e.setAttribute("class",l.class),l.title&&e.setAttribute("title",l.title),delete l.title,delete l.class,delete l.target,delete l.params,i.each(l,(t,i)=>{e.setAttribute(t,i)});const a=t.match(/^([a-z0-9]+:\/\/[^:\/?#]+(?:\/?[^?#]*)?)(\??[^#]*)(#?.*)$/);if(a&&a.length>0){t=a[1]+a[2];const e=a[2].length>0?"&":"?";r.length>0&&("&"===r[0]&&(r=r.substr(1)),r.length>0&&(t+=e+r)),t+=a[3]}e.setAttribute("href",t);const o=this.CKEditor.getSelection();o.selectRanges(this.ranges),o&&""===o.getSelectedText()&&o.selectElement(o.getStartElement()),o&&o.getSelectedText()?e.setText(o.getSelectedText()):e.setText(e.getAttribute("href")),this.CKEditor.insertElement(e),s.dismiss()}}let r=new l;return n.finalizeFunction=t=>{r.finalizeFunction(t)},r}));
\ No newline at end of file
-- 
GitLab