• Techblog369, India
  • March 27, 2023

How To Configure A Sendinblue SMTP Relay in Postfix?

Fix Email Issues in CyberPanel with SMTP Relay Setup Free Method. First Create a email using your Cyberpanel Under Emai Tab Create Email Second go to the SSL tab and click …

Create a simple password strength indicator with JavaScript

You’ve probably seen many examples of password strength indicators around the web. They let users know the password they’re using is weak and indicate how the strength changes when it’s modified. …

Install CKEditor on Strapi, In this guide, we will see how you can create a new Field for your administration panel

Step1

Generate a plugin

cd your-projectfolder

yarn strapi generate:plugin wysiwyg

Step2

Install the needed dependencies

cd plugins/wysiwyg
yarn add @ckeditor/ckeditor5-react @ckeditor/ckeditor5-build-classic

Step3

# Go back to strapi root folder

it will work only yarn, not npm. watch-admin help for project rebuilding automatically

cd ../..
yarn develop --watch-admin

Step4

Creating the MediaLib

Make folder components/MediaLib/index.js under ./plugins/wysiwyg/admin/src/
The path looks like that

./plugins/wysiwyg/admin/src/components/MediaLib/index.js

Then Paste the bellow code

import React, { useEffect, useState } from ‘react’;
import { useStrapi, prefixFileUrlWithBackendUrl } from ‘strapi-helper-plugin’;
import PropTypes from ‘prop-types’;

const MediaLib = ({ isOpen, onChange, onToggle }) => {
   const {
       strapi: {
           componentApi: { getComponent },
       },
   } = useStrapi();
   const [data, setData] = useState(null);
   const [isDisplayed, setIsDisplayed] = useState(false);

   useEffect(() => {
       if (isOpen) {
           setIsDisplayed(true);
       }
   }, [isOpen]);

   const Component = getComponent(‘media-library’).Component;

   const handleInputChange = data => {
       if (data) {
           const { url } = data;

           setData({ …data, url: prefixFileUrlWithBackendUrl(url) });
       }
   };

   const handleClosed = () => {
       if (data) {
           onChange(data);
       }

       setData(null);
       setIsDisplayed(false);
   };

   if (Component && isDisplayed) {
       return (
           <Component
               allowedTypes={[‘images’, ‘videos’, ‘files’]}
               isOpen={isOpen}
               multiple={false}
               noNavigation
               onClosed={handleClosed}
               onInputMediaChange={handleInputChange}
               onToggle={onToggle}
           />
       );
   }

   return null;
};

MediaLib.defaultProps = {
   isOpen: false,
   onChange: () => { },
   onToggle: () => { },
};

MediaLib.propTypes = {
   isOpen: PropTypes.bool,
   onChange: PropTypes.func,
   onToggle: PropTypes.func,
};

export default MediaLib;

Step5

Creating the WYSIWYG Wrapper

Path  ./plugins/wysiwyg/admin/src/components/Wysiwyg/index.js

Paste the below code in index.js

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { Button } from '@buffetjs/core';
import { Label, InputDescription, InputErrors } from 'strapi-helper-plugin';
import Editor from '../CKEditor';
import MediaLib from '../MediaLib';

const Wysiwyg = ({
   inputDescription,
   errors,
   label,
   name,
   noErrorsDescription,
   onChange,
   value,
}) => {
   const [isOpen, setIsOpen] = useState(false);
   let spacer = !isEmpty(inputDescription) ? <div style={{ height: '.4rem' }} /> : <div />;

   if (!noErrorsDescription && !isEmpty(errors)) {
       spacer = <div />;
   }

   const handleChange = data => {
       if (data.mime.includes('image')) {
           const imgTag = `<p><img src="${data.url}" caption="${data.caption}" alt="${data.alternativeText}"></img></p>`;
           const newValue = value ? `${value}${imgTag}` : imgTag;

           onChange({ target: { name, value: newValue } });
       }

       // Handle videos and other type of files by adding some code
   };

   const handleToggle = () => setIsOpen(prev => !prev);

   return (
       <div
           style={{
               marginBottom: '1.6rem',
               fontSize: '1.3rem',
               fontFamily: 'Lato',
           }}
       >
           <Label htmlFor={name} message={label} style={{ marginBottom: 10 }} />
           <div>
               <Button color="primary" onClick={handleToggle}>
                   MediaLib
       </Button>
           </div>
           <Editor name={name} onChange={onChange} value={value} />
           <InputDescription
               message={inputDescription}
               style={!isEmpty(inputDescription) ? { marginTop: '1.4rem' } : {}}
           />
           <InputErrors errors={(!noErrorsDescription && errors) || []} name={name} />
           {spacer}
           <MediaLib onToggle={handleToggle} isOpen={isOpen} onChange={handleChange} />
       </div>
   );
};

