GrapesJS / grapesjs

Free and Open source Web Builder Framework. Next generation tool for building templates without coding
https://grapesjs.com
BSD 3-Clause "New" or "Revised" License
22.37k stars 4.05k forks source link

How to use "append" create a structure for a side-menu in the editor and also is it possible to disable a plugin on selection of another one. #2325

Closed adityaMurarka closed 4 years ago

adityaMurarka commented 5 years ago

[Question]: 1.) I am trying to create a hamburger sidebar for the full-screen view instead of just the mobile view. But when we have dropped the plugin, on dropping any other plugin it is not getting a proper structure on the body to separate the other content and is overlapping. Is there any way to avoid it.

2.) Also on dropping of hamburger side menu, I want the Menu plugin should be disabled. Is there a way to do so.

3.) I would be very helpful if you help it implement it any other way if possible.

For reference: - I have used the menu default plugin and changed a bit to serve my purpose. I am attaching relevant files with respect to the plugin.

Index.js

`import grapesjs from 'grapesjs'; import loadBlocks from './blocks'; import loadComponents from './components'; import { hNavbarRef, navbarRef, navbarItemsRef, menuRef } from './consts';

export default grapesjs.plugins.add('ef-hamburger', (editor, opts = {}) => { let c = opts;

let defaults = { blocks: [hNavbarRef], defaultStyle: 1, navbarClsPfx: 'navbar', labelNavbar: 'navbar', labelNavbarContainer: 'Navbar Container', labelMenu: 'Navbar Menu', labelMenuLink: 'Menu link', labelBurger: 'Burger', labelBurgerLine: 'Burger Line', labelNavbarBlock: 'Hamburger', labelNavbarCategory: 'Extra', labelHome: 'Home', labelAbout: 'About', labelContact: 'Contact', };

// Load defaults for (let name in defaults) { if (!(name in c)) c[name] = defaults[name]; }

loadBlocks(editor, c); loadComponents(editor, c); }); ` consts.js

export const hNavbarRef = 'h-navbar', navbarRef = 'navbar', navbarItemsRef = 'navbar-items', menuRef = 'navbar-menu';

component.js

`export default (editor, opt = {}) => { const c = opt; const dc = editor.DomComponents; const defaultType = dc.getType('default'); const defaultModel = defaultType.model; const burgerType = 'burger-menu';

dc.addType(burgerType, {
  model: defaultModel.extend({
    defaults: {
      ...defaultModel.prototype.defaults,
      'custom-name': c.labelBurger,
      draggable: false,
      droppable: false,
      copyable: false,
      removable: false,
      script: function () {
        var transEndAdded;
        var isAnimating = 0;
        var stringCollapse = 'gjs-collapse';
        var clickEvent = 'click';
        var transitProp = 'max-height';
        var transitTiming = 'ease-in-out';
        var transitSpeed = 0.25;

        var getTransitionEvent = function() {
          var t, el = document.createElement('void');
          var transitions = {
            'transition': 'transitionend',
            'OTransition': 'oTransitionEnd',
            'MozTransition': 'transitionend',
            'WebkitTransition': 'webkitTransitionEnd'
          }

          for (t in transitions) {
            if (el.style[t] !== undefined){
              return transitions[t];
            }
          }
        }

        var transitEndEvent = getTransitionEvent();

        var getElHeight = function(el) {
          var style = window.getComputedStyle(el);
          var elDisplay = style.display;
          var elPos = style.position;
          var elVis = style.visibility;
          var currentHeight = style.height;
          var elMaxHeight = parseInt(style[transitProp]);

          if (elDisplay !== 'none' && elMaxHeight !== '0') {
            return el.offsetHeight;
          }

          el.style.height = 'auto';
          el.style.display = 'block';
          el.style.position = 'absolute';
          el.style.visibility = 'hidden';
          var height = el.offsetHeight;
          el.style.height = '';
          el.style.display = '';
          el.style.position = '';
          el.style.visibility = '';

          return height;
        };

        var toggleSlide = function(el) {
          isAnimating = 1;
          var elMaxHeight = getElHeight(el);
          var elStyle = el.style;
          elStyle.display = 'block';
          elStyle.transition = transitProp + ' ' + transitSpeed + 's ' + transitTiming;
          elStyle.overflowY = 'hidden';

          if (elStyle[transitProp] == '') {
            elStyle[transitProp] = 0;
          }

          if (parseInt(elStyle[transitProp]) == 0) {
            elStyle[transitProp] = '0';
            setTimeout(function() {
                elStyle[transitProp] = elMaxHeight + 'px';
            }, 10);
          } else {
            elStyle[transitProp] = '0';
          }
        }

        var toggle = function(e) {
          e.preventDefault();

          if (isAnimating) {
            return;
          }

          var navParent = this.closest(`[data-gjs=navbar]`);
          var navItems = navParent.querySelector(`[data-gjs=navbar-items]`);
          toggleSlide(navItems);

          if (!transEndAdded) {
            navItems.addEventListener(transitEndEvent, function() {
              isAnimating = 0;
              var itemsStyle = navItems.style;
              if (parseInt(itemsStyle[transitProp]) == 0) {
                itemsStyle.displatoggleSlidey = '';
                itemsStyle[transitProp] = '';
              }
            });
            transEndAdded = 1;
          }
        };

        if ( !(stringCollapse in this ) ) {
          this.addEventListener(clickEvent, toggle);
        }

        this[stringCollapse] = 1;
      },
    },
  }, {
    isComponent(el) {
      if(el.getAttribute &&
        el.getAttribute('data-gjs-type') == burgerType) {
        return {type: burgerType};
      }
    },
  }),
  view: defaultType.view,
});

} `

