Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom blocks #33

Closed
wants to merge 5 commits into from
Closed

Custom blocks #33

wants to merge 5 commits into from

Conversation

roelofr
Copy link
Collaborator

@roelofr roelofr commented Nov 17, 2019

Added support for custom blocks, via pluggable methods.

Closes #19.

How to use

Usage is split two-way: showing the block and rendering the HTML.

To show the block

  1. Register block in Javascript (as if you're registering a new Nova Field)
  2. Tap into window.novaEditorjsFields.tools
  3. Register block when you get the list of tools
  4. Return tools

To render the HTML

  1. Add your block validation to the nova-editorjs-php.php config. See editorjs-php.
  2. Register Macro on NovaEditorJs
  3. Done.

Example

We want to register the SimpleImage block from the The firt plugin tutorial.

  1. We create the block (see the tutorial)
  2. We register the block as a global
    const ImagePlugin = require('./image-plugin')
    
    if (!window.novaEditorjsFields) {
        window.novaEditorjsFields = {}
    }
    if (!window.novaEditorjsFields.tools) {
        window.novaEditorjsFields.tools = []
    }
    window.novaEditorjsFields.tools.push(tools => {
        tools.image = ImagePlugin
        return tools
    })
    The plugin is now automatically loaded when a new EditorJS is created
  3. Add the macro to convert to HTML in your Service Provider:
    use Advoor\NovaEditorJs\NovaEditorJs;
    
    // […]
    
    // ServiceProvider
    public function boot()
    {   
        NovaEditorJs::macro('renderImageField', function ($data) {
            return "<img src=\"{$data['url']}\" />";
        });
    }
  4. Done, in theory.

To do

  • Add Javascript hook
  • Add PHP Macro
  • Add test scenarios
  • Update Readme

@roelofr roelofr requested a review from advoor November 17, 2019 21:12
@roelofr roelofr mentioned this pull request Nov 17, 2019
@roelofr
Copy link
Collaborator Author

roelofr commented Nov 19, 2019

I'd really like some feedback on people who use this and want to add custom blocks. Does this seem like a good method to do this, or would you rather have a different solution?

@stevelacey
Copy link

stevelacey commented Jan 14, 2020

Nice work with this. I made progress without any tremendous effort at all.

You have a call to $this in a static context in NovaEditorJs.php, which was the only tweak I had to make to get this to work – but it raised the question of why I'm needing to use macroable behaviours at all, I'd change it to this, and leverage the existing template approach:

default:
    $htmlOutput .= view("nova-editor-js::{$block['type']}", $block['data'])->render();

The nova-editor-js views are already publishable, so adding extra ones for any additional plugins that are written or installed is no big ask. I chucked a basic quote template in that looked like this:

<div class="editor-js-block">
    <blockquote class="text-{{ $alignment }}">
        {{ $text }}
    </blockquote>

    @if (!empty($caption))
        <caption>{{ $caption }}</caption>
    @endif
</div>

The js I needed to be able to install the Quote plugin was pretty much as per your description:

const Quote = require('@editorjs/quote');

if (!window.novaEditorjsFields) {
    window.novaEditorjsFields = {}
}

if (!window.novaEditorjsFields.tools) {
    window.novaEditorjsFields.tools = []
}

window.novaEditorjsFields.tools.push(tools => {
    tools.quote = Quote
    return tools
})

Plus the config it requires:

            'quote' => [
                'text' => [
                    'type' => 'string',
                ],
                'caption' => [
                    'type' => 'string',
                    'required' => false,
                ],
                'alignment' => [
                    'type' => 'string',
                ],
            ],

You didn't provide an explanation for where I should be providing this JS... I stuffed it in this way in NovaServiceProvider, and added a new js output file into my webpack config, meh, works:

Nova::$scripts['nova-custom-js'] = public_path('/js/nova.js');

I might be nova-noobing with the above js injection approach, tips appreciated if there's an easy way to improve on this.

In terms of improving the experience for other NovaEditorJs users who want to add custom blocks, in lieu of any better ideas, I'd wrap up the window.novaEditorjsFields stuff in a js package, so that consumers interact with some sort of registry instead of directly stuffing things onto window themselves (even if that's still what's happening under the hood), something like:

const NovaEditor = require('nova-editor-js');
const Quote = require('@editorjs/quote');

NovaEditor.register(Quote);

Alternatively, write something that scaffolds that js from php, so we don't have to touch it at all (perhaps that's hard, where would the plugin come from) – either way I'd say this is sufficiently usable.

@roelofr
Copy link
Collaborator Author

roelofr commented Jul 31, 2020

This solution might work, but the code that @TheDeadCode made is a lot cleaner and I'd recommend using that.

Closing this.

@roelofr roelofr closed this Jul 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

how to add new tools?
2 participants