In this blog, we will learn to integrate React File Upload control to CKEditor5 (Classic Editor) using SharePoint Framework.
What is Classic Editor in CKEditor5?
Classic editor is what most users traditionally learn to associate with a rich text editor — a toolbar with an editing area placed in a specific position on the page, usually as a part of a form that you use to submit some content to the server.
Note
Ckeditor5 Classic Editor is not yet supported in IE11 browser.
The below code is tested in Chrome, Mozilla and Edge.
Code Usage
Install "ckeditor5-classic" from your node package manager console as shown below.
- PS C:\XXXX\SPFxSolutions\SpFxRichTextEditor>npm install --save ckeditor5-classic
Install "react-file-reader" from your node package manager console as shown below.
- PS C:\XXXX\SPFxSolutions\SpFxRichTextEditor>npm install --save react-file-reader
Install "office-ui-fabric-react" from your node package manager console as shown below.
- PS C:\XXXX\SPFxSolutions\SpFxRichTextEditor>npm install --save office-ui-fabric-react
Import "Classic Editor", "React File Upload" to your .tsx file as shown below.
- import ClassicEditor from 'ckeditor5-classic';
- import ReactFileReader from 'react-file-reader';
- import {Icon} from 'office-ui-fabric-react/lib/Icon';
Initiate default toolbar configuration settings for Classic Editor.
- ClassicEditor.defaultConfig = {
- toolbar: {
- items: [
- 'heading',
- '|',
- 'bold',
- 'italic',
- 'fontSize',
- 'fontFamily',
- 'fontColor',
- 'fontBackgroundColor',
- 'link',
- 'bulletedList',
- 'numberedList',
- 'imageUpload',
- 'insertTable',
- 'blockQuote',
- 'undo',
- 'redo'
- ]
- },
- image: {
- toolbar: [
- 'imageStyle:full',
- 'imageStyle:side',
- '|',
- 'imageTextAlternative'
- ]
- },
- fontFamily: {
- options: [
- 'Arial',
- 'Helvetica, sans-serif',
- 'Courier New, Courier, monospace',
- 'Georgia, serif',
- 'Lucida Sans Unicode, Lucida Grande, sans-serif',
- 'Tahoma, Geneva, sans-serif',
- 'Times New Roman, Times, serif',
- 'Trebuchet MS, Helvetica, sans-serif',
- 'Verdana, Geneva, sans-serif'
- ]
- },
- language: 'en'
- };
Declare the state variable to store ckeditor event
- export interface ICKeditorState {
- CKEditorEvent:any;
- }
Initiatlize the state variable in your constructor
- constructor(props: ISpFxRichTextEditorProps) {
- super(props);
- this.state = {
- CKEditorEvent:''
- };
- }
- }
Insert text area and React File Upload Control to render the CKeditor5 on load.
- public render(){
- return (
- <div id="fileUpload1">
- <ReactFileReader handleFiles={this.HandleFiles.bind(this)} base64={true} >
- <Icon iconName="BulkUpload" className="ms-IconExample" />
- </ReactFileReader>
- </div>
- <div>
- <textarea id="editor1"></textarea>
- </div>
- );
- }
Replace text area with CKEditor5 on componentDidMount and store in the CKeditor event in state variable.
- componentDidMount(){
- this.InitializeCKeditor();
- }
-
- public InitializeCKeditor(): void {
- try {
-
- ClassicEditor
- .create(document.querySelector("#editor1"), {
- }).then(editor => {
- console.log("CKEditor5 initiated");
- this.setState({CKEditorEvent : editor});
- }).catch(error => {
- console.log("Error in Classic Editor Create " + error);
- });
- } catch (error) {
- console.log("Error in InitializeCKeditor " + error);
- }
- }
HandleFiles - Upload to sharepoint library and retrieve the server relative url.
-
- HandleFiles = files => {
- try {
- this.HandleUploadedFiles(files, "fileUpload1", this.state.CKEditorEvent,
- "TestDocLibrary");
- } catch (error) {
- console.log("Error in HandleFiles " + error);
- }
- }
Handle Uploaded files from React file reader control
-
-
-
-
-
-
- public HandleUploadedFiles(files,fileDivId,rteEvent,DocLibPath):void{
-
- try {
- var fileExtension = this.GetFileExtension(files.fileList[0].name);
- var date = new Date();
- var guid = date.valueOf();
- var fileInternalName = files.fileList[0].name.substr(0, files.fileList[0].name.lastIndexOf('.'));
- var fileName = fileInternalName + "-" + guid + "." + fileExtension;
- var myBlob = this.Base64ToArrayBuffer(files.base64);
- this.GetFolderServerRelativeURL(myBlob, fileName,DocLibPath).then((fileURL) => {
- this.AppendToRichTextEditor(fileURL, files.fileList[0].name, fileExtension, fileDivId, rteEvent);
- }).catch((error) => {
- alert("Error while processing the promise call " + error)
- });
- } catch (error) {
- console.log("Error in HandleFiles " + error);
- }
- }
Get File Extension from the uploaded files
-
-
- public GetFileExtension(filename) {
- try{
- return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined;
- }catch(error){
- console.log("Error in Get File Extension " + error);
- }
- }
Convert base 64 image format to bytes array
-
- public Base64ToArrayBuffer(base64) {
- try {
- var binary_string = window.atob(base64.split(',')[1]);
- var len = binary_string.length;
- var bytes = new Uint8Array(len);
- for (var i = 0; i < len; i++) {
- bytes[i] = binary_string.charCodeAt(i);
- }
- return bytes.buffer;
- } catch (error) {
- console.log("Error in Base64ToArrayBuffer " + error);
- }
- }
Upload the file to sharepoint document library and get the server relative url of the uploaded file.
Note
Make sure your "webpart.ts" should contain site url and sphttpclient as shown below.
- public render(): void {
- const element: React.ReactElement<ISpFxRichTextEditorProps > = React.createElement(
- SpFxRichTextEditor,
- {
- spHttpClient: this.context.spHttpClient,
- siteUrl: this.context.pageContext.web.absoluteUrl,
- }
- );
-
- public GetFolderServerRelativeURL(file, FinalName, DocumentLibPath): Promise<any> {
- try {
- return new Promise((resolve) => {
- setTimeout(() => {
- const spOpts: ISPHttpClientOptions = {
- body: file
- };
- var redirectionURL = this.props.siteUrl + "/_api/Web/GetFolderByServerRelativeUrl('"+DocumentLibPath+"')/Files/Add(url='" + FinalName + "', overwrite=true)?$expand=ListItemAllFields"
- const response = this.props.spHttpClient.post(redirectionURL, SPHttpClient.configurations.v1, spOpts).then((response: SPHttpClientResponse) => {
- response.json().then(async (responseJSON: any) => {
- var serverRelURL = await responseJSON.ServerRelativeUrl;
- resolve(serverRelURL);
- });
- });
- }, Math.floor(Math.random() * 1000));
- });
- } catch (error) {
- console.log("Error in GetFolderServerRelativeURL " + error);
- }
-
- }
Append updated file content to CKEditor selection.
-
- public AppendToRichTextEditor(fileURL, displayName, fileExtension,fileDivId,rteEvent) {
- try {
- if (fileExtension.indexOf('png') == 0) {
- console.log('uploaded png file');
- } else {
- var appendText = '';
- var fileExt = fileExtension.toLowerCase();
- appendText = "<div id='"+fileDivId+"'><img src='/_layouts/15/images/ic" + fileExt + ".png'><a href='" + fileURL + "' >" + displayName + "</a></div>";
- const viewFragment = rteEvent.data.processor.toView(appendText);
- const modelFragment = rteEvent.data.toModel(viewFragment);
- rteEvent.model.insertContent(modelFragment, rteEvent.model.document.selection);
- }
- } catch (error) {
- console.log("Error in AppendToRichTextEditor " + error);
- }
- }
Please feel free to share your comments.
I hope this helps!!!!!