Unable to locate Ckeditor toolbar option within Vue (Laravel) framework

Currently, I am utilizing Ckeditor5 for Vue in Laravel. In accordance with the provided documentation, I have gone ahead and installed the necessary modules using the command

npm install --save @ckeditor/ckeditor5-vue @ckeditor/ckeditor5-build-classic
. Following that, I enabled Ckeditor in the resources/js/app.js file.

import CKEditor from '@ckeditor/ckeditor5-vue';
Vue.use( CKEditor );
const app = new Vue({
    el: '#app',
});

To continue, I imported ClassicEdditor into a Vue component as shown below:

<template>
 // A lot of code here
 <div class="editor">
    <ckeditor :editor="editor" v-model="editorData" :config="editorConfig"></ckeditor>
 </div>
</template>

<script>
  import Swal from 'sweetalert2';
  import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
  import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily'; // <----- Here is the error
  export default {
    props: ['groups'],

    mounted(){

    },
    data: function(){
      return {
        // My data
        editor: ClassicEditor,
        editorData: '',
        editorConfig: {
          // The configuration of the editor.
          toolbar: {
            items: [
              'FontFamily',
              '|',
              'bold',
              'italic',
              'underline',
              'subscript',
              'superscript',
              '|',
              'List',
              'Code',
              'EasyImage',
              'ImageUpload',
              '|',
              'link',
              'undo',
              'redo'
            ]
          }
        }
      }
    },
    methods: {
      // My methods here
    }
</script>

Upon implementation, I encountered a warning in the console:

toolbarview-item-unavailable: The requested toolbar item is unavailable {name: "FontFamily"}

The Error Codes page specified that:

There was a problem processing the configuration of the toolbar. The item with the given name does not exist so it was omitted when rendering the toolbar.

In an attempt to resolve this issue, I decided to install the plugin via npm and import it into the Vue component. However, after executing:

import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily';

An error was thrown by Ckeditor:

Uncaught CKEditorError: ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated

Even after reinstalling Ckeditor, the same issue persisted.

Answer №1

It appears that you are trying to import an existing build instead of creating a build from source. Please refer to the following link for an example:

<template>
    <div id="app">
        <ckeditor :editor="editor" v-model="editorData" :config="editorConfig"gt;</ckeditor>
    </div>
</template>

<script>
    // ⚠️ NOTE: We don't use @ckeditor/ckeditor5-build-classic any longer!
    // Since we're building CKEditor from source, we now utilize the source version of ClassicEditor.
    import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

    import EssentialsPlugin from '@ckeditor/ckeditor5-essentials/src/essentials';
    import BoldPlugin from '@ckeditor/ckeditor5-basic-styles/src/bold';
    import ItalicPlugin from '@ckeditor/ckeditor5-basic-styles/src/italic';
    import LinkPlugin from '@ckeditor/ckeditor5-link/src/link';
    import ParagraphPlugin from '@ckeditor/ckeditor5-paragraph/src/paragraph';

    export default {
        name: 'app',
        data() {
            return {
                editor: ClassicEditor,
                editorData: '<p>Content of the editor.</p>',
                editorConfig: {
                    plugins: [
                        EssentialsPlugin,
                        BoldPlugin,
                        ItalicPlugin,
                        LinkPlugin,
                        ParagraphPlugin
                    ],

                    toolbar: {
                        items: [
                            'bold',
                            'italic',
                            'link',
                            'undo',
                            'redo'
                        ]
                    }
                }
            };
        }
    };
</script>

To build from source in Laravel, add the following code to your webpack.mix.js file (source: here, updated the style-loading singleton to accommodate the API change they introduced)

const CKEditorWebpackPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin');
const CKEStyles = require('@ckeditor/ckeditor5-dev-utils').styles;
const CKERegex = {
  svg: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
  css: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css/,
};

Mix.listen('configReady', webpackConfig => {
  const rules = webpackConfig.module.rules;
  const targetSVG = /(\.(png|jpe?g|gif|webp)$|^((?!font).)*\.svg$)/;
  const targetFont = /(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/;
  const targetCSS = /\.css$/;

  // exclude CKE regex from mix's default rules
  for (let rule of rules) {
    if (rule.test.toString() === targetSVG.toString()) {
      rule.exclude = CKERegex.svg;
    }
    else if (rule.test.toString() === targetFont.toString()) {
      rule.exclude = CKERegex.svg;
    }
    else if (rule.test.toString() === targetCSS.toString()) {
      rule.exclude = CKERegex.css;
    }
  }
});

mix.webpackConfig({
  plugins: [
    new CKEditorWebpackPlugin({
      language: 'nl',
      addMainLanguageTranslationsToAllAssets: true
    }),
  ],
  module: {
    rules: [
      {
        test: CKERegex.svg,
        use: ['raw-loader'],
      },
      {
        test: CKERegex.css,
        use: [
          {
            loader: 'style-loader',
            options: {
              injectType: "singletonStyleTag",
            },
          },
          {
            loader: 'postcss-loader',
            options: CKEStyles.getPostCssConfig({
              themeImporter: {
                themePath: require.resolve('@ckeditor/ckeditor5-theme-lark'),
              },
              minify: true,
            }),
          },
        ],
      },
    ],
   },
});

Remember to npm install the loaders (raw-loader, style-loader, postcss-loader) and the modules you intend to use in your CKEditor.

Answer №2

Revamped J.Otten's response tailored for Laravel Mix version 6 (Webpack v5) and CKEditor version 32.

const CustomCKEditorPlugin = require('@ckeditor/ckeditor5-dev-webpack-plugin');
const CKEditorStyles = require('@ckeditor/ckeditor5-dev-utils').styles;
//Includes SVGs and CSS files from "node_modules/ckeditor5-*" and any other custom directories
const CKEditorRegEx = {
    svg: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/, //If there are custom plugins in your project with SVG icons, add their path to this regex.
    css: /ckeditor5-[^/\\]+[/\\].+\.css$/,
};

//Exclude CKEditor regex from mix's default rules
Mix.listen('configReady', config => {
    const rules = config.module.rules;
    const targetSVG = (/(\.(png|jpe?g|gif|webp|avif)$|^((?!font).)*\.svg$)/).toString();
    const targetFont = (/(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/).toString();
    const targetCSS = (/\.p?css$/).toString();

    rules.forEach(rule => {
        let test = rule.test.toString();
        if ([targetSVG, targetFont].includes(rule.test.toString())) {
            rule.exclude = CKEditorRegEx.svg;
        } else if (test === targetCSS) {
            rule.exclude = CKEditorRegEx.css;
        }
    });
});

mix.webpackConfig({
    plugins: [
        new CustomCKEditorPlugin({
            language: 'en',
            addMainLanguageTranslationsToAllAssets: true
        }),
    ],
    module: {
        rules: [
            {
                test: CKEditorRegEx.svg,
                use: ['raw-loader']
            },
            {
                test: CKEditorRegEx.css,
                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            injectType: 'singletonStyleTag',
                            attributes: {
                                'data-cke': true
                            }
                        }
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: CKEditorStyles.getPostCssConfig({
                                themeImporter: {
                                    themePath: require.resolve('@ckeditor/ckeditor5-theme-lark')
                                },
                                minify: true
                            })
                        }
                    }
                ]
            }
        ]
    }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The ng-blur functionality will only trigger if the click event occurs within the bounds of the textbox

I am facing an issue with a textbox that should display a certain value even after being deleted. When the input is cleared and clicked away from, I want the value to reappear in the textbox. Currently, there seems to be a problem with this functionality ...

What is the best way to arrange the keys of a JavaScript object in a customized

I am struggling to find a way to custom sort a JavaScript object properly. For example, I have the following object: var test = { 'yellow': [], 'green': [], 'red': [], 'blue': [] } And an array with values ...

What is the quickest method for cycling through the most ancient elements in a collection? (Efficient way to execute a queue)

See edit too I'm currently working in JavaScript, but I believe any readable pseudocode may be able to help answer my question. Describing my issue might be a bit of a challenge, so feel free to ask for clarifications. I'll respond promptly and ...

Create a default function within a mongoose field

Is there a way to achieve the following in my code: var categorySchema = new Schema({ id: { unique: true, default: function() { //set the last item inserted id + 1 as the current value. } }, name: String }); Can this be done? ...

The Node.js engine isn't updating to support compatibility with Firebase functions

Encountered First Failure Below is the content of package.json "engines": { "node": "8.0.0" }, Error: The engines field in the functions directory's package.json is unsupported. You can choose from: {&quo ...

What type of information is typically stored in the idsrv cookie on IdentityServer4?

Looking to implement IdentityServer for the authentication aspect of my single page application. After noticing the generation of certain cookies, I delved into the documentation to learn more about the idsrv cookie. From what I gathered, besides the authe ...

Iterating through a JSON array using the JQuery .each method

Greetings! I'm trying to figure out how to access the msg -> items using jQuery's .each() method. { "msg": [ { "msg_id": "18628", "msg_userid": "12", "msg ...

What is the best way to download and execute a Javascript script in real-time using the Javascript console?

Is there a quick JavaScript console command to download and run a script from a remote source? I am interested in finding an efficient method to obtain this specific script for interactive experimentation on various pages that may not have jQuery loaded. ...

Having trouble syncing a controller with AngularJS

Despite numerous attempts, I am still struggling to make a single controller function properly. Lately, I've been working on Angular projects and no matter what I do, my controllers just won't cooperate. In my latest project, everything is withi ...

Firebase predeploy error code 254 detected

Upon attempting to deploy my website using the command firebase deploy, I encountered the following error: === Deploying to 'project'... i deploying database, functions, hosting Running command: npm --prefix "%RESOURCE_DIR%" run lint npm ERR! ...

Fill in a radio button automatically

While training on a website, I attempted to automatically fill a radio button type. However, when I used the code from the site in my Google Chrome console, it returned undefined. The website: the html: view-source:https://benalexkeen.com/autofilling-for ...

Angular: Revise information in a table row

Hi there, I am currently in the process of learning Angular and could use some assistance with a specific functionality. I have a dynamic table and a form set up, and my goal is to populate the input boxes in the form with data from any row of the dynamic ...

I keep encountering an issue where I am receiving a TypeError stating that I cannot read the property 'now' of undefined

What could be causing the error I am experiencing? Here is the relevant code snippet: this.state = { now: 0 } setInterval(function () { this.setState({ now: this.state.now + 1}); }, 100); I am attempting to increment the 'now' value ...

The functionality of ko.utils.arrayFilter is malfunctioning

I am attempting to sort out an array by excluding users who are already on a previous list: FullList: Tom, Tim, Jim, Jill UsersList: Tom, Jill With the help of a colleague, I managed to utilize this array filter. However, the issue is that the fil ...

Node development does not operate continuously

I'm facing a minor issue with node-dev. I followed the instructions in the readme file and successfully installed it. However, when I run the command like so: node-dev somescript.js, it only runs once as if I used regular node without -dev. It doesn&a ...

When stacking multiple geometries and utilizing EdgesHelper, edges may be inadvertently omitted

Having just started experimenting with three.js, I'm not entirely sure if I've made an error in my approach. You can view my demo here (use the left and right arrow keys to navigate): The issue I'm facing is that the "inner edges" are not ...

Discovering the way to retrieve background height following a window resize using jQuery

Is there a way to obtain the background height once the window has been resized? div { background-image: url(/images/somebackground.jpg); background-size: 100% 90%; background-repeat: no-repeat; width: 70%; background-size: contain; ...

Learn how to utilize the Angular reactive form to set default values based on a previously saved object

My work on the reactive form is almost complete, with all basic logic in place. However, I am facing a single issue that is holding me back. As per the requirements, all input fields should be pre-filled with previously entered data by the user, if availab ...

The bundle injected by Webpack-dev-server into the HTML page fails to display any rendered content

Whenever I execute webpack-dev-server (Command: "webpack-dev-server --mode development --open --progress --hot"), the bundle gets injected into the html page, but nothing actually appears on the screen. This is how my Webpack.config.js file looks like: v ...

Compose an abbreviated version of the function

I am facing an issue with a function that involves calling out specific states with similar lines of code. Below is the function in question: DoThis(type) { if (type === 'a') { this.setState({ activeA: { display: 'block', opac ...