Files
cms-rte-ckeditor/Resources/Public/JavaScript/ckeditor5.js
T

14 lines
7.2 KiB
JavaScript

/*
* 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.overrides).flat(1);return r.filter(n=>!f.includes(n))}async prefixAndLoadContentsCss(){if(!Array.isArray(this.options.contentsCss))return;const o=(await Promise.allSettled(this.options.contentsCss.map(t=>this.prefixContentsCss(t,this.getAttribute("id"))))).map(t=>t.status==="fulfilled"?t.value:null).filter(t=>t!==null);o.forEach(t=>this.styleSheets.set(t,!0)),document.adoptedStyleSheets=[...document.adoptedStyleSheets,...o]}async prefixContentsCss(e,o){let t;try{t=await(await new L(e).get()).resolve()}catch(r){throw console.error(`Failed to fetch CSS content for CKEditor 5 prefixing: "${e}"`,r),new Error}const s=[`#${o} .ck-content`];this.options.toolbar.items.includes("fullscreen")&&s.push(".ck-fullscreen__editable .ck-content");let i="";for(const r of s)i+=K(t,e,r);const a=new CSSStyleSheet;return await a.replace(i),a}applyEditableElementStyles(e,o,t){const s=e.editing.view,i={"min-height":t,"min-width":o};Object.keys(i).forEach(a=>{const r=i[a];if(!r)return;let f;typeof r=="number"||!Number.isNaN(Number(f))?f=`${r}px`:f=r,s.change(n=>{n.setStyle(a,f,s.document.getRoot())})})}handleWordCountPlugin(e,o){if(e.plugins.has("WordCount")&&(o?.displayWords||o?.displayCharacters)){const t=e.plugins.get("WordCount");this.appendChild(t.wordCountContainer)}}applyReadOnly(e,o){o&&e.enableReadOnlyMode("typo3-lock")}};k([A({type:Object})],h.prototype,"options",void 0),k([O({slot:"textarea"})],h.prototype,"target",void 0),h=k([M("typo3-rte-ckeditor-ckeditor5")],h);function E(l,e){if(l!==null&&typeof l=="object"){if(Array.isArray(l))return l.map(t=>e(t)??E(t,e));const o={};for(const[t,s]of Object.entries(l))o[t]=e(s)??E(s,e);return o}return l}function C(l){return E(l,e=>{if(e!==null&&typeof e=="object"&&"pattern"in e&&typeof e.pattern=="string"){const o=e;return new RegExp(o.pattern,o.flags||void 0)}return null})}function S(l){return l.map(e=>typeof e=="string"?{module:e,exports:["default"]}:e)}export{h as CKEditor5Element};