blocks.js

`import { hNavbarRef, navbarRef, navbarItemsRef, menuRef } from "./consts";

export default (editor, opt = {}) => { const c = opt; const bm = editor.BlockManager; const navbarPfx = c.navbarClsPfx || 'navbar'; const style = c.defaultStyle ? `

` : '';

  bm.add(hNavbarRef, {
    label: `
      <svg class="gjs-block-svg" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
        // <path class="gjs-block-svg-path" d="M22,9 C22,8.4 21.5,8 20.75,8 L3.25,8 C2.5,8 2,8.4 2,9 L2,15 C2,15.6 2.5,16 3.25,16 L20.75,16 C21.5,16 22,15.6 22,15 L22,9 Z M21,15 L3,15 L3,9 L21,9 L21,15 Z" fill-rule="nonzero"></path>
        <rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
        <rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
        <rect class="gjs-block-svg-path" x="15" y="10" width="5" height="1"></rect>
      </svg>
      <div class="gjs-block-label">${c.labelNavbarBlock}</div>`,
    category: 'Event Gadgets',
    content: `
    <div class = "hamburgercontainer">
    <!--    Made by Erik Terwan    -->
    <!--   24th of November 2015   -->
    <!--        MIT License        -->

      <div id="menuToggle">

        <!--
        A fake / hidden checkbox is used as click reciever,
        so you can use the :checked selector on it.
        -->
        <input type="checkbox" />

        <!--
        Some spans to act as a hamburger.

        They are acting like a real hamburger,
        not that McDonalds stuff.
        -->
        <span></span>
        <span></span>
        <span></span>

        <!--
        Too bad the menu has to be inside of the button but hey, it's pure CSS magic.
        -->

        <ul id="menu">
          <a href="#"><li>Home</li></a>
          <a href="#"><li>About</li></a>
          <a href="#"><li>Info</li></a>
          <a href="#"><li>Contact</li></a>

        </ul>
      </div>
      </div>

      ${style}
    `,
    components:[{
      tagName: 'div',
            removable: true,
            draggable: false,
            copyable: true,
            droppable:false
    }],
  });

} `

Screenshot from 2019-10-12 18-51-56 Screenshot from 2019-10-12 18-52-01

artf commented 4 years ago

If you need to customize a component read and understand how they work here: https://grapesjs.com/docs/modules/Components.html You have total control over the component in the canvas by using its View