WYSIWIG Editor in MVC Widget Properties

Jim Piller asked on August 11, 2019 17:08

Hello,

I have implemented the TextEditorWidget in my current project, which is fine for simple editing. However, if the content editor wants to do something a little more complex, such as insert an image or link some text to another page in the site, this inline editor really doesn't seem to support that. My thought was to add widget properties to the TextEditorWidget component and in the properties dialog, offer the WYSIWIG editor, so that if they just need to bold some text, they can from the inline editor, but if they want to do the more complicated things, they can use the built in WYSIWIG from Kentico that works really well.

My question is, can I do this with the EditingComponent properties? Is there a property for the WYSIWIG editor? If not, how can I accomplish this?

Thanks,

Jim Piller

Correct Answer

Jim Piller answered on August 24, 2019 16:02

Sean and anyone else that stumbles across this Q & A!

I finally figured out how to extend the Medium editor in Kentico 12 SP. Thanks very much to your answers above Sean, they led me to the correct setup. Here are my steps:

  1. Add the java script file for the Medium editor extension to the folder where medium-editor.js is located. In my case, I used the Text Widget right out of the Kentico documentation examples, so it's located in /Content/InlineEditors/TextEditor/medium-editor/js/medium-editor.js
  2. At the top of the text-editor.js file, add a reference to the Medium Button extension like so:

    MediumButton = window['MediumButton'];

  3. In the buttons string array, add the name of the button that you want to add. In my case, it was just like Sean's above, "smallButton"

    buttons: ["bold", "italic", "underline", "orderedlist", "unorderedlist", "h1", "h2", "h3", "h4", "justifyLeft", "justifyCenter", "justifyRight", "smallButton"]

  4. In the extensions section, initialize the new button w/ the correct properties:

    extensions: { imageDragging: {}, smallButton: new MediumButton({ label: 'SM', start: '' }) }

NOTE: The button name has to match what you put in the string array, otherwise the button will not show up on the toolbar.

  1. Push your code to your site and that's it! The "SM" button should now appear on your toolbar!

I've included the entire code snippet that goes inside the opening function in the text-editor.js file that I'm using so that everyone can see how all the pieces come together:

window.kentico.pageBuilder.registerInlineEditor("text-editor", {
    init: function (options) {
        var editor = options.editor;

        MediumButton = window['MediumButton'];

        var config = {
            toolbar: {
              buttons: ["bold", "italic", "underline", "orderedlist", "unorderedlist", "h1", "h2", "h3", "h4", "justifyLeft", "justifyCenter", "justifyRight", "smallButton"]
            },
            imageDragging: false,
            extensions: {
                imageDragging: {},
                smallButton: new MediumButton({
                    label: '<b>SM</b>',
                    start: '<small>',
                    end: '</small>'
                })
            }
        };

        if (editor.dataset.enableFormatting === "False") {
            config.toolbar = false;
            config.keyboardCommands = false;
        }

        var mediumEditor = new MediumEditor(editor, config);

        mediumEditor.subscribe("editableInput", function () {
            var event = new CustomEvent("updateProperty", {
                detail: {
                    name: options.propertyName,
                    value: mediumEditor.getContent(),
                    refreshMarkup: false
                }
            });

            editor.dispatchEvent(event);
        });
    },

    destroy: function (options) {
        var mediumEditor = MediumEditor.getEditorFromElement(options.editor);
        if (mediumEditor) {
            mediumEditor.destroy();
        }
    },

    dragStart: function (options) {
        var mediumEditor = MediumEditor.getEditorFromElement(options.editor);
        var focusedElement = mediumEditor && mediumEditor.getFocusedElement();

        var focusedMediumEditor = focusedElement && MediumEditor.getEditorFromElement(focusedElement);
        var toolbar = focusedMediumEditor && focusedMediumEditor.getExtensionByName("toolbar");

        if (focusedElement && toolbar) {
            toolbar.hideToolbar();
            focusedElement.removeAttribute("data-medium-focused");
        }
    }
});

})

