mjawad096 / laravel-grapesjs

This package provide an esay way to integrate GrapesJS into your laravel proejct.
MIT License
107 stars 54 forks source link

How can I add add custom button for any element ? #36

Closed sergeynilov closed 2 years ago

sergeynilov commented 2 years ago

Using jd-dotlogics/laravel-grapesjs 3 in laravel 8 app Can I do custom button for elements in GrapeJS editor with possibility to enter title/url of this new custom button: https://prnt.sc/yCg4SyzkPfhD

Thanks!

ghost commented 2 years ago

@sergeynilov For this, you can create a new plugin and in that plugin you need to add a new toolbar with your logic -- You can get help regarding toolbar from this issue link

sergeynilov commented 2 years ago

Thanks for your feedback! I compare code in provided link with unpacked public/vendor/laravel-grapesjs/assets/editor.js file and see it somewhat different, I try manually edit public/vendor/laravel-grapesjs/assets/editor.js file - this way seems more convinient for me. As apart from custom button at toolbar I have to send requests to save in db custom data and read them from db when editor is opened next time. So I added the new button with line :

let elementRefs= [] // ref urls for all elements
(() => {
  var t, e = {
  ...
            cssIcons: "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css",
            icons: {
              close: '<svg viewBox="0 0 24 24"><path fill="currentColor" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"></path></svg>',
              customUrl: '<span onclick="alert(-);javascript:customUrlClick(this)"></span><svg viewBox="0 0 24 24" ><path fill="currentColor" d="M13,20H11V8L5.5,13.5L4.08,12.08L12,4.16L19.92,12.08L18.5,13.5L13,8V20Z"  /></svg><span>'
            },
  ... 

                    if (!e.get("toolbar") && t) {
                      var r = [];
                      e.collection && r.push({
                        label: t.getIcon("customUrl"), command: function (t) {

                          var url = window.prompt('Enter valid url for selected element');
                          if(url) {
                            t.id = 'a__1';
                            elementRefs.push({ // array of entered elements here
                              custom_id:t.id,
                              url:url,
                            })
                            // also I can make request to server to save entered ur.
                            console.log('AFTER elementRefs ::')
                            console.log(elementRefs)

                          }
                          return false
                          return t.runCommand("customUrlClick", {force: 1})
                        }
                      }),

But the problem is that next time opening this page in grapejs editor I need to tie all values from my db with elements to which urls were entered manually. Any hints in which part of the editor.js file elements are generated and in which way unique ID(cids,uuid etc) can be assigned to them? So that they will be the same for next times ?

sergeynilov commented 2 years ago

Could you please to open and review my question ?

ghost commented 2 years ago

@sergeynilov you should never directly edit the public/vendor/laravel-grapesjs/assets/editor.js. Instead, you should create a custom plugin to add this toolbar button in the config file

Please provide more details, so I can help you out solving this problem, like

  1. for which task do you need to add the new toolbar button? e.g a div, p, etc?
  2. What will be the functionality of this new toolbar?
sergeynilov commented 2 years ago

I need : 1) To add new custom button at toolbar 2) By clicking on this custom button to open JS prompt method 3) If prompt method was closed with success to save entered value(external url) with unique id of selected element in db with request to server. 4) next time opening this page in grapejs editor I need to tie all values from my db with elements to which urls were entered manually. So clicking on the same element for the second time user will see priorly entered value(external url) 5) Points above in “Edit” mode. When page is in “Preview” mode I need by clicking on element if it has custom data entered priorly (external url) to open this external url. 6) Can I catch clicking on any element in “Preview” mode ?

Manually editing public/vendor/laravel-grapesjs/assets/editor.js file I made 3 first points(last without posting request to server). If this task can be implemented with custom plugin please detalize in steps how can I do it.

ghost commented 2 years ago

@sergeynilov

  1. next time opening this page in grapejs editor I need to tie all values from my db with elements to which urls were entered manually. So clicking on the same element for the second time user will see priorly entered value(external URL)

Do you need to add this value in the element attribute? e.g \

... It will automatically be saved in DB when you save the editor and will be loaded next time.

Let me know if you need a different concern.

sergeynilov commented 2 years ago

Thanks for your feedback! I see it a bit different : 1) For any element on the form I need some unique custom_id and sending saving request save unique custom_id/Entered value

2) Next time when editor is opened by manager request to db must be send and these Entered value created prior sessions must be tied to any element by these unique custom_id. Can I create somehow these unique custom_id ?

3) When page is in “Preview" mode if there is a way to catch click/dblclick on any element of the page? I searched and did not find this part of code.

ghost commented 2 years ago

@sergeynilov Oh I see, but it seems that is relevant to the core grapesjs. I can only help you create a plugin that makes a new toolbar for the elements (see below) and for the other function, you need to add your custom logic.

To create a plugin create a new file at /public/js/gjs-custom-plugin.js

window.grapesjs.plugins.add('gjs-custom-plugin', function(editor, opts){
    let COMMAND_ID = 'custom-comand';

    //This will add new toolbar for all elements
    editor.on('component:selected', () => {
        const component = editor.getSelected();
        const toolbar = component.get('toolbar');

        const commandExists = toolbar.some(item => item.command === COMMAND_ID);

        // if it doesn't already exist, add it
        if (!commandExists && component.get('tagName') !== 'body') {
          let tool = {
            attributes: { 'class': 'fa fa-link' },
            command: COMMAND_ID
          };

          toolbar.splice(-2, 0, tool);

          component.set('toolbar', toolbar);
        }
    });

    //Register comand
    editor.Commands.add(COMMAND_ID, {
        run: (editor, sender) => {
            //Add your logic here, as that command will be executed when the toolbar icon will be clicked
        },
    });
});

Add Your logic to the command's call back that will be executed when the toolbar icon is clicked And then in the config file register your plugin

'plugins' => [
    'default' => [
        ...
    ],
    'custom' => [
        ...
        'gjs-custom-plugin' => 'public/js/gjs-custom-plugin.js',
        ...
    ],
],

I hope it will help you.