Skip to content

Commit

Permalink
Improve cloud injector error reporting.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mati365 committed Jan 13, 2025
1 parent ac3afb3 commit 70ea63c
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 13 deletions.
23 changes: 12 additions & 11 deletions demos/cdn-react/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CKEditorCloudDemo } from './CKEditorCloudDemo.js';
import { CKEditorCloudPluginsDemo } from './CKEditorCloudPluginsDemo.js';
import { CKEditorCKBoxCloudDemo } from './CKEditorCKBoxCloudDemo.js';
import { CKEditorCloudContextDemo } from './CKEditorCloudContextDemo.js';
import { CKEditorCloudLocalPluginsDemo } from './CKEditorCloudLocalPluginDemo.js';

const EDITOR_CONTENT = `
<h2>Sample</h2>
Expand All @@ -22,29 +23,29 @@ const EDITOR_CONTENT = `
<a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/development/custom-builds.html">custom build</a> works fine.</p>
`;

const DEMOS = [ 'Editor', 'Context', 'CKBox', 'Cloud Plugins' ] as const;
const EDITOR_CONTENT_ELEMENTS = {
Editor: <CKEditorCloudDemo content={ EDITOR_CONTENT } />,
Context: <CKEditorCloudContextDemo />,
CKBox: <CKEditorCKBoxCloudDemo content={ EDITOR_CONTENT } />,
'Cloud Plugins': <CKEditorCloudPluginsDemo content={ EDITOR_CONTENT } />,
'Cloud Local Plugins': <CKEditorCloudLocalPluginsDemo content={ EDITOR_CONTENT } />
};

type Demo = ( typeof DEMOS )[ number ];
type Demo = keyof typeof EDITOR_CONTENT_ELEMENTS;

export const App = (): ReactNode => {
const [ currentDemo, setCurrentDemo ] = useState<Demo>( 'Editor' );

const content = ( {
Editor: <CKEditorCloudDemo content={ EDITOR_CONTENT } />,
Context: <CKEditorCloudContextDemo />,
CKBox: <CKEditorCKBoxCloudDemo content={ EDITOR_CONTENT } />,
'Cloud Plugins': <CKEditorCloudPluginsDemo content={ EDITOR_CONTENT } />
} )[ currentDemo ];
const content = EDITOR_CONTENT_ELEMENTS[ currentDemo ];

return (
<React.StrictMode>
<h1>CKEditor 5 – React Component – CDN demo</h1>

<div className="buttons" style={ { textAlign: 'center' } }>
{ DEMOS.map( demo => (
{ Object.keys( EDITOR_CONTENT_ELEMENTS ).map( demo => (
<button
key={ demo }
onClick={ () => setCurrentDemo( demo ) }
onClick={ () => setCurrentDemo( demo as Demo ) }
disabled={ demo === currentDemo}
>
{ demo } demo
Expand Down
62 changes: 62 additions & 0 deletions demos/cdn-react/CKEditorCloudLocalPluginDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/

import React, { type ReactNode } from 'react';
import type { Plugin } from 'ckeditor5';

import { getCKCdnClassicEditor } from './getCKCdnClassicEditor.js';
import { CKEditor, useCKEditorCloud } from '../../src/index.js';

type CKEditorCloudLocalPluginsDemoProps = {
content: string;
};

declare global {
interface Window {
MyLocalPlugin: typeof Plugin;
}
}

export const CKEditorCloudLocalPluginsDemo = ( { content }: CKEditorCloudLocalPluginsDemoProps ): ReactNode => {
const cloud = useCKEditorCloud( {
version: '43.0.0',
plugins: {
MyLocalPlugin: [
'/demos/cdn-react/local-plugin.umd.js'
]
}
} );

if ( cloud.status !== 'success' ) {
return <div>Loading...</div>;
}

const CKEditorClassic = getCKCdnClassicEditor( {
cloud,
additionalPlugins: [
cloud.loadedPlugins.MyLocalPlugin
],
overrideConfig: {
toolbar: {
items: [
'highlight',
'|', 'undo', 'redo',
'|', 'heading',
'|', 'bold', 'italic',
'|', 'link', 'uploadImage', 'insertTable', 'blockQuote', 'mediaEmbed',
'|', 'bulletedList', 'numberedList', 'outdent', 'indent',
'|', 'MathType', 'ChemType'
]
}
}
} );

return (
<CKEditor
editor={ CKEditorClassic }
data={ content }
/>
);
};
100 changes: 100 additions & 0 deletions demos/cdn-react/local-plugin.umd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/

/* global window */

const { Plugin, Command, ButtonView } = window.CKEDITOR;

class HighlightCommand extends Command {
execute() {
const model = this.editor.model;
const selection = model.document.selection;

model.change( writer => {
const ranges = model.schema.getValidRanges( selection.getRanges(), 'highlight' );

for ( const range of ranges ) {
if ( this.value ) {
writer.removeAttribute( 'highlight', range );
} else {
writer.setAttribute( 'highlight', true, range );
}
}
} );
}

refresh() {
const model = this.editor.model;
const selection = model.document.selection;
const isAllowed = model.schema.checkAttributeInSelection( selection, 'highlight' );

this.isEnabled = isAllowed;
this.value = this.isHighlightedNodeSelected();
}

isHighlightedNodeSelected() {
const { model } = this.editor;
const { schema } = model;
const selection = model.document.selection;

if ( selection.isCollapsed ) {
return selection.hasAttribute( 'highlight' );
}

return selection.getRanges().some( range =>
Array
.from( range.getItems() )
.some( item =>
schema.checkAttribute( item, 'highlight' ) &&
item.hasAttribute( 'highlight' )
)
);
}
}

window.MyLocalPlugin = class MyCustomPlugin extends Plugin {
static get pluginName() {
return 'MyCustomPlugin';
}

init() {
const editor = this.editor;

editor.model.schema.extend( '$text', { allowAttributes: 'highlight' } );

editor.conversion.attributeToElement( {
model: 'highlight',
view: {
name: 'span',
styles: {
'background-color': 'yellow'
}
}
} );

const command = new HighlightCommand( editor );

editor.commands.add( 'highlight', command );

editor.ui.componentFactory.add( 'highlight', locale => {
const view = new ButtonView( locale );

view.bind( 'isOn' ).to( command, 'value' );
view.set( {
label: 'Highlight',
withText: true,
tooltip: true
} );

view.on( 'execute', () => {
editor.execute( 'highlight' );
editor.editing.view.focus();
} );

return view;
} );
}
};

10 changes: 10 additions & 0 deletions src/cloud/useCKEditorCloud.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import {
isCKEditorCloudLoaderError,
loadCKEditorCloud,
type CKEditorCloudConfig,
type CKEditorCloudResult
Expand Down Expand Up @@ -52,6 +53,15 @@ export default function useCKEditorCloud<Config extends CKEditorCloudConfig>(
};
}

// Expose the error in a more user-friendly way.
if ( result.status === 'error' ) {
if ( isCKEditorCloudLoaderError( result.error ) ) {
result.error.dump();
} else {
console.error( result.error );
}
}

return result;
}

Expand Down
2 changes: 0 additions & 2 deletions src/hooks/useAsyncCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ export const useAsyncCallback = <A extends Array<unknown>, R>(

return result;
} catch ( error: any ) {
console.error( error );

// Update the state if the component is still mounted and the execution UUID matches the previous one, otherwise
if ( !unmountedRef.current && prevExecutionUIDRef.current === currentExecutionUUID ) {
setAsyncState( {
Expand Down

0 comments on commit 70ea63c

Please sign in to comment.