1 votesVote for this answer Unmark Correct answer

Recent Answers


Sean Wright answered on August 12, 2019 04:24 (last edited on August 12, 2019 04:27)

The built-in TextEditorWidget uses Medium Editor as the client-side library for providing rich UX.

This library is supposed to be a clone of the editor available when writing on https://medium.com/, which doesn't provide WYSIWYG functionality.

You would need to swap the "InlineEditors/_TextEditor" for a different InlineEditor for the TextWidget when the user selects the "Use WYSIWYG" option in the Widget Properties.

Edit the _TextWidget.cshtml to switch between editors.

@model  TextWidgetViewModel

@if (Context.Kentico().PageBuilder().EditMode)
{
    if (Model.UseWYSIWYG)
    {
        // Implement this yourself

        Html.RenderPartial("InlineEditors/_WYSIWYG", new WYSIWYGEditorViewModel
        {
            PropertyName = nameof(TextWidgetProperties.Text),
            Text = Model.Text
        });
    }
    else
    {
        Html.RenderPartial("InlineEditors/_TextEditor", new TextEditorViewModel
        {
            PropertyName = nameof(TextWidgetProperties.Text),
            Text = Model.Text
        });
    }
}
else
{
    @Html.Raw(Model.Text);
}

The above "InlineEditors/_WYSIWYG" and WYSIWYGEditorViewModel don't exist - you would need to create them yourself, but the existing "InlineEditors/_TextEditor" would be a good template.

You can also check the new marketplace for more Widgets and Editors https://devnet.kentico.com/marketplace.

