Skip to content
Snippets Groups Projects
Commit 4c0a7851 authored by Benjamin Franzke's avatar Benjamin Franzke
Browse files

[TASK] Use plain script-loading for CKEditor v4

CKEditor is now loaded via a plain <script async> tag in
preparation for a transition from requirejs to ES6 modules.

CKEditor v4 is not available as ES6 module and can not easily
be transformed into a strict-mode compatible module.
CKEditor v4 requires `this` to be the global window object
in various functions, but `this` is not bound to the global
window object in strict-mode (as implied by <script type="module">).

Note: CKEditor is not a real AMD module anyway, but is configured
to be shimed by requirejs to be loadable as AMD module,
therefore it can safely be loaded using good old <script>.

Releases: main
Resolves: #96394
Related: #96323
Change-Id: Ife0b476ba29b85f85dfd654ea096cdf30c47b6ef
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72733


Tested-by: default avatarcore-ci <typo3@b13.com>
Tested-by: default avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Tested-by: default avatarBenni Mack <benni@typo3.org>
Tested-by: default avatarBenjamin Franzke <bfr@qbus.de>
Reviewed-by: default avatarAndreas Fernandez <a.fernandez@scripting-base.de>
Reviewed-by: default avatarBenni Mack <benni@typo3.org>
Reviewed-by: default avatarBenjamin Franzke <bfr@qbus.de>
parent 5e476ad6
Branches
Tags
No related merge requests found
import module from 'module';
let ckeditorPromise: Promise<typeof window.CKEDITOR>|null = null;
function loadScript(url: string): Promise<Event> {
return new Promise((resolve, reject) => {
const newScript = document.createElement('script');
newScript.async = true
newScript.onerror = reject;
newScript.onload = (ev: Event) => resolve(ev);
newScript.src = url;
document.head.appendChild(newScript);
});
}
export function loadCKEditor(): Promise<typeof window.CKEDITOR> {
if (ckeditorPromise === null) {
const scriptUrl = module.uri.replace(/\/[^\/]+\.js/, '/Contrib/ckeditor.js')
ckeditorPromise = loadScript(scriptUrl).then(() => window.CKEDITOR);
}
return ckeditorPromise;
}
......@@ -11,6 +11,7 @@
* The TYPO3 project - inspiring people to share!
*/
import {loadCKEditor} from 'TYPO3/CMS/RteCkeditor/CKEditorLoader';
import $ from 'jquery';
import FormEngine = require('TYPO3/CMS/Backend/FormEngine');
......@@ -31,7 +32,7 @@ interface CKEditorExternalPlugin {
*/
export class FormEngineInitializer {
public static initializeCKEditor(options: CKEditorOptions): void {
import('ckeditor').then(({default: CKEDITOR}) => {
loadCKEditor().then((CKEDITOR) => {
CKEDITOR.timestamp += '-' + options.configurationHash;
options.externalPlugins
.forEach((item: CKEditorExternalPlugin) => CKEDITOR.plugins.addExternal(item.name, item.resource, ''));
......
......@@ -13,7 +13,6 @@
import $ from 'jquery';
import LinkBrowser = require('TYPO3/CMS/Recordlist/LinkBrowser');
import 'ckeditor';
import Modal = require('TYPO3/CMS/Backend/Modal');
/**
......
......@@ -138,7 +138,6 @@ interface Window {
* Needed type declarations for provided libs
*/
declare module 'muuri';
declare module 'ckeditor';
declare module 'codemirror';
declare module 'flatpickr/flatpickr.min';
declare module 'flatpickr/locales';
......
......@@ -31,6 +31,8 @@ final class PageRendererRenderPreProcess
{
// @todo: Add an event to PageRenderer for registration of RequireJS configuration, see #93236
if ($pageRenderer->getApplicationType() === 'BE') {
// @todo: Unused in TYPO3 core, but kept for requirejs compatibility in backend modules.
// Remove/deprecate when requirejs is deprecated.
$pageRenderer->addRequireJsConfiguration([
'shim' => [
'ckeditor' => ['exports' => 'CKEDITOR'],
......
/*
* 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!
*/
var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","module"],(function(e,t,o){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.loadCKEditor=void 0,o=__importDefault(o);let r=null;t.loadCKEditor=function(){if(null===r){const t=o.default.uri.replace(/\/[^\/]+\.js/,"/Contrib/ckeditor.js");r=(e=t,new Promise((t,o)=>{const r=document.createElement("script");r.async=!0,r.onerror=o,r.onload=e=>t(e),r.src=e,document.head.appendChild(r)})).then(()=>window.CKEDITOR)}var e;return r}}));
\ No newline at end of file
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,i,n){void 0===n&&(n=i),Object.defineProperty(e,n,{enumerable:!0,get:function(){return t[i]}})}:function(e,t,i,n){void 0===n&&(n=i),e[n]=t[i]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)"default"!==i&&Object.prototype.hasOwnProperty.call(e,i)&&__createBinding(t,e,i);return __setModuleDefault(t,e),t},__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","jquery","TYPO3/CMS/Backend/FormEngine"],(function(e,t,i,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.FormEngineInitializer=void 0,i=__importDefault(i);t.FormEngineInitializer=class{static initializeCKEditor(t){new Promise((t,i)=>{e(["ckeditor"],t,i)}).then(__importStar).then(({default:e})=>{e.timestamp+="-"+t.configurationHash,t.externalPlugins.forEach(t=>e.plugins.addExternal(t.name,t.resource,"")),i.default(()=>{const a=t.fieldId,r="#"+i.default.escapeSelector(a);e.replace(a,t.configuration);const o=e.instances[a];o.on("change",e=>{let t=e.sender.commands;o.updateElement(),n.Validation.validateField(i.default(r)),n.Validation.markFieldAsChanged(i.default(r)),void 0!==t.maximize&&1===t.maximize.state&&o.on("maximize",e=>{i.default(this).off("maximize"),n.Validation.markFieldAsChanged(i.default(r))})}),o.on("mode",e=>{if("source"===e.editor.mode){const e=o.editable();e.attachListener(e,"change",()=>{n.Validation.markFieldAsChanged(i.default(r))})}}),document.addEventListener("inline:sorting-changed",()=>{o.destroy(),e.replace(a,t.configuration)}),document.addEventListener("formengine:flexform:sorting-changed",()=>{o.destroy(),e.replace(a,t.configuration)})})})}}}));
\ No newline at end of file
var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","TYPO3/CMS/RteCkeditor/CKEditorLoader","jquery","TYPO3/CMS/Backend/FormEngine"],(function(e,i,t,a,n){"use strict";Object.defineProperty(i,"__esModule",{value:!0}),i.FormEngineInitializer=void 0,a=__importDefault(a);i.FormEngineInitializer=class{static initializeCKEditor(e){t.loadCKEditor().then(i=>{i.timestamp+="-"+e.configurationHash,e.externalPlugins.forEach(e=>i.plugins.addExternal(e.name,e.resource,"")),a.default(()=>{const t=e.fieldId,o="#"+a.default.escapeSelector(t);i.replace(t,e.configuration);const d=i.instances[t];d.on("change",e=>{let i=e.sender.commands;d.updateElement(),n.Validation.validateField(a.default(o)),n.Validation.markFieldAsChanged(a.default(o)),void 0!==i.maximize&&1===i.maximize.state&&d.on("maximize",e=>{a.default(this).off("maximize"),n.Validation.markFieldAsChanged(a.default(o))})}),d.on("mode",e=>{if("source"===e.editor.mode){const e=d.editable();e.attachListener(e,"change",()=>{n.Validation.markFieldAsChanged(a.default(o))})}}),document.addEventListener("inline:sorting-changed",()=>{d.destroy(),i.replace(t,e.configuration)}),document.addEventListener("formengine:flexform:sorting-changed",()=>{d.destroy(),i.replace(t,e.configuration)})})})}}}));
\ No newline at end of file
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery","TYPO3/CMS/Recordlist/LinkBrowser","TYPO3/CMS/Backend/Modal","ckeditor"],(function(t,e,i,n,s){"use strict";i=__importDefault(i);class l{constructor(){this.plugin=null,this.CKEditor=null,this.ranges=[],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.default.each(e.CKEDITOR.instances,(e,i)=>{i.id===t&&(this.CKEditor=i)})}window.addEventListener("beforeunload",()=>{this.CKEditor.getSelection().selectRanges(this.ranges)}),this.ranges=this.CKEditor.getSelection().getRanges(),i.default.extend(l,i.default("body").data()),i.default(".t3js-class-selector").on("change",()=>{i.default("option:selected",this).data("linkTitle")&&i.default(".t3js-linkTitle").val(i.default("option:selected",this).data("linkTitle"))}),i.default(".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 a=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.default.each(l,(t,i)=>{e.setAttribute(t,i)});const r=t.match(/^([a-z0-9]+:\/\/[^:\/?#]+(?:\/?[^?#]*)?)(\??[^#]*)(#?.*)$/);if(r&&r.length>0){t=r[1]+r[2];const e=r[2].length>0?"&":"?";a.length>0&&("&"===a[0]&&(a=a.substr(1)),a.length>0&&(t+=e+a)),t+=r[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 a=new l;return n.finalizeFunction=t=>{a.finalizeFunction(t)},a}));
\ No newline at end of file
var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};define(["require","exports","jquery","TYPO3/CMS/Recordlist/LinkBrowser","TYPO3/CMS/Backend/Modal"],(function(t,e,i,n,s){"use strict";i=__importDefault(i);class l{constructor(){this.plugin=null,this.CKEditor=null,this.ranges=[],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.default.each(e.CKEDITOR.instances,(e,i)=>{i.id===t&&(this.CKEditor=i)})}window.addEventListener("beforeunload",()=>{this.CKEditor.getSelection().selectRanges(this.ranges)}),this.ranges=this.CKEditor.getSelection().getRanges(),i.default.extend(l,i.default("body").data()),i.default(".t3js-class-selector").on("change",()=>{i.default("option:selected",this).data("linkTitle")&&i.default(".t3js-linkTitle").val(i.default("option:selected",this).data("linkTitle"))}),i.default(".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 a=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.default.each(l,(t,i)=>{e.setAttribute(t,i)});const r=t.match(/^([a-z0-9]+:\/\/[^:\/?#]+(?:\/?[^?#]*)?)(\??[^#]*)(#?.*)$/);if(r&&r.length>0){t=r[1]+r[2];const e=r[2].length>0?"&":"?";a.length>0&&("&"===a[0]&&(a=a.substr(1)),a.length>0&&(t+=e+a)),t+=r[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 a=new l;return n.finalizeFunction=t=>{a.finalizeFunction(t)},a}));
\ 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