Wysiwyg.defaultProps = {
   errors: [],
   inputDescription: null,
   label: '',
   noErrorsDescription: false,
   value: '',
};

Wysiwyg.propTypes = {
   errors: PropTypes.array,
   inputDescription: PropTypes.oneOfType([
       PropTypes.string,
       PropTypes.func,
       PropTypes.shape({
           id: PropTypes.string,
           params: PropTypes.object,
       }),
   ]),
   label: PropTypes.oneOfType([
       PropTypes.string,
       PropTypes.func,
       PropTypes.shape({
           id: PropTypes.string,
           params: PropTypes.object,
       }),
   ]),
   name: PropTypes.string.isRequired,
   noErrorsDescription: PropTypes.bool,
   onChange: PropTypes.func.isRequired,
   value: PropTypes.string,
};

export default Wysiwyg;

Step6

Implementing CKEditor
Path ./plugins/wysiwyg/admin/src/components/CKEditor/index.js
Paste the below code

import React from 'react';
import PropTypes from 'prop-types';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import styled from 'styled-components';

const Wrapper = styled.div`
 .ck-editor__main {
   min-height: 200px;
   > div {
     min-height: 200px;
   }
 }
`;

const configuration = {
   toolbar: [
       'heading',
       '|',
       'bold',
       'italic',
       'link',
       'bulletedList',
       'numberedList',
       '|',
       'indent',
       'outdent',
       '|',
       'blockQuote',
       'insertTable',
       'mediaEmbed',
       'undo',
       'redo',
   ],
};

const Editor = ({ onChange, name, value }) => {
   return (
       <Wrapper>
           <CKEditor
               editor={ClassicEditor}
               config={configuration}
               data={value}
               onReady={editor => editor.setData(value)}
               onChange={(event, editor) => {
                   const data = editor.getData();
                   onChange({ target: { name, value: data } });
               }}
           />
       </Wrapper>
   );
};

Editor.propTypes = {
   onChange: PropTypes.func.isRequired,
   name: PropTypes.string.isRequired,
   value: PropTypes.string,
};

export default Editor;

At this point, we have simply created a new plugin that is mounted in our project but our custom Field has not been
registered yet.

Registering a our new Field

Path — ./plugins/wysiwyg/admin/src/index.js

import pluginPkg from '../../package.json';
import Wysiwyg from './components/Wysiwyg';
import pluginId from './pluginId';
import App from './containers/App';
import Initializer from './containers/Initializer';
import lifecycles from './lifecycles';
import trads from './translations';

export default strapi => {
 const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
 const icon = pluginPkg.strapi.icon;
 const name = pluginPkg.strapi.name;

 const plugin = {
   blockerComponent: null,
   blockerComponentProps: {},
   description: pluginDescription,
   icon,
   id: pluginId,
   initializer: Initializer,
   injectedComponents: [],
   isReady: false,
   isRequired: pluginPkg.strapi.required || false,
   layout: null,
   lifecycles,
   mainComponent: null,
   name,
   preventComponentRendering: false,
   trads,
   // menu: {
   //   pluginsSectionLinks: [
   //     {
   //       destination: `/plugins/${pluginId}`,
   //       icon,
   //       label: {
   //         id: `${pluginId}.plugin.name`,
   //         defaultMessage: name,
   //       },
   //       name,
   //       permissions: [
   //         // Uncomment to set the permissions of the plugin here
   //         // {
   //         //   action: '', // the action name should be plugins::plugin-name.actionType
   //         //   subject: null,
   //         // },
   //       ],
   //     },
   //   ],
   //},
 };
 strapi.registerField({ type: 'wysiwyg', Component: Wysiwyg });
 return strapi.registerPlugin(plugin);
};

Finally, you will have to rebuild strapi so the new plugin is loaded correctly

yarn build

If you want to remove WYSIWYG from your plugin folder then just remove the below code from .plugins/wysiwyg/admin/src/index.js

// menu: {
   //   pluginsSectionLinks: [
   //     {
   //       destination: `/plugins/${pluginId}`,
   //       icon,
   //       label: {
   //         id: `${pluginId}.plugin.name`,
   //         defaultMessage: name,
   //       },
   //       name,
   //       permissions: [
   //         // Uncomment to set the permissions of the plugin here
   //         // {
   //         //   action: '', // the action name should be plugins::plugin-name.actionType
   //         //   subject: null,
   //         // },
   //       ],
   //     },
   //   ],
   //},

Author

nw.ippm@gmail.com

Leave a Reply

Your email address will not be published. Required fields are marked *