LogoLogo
v2.2.0
v2.2.0
  • 🌸What is Petal Pro?
  • πŸ’‘Changelog
  • ⏫Upgrade guide
  • Guides
    • πŸš€Creating a web app from start to finish
    • 🌎Deploy to Fly.io
    • πŸ’³Adding a subscription
    • πŸ”’Creating Your Own API
    • πŸ”ŒContent Editor - adding your own plug-in
  • πŸ‘©β€πŸ³Recipes
    • πŸ’How to apply a recipe with git cherry pick
    • #️⃣UUIDs
    • ✍️First/Last name
    • πŸ—ΊοΈGoogle Maps
    • Password Hashing for Windows
  • Fundamentals
    • πŸ’ΏInstallation
    • πŸ“‚Folder structure
    • πŸ—ƒοΈIncluded Pages
    • πŸ˜€Users & Authentication
    • 🏒Organizations & Multitenancy
    • πŸ’³Stripe billing
    • Blog/CMS
    • πŸ””User Notifications
    • 🧊Components
    • ⬛Dark mode
    • 🎨Branding
    • 🌱Seeding
    • πŸ“„Layouts & Menus
    • πŸ–ΌοΈImage uploads
    • πŸ‘₯Impersonation
    • πŸ› οΈBackground Tasks and Jobs
    • πŸ”§Util & Helpers
    • πŸ“§Emails
    • πŸͺJavascript Hooks
    • πŸ“šExtra Hex Libraries
    • πŸ—οΈGenerators
    • πŸ—£οΈTranslations
    • πŸ–οΈContributing
    • πŸ›«Deployment
    • πŸ›‘οΈTesting
    • πŸ”’REST API
Powered by GitBook
On this page
  • Introduction
  • The Idea
  • The Folder Structure
  • Creating our Plug-in
  • Updating the Renderer
  • Installing a Third Party Plug-in

Was this helpful?

  1. Guides

Content Editor - adding your own plug-in

Adding an Editor.js plug-in and adjusting the renderer

PreviousCreating Your Own APINextRecipes

Last updated 5 months ago

Was this helpful?

Introduction

The Content Editor is currently based on . Editor.js is based on a plug-in eco-system. Petal Pro comes pre-installed with a that allow you to do common activities in a blog post (such as editing text, creating lists and tables, inserting images, etc).

However, what if you wanted to install your own Editor.js plug-in? There's nothing stopping you! There's only one extra thing to consider - the renderer needs to be adjusted to allow for the data of the new plug-in.

Though this may seem daunting. Updating the renderer is surprisingly trivial! In fact, creating your own Editor.js plug-in is pretty easy too. The rest of this guide will show you how to create your own Editor.js plug-in and adjust the Content Editor renderer.

The Idea

To start we need an idea for our plug-in. How about we build Markdown plug-in? Let's come up with some requirements:

  • User can paste their markdown text into a textarea

  • Markdown text is saved unaltered in the Editor.js json

  • Update the renderer to show html instead of markdown (using )

The Folder Structure

Before we start, it may help to provide an overview of the Petal Pro folder structure with regards to Editor.js and the Content Editor component:

β”œβ”€β”€ assets
β”‚   β”œβ”€β”€ css
β”‚   β”‚   β”œβ”€β”€ editorjs.css
β”‚   β”œβ”€β”€ js
β”‚   β”‚   β”œβ”€β”€ editorjs
β”‚   β”‚   β”‚   β”œβ”€β”€ petal-image.js
β”‚   β”‚   β”œβ”€β”€ hooks
β”‚   β”‚   β”‚   β”œβ”€β”€ editorjs-hook.js
β”‚   β”œβ”€β”€ package.json
β”œβ”€β”€ lib
β”‚   β”œβ”€β”€ petal_pro_web
β”‚   β”‚   β”œβ”€β”€ components
β”‚   β”‚   β”‚   β”œβ”€β”€ pro_components
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ content_editor.ex

Moving through the files, top to bottom:

  • editorjs.css is for Petal Pro styles that apply to Editor.js

  • editorjs-hook.js is the JavaScript hook

  • The assets folder is where package.json is kept. This is where you would install your Editor.js plug-ins

  • content-editor.ex is the component that uses the hook and where the renderer is

The plug-in that we're going to create will be placed adjacent to the petal-image.js file.

Creating our Plug-in

Create a file called /assets/js/editorjs/petal-markdown.js:

petal-markdown.js
export default class PetalMarkdown {
  static get toolbox() {
    return {
      title: "Markdown",
      icon: '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"><path stroke-linecap="round" stroke-linejoin="round" d="M5.25 8.25h15m-16.5 7.5h15m-1.8-13.5-3.9 19.5m-2.1-19.5-3.9 19.5" /></svg>',
    };
  }

