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

[BUGFIX] Correct registration of toolbar link buttons in CKEditor 5

The CKEditor 5 has very limited support for managing links.
By default, you only get a simple input field for a string.
To bring the known and loved easy-to-use LinkBrowser to
CKEditor 5 we need to overwrite the existing linking
capabilities.

For developers and integrators, this overwrite should be
invisible as it was before with the CKEditor 4 integration.
Instead of teaching the users that they need to load custom
modules to change the link behavior, we are already migrating
this in the background for them. A typical developer can just
follow the CKEditor 5 guide to configuring the editor to its
needs and the Core is already doing the adjustments and
replacements of modules for them.

We currently overwrite the existing link and unlink commands,
but we register the toolbar buttons with a prefix. This makes
existing CKEditor configurations incompatible since the
linking buttons are missing in the toolbar.

To make migrations easier we a...
parent a97c0056
Branches
Tags
No related merge requests found
......@@ -117,7 +117,7 @@ export class CKEditor5Element extends LitElement {
wordCount: this.options.wordCount || null,
typo3link: this.options.typo3link || null,
// alternative, purge from `plugins` (classes) above already (probably better)
removePlugins: this.options.removePlugins || ['Link'],
removePlugins: this.options.removePlugins || [],
} as any;
if (this.options.language) {
config.language = this.options.language;
......
......@@ -267,7 +267,7 @@ export class Typo3LinkUI extends Core.Plugin {
});
// re-uses 'Link' plugin name -> original plugin 'Link' needs to be removed during runtime
editor.ui.componentFactory.add('Typo3Link', locale => {
editor.ui.componentFactory.add('link', locale => {
const linkButton = new UI.ButtonView(locale);
linkButton.isEnabled = true;
linkButton.label = t('Link');
......@@ -280,7 +280,7 @@ export class Typo3LinkUI extends Core.Plugin {
this.listenTo(linkButton, 'execute', () => this.showUI());
return linkButton;
});
editor.ui.componentFactory.add('Typo3Unlink', locale => {
editor.ui.componentFactory.add('unlink', locale => {
const unlinkButton = new UI.ButtonView(locale);
unlinkButton.isEnabled = true;
unlinkButton.label = t( 'Unlink');
......
......@@ -25,8 +25,8 @@ editor:
- alignment
- '|'
- findAndReplace
- Typo3Link
- Typo3Unlink
- link
- unlink
- SoftHyphen
- '|'
- removeFormat
......
......@@ -39,7 +39,8 @@ editor:
- find
- selectAll
- '|'
- Link
- link
- unlink
- SoftHyphen
- insertTable
- tableColumn
......
......@@ -19,4 +19,4 @@ var __decorate=function(t,e,o,i){var n,r=arguments.length,s=r<3?e:null===i?i=Obj
data-formengine-validation-rules="${this.formEngine.validationRules}"
>${this.formEngine.value}</textarea>
<div class="${this.elements.wordCount.className}"></div>
`}firstUpdated(){if(!(this.target instanceof HTMLElement))throw new Error("No rich-text content target found.");const t=(this.options.importModules||[]).map((t=>import(t)));Promise.all(t).then((t=>{const e=t.filter((t=>t.default)).map((t=>t.default)),o=CKEditor5.builtinPlugins.concat(e),i=[].concat(...o.filter((t=>t.overrides?.length>0)).map((t=>t.overrides))),n=o.filter((t=>!i.includes(t)));let r={toolbar:this.options.toolbar,plugins:n,wordCount:this.options.wordCount||null,typo3link:this.options.typo3link||null,removePlugins:this.options.removePlugins||["Link"]};this.options.language&&(r.language=this.options.language),this.options.style&&(r.style=this.options.style),this.options.table&&(r.table=this.options.table),this.options.heading&&(r.heading=this.options.heading),this.options.alignment&&(r.alignment=this.options.alignment),CKEditor5.create(this.target,r).then((t=>{this.applyEditableElementStyles(t),this.applyWordCountWidget(t),this.applyReadOnly(t)}))}))}applyEditableElementStyles(t){const e=t.editing.view,o={"min-height":this.options.height,"min-width":this.options.width};Object.keys(o).forEach((t=>{let i=o[t];i&&(isFinite(i)&&!Number.isNaN(parseFloat(i))&&(i+="px"),e.change((o=>{o.setStyle(t,i,e.document.getRoot())})))}))}applyWordCountWidget(t){const e=t.plugins.get("WordCount");this.querySelector(this.elements.wordCount.selector).appendChild(e.wordCountContainer)}applyReadOnly(t){this.options.readOnly&&t.enableReadOnlyMode("typo3-lock")}};__decorate([property({type:Object})],CKEditor5Element.prototype,"options",void 0),__decorate([property({type:Object,attribute:"form-engine"})],CKEditor5Element.prototype,"formEngine",void 0),__decorate([query("textarea")],CKEditor5Element.prototype,"target",void 0),CKEditor5Element=__decorate([customElement("typo3-rte-ckeditor-ckeditor5")],CKEditor5Element);export{CKEditor5Element};
\ No newline at end of file
`}firstUpdated(){if(!(this.target instanceof HTMLElement))throw new Error("No rich-text content target found.");const t=(this.options.importModules||[]).map((t=>import(t)));Promise.all(t).then((t=>{const e=t.filter((t=>t.default)).map((t=>t.default)),o=CKEditor5.builtinPlugins.concat(e),i=[].concat(...o.filter((t=>t.overrides?.length>0)).map((t=>t.overrides))),n=o.filter((t=>!i.includes(t)));let r={toolbar:this.options.toolbar,plugins:n,wordCount:this.options.wordCount||null,typo3link:this.options.typo3link||null,removePlugins:this.options.removePlugins||[]};this.options.language&&(r.language=this.options.language),this.options.style&&(r.style=this.options.style),this.options.table&&(r.table=this.options.table),this.options.heading&&(r.heading=this.options.heading),this.options.alignment&&(r.alignment=this.options.alignment),CKEditor5.create(this.target,r).then((t=>{this.applyEditableElementStyles(t),this.applyWordCountWidget(t),this.applyReadOnly(t)}))}))}applyEditableElementStyles(t){const e=t.editing.view,o={"min-height":this.options.height,"min-width":this.options.width};Object.keys(o).forEach((t=>{let i=o[t];i&&(isFinite(i)&&!Number.isNaN(parseFloat(i))&&(i+="px"),e.change((o=>{o.setStyle(t,i,e.document.getRoot())})))}))}applyWordCountWidget(t){const e=t.plugins.get("WordCount");this.querySelector(this.elements.wordCount.selector).appendChild(e.wordCountContainer)}applyReadOnly(t){this.options.readOnly&&t.enableReadOnlyMode("typo3-lock")}};__decorate([property({type:Object})],CKEditor5Element.prototype,"options",void 0),__decorate([property({type:Object,attribute:"form-engine"})],CKEditor5Element.prototype,"formEngine",void 0),__decorate([query("textarea")],CKEditor5Element.prototype,"target",void 0),CKEditor5Element=__decorate([customElement("typo3-rte-ckeditor-ckeditor5")],CKEditor5Element);export{CKEditor5Element};
\ No newline at end of file
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
import{UI,Core,Engine,Typing,Link,LinkUtils,Widget,Utils}from"@typo3/ckeditor5-bundle.js";import{DoubleClickObserver}from"@typo3/rte-ckeditor/observer/double-click-observer.js";import{default as modalObject}from"@typo3/backend/modal.js";const linkIcon='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z"/></svg>',unlinkIcon='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184zm4.919 10.562-1.414 1.414a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 0 1 1.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414z"/></svg>';export const LINK_ALLOWED_ATTRIBUTES=["href","title","class","target","rel"];export function addLinkPrefix(e){return"link"+(e.charAt(0).toUpperCase()+e.slice(1))}export class Typo3LinkCommand extends Core.Command{refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement()||Utils.first(t.getSelectedBlocks());LinkUtils.isLinkableElement(i,e.schema)?(this.value=i.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(i,"linkHref")):(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref"))}execute(e,t={}){const i=this.editor.model,n=i.document.selection;i.change((o=>{if(n.isCollapsed){const r=n.getFirstPosition();if(n.hasAttribute("linkHref")){const l=Typing.findAttributeRange(r,"linkHref",n.getAttribute("linkHref"),i);o.setAttribute("linkHref",e,l);for(const[e,i]of Object.entries(t.attrs))o.setAttribute(e,i,l);o.setSelection(o.createPositionAfter(l.end.nodeBefore))}else if(""!==e){const l=Utils.toMap(n.getAttributes());l.set("linkHref",e);for(const[e,i]of Object.entries(t.attrs))l.set(e,i);const{end:s}=i.insertContent(o.createText(e,l),r);o.setSelection(s)}o.removeSelectionAttribute("linkHref")}else{const t=i.schema.getValidRanges(n.getRanges(),"linkHref"),r=[];for(const e of n.getSelectedBlocks())i.schema.checkAttribute(e,"linkHref")&&r.push(o.createRangeOn(e));const l=r.slice();for(const e of t)this.isRangeToUpdate(e,r)&&l.push(e);for(const t of l)o.setAttribute("linkHref",e,t)}}))}isRangeToUpdate(e,t){for(const i of t)if(i.containsRange(e))return!1;return!0}}export class Typo3UnlinkCommand extends Core.Command{refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement();LinkUtils.isLinkableElement(i,e.schema)?(this.value=i.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(i,"linkHref")):(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref"))}execute(){const e=this.editor.model,t=e.document.selection;e.change((i=>{const n=t.isCollapsed?[Typing.findAttributeRange(t.getFirstPosition(),"linkHref",t.getAttribute("linkHref"),e)]:e.schema.getValidRanges(t.getRanges(),"linkHref");for(const e of n)i.removeAttribute("linkHref",e),i.removeAttribute("linkTarget",e),i.removeAttribute("linkClass",e),i.removeAttribute("linkTitle",e),i.removeAttribute("linkRel",e)}))}}export class Typo3LinkEditing extends Core.Plugin{init(){const e=this.editor;window.editor=e,e.model.schema.extend("$text",{allowAttributes:["linkTitle","linkClass","linkTarget","linkRel"]}),e.conversion.for("downcast").attributeToElement({model:"linkTitle",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{title:e},{priority:5});return t.setCustomProperty("linkTitle",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkTitle",value:e=>e.getAttribute("title")}}),e.conversion.for("downcast").attributeToElement({model:"linkClass",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{class:e},{priority:5});return t.setCustomProperty("linkClass",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkClass",value:e=>e.getAttribute("class")}}),e.conversion.for("downcast").attributeToElement({model:"linkTarget",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{target:e},{priority:5});return t.setCustomProperty("linkTarget",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkTarget",value:e=>e.getAttribute("target")}}),e.conversion.for("downcast").attributeToElement({model:"linkRel",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{rel:e},{priority:5});return t.setCustomProperty("linkRel",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkRel",value:e=>e.getAttribute("rel")}}),e.commands.add("link",new Typo3LinkCommand(e)),e.commands.add("unlink",new Typo3UnlinkCommand(e))}}Typo3LinkEditing.pluginName="Typo3LinkEditing";export class Typo3LinkUI extends Core.Plugin{init(){const e=this.editor;e.editing.view.addObserver(DoubleClickObserver),e.editing.view.addObserver(Engine.ClickObserver),this.createToolbarLinkButtons()}createToolbarLinkButtons(){const e=this.editor,t=e.commands.get("link"),i=e.commands.get("unlink"),n=e.t;e.keystrokes.set(LinkUtils.LINK_KEYSTROKE,((e,i)=>{i(),t.isEnabled&&this.showUI()})),e.ui.componentFactory.add("Typo3Link",(e=>{const i=new UI.ButtonView(e);return i.isEnabled=!0,i.label=n("Link"),i.icon=linkIcon,i.keystroke=LinkUtils.LINK_KEYSTROKE,i.tooltip=!0,i.isToggleable=!0,i.bind("isEnabled").to(t,"isEnabled"),i.bind("isOn").to(t,"value",(e=>!!e)),this.listenTo(i,"execute",(()=>this.showUI())),i})),e.ui.componentFactory.add("Typo3Unlink",(e=>{const t=new UI.ButtonView(e);return t.isEnabled=!0,t.label=n("Unlink"),t.icon=unlinkIcon,t.tooltip=!0,t.isToggleable=!0,t.bind("isEnabled").to(i,"isEnabled"),t.bind("isOn").to(i,"value",(e=>!!e)),this.listenTo(t,"execute",(()=>i.execute())),t}))}showUI(){const e=this.getSelectedLinkElement();this.openLinkBrowser(this.editor,e)}getSelectedLinkElement(){const e=this.editor.editing.view,t=e.document.selection,i=t.getSelectedElement();if(t.isCollapsed||i&&Widget.isWidget(i))return this.findLinkElementAncestor(t.getFirstPosition());{const i=t.getFirstRange().getTrimmed(),n=this.findLinkElementAncestor(i.start),o=this.findLinkElementAncestor(i.end);return n&&n==o&&e.createRangeIn(n).getTrimmed().isEqual(i)?n:null}}findLinkElementAncestor(e){return e.getAncestors().find((e=>LinkUtils.isLinkElement(e)))}openLinkBrowser(e,t){let i="";t&&(i+="&P[curUrl][url]="+encodeURIComponent(t.getAttribute("href")),["target","class","title","rel"].forEach((e=>{const n=t.getAttribute(e);n&&(i+="&P[curUrl]["+e+"]="+encodeURIComponent(n))}))),this.openElementBrowser(e,"Link",this.makeUrlFromModulePath(e,e.config.get("typo3link")?.routeUrl,i))}makeUrlFromModulePath(e,t,i){return t+(-1===t.indexOf("?")?"?":"&")+"&contentsLanguage=en&editorId=123"+(i||"")}openElementBrowser(e,t,i){modalObject.advanced({type:modalObject.types.iframe,title:t,content:i,size:modalObject.sizes.large,callback:t=>{t.userData.ckeditor=e,t.querySelector(".t3js-modal-body")?.setAttribute("id","123")}})}}Typo3LinkUI.pluginName="Typo3LinkUI";export default class Typo3Link extends Core.Plugin{}Typo3Link.pluginName="Typo3Link",Typo3Link.requires=[Link.LinkEditing,Link.AutoLink,Typo3LinkEditing,Typo3LinkUI],Typo3Link.overrides=[Link.Link];
\ No newline at end of file
import{UI,Core,Engine,Typing,Link,LinkUtils,Widget,Utils}from"@typo3/ckeditor5-bundle.js";import{DoubleClickObserver}from"@typo3/rte-ckeditor/observer/double-click-observer.js";import{default as modalObject}from"@typo3/backend/modal.js";const linkIcon='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z"/></svg>',unlinkIcon='<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184zm4.919 10.562-1.414 1.414a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 0 1 1.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414z"/></svg>';export const LINK_ALLOWED_ATTRIBUTES=["href","title","class","target","rel"];export function addLinkPrefix(e){return"link"+(e.charAt(0).toUpperCase()+e.slice(1))}export class Typo3LinkCommand extends Core.Command{refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement()||Utils.first(t.getSelectedBlocks());LinkUtils.isLinkableElement(i,e.schema)?(this.value=i.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(i,"linkHref")):(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref"))}execute(e,t={}){const i=this.editor.model,n=i.document.selection;i.change((o=>{if(n.isCollapsed){const r=n.getFirstPosition();if(n.hasAttribute("linkHref")){const l=Typing.findAttributeRange(r,"linkHref",n.getAttribute("linkHref"),i);o.setAttribute("linkHref",e,l);for(const[e,i]of Object.entries(t.attrs))o.setAttribute(e,i,l);o.setSelection(o.createPositionAfter(l.end.nodeBefore))}else if(""!==e){const l=Utils.toMap(n.getAttributes());l.set("linkHref",e);for(const[e,i]of Object.entries(t.attrs))l.set(e,i);const{end:s}=i.insertContent(o.createText(e,l),r);o.setSelection(s)}o.removeSelectionAttribute("linkHref")}else{const t=i.schema.getValidRanges(n.getRanges(),"linkHref"),r=[];for(const e of n.getSelectedBlocks())i.schema.checkAttribute(e,"linkHref")&&r.push(o.createRangeOn(e));const l=r.slice();for(const e of t)this.isRangeToUpdate(e,r)&&l.push(e);for(const t of l)o.setAttribute("linkHref",e,t)}}))}isRangeToUpdate(e,t){for(const i of t)if(i.containsRange(e))return!1;return!0}}export class Typo3UnlinkCommand extends Core.Command{refresh(){const e=this.editor.model,t=e.document.selection,i=t.getSelectedElement();LinkUtils.isLinkableElement(i,e.schema)?(this.value=i.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(i,"linkHref")):(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(t,"linkHref"))}execute(){const e=this.editor.model,t=e.document.selection;e.change((i=>{const n=t.isCollapsed?[Typing.findAttributeRange(t.getFirstPosition(),"linkHref",t.getAttribute("linkHref"),e)]:e.schema.getValidRanges(t.getRanges(),"linkHref");for(const e of n)i.removeAttribute("linkHref",e),i.removeAttribute("linkTarget",e),i.removeAttribute("linkClass",e),i.removeAttribute("linkTitle",e),i.removeAttribute("linkRel",e)}))}}export class Typo3LinkEditing extends Core.Plugin{init(){const e=this.editor;window.editor=e,e.model.schema.extend("$text",{allowAttributes:["linkTitle","linkClass","linkTarget","linkRel"]}),e.conversion.for("downcast").attributeToElement({model:"linkTitle",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{title:e},{priority:5});return t.setCustomProperty("linkTitle",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkTitle",value:e=>e.getAttribute("title")}}),e.conversion.for("downcast").attributeToElement({model:"linkClass",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{class:e},{priority:5});return t.setCustomProperty("linkClass",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkClass",value:e=>e.getAttribute("class")}}),e.conversion.for("downcast").attributeToElement({model:"linkTarget",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{target:e},{priority:5});return t.setCustomProperty("linkTarget",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkTarget",value:e=>e.getAttribute("target")}}),e.conversion.for("downcast").attributeToElement({model:"linkRel",view:(e,{writer:t})=>{const i=t.createAttributeElement("a",{rel:e},{priority:5});return t.setCustomProperty("linkRel",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{title:!0}},model:{key:"linkRel",value:e=>e.getAttribute("rel")}}),e.commands.add("link",new Typo3LinkCommand(e)),e.commands.add("unlink",new Typo3UnlinkCommand(e))}}Typo3LinkEditing.pluginName="Typo3LinkEditing";export class Typo3LinkUI extends Core.Plugin{init(){const e=this.editor;e.editing.view.addObserver(DoubleClickObserver),e.editing.view.addObserver(Engine.ClickObserver),this.createToolbarLinkButtons()}createToolbarLinkButtons(){const e=this.editor,t=e.commands.get("link"),i=e.commands.get("unlink"),n=e.t;e.keystrokes.set(LinkUtils.LINK_KEYSTROKE,((e,i)=>{i(),t.isEnabled&&this.showUI()})),e.ui.componentFactory.add("link",(e=>{const i=new UI.ButtonView(e);return i.isEnabled=!0,i.label=n("Link"),i.icon=linkIcon,i.keystroke=LinkUtils.LINK_KEYSTROKE,i.tooltip=!0,i.isToggleable=!0,i.bind("isEnabled").to(t,"isEnabled"),i.bind("isOn").to(t,"value",(e=>!!e)),this.listenTo(i,"execute",(()=>this.showUI())),i})),e.ui.componentFactory.add("unlink",(e=>{const t=new UI.ButtonView(e);return t.isEnabled=!0,t.label=n("Unlink"),t.icon=unlinkIcon,t.tooltip=!0,t.isToggleable=!0,t.bind("isEnabled").to(i,"isEnabled"),t.bind("isOn").to(i,"value",(e=>!!e)),this.listenTo(t,"execute",(()=>i.execute())),t}))}showUI(){const e=this.getSelectedLinkElement();this.openLinkBrowser(this.editor,e)}getSelectedLinkElement(){const e=this.editor.editing.view,t=e.document.selection,i=t.getSelectedElement();if(t.isCollapsed||i&&Widget.isWidget(i))return this.findLinkElementAncestor(t.getFirstPosition());{const i=t.getFirstRange().getTrimmed(),n=this.findLinkElementAncestor(i.start),o=this.findLinkElementAncestor(i.end);return n&&n==o&&e.createRangeIn(n).getTrimmed().isEqual(i)?n:null}}findLinkElementAncestor(e){return e.getAncestors().find((e=>LinkUtils.isLinkElement(e)))}openLinkBrowser(e,t){let i="";t&&(i+="&P[curUrl][url]="+encodeURIComponent(t.getAttribute("href")),["target","class","title","rel"].forEach((e=>{const n=t.getAttribute(e);n&&(i+="&P[curUrl]["+e+"]="+encodeURIComponent(n))}))),this.openElementBrowser(e,"Link",this.makeUrlFromModulePath(e,e.config.get("typo3link")?.routeUrl,i))}makeUrlFromModulePath(e,t,i){return t+(-1===t.indexOf("?")?"?":"&")+"&contentsLanguage=en&editorId=123"+(i||"")}openElementBrowser(e,t,i){modalObject.advanced({type:modalObject.types.iframe,title:t,content:i,size:modalObject.sizes.large,callback:t=>{t.userData.ckeditor=e,t.querySelector(".t3js-modal-body")?.setAttribute("id","123")}})}}Typo3LinkUI.pluginName="Typo3LinkUI";export default class Typo3Link extends Core.Plugin{}Typo3Link.pluginName="Typo3Link",Typo3Link.requires=[Link.LinkEditing,Link.AutoLink,Typo3LinkEditing,Typo3LinkUI],Typo3Link.overrides=[Link.Link];
\ 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