TYPO3 v15 dev-main snapshot ()

This commit is contained in:
wappler committed 2026-08-10 22:31:36 +02:00
commit 1e393722e8
183 files changed
+7832

No files matched your search

+13
View File
@@ -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{LitElement as R,html as T}from"lit";import{property as A,queryAssignedElements as O,customElement as M}from"lit/decorators.js";import L from"@typo3/core/ajax/ajax-request.js";import j from"@typo3/core/event/debounce-event.js";import{prefixAndRebaseCss as K}from"@typo3/rte-ckeditor/css-prefixer.js";import{ClassicEditor as N}from"@ckeditor/ckeditor5-editor-classic";var k=function(l,e,o,t){var s=arguments.length,i=s<3?e:t===null?t=Object.getOwnPropertyDescriptor(e,o):t,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(l,e,o,t);else for(var r=l.length-1;r>=0;r--)(a=l[r])&&(i=(s<3?a(i):s>3?a(e,o,i):a(e,o))||i);return s>3&&i&&Object.defineProperty(e,o,i),i};const H=[{module:"@ckeditor/ckeditor5-block-quote",exports:["BlockQuote"]},{module:"@ckeditor/ckeditor5-essentials",exports:["Essentials"]},{module:"@ckeditor/ckeditor5-find-and-replace",exports:["FindAndReplace"]},{module:"@ckeditor/ckeditor5-heading",exports:["Heading"]},{module:"@ckeditor/ckeditor5-indent",exports:["Indent","IndentBlock"]},{module:"@ckeditor/ckeditor5-link",exports:["Link"]},{module:"@ckeditor/ckeditor5-list",exports:["List"]},{module:"@ckeditor/ckeditor5-paragraph",exports:["Paragraph"]},{module:"@ckeditor/ckeditor5-clipboard",exports:["PastePlainText"]},{module:"@ckeditor/ckeditor5-paste-from-office",exports:["PasteFromOffice"]},{module:"@ckeditor/ckeditor5-remove-format",exports:["RemoveFormat"]},{module:"@ckeditor/ckeditor5-table",exports:["Table","TableToolbar","TableProperties","TableCellProperties","TableCaption"]},{module:"@ckeditor/ckeditor5-typing",exports:["TextTransformation"]},{module:"@ckeditor/ckeditor5-source-editing",exports:["SourceEditing"]},{module:"@ckeditor/ckeditor5-alignment",exports:["Alignment"]},{module:"@ckeditor/ckeditor5-style",exports:["Style"]},{module:"@ckeditor/ckeditor5-html-support",exports:["GeneralHtmlSupport"]},{module:"@ckeditor/ckeditor5-basic-styles",exports:["Bold","Italic","Subscript","Superscript","Strikethrough","Underline"]},{module:"@ckeditor/ckeditor5-special-characters",exports:["SpecialCharacters","SpecialCharactersEssentials"]},{module:"@ckeditor/ckeditor5-horizontal-line",exports:["HorizontalLine"]}];let h=class extends R{constructor(){super(...arguments),this.options={},this.styleSheets=new Map}connectedCallback(){super.connectedCallback(),this.prefixAndLoadContentsCss()}disconnectedCallback(){super.disconnectedCallback(),document.adoptedStyleSheets=document.adoptedStyleSheets.filter(e=>!this.styleSheets.has(e)),this.styleSheets.clear()}firstUpdated(){this.target[0]instanceof HTMLTextAreaElement?this.initCKEditor():this.renderRoot.querySelector('slot[name="textarea"]').addEventListener("slotchange",()=>this.initCKEditor(),{once:!0})}async initCKEditor(){if(!(this.target[0]instanceof HTMLTextAreaElement))throw new Error("No rich-text <textarea> content target found.");const{importModules:e,removeImportModules:o,width:t,height:s,readOnly:i,debug:a,toolbar:r,placeholder:f,htmlSupport:n,wordCount:u,typo3link:p,removePlugins:g,...c}=this.options;"extraPlugins"in c&&delete c.extraPlugins,"contentsCss"in c&&delete c.contentsCss;let x={};"fullscreen"in c&&(x=c.fullscreen,delete c.fullscreen),x.container=document.querySelector(".module-body");const v=await this.resolvePlugins(H,e,o),m={licenseKey:"GPL",...c,toolbar:r,plugins:v,placeholder:f,wordCount:u,typo3link:p||null,removePlugins:g||[],fullscreen:x};n!==void 0&&(m.htmlSupport=C(n)),m?.typing?.transformations!==void 0&&(m.typing.transformations=C(m.typing.transformations)),N.create(this.target[0],m).then(d=>{if(this.applyEditableElementStyles(d,t,s),this.handleWordCountPlugin(d,u),this.applyReadOnly(d,i),d.model.document.on("change:data",()=>{d.updateSourceElement(),this.target[0].dispatchEvent(new Event("change",{bubbles:!0,cancelable:!0}))}),d.plugins.has("SourceEditing")){const y=d.plugins.get("SourceEditing");y.on("change:isSourceEditingMode",(I,$,w)=>{for(const[P]of d.editing.view.domRoots)if(w){const b=d.ui.getEditableElement(`sourceEditing:${P}`);if(b instanceof HTMLTextAreaElement)new j("input",()=>{y.updateEditorData()},100).bindTo(b);else throw new Error("Cannot find textarea related to source editing. Has CKEditor been upgraded?")}})}a&&import("@ckeditor/ckeditor5-inspector").then(({default:y})=>y.attach(d,{isCollapsed:!0}))})}render(){return T`<slot name=textarea></slot><slot></slot>`}async resolvePlugins(e,o,t){const s=S(t||[]),i=S([...e,...o||[]]).map(n=>{const{module:u}=n;let{exports:p}=n;for(const g of s)g.module===u&&(p=p.filter(c=>!g.exports.includes(c)));return{module:u,exports:p}}),a=await Promise.all(i.map(async n=>{try{return{module:await import(n.module),exports:n.exports}}catch(u){return console.error(`Failed to load CKEditor 5 module ${n.module}`,u),{module:null,exports:[]}}})),r=[];a.forEach(({module:n,exports:u})=>{for(const p of u)p in n?r.push(n[p]):console.error(`CKEditor 5 plugin export "${p}" not available in`,n)});const f=r.filter(n=>n.overrides?.length>0).map(n=>n.ovLine truncated
@@ -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*as r from"css-tree";function p(n,s,e){const t=r.parse(n),i=u(e),a=o(s);return r.walk(t,l=>(a(l),i(l))),r.generate(t)}function o(n){return s=>{if(s.type!=="Url")return;const e=s;if(e.value.startsWith("data:")||e.value.startsWith("/")||e.value.includes("://"))return;const t=new URL(n.replace(/\?.+/,"")+"/../"+e.value,document.baseURI);e.value=t.pathname+t.search+t.hash}}function u(n){return n===""?()=>{}:s=>{if(s.type!=="Selector")return;const e=s;if(e.children.isEmpty)return r.walk.skip;const t=r.parse(n+"{}"),i=r.find(t,l=>l.type==="Selector");if(i===null)throw new Error(`Failed to parse "${n}" as CSS prefix`);if(e.children.first.type==="PseudoClassSelector"&&e.children.first.name==="root")return e.children.shift(),e.children.prependList(i.children),r.walk.skip;let a=!1;return e.children.forEach((l,c)=>{l.type==="TypeSelector"&&["html","body"].includes(l.name.toLowerCase())&&(a?e.children.remove(c):(e.children.replace(c,i.children),a=!0))}),a||(e.children.unshift({type:"Combinator",loc:null,name:" "}),e.children.prependList(i.children)),r.walk.skip}}export{u as cssPrefixer,o as cssRelocator,p as prefixAndRebaseCss};
@@ -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*as d from"@ckeditor/ckeditor5-ui";import*as h from"@ckeditor/ckeditor5-core";import*as U from"@ckeditor/ckeditor5-engine";import*as f from"@ckeditor/ckeditor5-typing";import*as y from"@ckeditor/ckeditor5-widget";import*as v from"@ckeditor/ckeditor5-utils";import*as b from"@ckeditor/ckeditor5-link";import{LinkUtils as k}from"@ckeditor/ckeditor5-link";import p from"@typo3/backend/modal.js";import{IconLink as I,IconUnlink as R,IconPencil as V}from"@ckeditor/ckeditor5-icons";const C=["href","title","class","target","rel","download"];function x(c){return"link"+(c.charAt(0).toUpperCase()+c.slice(1))}function A(c){return c.startsWith("link")&&c.length>=5?c.charAt(4).toLowerCase()+c.slice(5):c}class E extends h.Command{constructor(){super(...arguments),this.attrs={}}refresh(){const e=this.editor.model,n=e.document.selection,t=n.getSelectedElement()||v.first(n.getSelectedBlocks()),o=k.isLinkableElement(t,e.schema)?t:n;o===t?(this.value=t.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttribute(t,"linkHref")):(this.value=n.getAttribute("linkHref"),this.isEnabled=e.schema.checkAttributeInSelection(n,"linkHref"));const s=this.editor.plugins.get("GeneralHtmlSupport").getGhsAttributeNameForElement("a"),l={};for(const a of this.getLinkAttributesAllowedOnText(e.schema))if(a!=="linkHref")if(a===s){const r=o.getAttribute(a);r?.classes&&r.classes.length!==0&&(l.class=r.classes.join(" "))}else{const r=o.getAttribute(a);r!==void 0&&(l[A(a)]=r)}this.attrs=l}execute(e,n={}){const t=this.editor.model,o=t.document.selection;t.change(i=>{if(o.isCollapsed){const s=o.getFirstPosition();if(o.hasAttribute("linkHref")){const l=f.findAttributeRange(s,"linkHref",o.getAttribute("linkHref"),t);i.setAttribute("linkHref",e,l);for(const[a,r]of Object.entries(this.composeLinkAttributes(n)))r!==null?i.setAttribute(a,r,l):i.removeAttribute(a,l);i.setSelection(i.createPositionAfter(l.end.nodeBefore))}else if(e!==""){const l=v.toMap(o.getAttributes());l.set("linkHref",e);for(const[r,m]of Object.entries(this.composeLinkAttributes(n)))m!==null&&l.set(r,m);const{end:a}=t.insertContent(i.createText(e,l),s);i.setSelection(a)}this.removeLinkAttributesFromSelection(i,this.getLinkAttributesAllowedOnText(t.schema))}else{const s=t.schema.getValidRanges(o.getRanges(),"linkHref"),l=[];for(const r of o.getSelectedBlocks())t.schema.checkAttribute(r,"linkHref")&&l.push(i.createRangeOn(r));const a=l.slice();for(const r of s)this.isRangeToUpdate(r,l)&&a.push(r);for(const r of a){i.setAttribute("linkHref",e,r);for(const[m,g]of Object.entries(this.composeLinkAttributes(n)))g!==null?i.setAttribute(m,g,r):i.removeAttribute(m,r)}}})}getLinkAttributesAllowedOnText(e){return e.getDefinition("$text").allowAttributes.filter(t=>t.startsWith("link")||t==="htmlA")}removeLinkAttributesFromSelection(e,n){e.removeSelectionAttribute("linkHref");for(const t of n)e.removeSelectionAttribute(t)}composeLinkAttributes(e){const n={};for(const[t,o]of Object.entries(e.attrs))if(t==="linkClass"){const s=this.editor.plugins.get("GeneralHtmlSupport").getGhsAttributeNameForElement("a"),l=this.editor.model.document.selection;let a;l.hasAttribute(s)?a={...l.getAttribute(s)}:a={};const r=o.replace(/\s+/g," ").trim();r!==""?a.classes=r.split(" "):"classes"in a&&delete a.classes,n[s]=Object.keys(a).length!==0?a:null}else n[t]=o!==""?o:null;return n}isRangeToUpdate(e,n){for(const t of n)if(t.containsRange(e))return!1;return!0}}class w extends h.Command{refresh(){const e=this.editor.model,n=e.document.selection,t=n.getSelectedElement();k.isLinkableElement(t,e.schema)?this.isEnabled=e.schema.checkAttribute(t,"linkHref"):this.isEnabled=e.schema.checkAttributeInSelection(n,"linkHref")}execute(){const e=this.editor.model,n=e.document.selection;e.change(t=>{const o=n.isCollapsed?[f.findAttributeRange(n.getFirstPosition(),"linkHref",n.getAttribute("linkHref"),e)]:e.schema.getValidRanges(n.getRanges(),"linkHref");for(const i of o)t.removeAttribute("linkHref",i),t.removeAttribute("linkTarget",i),t.removeAttribute("linkTitle",i),t.removeAttribute("linkRel",i),t.removeAttribute("linkDownload",i),t.removeAttribute("linkDataRteError",i)})}}class T extends h.Plugin{static{this.pluginName="Typo3LinkEditing"}init(){const e=this.editor;window.editor=e,e.model.schema.extend("$text",{allowAttributes:["linkTitle","linkTarget","linkRel","linkDownload","linkDataRteError"]}),e.plugins.get("DataFilter").loadAllowedConfig([{name:"a",classes:!0}]),e.conversion.for("downcast").attributeToElement({model:"linkDataRteError",view:(t,{writer:o})=>{const i=o.createAttributeElement("a",{"data-rte-error":t},{priority:5});return o.setCustomProperty("linkDataRteError",!0,i),i}}),e.conversion.for("upcast").elementToAttribute({view:{name:"a",attributes:{"data-rte-error":!0}},model:{key:"linkDataRteError",value:t=>t.getAttribute("data-rte-error")}}),e.conversion.for("downcast").attributeToElement({model:"linkTitle",view:(t,{writer:o})=>{const i=o.createAttributeElement("a",{title:t},{priority:5});return o.setCustomProperty("Line truncated
@@ -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*as w from"@ckeditor/ckeditor5-core";import*as x from"@ckeditor/ckeditor5-ui";import*as y from"@ckeditor/ckeditor5-utils";import*as S from"@ckeditor/ckeditor5-typing";class p extends w.Plugin{static{this.pluginName="Whitespace"}static{this.requires=[S.Typing]}init(){const e=this.editor,h=e.commands.get("insertText"),a=y.env.isMac?"Alt":"Ctrl";e.ui.componentFactory.add("softhyphen",s=>{const t=new x.ButtonView(s);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.keystroke=`${a}+Shift+-`,t.tooltip=!0,t.bind("isEnabled").to(h),t.on("execute",()=>this.insertSoftHyphen()),t}),e.keystrokes.set([a,"Shift",189],(s,t)=>{this.insertSoftHyphen(),t()}),e.keystrokes.set([a,"Shift","Space"],(s,t)=>{this.insertNonBreakingSpace(),t()}),e.conversion.for("editingDowncast").add(s=>{s.on("insert:$text",(t,c,o)=>{if(!o.consumable.consume(c.item,t.name))return;const n=o.writer,m=c.item.data.split(/([\u00AD\u00A0])/).filter(i=>i!=="");let r=c.range.start;m.forEach(i=>{const d=i==="\xAD"?"-":i;if(n.insert(o.mapper.toViewPosition(r),n.createText(d)),i==="\xAD"||i==="\xA0"){const l=i==="\xAD"?"softhyphen":"nbsp",f=Math.random().toString(16).slice(2),g=n.createAttributeElement("span",{class:`ck ck-${l}`},{id:f}),u=n.createRange(o.mapper.toViewPosition(r),o.mapper.toViewPosition(r.getShiftedBy(i.length)));n.wrap(u,g)}r=r.getShiftedBy(i.length)})},{priority:"high"})})}insertNonBreakingSpace(){const e=this.editor;e.execute("insertText",{text:"\xA0"}),e.editing.view.focus()}insertSoftHyphen(){const e=this.editor;e.execute("insertText",{text:"\xAD"}),e.editing.view.focus()}}export{p as Whitespace,p as default};
@@ -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 l from"@typo3/backend/link-browser.js";import o from"@typo3/backend/modal.js";import a from"@typo3/core/event/regular-event.js";import{LINK_ALLOWED_ATTRIBUTES as u,addLinkPrefix as d}from"@typo3/rte-ckeditor/plugin/typo3-link.js";import"@typo3/backend/element/combobox-element.js";class h{constructor(){this.editor=null,this.selectionStartPosition=null,this.selectionEndPosition=null}initialize(){this.editor=o.currentModal.userData.editor,this.selectionStartPosition=o.currentModal.userData.selectionStartPosition,this.selectionEndPosition=o.currentModal.userData.selectionEndPosition;const e=document.querySelector(".t3js-removeCurrentLink");e!==null&&new a("click",t=>{t.preventDefault(),this.restoreSelection(),this.editor.execute("unlink"),o.dismiss()}).bindTo(e)}finalizeFunction(e){const t=l.getLinkAttributeValues(),i=t.params?t.params:"";delete t.params;const s=this.convertAttributes(t,"");this.restoreSelection(),this.editor.execute("link",this.sanitizeLink(e,i),s),o.dismiss()}restoreSelection(){this.editor.model.change(e=>{const t=[e.createRange(this.selectionStartPosition,this.selectionEndPosition)];e.setSelection(t)})}convertAttributes(e,t){const i={attrs:{}};for(const[n,s]of Object.entries(e))u.includes(n)&&(i.attrs[d(n)]=s);return typeof t=="string"&&t!==""&&(i.linkText=t),i}sanitizeLink(e,t){const i=e.match(/^([a-z0-9]+:\/\/[^:/?#]+(?:\/?[^?#]*)?)(\??[^#]*)(#?.*)$/);if(i&&i.length>0){e=i[1]+i[2];const n=i[2].length>0?"&":"?";t.length>0&&(t.startsWith("&")&&(t=t.substr(1)),t.length>0&&(e+=n+t)),e+=i[3]}return e}}const c=new h;l.finalizeFunction=r=>{c.finalizeFunction(r)};export{c as default};