  constructor({ data, block }) {
    this.data = data;
    this.block = block;
    this.wrapper = undefined;
  }

  render() {
    this.wrapper = document.createElement("div");

    const markdown_input = document.createElement("textarea");
    markdown_input.placeholder = "Paste your markdown here...";
    markdown_input.value = this.data.markdown || "";
    markdown_input.classList.add("petal-markdown");

    this.wrapper.append(markdown_input);

    return this.wrapper;
  }

  save(blockContent) {
    const markdown_input = blockContent.querySelector("textarea");

    return {
      markdown: markdown_input ? markdown_input.value : "",
    };
  }
}

The toolbox() static getter is used by Editor.js when showing the menu:

The render() method is used to generate the textarea that's displayed in the editor. Note that the petal-markdown class is added to the textarea (this is referenced in the CSS below).

Finally, the save() method is used to generate the output for the json document. It's an object with a single markdown property.

Add the following class to /assets/css/editorjs.css:

editorjs.css
/* Add this to the bottom */

.codex-editor textarea.petal-markdown {
  @apply w-full rounded-md min-h-32 bg-gray-100 dark:bg-gray-950 dark:text-gray-400 border-gray-200 dark:border-gray-600 ring-0;
}

The last step is to configure our new plug-in within the js hook. Most of the code from this file has been cut to keep the contents short. But you only need to do two things - add the import and add the tool:

editorjs-hook.js
import EditorJS from "@editorjs/editorjs";

// Add import
import PetalMarkdown from "../editorjs/petal-markdown";

const EditorJsHook = {
  mounted() {
    this.editor = new EditorJS({
      tools: {
        // Add tool
        petalMarkdown: PetalMarkdown,
      },
    });
  },
};

export default EditorJsHook;

Now in the editor, once you add a Markdown block, this is what our data entry looks like:

Now our plug-in is complete and the first two requirements are met:

  • The user can paste markdown text into a textarea; and

  • The data is saved in the output for the json.

Updating the Renderer

The final step is to update the Content Editor so that it renders the markdown as HTML. If you look in:

/lib/petal_pro_web/components/pro_components/content_editor.js

You'll see that there's a function component called content:

attr :json, :string, required: true

def content(assigns) do
  json_object = decode_json(assigns.json)

  blocks =
    case json_object do
      %{"blocks" => blocks} -> MapExt.atomize_keys(blocks)
      _ -> []
    end

  assigns = assign(assigns, :blocks, blocks)

  ~H"""
  <.block :for={block <- @blocks} block={block} />
  """
end

It decodes the Editor.js json and generates a list of blocks. It then calls the .block function component for each item in the array. The .block function uses pattern matching to render content for a plug-in. Here's what the .block function looks like for our new plug-in:

defp block(%{block: %{type: "petalMarkdown", data: %{markdown: markdown}}} = assigns) do
  assigns = assign(assigns, :markdown, markdown)

  ~H"""
  <PetalProWeb.Markdown.pretty_markdown content={@markdown} />
  """
end

In content_editor.ex this needs to be placed above the "catch all" .block function:

content_editor.ex
...

def content(assigns) do
  ...
end

attr :block, :map, required: true

...

defp block(%{block: %{type: "petalMarkdown", data: %{markdown: markdown}}} = assigns) do
  assigns = assign(assigns, :markdown, markdown)

  ~H"""
  <PetalProWeb.Markdown.pretty_markdown content={@markdown} />
  """
end

defp block(assigns) do
  ~H""
end

...

And with that, we're done! The third requirement is met:

  • The Content Editor renderer has been adjusted for our new plug-in

Installing a Third Party Plug-in

cd assets
npm add @editorjs/checklist

Then you'd have to configure the Editor.js hook:

import EditorJS from "@editorjs/editorjs";

// Add import
import CheckList from '@editorjs/checklist';

const EditorJsHook = {
  mounted() {
    this.editor = new EditorJS({
      tools: {
        // Add tool
        checkList: CheckList,
      },
    });
  },
};

export default EditorJsHook;

However, you'd still have to update the Content Editor renderer.

petal-image.js is an Editor.js plug-in that we wrote for the

We won't go into detail about the ins and outs of Editor.js. If you want to learn more, head on over to their . We'll just highlight the parts that are important to our new markdown feature.

You can choose from any of the Choose a plug-in and look for the npm command in the relevant README. For example, if you were to install the , this is what you would do at the command line:

πŸ”Œ
documentation
available plug-ins.
checklist plug-in
component
Editor.js
Earmark
set of plug-ins
File Browser
Editor.js menu
Data entry for markdown/plain text