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.38k stars 4.05k forks source link

BUG: (0.16.41) Components have lost their styles #3289

Closed bgrand-ch closed 3 years ago

bgrand-ch commented 3 years ago

Version: 0.16.41

Are you able to reproduce the bug from the demo?

[X] Yes [ ] No

What is the expected behavior?

1) Copy selected parent component (container) to the clipboard. 2) Paste selected parent component (container) from the clipboard (into the same page or an other page). 3) All components keep ID styles and inline styles.

What is the current behavior?

1) Copy selected parent component (container) to the clipboard. 2) Paste selected parent component (container) from the clipboard (into the same page or an other page). 3) Components have lost their ID styles, but not their inline styles.

Components don't have a regenerated style ID, but the same previous ID with a "-2" appended.

Are you able to attach screenshots, screencasts or a live demo?

[X] Yes (attach) [ ] No

https://jsfiddle.net/bgrand_ch/71yuz26p/33/

From the jsfiddle above, follow the next steps :

1) Select one component. 2) Copy this component with Ctrl/Cmd + C. 3) Paste the copied component with Ctrl/Cmd + V. 4) All defined style have lost, inline style have preserved.

Copy-paste plugin (with Quasar notifications system):

import { Notify } from 'quasar'

/**
 * Copy paste into same page and between pages
 * @see https://grapesjs.com/docs/modules/Plugins.html
 * @param {object} editor
 * @param {object} options
 * @returns {void}
 */
export default function (editor, options) {
  /**
   * Copy a component to clipboard
   * @see https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText
   * @returns {void}
   */
  editor.Commands.add('core:copy', async () => {
    let timeoutId = null

    try {
      timeoutId = showNotification({
        message: 'Élément en cours de copie...',
        type: 'info',
        timeout: 600
      })

      await navigator.clipboard.writeText(
        JSON.stringify(
          getSelectedParent()
        )
      )

      showNotification({
        message: 'Élément copié avec succès !',
        type: 'success'
      })
    } catch (error) {
      showNotification({
        message: 'Impossible de copier l\'élément.',
        error
      })
    } finally {
      clearTimeout(timeoutId)
    }
  })

  /**
   * Paste a component from clipboard
   * @see https://grapesjs.com/docs/api/editor.html
   * @see https://grapesjs.com/docs/api/component.html
   * @see https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/readText
   * @returns {void}
   */
  editor.Commands.add('core:paste', async () => {
    let timeoutId = null

    try {
      timeoutId = showNotification({
        message: 'Élément en cours de collage...',
        type: 'info',
        timeout: 600
      })

      const selectedParent = JSON.parse(
        await navigator.clipboard.readText()
      )

      editor.getWrapper().append(selectedParent, {
        at: getSelectedParent().index() + 1
      })

      showNotification({
        message: 'Élément collé avec succès !',
        type: 'success'
      })
    } catch (error) {
      showNotification({
        message: 'Impossible de coller l\'élément.',
        error
      })
    } finally {
      clearTimeout(timeoutId)
    }
  })

  /**
   * Retrieves the parent component
   * @see https://grapesjs.com/docs/api/editor.html
   * @see https://grapesjs.com/docs/api/component.html
   * @returns {object}
   */
  function getSelectedParent () {
    return editor
      .getSelected()
      .closest(options?.parentSelector || '#wrapper > div')
  }

  /**
   * Shows a notification to the user
   * @see https://quasar.dev/quasar-plugins/notify
   * @param {string} message
   * @param {string} [type]
   * @param {object} [error]
   * @param {number} [timeout]
   * @returns {number|void}
   */
  function showNotification ({
    message,
    type = 'error',
    error = {},
    timeout = 0
  } = {}) {
    const notifType = {
      info: { icon: 'info', color: 'blue' },
      success: { icon: 'check_circle', color: 'green' },
      error: { icon: 'error', color: 'red' }
    }
    const options = {
      message,
      color: notifType[type].color,
      icon: notifType[type].icon
    }

    if (error instanceof Error) {
      options.caption = `Pour l'IT : ${error?.message}`
    }

    const notify = () => Notify.create(options)

    if (timeout > 0) {
      return setTimeout(() => notify(), timeout)
    }

    notify()
  }
}
artf commented 3 years ago

That because you've updated original commands with your versions (incorrectly). Indeed, if I remove your plugin from the demo everything works as expected. Please check the original copy and paste command, you should clone components before paste, so, your implementation couldn't work.

bgrand-ch commented 3 years ago

@artf Thanks for your answer. A link or an example or more explanations please? 😅

artf commented 3 years ago

Just check the original commands https://github.com/artf/grapesjs/blob/dev/src/commands/view/CopyComponent.js https://github.com/artf/grapesjs/blob/dev/src/commands/view/PasteComponent.js