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

BUG: getDirtyCount() non deterministic after load #5385

Closed padcom closed 1 year ago

padcom commented 1 year ago

GrapesJS version

What browser are you using?

Chrome

Reproducible demo link

https://github.com/padcom/grapesjs-bug-dirty-count-non-deterministic/blob/master/index.html

Describe the bug

Currently, when the user calls await load() the dirty count is zero. Only after the next event loop or later the count is increased. Therefore:

await editor.load()
console.log(editor.getDirtyCount())

prints out 0 but after a milisecond:

setTimeout(() => console.log(editor.getDirtyCount(), 1)

the number of changes is 1.

Expected behavior is that after awaiting the call to load(), if indeed as described in #5373 the editor is changed it should be so immediately after the call to load()



### Code of Conduct

- [X] I agree to follow this project's Code of Conduct
artf commented 1 year ago

Added also load options in order to clear the editor internal state post load

const storageOptions = {};
const loadOptions = { clear: true };
await editor.load(storageOptions, loadOptions);
editor.getDirtyCount(); // should always be 0 post load
padcom commented 1 year ago

Thank you! Looking forward to the next release!

artf commented 1 year ago

Already available here https://github.com/GrapesJS/grapesjs/releases/tag/v0.21.6

padcom commented 1 year ago

I checked the current implementation with the latest dev branch and... before the call to load() returns the storage manages to persist the changes if autosave is enabled. So the problem with saving a project that has just been loaded is still there.

The current remedy to it is to disable autoload before saving and then re-enabling it. Would you be open to making that part of the grapesjs codebase?

  async load<T extends StorageOptions>(options?: T, loadOptions: EditorLoadOptions = {}) {
    const autosave = this.Storage.config.autosave || true
    this.Storage.setAutosave(false)
    try {
      const result = await this.Storage.load(options);
      this.loadData(result);
      // Wait in order to properly update the dirty counter (#5385)
      await wait();

      if (loadOptions.clear) {
        this.UndoManager.clear();
        this.clearDirtyCount();
      }
      return result;
    } finally {
      this.Storage.setAutosave(autosave)
    }
  }
artf commented 1 year ago

I guess you can simply initialize the editor with autosave: false and run editor.Storage.setAutosave(true) right after your initial load.