Skip to content

dotCMS/dotcms-block-editor-rollup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dotCMS Block Editor: Remote Extensions

The Block Editor field in dotCMS is a rich content editor that allows you to create content in units called “blocks.” Every paragraph, image, code snippet, list, etc., is stored as a block capable of being edited, drag-and-drop reordered, transformed, or deleted.

By default, the Block Editor includes a variety of pre-defined block types — including Paragraphs, Headings, Lists, Images, Tables, and Contentlets. (For more information, see the documentation.)

In dotCMS 23.03 or later, you can also extend the capabilities of the Block Editor by creating extensions and including them in your dotCMS instance.

Creating Remote Extensions

Follow these steps to expand the Block Editor's functionality by creating a new remote extension with a pre-generated example.

  1. Clone this repository

    git clone https://github.com/dotCMS/dotcms-block-editor-rollup.git
    
  2. Install the required dependencies

    At the root of the workspace, run:

    npm install
    
  3. Build the extensions

    Run the following command:

    npm run build
    

    This will generate the /dist/ folder with a compiled Javascript custom-blocks.js file inside, which contains the extensions defined in the custom-blocks project library.

  4. Browse to /dist/lib

    After running the previous command, it should generate a folder structure like the one below.

    Example of directory containing output javascript.

And just like that, you have a first extension. Now you can upload it to your dotCMS instance.

Adding the Extension to a dotCMS Block Editor Field

Take a look inside the /dist/ folder, and you'll see a compiled Javascript file, in this case named custom-blocks.js.

(Its exact file name may differ as defined in the project files — specifically, in the fileName property in /src/rollup.config.js. We recommend choosing a meaningful name!)

This file needs to be uploaded to a directory of your choice. Browse to that directory in the Site Browser — in this case, /application/block-editor/extensions — and then click the “Add” button.

Screenshot of site browser with uploaded file.

Once the file is uploaded, go to the Block Editor field's settings within the Content Type, and browse to the tab displaying its field variables. Include the new variable customBlocks (case sensitive), which defines the remote extensions in use by the Block Editor.

For its value, it requires a JSON object with the property extensions. Its value is an array of objects, each representing a new extension. At bare minimum, each object must have a url. For example:

{
	"extensions": [{
		"url": "https://local.dotcms.site:8443/application/block-editor/extensions/custom-blocks.js"
	}]
}

When added, the result should resemble the image below, which uses the parameters above.

Screenshot 2023-03-17 at 3 28 03 PM

After setting this field variable, the Block Editor's behavior will change according to the extensions you've implemented. The example extension adds an "Add" button that creates a "Hello World" block, as seen below:

Screenshot 2023-03-17 at 3 29 18 PM

Adding the Extension as a Custom Block

Suppose, instead of a button, you'd prefer for your extension to be selectable from the list of blocks. This can be achieved with just a small modifiction to the JSON we added to the Block Editor field variable.

After the url property, add a property named actions. This consists of an array of objects. Each object has three properties.

Property Description
command The extension command being invoked at block selection
menuLabel The label visible in the block list
icon The name of the Material UI icon displayed in the block list

For example, if we replace the previous customBlocks JSON with this new value, including an actions array of a single object:

{
	"extensions": [{
		"url": "https://local.dotcms.site:8443/application/block-editor/extensions/custom-blocks.js",
		"actions": [{
			"command": "addHelloWorld",
			"menuLabel": "Hello World",
			"icon": "javascript"
		}]
	}]
}

Screenshot of field variables dialog again, with new value.

... this results in a brand new block in the block list, based on the above specifications:

Screenshot of new custom button inside the block list.

Clicking this block creates the same golden "Hello World" box as earlier, as it invokes the same addHelloWorld function.

Multiple Actions

In the event of a remote extension with multiple defined commands, adding multiple blocks is as simple as adding more objects to the actions array, e.g.:

{
	"extensions": [{
		"url": "https://local.dotcms.site:8443/application/block-editor/extensions/custom-blocks.js",
		"actions": [{
			"command": "addHelloWorld",
			"menuLabel": "Custom Node",
			"icon": "javascript"
		}, {
			"command": "toggleHighlight",
			"menuLabel": "Highlight Custom",
			"icon": "highlight"
		}, {
			"command": "somethingElseEntirely",
			"menuLabel": "You Get The Idea",
			"icon": "add"
		}]
	}]
}

Creating Your Own Custom Extensions

One of the strengths of Tiptap is its extensibility. You don’t have to depend purely on its provided tools or even existing extensions; rather, you can extend the editor to your own liking.

With custom extensions you can add new blocks and new functionalities on top of what already exists — even completely from scratch. Let’s start with a few common examples of how you can extend existing nodes, marks and extensions.

First, create an initial skeleton, in which you create a Node that contains the basic functionality you're adding:

import { Node } from '@tiptap/core';

const CustomNode = Node.create({
  name: 'customNode',
  // Your code goes here, for example:
  addNodeView() {
    return () => {
        const dom = document.createElement('div');
        dom.contentEditable = 'false';
        const label = document.createElement('label');
        dom.append(label);
        return { dom };
    };
  },
})

Next, add commands that trigger the extension into the Block Editor. We'll be making use of the Tiptap addCommands() function:

    addCommands() {
      return {
         addHelloWorld: () => ({ commands }) => {
            return  commands.insertContent({ type: this.name });
         }   
      }
    },
    

You can see code resembling the above in the Typescript source from the current project: src/lib/custom-blocks.ts.

FAQ

  1. What is a Block Editor, and how does it work?

    The Block Editor is a tool for building rich text in WYSIWYG ("What You See Is What You Get") fashion. Per "rich text," it allows you to insert different kinds of content like images, videos, tables, code blocks and more into your text area.

    Each new paragraph, table, etc., is stored as an element called a "block," which is a self-contained unit of pure JSON. This makes the Block Editor portable and highly tractable for use in both traditional (through a user interface) and headless (through an API) paradigms.

  2. What is ProseMirror?

    ProseMirror describes itself as "a toolkit for building rich-text editors on the web":

    ProseMirror tries to bridge the gap between editing explicit, unambiguous content like Markdown or XML, and classical WYSIWYG editors.

    It does this by implementing a WYSIWYG-style editing interface for documents more constrained and structured than plain HTML. You can customize the shape and structure of the documents your editor creates, and tailor them to your application's needs.

  3. What is Tiptap?

    Tiptap is "a headless wrapper around ProseMirror":

    Tiptap comes with sensible defaults, a lot of extensions and a friendly API to customize every aspect. It’s backed by a welcoming community, open source, and free.

    Tiptap does not provide a user interface, but offers robust tools for building your own. The Block Editor was built using these tools.

  4. What is Rollup?

    Rollup is a module bundler for JavaScript which compiles small pieces of code into something larger and more complex, such as a library or application.

  5. Where can I find the Material UI Icons?

    The Material UI Icons can be found in Google Fonts. Use the icon name as the value of the icon property in the customBlocks JSON.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published