Kentico has a GitHub repo of sample Widgets, here is their RichTextWidget (https://github.com/Kentico/ems-mvc-components/tree/master/Kentico.Widget.RichText).

0 votesVote for this answer Mark as a Correct answer

Jim Piller answered on August 12, 2019 15:03

Sean,

Thanks for the answer over the weekend, I appreciate it! I have this working to an extent in that when the content editor clicks the gear icon and goes to the properties for the widget, it displays the content in a text area. My real question is, does Kentico currently have an Editing Component property to render the WYSIWIG built into Kentico like this:

[EditingComponent(RichTextComponent.IDENTIFIER)]

or something similar to that?

Thanks,

Jim Piller

0 votesVote for this answer Mark as a Correct answer

Sean Wright answered on August 12, 2019 15:20

Ah, you want to use WSYIWYG as a form control - no I don't believe that exists currently, but it shouldn't be too hard to build.

Check out the docs covering Developing Form Components

0 votesVote for this answer Mark as a Correct answer

Jim Piller answered on August 19, 2019 23:15

Hey Sean,

So I have a follow up question. I was exploring the documentation for medium editor, which is the inline editor used in the text widget for dancing goats, and I found an extension that would allow for the insertion of tags w/ a css class name. This would go a long way to helping me w/ my WYSIWIG problem, but I'm not sure how to initialize the plugin. I have the js file downloaded and in the project, but where do I reference it so that Kentico / medium editor knows about it?

Thanks,

Jim P.

0 votesVote for this answer Mark as a Correct answer

Sean Wright answered on August 20, 2019 01:06 (last edited on August 20, 2019 07:07)

Jim,

If you have the TextEditor inline editor integrated into your MVC project, then you should have a file \Content\InlineEditors\TextEditor\medium-editor\medium-editor.js in your MVC project.

This file is where you can configure addition settings for the MediumEditor library.

You should put any addition extensions/plugins for the MediumEditor library in the same folder as medium-editor.js, but with a new file name.

For example, I'm also using MediumButton to add a button to wrap text in <small>{text}</small>.

So I also have \Content\InlineEditors\TextEditor\medium-editor\medium-button.js and I access it in my \Content\InlineEditors\TextEditor\text-editor.js like so...

MediumButton = window['MediumButton'];

config.extensions['smallButton'] = new MediumButton({
  label: '<b>SM</b>',
  start: '<small>',
  end: '</small>',
});

The object you pass to window.kentico.pageBuilder.registerInlineEditor() has an init property which is a callback function.

When that function is called, all your JavaScript libraries should be loaded and ready to use - if you try to access them on the line before window.kentico.pageBuilder.registerInlineEditor() then they might not yet be available.

0 votesVote for this answer Mark as a Correct answer

Jim Piller answered on August 20, 2019 05:36

Sean,

While trying to add the extension, I seem to have broken my text widget beyond repair. Not sure what I did to break it as the js code is right out of the training / dancing goats site, but I keep getting the error that MediumEditor is not defined. Sounds like a pathing issue to the medium-editor.js file, but again, I followed the instructions in the Kentico training and it's still broken. Any thoughts? this is my text-editor.js code.

(function () {
window.kentico.pageBuilder.registerInlineEditor("text-editor", {
    init: function (options) {
        var editor = options.editor;
        var config = {
            toolbar: {
                buttons: [
                    "bold",
                    "italic",
                    "underline",
                    "orderedlist",
                    "unorderedlist",
                    "h1",
                    "h2",
                    "h3",
                    "customHtml"
                ]
            },
            imageDragging: false,
            extensions: {
                imageDragging: {}
            }
        };

        var mediumEditor = new MediumEditor(editor, config);

        mediumEditor.subscribe("editableInput", function () {
            var event = new CustomEvent("updateProperty", {
                detail: {
                    name: options.propertyName,
                    value: mediumEditor.getContent(),
                    refreshMarkup: false
                }
            });

            editor.dispatchEvent(event);
        });
    },

    destroy: function (options) {
        var mediumEditor = MediumEditor.getEditorFromElement(options.editor);
        if (mediumEditor) {
            mediumEditor.destroy();
        }
    }
});

})();

0 votesVote for this answer Mark as a Correct answer

Sean Wright answered on August 21, 2019 23:16

Jim,

In this DevNet Article it is mentioned that

If your project is in debug mode, make sure your resources do not have “.min” in their naming as they will not be bundled since they are considered release resources, not debug. You can either simply remove the “.min” from the naming, or use the non-minified resource while in development.

Does this apply to your issues?

0 votesVote for this answer Mark as a Correct answer

Jim Piller answered on August 22, 2019 18:21

Sean,

I was able to fix the text widget by basically removing it and then re-adding it. Not sure what exactly broke, but that piece is fixed. As for extending the Medium editor, do I put the extension code in this area in the text-editor.js file:

extensions:{
    <!-- Extension code here?
}

This is the part that is confusing me.

0 votesVote for this answer Mark as a Correct answer

Sean Wright answered on August 22, 2019 19:13

I added my smallButton by adding it to the config.toolbar.buttons array.

const config = {
    toolbar: {
      buttons: [
        'bold',
        'italic',
        'underline',
        'orderedlist',
        'unorderedlist',
        'h1',
        'h2',
        'h3',
        'anchor',
        'smallButton', // <-- new button
      ],
    },
    imageDragging: false,
    extensions: {
      imageDragging: {},
    },
  };
0 votesVote for this answer Mark as a Correct answer

Jim Piller answered on August 22, 2019 19:35

And that's all you had to do? Don't you have to somehow register the Medium editor extension, or is just having the java script file in the folder enough?

0 votesVote for this answer Mark as a Correct answer

Sean Wright answered on August 24, 2019 18:15

Jim,

Just adding the new file, \Content\InlineEditors\TextEditor\medium-editor\medium-button.js, is enough, since Kentico's PageBuilder utilities automatically create a bundle including all those files.

I registered my Button extension in one of my previous answers with the following code:

MediumButton = window['MediumButton'];

config.extensions['smallButton'] = new MediumButton({
  label: '<b>SM</b>',
  start: '<small>',
  end: '</small>',
});
0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.