CKEditor5: add text when copying/cutting - events

I am trying to capture the event when a user uses copy/cut so that I can add some text at the end of the text placed into the pastebin.
On a traditional textarea I would listen to the "copy" event.
On CKEditor the appropriate event seems to be clipboardOutput.
But I am not clear now how to hook into CKEditor specific events and how to integrate into output pipeline.
Would appreciate some pointers.
I have the editor running with this code:
ClassicEditor
.create( document.querySelector( '#editor' ), { } )
.catch( error => {
console.error( error );
} );
I tried adding this code below but it doesn't seem to trigger
ClassicEditor.model.document.on( 'clipboardOutput', (eventInfo, data) => {
console.log(eventInfo, data);
} );

The clipboardOutput event is fired on view.Document instance.
You could use UpcastWriter to modify view.DocumentFragment provided in data.content property of the event data.
Example:
editor.editing.view.document.on( 'clipboardOutput', ( eventInfo, data ) => {
const writer = new UpcastWriter( editor.editing.view.document );
const paragraph = writer.createElement( 'p', null, [
writer.createText( 'foobar' )
] );
writer.appendChild( paragraph, data.content );
} );

Related

How can I add content into a CKeditor5 by clicking on an outside element

I have a few buttons outside of the Ckeditor on my page, and I want to click on them and add content to the Ckeditor5.
By clicking on the buttons, I make an ajax call to retrieve the content from the server, but I'm having trouble inserting it. This is my code right now:
success: function (data) {
ClassicEditor
.create( document.querySelector( '.ckeditor' ), {
language: 'he',
} )
.then( editor => {
editor.model.change( writer => {
const insertPosition = editor.model.document.selection.getFirstPosition();
writer.insertText(data, insertPosition );
} );
} )
.catch( error => {
console.error( error );
} );
}
But this code duplicates my editor, and I don't know how to get the "editor" object without using ".create". can anyone help me with this?

How to add values to channelData of message using hooks

I am using the Customization Plain UI sample and need to add custom data to the channelData. What is the best way to accomplish this when using this sample?
You can add a store middleware to the Customization Plain UI sample that adds custom channel data by passing a custom store as a prop to the Composer component. For more details, take a look at the Piggyback Data Web Chat Sample.
export default () => {
...
const store = useMemo(() => createStore({}, () => next => action => {
if (action.type === 'DIRECT_LINE/POST_ACTIVITY') {
action = simpleUpdateIn(
action,
['payload', 'activity', 'channelData', 'email'],
() => 'johndoe#example.com'
);
}
return next(action);
}), []);
...
return (
<React.Fragment>
...
{!!directLine && (
<Components.Composer directLine={directLine} store={store}>
<PlainWebChat />
</Components.Composer>
)}
</React.Fragment>
);
};

Can you render user message before it appears in webchat?

For MS Botframework webchat, Is there a way to intercept user message before being rendered in webchat and change it?
This is easy to accomplish using the createStore() method.
In the web chat script located in your page, create the store using the above method. In it, match the action.type to 'WEB_CHAT/SEND_MESSAGE'. This will capture every message that is passed thru the web chat component before it is displayed.
Be aware, this altered text (or whatever value you are changing) is what is sent to the bot. action is the root object. action.payload, effectively, represents the activity. This is where you will find the text value, etc.
Within the if statement, perform whatever change you are looking to make, then return the action object.
Lastly, include the store object within the renderWebChat component. This should set you up.
In the example below, I am appending text to the text field altering it before it is rendered and displayed.
<script>
( async function () {
const res = await fetch( 'http://somesite/directline/token', { method: 'POST' } );
const { token } = await res.json();
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore( {}, ( { dispatch } ) => next => action => {
if ( action.type === 'WEB_CHAT/SEND_MESSAGE' ) {
action.payload.text = action.payload.text + ' (Hello from behind the curtain)'
}
return next( action );
} );
window.WebChat.renderWebChat( {
directLine: window.WebChat.createDirectLine( { token } ),
userID: 'user123',
username: 'johndoe',
botAvatarInitials: 'BB',
userAvatarInitials: 'JD',
store
}, document.getElementById( 'webchat' ) );
document.querySelector( '#webchat > *' ).focus();
} )().catch( err => console.error( err ) );
</script>
Hope of help!

Why does CKEditor5 use a promise to initialize it?

Example:
ClassicEditor
.create( document.querySelector( '#editor' ) )
.then( editor => {
console.log( editor );
} )
.catch( error => {
console.error( error );
} );
Why would editor creation need to be asynchronous?
The editor initialization can be asynchronous because some editor features or editor UI may require asynchronous initialisation.
I'm inconcrete on purpose here. As a framework developer, I don't know what kind of features the users of the framework will want to implement. However, I know some examples from the past:
an <iframe>-based editor (iframes are initialized asynchronously), i.e. an editor in which the content is edited within an <iframe>,
real-time collaboration features which need to retrieve the content from the server.
If you're implementing a plugin which need to defer initialisation, then you can simply return a promise from its init() or afterInit() methods:
class MyPlugin extends Plugin {
init() {
return new Promise( resolve => {
// Call resolve() once your plugin is ready:
resolve();
} );
}
}

How to add a custom listener in CKEditor 4.8? editor.on is not a function

I'm trying to follow the guide of inserting a custom listener for CKEDITOR using "editor.on", inserting into ckeditor.config.js but I get
Uncaught TypeError: editor.on is not a function
I need this in order to change editor request & response to get JSON so that the uploadimage plugin can work. Any advice much appreciated.
I found a way to load it in the ckeditor.config.js that worked for me, but if you know a better way or are aware of any implications please correct me, thanks.
CKEDITOR.on( 'instanceReady', function( ev ) {
ev.editor.on // followed by the code
} );
example code for the guide above I used:
CKEDITOR.on( 'instanceReady', function( ev ) {
ev.editor.on( 'fileUploadRequest', function( evt ) {
var xhr = evt.data.fileLoader.xhr;
xhr.setRequestHeader( 'Cache-Control', 'no-cache' );
xhr.setRequestHeader( 'X-CUSTOM', 'HEADER' );
xhr.withCredentials = true;
} );

Resources